Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comply with html reporter format #160

Merged
merged 48 commits into from Mar 20, 2019
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
460023f
WIP: Start on mapper
legopiraat Aug 6, 2018
93eba12
WIP: First setup to generate classes based on the html reporter spec
legopiraat Aug 9, 2018
86e7c77
Fill in a few more fields
legopiraat Aug 12, 2018
8e3cb2a
Add file source to report structure
legopiraat Aug 12, 2018
f3f6fae
Add plumbing so we can validate the html reporter output against the …
legopiraat Sep 1, 2018
c0b60c7
Merge branch 'master' into HTML-Reporter
legopiraat Sep 20, 2018
b8b7c5e
Merge branch 'HTML-Reporter' into Comply-html-reporter-format
legopiraat Sep 20, 2018
2f6779e
Add names to mutants so we can have it in the html report
legopiraat Sep 20, 2018
55329ce
Merge branch 'Mutant-name-for-html-report' into Comply-html-reporter-…
legopiraat Sep 20, 2018
17680bf
Add html reporter to list of available reporters + add mutator name t…
legopiraat Sep 20, 2018
aa90691
Add test to make sure multiple reporters are invoked when specified
legopiraat Sep 20, 2018
d9153d0
Merge branch 'master' of https://github.com/stryker-mutator/stryker4s…
legopiraat Jan 20, 2019
e081c48
More of the merge
legopiraat Jan 20, 2019
cfc2522
Add location
legopiraat Jan 20, 2019
fbdb58e
Cleanup tests and add schema in resources
hugo-vrijswijk Feb 19, 2019
e00f474
Add test for validating generated json
hugo-vrijswijk Feb 19, 2019
632fe0b
Update everit-json-schema version (using jitpack now)
hugo-vrijswijk Feb 19, 2019
3441459
WIP
hugo-vrijswijk Feb 19, 2019
514dc4f
Merge remote-tracking branch 'origin/master' into Comply-html-reporte…
hugo-vrijswijk Feb 19, 2019
a9ffa5b
Remove Circe parser dependency (no parsing is done, only writing)
hugo-vrijswijk Feb 19, 2019
a548118
Redo html report case classes
hugo-vrijswijk Feb 19, 2019
cf1d7ed
WIP: Add test for mapping validation
hugo-vrijswijk Feb 19, 2019
3abff6b
WIP
hugo-vrijswijk Feb 19, 2019
1a2bf82
Fix rename issue
hugo-vrijswijk Feb 19, 2019
6a9889e
Add new flat structure report schema
hugo-vrijswijk Feb 21, 2019
1b36880
Move reporter to stryker4s.report package and add new report case cla…
hugo-vrijswijk Feb 21, 2019
ab84208
Move tests and replace report json with new version
hugo-vrijswijk Feb 21, 2019
92bdae4
Implement MutantMapper and add tests
hugo-vrijswijk Feb 21, 2019
aa3d36f
Add html report files to resources
hugo-vrijswijk Feb 21, 2019
ab2a0a3
Fix mapper not finding correct file source
hugo-vrijswijk Feb 22, 2019
f92dde3
Fix html reporter
hugo-vrijswijk Feb 22, 2019
f9ac27d
Fix test not finding files
hugo-vrijswijk Feb 22, 2019
6d64b56
Remove stryker4s.conf
Wmaarts Feb 22, 2019
5d818bb
Small refactorings and comments
hugo-vrijswijk Feb 22, 2019
564eb52
Remove unused code
hugo-vrijswijk Feb 22, 2019
a582084
Merge branch 'feat-html-reporter' into Comply-html-reporter-format
hugo-vrijswijk Feb 25, 2019
683435a
Formatting
hugo-vrijswijk Feb 25, 2019
00ec106
Ugly-print json and add test
hugo-vrijswijk Feb 27, 2019
308d05e
Update mutation-test-elements.js to v0.0.7
hugo-vrijswijk Feb 27, 2019
d1cf0bd
Remove generated sources, and fetch them as a dependency from webjars…
hugo-vrijswijk Mar 17, 2019
36a6916
Merge remote-tracking branch 'origin/master' into Comply-html-reporte…
hugo-vrijswijk Mar 17, 2019
ccddc52
Move report modelclasses into single file
hugo-vrijswijk Mar 17, 2019
faa01e5
Small renaming in MutantRunResultMapper
hugo-vrijswijk Mar 17, 2019
bfc5431
Fix and simplify MutantRunResultMapperTest
hugo-vrijswijk Mar 17, 2019
34eadd4
Edit html config documentation
hugo-vrijswijk Mar 17, 2019
d2b75d2
Fix test
hugo-vrijswijk Mar 17, 2019
cc072dc
Update to v1.0.1 of mutation-testing-report
hugo-vrijswijk Mar 18, 2019
40ec153
Merge remote-tracking branch 'origin/master' into Comply-html-reporte…
hugo-vrijswijk Mar 20, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 0 additions & 1 deletion core/src/main/scala/stryker4s/config/Config.scala
@@ -1,7 +1,6 @@
package stryker4s.config

import better.files._
import org.apache.logging.log4j.Level
import pureconfig.ConfigWriter

case class Config(mutate: Seq[String] = Seq("**/main/scala/**/*.scala"),
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/scala/stryker4s/config/ReporterType.scala
Expand Up @@ -7,3 +7,7 @@ sealed trait ReporterType {
case object ConsoleReporterType extends ReporterType {
override val name: String = "console"
}

case object HtmlReporterType extends ReporterType {
override val name: String = "html"
}
Expand Up @@ -4,7 +4,7 @@ import java.nio.file.Path

import better.files.File
import pureconfig.ConfigReader
import stryker4s.config.{ConsoleReporterType, ExcludedMutations, ReporterType}
import stryker4s.config.{ConsoleReporterType, ExcludedMutations, HtmlReporterType, ReporterType}

trait ConfigReaderImplicits {

Expand All @@ -17,6 +17,7 @@ trait ConfigReaderImplicits {
private[config] implicit val toReporterList: ConfigReader[ReporterType] =
ConfigReader[String] map {
case ConsoleReporterType.name => ConsoleReporterType
case HtmlReporterType.name => HtmlReporterType
}

private[config] implicit val exclusions: ConfigReader[ExcludedMutations] =
Expand Down
Expand Up @@ -4,7 +4,6 @@ import java.nio.file.Path

import better.files.File
import com.typesafe.config.ConfigRenderOptions
import org.apache.logging.log4j.Level
import pureconfig.ConfigWriter
import stryker4s.config.{ExcludedMutations, ReporterType}

Expand Down
34 changes: 34 additions & 0 deletions core/src/main/scala/stryker4s/report/HtmlReporter.scala
@@ -0,0 +1,34 @@
package stryker4s.report
import better.files.Resource
import stryker4s.config.Config
import stryker4s.model.MutantRunResults
import stryker4s.report.mapper.MutantRunResultMapper

class HtmlReporter(implicit config: Config) extends FinishedRunReporter with MutantRunResultMapper {

private val reportVersion = "0.0.7"

def indexHtml(json: String): String = {
val mutationTestElementsScript = Resource.getAsString(
s"META-INF/resources/webjars/mutation-testing-elements/$reportVersion/dist/mutation-test-elements.js")

s"""<!DOCTYPE html>
|<html>
|<body>
| <mutation-test-report-app title-postfix="Stryker4s report"></mutation-test-report-app>
| <script>
| document.querySelector('mutation-test-report-app').report = $json
| </script>
| <script>
| $mutationTestElementsScript
| </script>
|</body>
|</html>""".stripMargin
}

override def reportRunFinished(runResults: MutantRunResults): Unit = {
val mapped = toReport(runResults).toJson

println(mapped)
}
}
3 changes: 2 additions & 1 deletion core/src/main/scala/stryker4s/report/Reporter.scala
@@ -1,13 +1,14 @@
package stryker4s.report

import stryker4s.config.{Config, ConsoleReporterType}
import stryker4s.config.{Config, ConsoleReporterType, HtmlReporterType}
import stryker4s.model.{Mutant, MutantRunResult, MutantRunResults}

class Reporter(implicit config: Config) extends FinishedRunReporter with ProgressReporter {

def reporters: Seq[MutationRunReporter] = {
config.reporters collect {
case ConsoleReporterType => new ConsoleReporter()
case HtmlReporterType => new HtmlReporter()
}
}

Expand Down
@@ -0,0 +1,61 @@
package stryker4s.report.mapper
import java.nio.file.Path

import stryker4s.config.{Config, Thresholds => ConfigThresholds}
import stryker4s.model._
import stryker4s.report.model.MutantStatus.MutantStatus
import stryker4s.report.model._

trait MutantRunResultMapper {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a couple of thoughts about this trait.

  1. There's one test that covers all the methods, shouldn't we split this up more? That way if a test fails it's easier to identify where the bug is, but I'm not sure how important that is.
  2. If we're not going to do nr 1, all of these methods can be marked private except toReport, if I'm correct.
  3. The method names slightly throw me off. i.e. toLocation makes more sense as an extension method. Now for example you're calling toMutantStatus, but I'm thinking: "you're going to MutantStatus... from where exactly?" if that makes sense. To me something like mapRunResultToMutantStatus makes more sense.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1. There's one test that covers all the methods, shouldn't we split this up more? That way if a test fails it's easier to identify where the bug is, but I'm not sure how important that is.

I agree. The single test is a bit massive. The thing is though is that the 'top' map function calls the other functions anyway. So then having tests for the 'smaller' functions is a bit redundant

3. The method names slightly throw me off. i.e. `toLocation` makes more sense as an extension method. Now for example you're calling `toMutantStatus`, but I'm thinking: "you're going to MutantStatus... from where exactly?" if that makes sense. To me something like `mapRunResultToMutantStatus` makes more sense.

Hmm, I feel like the "from where" is already apparent from it being given as a parameter (as well as the signature). Having names like mapRunResultToMutantStatus will get pretty big and unreadable. I agree the names could be better though


private val schemaVersion = "1"

def toReport(mutantRunResults: MutantRunResults)(implicit config: Config): MutationTestReport = MutationTestReport(
schemaVersion,
toThresholds(config.thresholds),
toMutationTestResultMap(mutantRunResults.results.toSeq)
)

private def toThresholds(thresholds: ConfigThresholds): Thresholds =
Thresholds(high = thresholds.high, low = thresholds.low)

private def toMutationTestResultMap(results: Seq[MutantRunResult])(
implicit config: Config): Map[String, MutationTestResult] =
results groupBy (_.fileSubPath) map {
case (path, runResults) => path.toString.replace('\\', '/') -> toMutationTestResult(runResults)
}

private def toMutationTestResult(runResults: Seq[MutantRunResult])(implicit config: Config): MutationTestResult =
MutationTestResult(
fileContentAsString(runResults.head.fileSubPath),
runResults.map(toMutantResult)
)

private def toMutantResult(runResult: MutantRunResult): MutantResult = {
val mutant = runResult.mutant
MutantResult(
mutant.id.toString,
mutant.mutationType.mutationName,
mutant.mutated.syntax,
toLocation(mutant.original.pos),
toMutantStatus(runResult)
)
}

private def toLocation(pos: scala.meta.inputs.Position): Location = Location(
start = Position(line = pos.startLine + 1, column = pos.startColumn + 1),
end = Position(line = pos.endLine + 1, column = pos.endColumn + 1)
)

private def toMutantStatus(mutant: MutantRunResult): MutantStatus = mutant match {
case _: Survived => MutantStatus.Survived
case _: Killed => MutantStatus.Killed
case _: NoCoverage => MutantStatus.NoCoverage
case _: TimedOut => MutantStatus.Timeout
case _: Error => MutantStatus.CompileError
}

private def fileContentAsString(path: Path)(implicit config: Config): String =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason this is private instead of private[this]? (I'm actually not sure about the difference. 🙈 )

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no real reason other than consistency. private means objects of other types can not access it. private[this] means objects of the same type also cannot access it. So it's slightly tighter encapsulation. (You can also have protected[com.packagename] for example). It's explained better here

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think there's consistency on this throughout stryker4s though.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True. But now there is within the class

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess we'll save this discussion for later then. x)

(config.baseDir / path.toString).contentAsString

}
@@ -0,0 +1,35 @@
package stryker4s.report.model
import io.circe.Encoder
import stryker4s.report.model.MutantStatus.MutantStatus

final case class MutationTestReport(schemaVersion: String,
thresholds: Thresholds,
files: Map[String, MutationTestResult]) {

private implicit val encoder: Encoder[MutantStatus] = Encoder.enumEncoder(MutantStatus)

def toJson: String = {
import io.circe.generic.auto._
import io.circe.syntax._
this.asJson.noSpaces
}
}

final case class MutationTestResult(source: String, mutants: Seq[MutantResult], language: String = "scala")

final case class MutantResult(id: String,
mutatorName: String,
replacement: String,
location: Location,
status: MutantStatus)

final case class Location(start: Position, end: Position)

final case class Position(line: Int, column: Int)

final case class Thresholds(high: Int, low: Int)

object MutantStatus extends Enumeration {
Wmaarts marked this conversation as resolved.
Show resolved Hide resolved
type MutantStatus = Value
val Killed, Survived, NoCoverage, CompileError, Timeout = Value
}