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

Extract diff module #756

merged 7 commits into from Apr 24, 2024

Conversation

majk-p
Copy link
Contributor

@majk-p majk-p commented Mar 26, 2024

This PR aims to extract diff calculation to a separate module to resolve #745

Since diff had to share a bit of code with the rest of munit, I've also extracted munit-core that provides the minimal common part.

Comment on lines +291 to +310
private def exceptionHandlerFromAssertions(
assertions: Assertions,
clues: => Clues
): ComparisonFailExceptionHandler =
new ComparisonFailExceptionHandler {
def handle(
message: String,
obtained: String,
expected: String,
loc: Location
): Nothing = {
assertions.failComparison(message, obtained, expected, clues)(loc)
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I decided to extract this from ComparisonFailExceptionHandler so that the scala-diff package doesn't need to depend on Assertions

@majk-p
Copy link
Contributor Author

majk-p commented Mar 26, 2024

@valencik @tgodzik this change breaks mima on purpose due to reorganisation of modules. Please advise what's your preferred strategy to deal with mima check considering 1.0.0 is underway.

build.sbt Outdated
.jsConfigure(sharedJSConfigure)
.jsSettings(sharedJSSettings)

lazy val munitDiff = crossProject(JSPlatform, JVMPlatform, NativePlatform)
Copy link
Contributor

Choose a reason for hiding this comment

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

Ideally munitDiff would not depend on anything, it should not be about testing really.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As far as I understand it, both diff and munit need things like Location along with macros that generate it. Do you prefer code duplication over shared core module?

Copy link
Contributor

Choose a reason for hiding this comment

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

I would not use Location for diff if possible, seems like it's not really core functionality.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we can try getting rid of Location, I'll give it a try. What about AnsiColors? Should it be a part of diff module?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think so, since it might be useful for showing the diff.

@tgodzik
Copy link
Contributor

tgodzik commented Mar 27, 2024

@valencik @tgodzik this change breaks mima on purpose due to reorganisation of modules. Please advise what's your preferred strategy to deal with mima check considering 1.0.0 is underway.

Extracting munitDiff will break mima anyway. It's probably the last chance to do it. We should work on actual release later on. Any objections?

@valencik
Copy link
Collaborator

@valencik @tgodzik this change breaks mima on purpose due to reorganisation of modules. Please advise what's your preferred strategy to deal with mima check considering 1.0.0 is underway.

I first want to note that the ecosystem is eager for a 1.0 release.
It is not ideal to be on milestones this long.
And we have a split of projects on 0.7.x and 1.0.x milestones throughout the ecosystem.

However, I wanted to at least bump us to the latest Scala 3 LTS before cutting 1.0.
Unfortunately, we're blocked by scala/scala3#19594 not having yet been ported back to a LTS version.

All this to say, I don't have strong objections to the plan here.

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

import munit.Location

Choose a reason for hiding this comment

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

I wonder if assertNoDiff should still be part of this Diffs object? Each testing library does assertions differently.

It might be better to have something like createReportIfDiff and use this in Assertions:

    def createReportIfDiff(
      obtained: String,
      expected: String,
      title: String,
      printObtainedAsStripMargin: Boolean
    ): Option[String] = {
      if (obtained.isEmpty && !expected.isEmpty) {
        val msg =
          s"""|Obtained empty output!
              |=> Expected:
              |$expected""".stripMargin
        Some(msg)
      } else {
        val diff = new Diff(obtained, expected)
        if (diff.isEmpty) None
        else {
          Some(diff.createReport(title, printObtainedAsStripMargin))
        }
      }
    }

However, I'm not sure how we feel about removing assertNoDiff from here entirely.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think that's totally fine, asserts can live elsewhere

@@ -0,0 +1,13 @@
package munit.diff

class Clue[+T](

Choose a reason for hiding this comment

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

I don't think Clue should be a type in the diff library. From what I understand, it's been moved here so that we can give it a custom representation in Printers.

That being said, I haven't thought of alternative approaches.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Me neither, I did this to satisfy the compiler, I also don't have a better idea yet

@@ -51,10 +54,10 @@ trait Assertions extends MacroCompat.CompileErrorMacro {
clue: => Any = "diff assertion failed"
)(implicit loc: Location): Unit = {
StackTraces.dropInside {
Diffs.assertNoDiff(
DiffsAssetion.assertNoDiff(
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
DiffsAssetion.assertNoDiff(
DiffsAssertion.assertNoDiff(

Copy link
Contributor

Choose a reason for hiding this comment

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

Could you fix this one? It's super minor

case x: Float => out.append(x.toString())
case x: Double => out.append(x.toString())
case x: String => printString(x, out, printer)
case x: Clues =>
Copy link
Contributor

Choose a reason for hiding this comment

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

Could we just make Printer a class and add support for Clues in a child class?

Or maybe a custom class like:

trait CustomPrintable{
  def append(out: StringBuilder)
}

and make Clue implement it?

def empty: Clues = new Clues(List())
def fromValue[T](value: T): Clues = new Clues(List(Clue.fromValue(value)))
}
// class Clues(val values: List[Clue[_]]) {
Copy link
Contributor

Choose a reason for hiding this comment

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

TODO remove if we decide to leave Clue in the current position

package munit.diff

/**
* Don't override this ever
Copy link
Contributor

Choose a reason for hiding this comment

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

Would be great to mention why a bit

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No longer relevant, shouldn't be pushed in the first place 😉

@@ -51,10 +54,10 @@ trait Assertions extends MacroCompat.CompileErrorMacro {
clue: => Any = "diff assertion failed"
)(implicit loc: Location): Unit = {
StackTraces.dropInside {
Diffs.assertNoDiff(
DiffsAssetion.assertNoDiff(
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you fix this one? It's super minor

@tgodzik
Copy link
Contributor

tgodzik commented Apr 23, 2024

You might want to rebase the PR to see if it passes.

@majk-p
Copy link
Contributor Author

majk-p commented Apr 23, 2024

After brainstorming with @zainab-ali and inspired by this commit I did an overhaul of this change. Most of the Printers functionality remains in munit while only logic for string cleanup is extracted to diff (since it's the only used part). I think it makes things cleaner and we no longer have to deal with disentangling Clues.

@tgodzik
Copy link
Contributor

tgodzik commented Apr 23, 2024

Looks like the compilation is failing, could you take a look?

@majk-p
Copy link
Contributor Author

majk-p commented Apr 23, 2024

I just run compile and test locally and everything worked well. I cannot see the CI logs in actions 😞

build.sbt Outdated
@@ -214,7 +214,7 @@ lazy val munit = crossProject(JSPlatform, JVMPlatform, NativePlatform)
.settings(
sharedSettings,
Compile / unmanagedSourceDirectories ++=
crossBuildingDirectories("munit", "main").value,
crossBuildingDirectories("scala-diff", "main").value,
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this change correct?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's right, missed it during cleanup

Copy link
Contributor

@tgodzik tgodzik left a comment

Choose a reason for hiding this comment

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

LGTM from me! Thanks for the great work!

I added 3 more commits:

  • rename to munit-diff since we have package munit.diff everywhere so it makes much more sense
  • fix mdoc docs generation
  • fix mima exceptions

@zainab-ali what do you think?

My next plan is to remove any deprecation we can find and release an RC1

@tgodzik tgodzik requested a review from zainab-ali April 24, 2024 08:26
@zainab-ali
Copy link

Thanks @majk-p and @tgodzik, the PR itself looks great!

Unfortunately the rencent changes to munit include a Native upgrade to 0.5. Weaver has a way to go until moving to 0.5 itself - see the discussion for cats-effect.

I'm brainstorming approaches we could take. Would it be viable to release this on 0.4.x too?

@tgodzik
Copy link
Contributor

tgodzik commented Apr 24, 2024

I can do that manually later on. Hopefully, this time it will work reasonably.

@tgodzik tgodzik merged commit a66abd5 into scalameta:main Apr 24, 2024
9 checks passed
mzuehlke added a commit to mzuehlke/munit-scalacheck that referenced this pull request Apr 26, 2024
changes because munit-diff is now an independent artifact: scalameta/munit#756
* add dependency for munit-diff
* adapt imports
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Request: Publish internal difflib as a micro-library
4 participants