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

Extract diff module #756

Merged
merged 7 commits into from Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
103 changes: 27 additions & 76 deletions build.sbt
@@ -1,4 +1,3 @@
import com.typesafe.tools.mima.core._
import sbtcrossproject.CrossPlugin.autoImport.crossProject
import sbtcrossproject.CrossPlugin.autoImport.CrossType
import scala.collection.mutable
Expand Down Expand Up @@ -66,81 +65,7 @@ def isScala3(v: Option[(Long, Long)]): Boolean = v.exists(_._1 == 3)
lazy val skipIdeaSettings =
SettingKey[Boolean]("ide-skip-project").withRank(KeyRanks.Invisible) := true
lazy val mimaEnable: List[Def.Setting[_]] = List(
mimaBinaryIssueFilters ++= List(
ProblemFilters.exclude[DirectMissingMethodProblem](
"munit.MUnitRunner.descriptions"
),
ProblemFilters.exclude[DirectMissingMethodProblem](
"munit.MUnitRunner.testNames"
),
ProblemFilters.exclude[DirectMissingMethodProblem](
"munit.MUnitRunner.munitTests"
),
ProblemFilters.exclude[DirectMissingMethodProblem](
"munit.ValueTransforms.munitTimeout"
),
ProblemFilters.exclude[MissingTypesProblem]("munit.FailException"),
ProblemFilters.exclude[MissingTypesProblem]("munit.FailSuiteException"),
ProblemFilters.exclude[MissingTypesProblem](
"munit.TestValues$FlakyFailure"
),
ProblemFilters.exclude[DirectMissingMethodProblem](
"munit.internal.junitinterface.JUnitComputer.this"
),
// Known breaking changes for MUnit v1
ProblemFilters.exclude[DirectMissingMethodProblem](
"munit.Assertions.assertNotEquals"
),
ProblemFilters.exclude[DirectMissingMethodProblem](
"munit.Assertions.assertEquals"
),
ProblemFilters.exclude[IncompatibleMethTypeProblem](
"munit.Assertions.assertNotEquals"
),
ProblemFilters.exclude[IncompatibleMethTypeProblem](
"munit.Assertions.assertEquals"
),
ProblemFilters.exclude[IncompatibleMethTypeProblem](
"munit.FunSuite.assertNotEquals"
),
ProblemFilters.exclude[IncompatibleMethTypeProblem](
"munit.FunSuite.assertEquals"
),
ProblemFilters.exclude[IncompatibleMethTypeProblem](
"munit.FunSuite.munitTestTransform"
),
ProblemFilters.exclude[MissingClassProblem]("munit.GenericAfterEach"),
ProblemFilters.exclude[MissingClassProblem]("munit.GenericBeforeEach"),
ProblemFilters.exclude[MissingClassProblem]("munit.GenericTest"),
ProblemFilters.exclude[DirectMissingMethodProblem](
"munit.MUnitRunner.createTestDescription"
),
ProblemFilters.exclude[IncompatibleMethTypeProblem](
"munit.Suite.beforeEach"
),
ProblemFilters.exclude[IncompatibleMethTypeProblem](
"munit.Suite.afterEach"
),
ProblemFilters.exclude[MissingClassProblem]("munit.Suite$Fixture"),
ProblemFilters.exclude[IncompatibleMethTypeProblem](
"munit.TestTransforms#TestTransform.apply"
),
ProblemFilters.exclude[IncompatibleMethTypeProblem](
"munit.FunFixtures#FunFixture.this"
),
ProblemFilters.exclude[IncompatibleMethTypeProblem](
"munit.SuiteTransforms#SuiteTransform.this"
),
ProblemFilters.exclude[IncompatibleMethTypeProblem](
"munit.TestTransforms#TestTransform.this"
),
ProblemFilters.exclude[IncompatibleMethTypeProblem](
"munit.ValueTransforms#ValueTransform.this"
),
ProblemFilters.exclude[DirectMissingMethodProblem](
"munit.ScalaCheckSuite.unitToProp"
)
),
mimaBinaryIssueFilters ++= MimaExclusions.list,
mimaPreviousArtifacts := {
if (crossPaths.value)
Set("org.scalameta" %% moduleName.value % previousVersion)
Expand Down Expand Up @@ -246,6 +171,8 @@ lazy val munit = crossProject(JSPlatform, JVMPlatform, NativePlatform)
)
)
.jvmConfigure(_.dependsOn(junit))
.dependsOn(munitDiff)

lazy val munitJVM = munit.jvm
lazy val munitJS = munit.js
lazy val munitNative = munit.native
Expand All @@ -270,6 +197,30 @@ lazy val plugin = project
)
.disablePlugins(MimaPlugin)

lazy val munitDiff = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.in(file("munit-diff"))
.settings(
moduleName := "munit-diff",
sharedSettings,
libraryDependencies ++= List(
"org.scala-lang" % "scala-reflect" % {
if (isScala3Setting.value) scala213
else scalaVersion.value
} % Provided
)
)
.jvmSettings(
sharedJVMSettings
)
.nativeConfigure(sharedNativeConfigure)
.nativeSettings(
sharedNativeSettings
)
.jsConfigure(sharedJSConfigure)
.jsSettings(sharedJSSettings)
// TODO Reenable on 1.0.0
.disablePlugins(MimaPlugin)

lazy val tests = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.dependsOn(munit)
.enablePlugins(BuildInfoPlugin)
Expand Down
4 changes: 2 additions & 2 deletions docs/tests.md
Expand Up @@ -132,7 +132,7 @@ Override `printer` to customize the comparison of two values :
```scala mdoc
import java.time.Instant
import munit.FunSuite
import munit.Printer
import munit.diff.Printer

class CompareDatesOnlyTest extends FunSuite {
override val printer = Printer.apply {
Expand All @@ -152,7 +152,7 @@ or to customize the printed clue in case of a failure :

```scala mdoc
import munit.FunSuite
import munit.Printer
import munit.diff.Printer

class CustomListOfCharPrinterTest extends FunSuite {
override val printer = Printer.apply {
Expand Down
@@ -1,4 +1,4 @@
package munit.internal.difflib
package munit.diff

import java.util

Expand Down
@@ -1,4 +1,4 @@
package munit.internal.difflib
package munit.diff

sealed abstract class Delta[T](original: Chunk[T], revised: Chunk[T]) {

Expand Down
@@ -1,7 +1,7 @@
package munit.internal.difflib
package munit.diff

import munit.internal.console.{AnsiColors, Printers}
import munit.internal.difflib
import munit.diff.console.Printers
import munit.diff.console.AnsiColors

import scala.collection.JavaConverters._

Expand Down Expand Up @@ -74,11 +74,11 @@ class Diff(val obtained: String, val expected: String) extends Serializable {
original: Seq[String],
revised: Seq[String]
): String = {
val diff = difflib.DiffUtils.diff(original.asJava, revised.asJava)
val diff = DiffUtils.diff(original.asJava, revised.asJava)
val result =
if (diff.getDeltas.isEmpty) ""
else {
difflib.DiffUtils
DiffUtils
.generateUnifiedDiff(
"obtained",
"expected",
Expand Down
@@ -1,4 +1,4 @@
package munit.internal.difflib
package munit.diff

import java.util

Expand Down
@@ -1,4 +1,4 @@
package munit.internal.difflib
package munit.diff

import java.util

Expand Down
@@ -1,3 +1,3 @@
package munit.internal.difflib
package munit.diff

class DifferentiationFailedException(message: String) extends Exception(message)
28 changes: 28 additions & 0 deletions munit-diff/shared/src/main/scala/munit/diff/Diffs.scala
@@ -0,0 +1,28 @@
package munit.diff

object Diffs {

def create(obtained: String, expected: String): Diff =
new Diff(obtained, expected)

def createDiffOnlyReport(
obtained: String,
expected: String
): String = {
create(obtained, expected).createDiffOnlyReport()
}

def createReport(
obtained: String,
expected: String,
title: String,
printObtainedAsStripMargin: Boolean = true
): String = {
create(obtained, expected).createReport(title, printObtainedAsStripMargin)
}

def unifiedDiff(obtained: String, expected: String): String = {
create(obtained, expected).unifiedDiff
}

}
@@ -1,4 +1,4 @@
package munit.internal.difflib
package munit.diff

trait Equalizer[T] {
def equals(original: T, revised: T): Boolean
Expand Down
@@ -1,29 +1,29 @@
package munit.internal.difflib
package munit.diff

import java.util

class MyersDiff[T](equalizer: Equalizer[T])
extends munit.internal.difflib.DiffAlgorithm[T] {
extends munit.diff.DiffAlgorithm[T] {
def this() = this(Equalizer.default[T])
override def diff(
original: util.List[T],
revised: util.List[T]
): munit.internal.difflib.Patch[T] = {
): munit.diff.Patch[T] = {
try {
buildRevision(buildPath(original, revised), original, revised)
} catch {
case e: DifferentiationFailedException =>
e.printStackTrace()
new munit.internal.difflib.Patch[T]()
new munit.diff.Patch[T]()
}
}
private def buildRevision(
_path: PathNode,
orig: util.List[T],
rev: util.List[T]
): munit.internal.difflib.Patch[T] = {
): munit.diff.Patch[T] = {
var path = _path
val patch = new munit.internal.difflib.Patch[T]
val patch = new munit.diff.Patch[T]
if (path.isSnake) path = path.prev
while (
path != null &&
Expand All @@ -40,22 +40,22 @@ class MyersDiff[T](equalizer: Equalizer[T])
val ianchor = path.i
val janchor = path.j
val original =
new munit.internal.difflib.Chunk[T](
new munit.diff.Chunk[T](
ianchor,
copyOfRange(orig, ianchor, i)
)
val revised =
new munit.internal.difflib.Chunk[T](
new munit.diff.Chunk[T](
janchor,
copyOfRange(rev, janchor, j)
)
val delta: munit.internal.difflib.Delta[T] =
val delta: munit.diff.Delta[T] =
if (original.size == 0 && revised.size != 0) {
new munit.internal.difflib.InsertDelta[T](original, revised)
new munit.diff.InsertDelta[T](original, revised)
} else if (original.size > 0 && revised.size == 0) {
new munit.internal.difflib.DeleteDelta[T](original, revised)
new munit.diff.DeleteDelta[T](original, revised)
} else {
new munit.internal.difflib.ChangeDelta[T](original, revised)
new munit.diff.ChangeDelta[T](original, revised)
}
patch.addDelta(delta)
if (path.isSnake) {
Expand Down
@@ -1,4 +1,4 @@
package munit.internal.difflib
package munit.diff

import java.util
import java.util.{Collections, Comparator}
Expand Down
@@ -1,4 +1,4 @@
package munit.internal.difflib
package munit.diff

sealed abstract class PathNode(val i: Int, val j: Int, val prev: PathNode) {

Expand Down
@@ -1,4 +1,4 @@
package munit
package munit.diff

/**
* Implement this trait to customize the default printer
Expand Down
@@ -1,4 +1,4 @@
package munit.internal.console
package munit.diff.console

object AnsiColors {
val LightRed = "\u001b[91m"
Expand Down
59 changes: 59 additions & 0 deletions munit-diff/shared/src/main/scala/munit/diff/console/Printers.scala
@@ -0,0 +1,59 @@
package munit.diff.console

import munit.diff.{EmptyPrinter, Printer}

import scala.annotation.switch

object Printers {

def print(input: String): String = {
val out = new StringBuilder()
printString(input, out, EmptyPrinter)
munit.diff.console.AnsiColors.filterAnsi(out.toString())
}

def printString(
string: String,
out: StringBuilder,
printer: Printer
): Unit = {
val isMultiline = printer.isMultiline(string)
if (isMultiline) {
out.append('"')
out.append('"')
out.append('"')
out.append(string)
out.append('"')
out.append('"')
out.append('"')
} else {
out.append('"')
var i = 0
while (i < string.length()) {
printChar(string.charAt(i), out)
i += 1
}
out.append('"')
}
}

def printChar(
c: Char,
sb: StringBuilder,
isEscapeUnicode: Boolean = true
): Unit =
(c: @switch) match {
case '"' => sb.append("\\\"")
case '\\' => sb.append("\\\\")
case '\b' => sb.append("\\b")
case '\f' => sb.append("\\f")
case '\n' => sb.append("\\n")
case '\r' => sb.append("\\r")
case '\t' => sb.append("\\t")
case c =>
val isNonReadableAscii = c < ' ' || (c > '~' && isEscapeUnicode)
if (isNonReadableAscii && !Character.isLetter(c))
sb.append("\\u%04x".format(c.toInt))
else sb.append(c)
}
}
Expand Up @@ -4,7 +4,7 @@

package munit.internal.junitinterface

import munit.internal.console.AnsiColors
import munit.diff.console.AnsiColors
import sbt.testing._
import munit.internal.PlatformCompat

Expand Down