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
Add tests for ConsoleReporter. #5675
Conversation
Added 2 files, am not certain about the coding style. |
I think it's the git style. You didn't intend to commit all the extra files. |
Yeah, exactly. Anyways, just to clarify, I have signed the CLA. |
@adriaanm, could you review it? |
Since (Using This test could also subsume the new test at #5667 where probably an end-to-end test is overkill. Note that maxerr isn't fixed at 100 now, so setting it explicitly for the test is useful (instead of testing the default). |
|
||
// finish test | ||
reporter.ERROR.count = 0 | ||
reporter finish; // don't know why but I'm requiring ';' here, otherwise the file does not compile |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest not enabling postfixOps at all.
val reporter = new ConsoleReporter(new Settings()) | ||
|
||
// printMessage test | ||
reporter printMessage("Hello World!") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest using dot-selection, especially with parens.
reporter.printMessage("hello, world.")
reporter printMessage "hello, world." // Recently, I use this style less, but community hasn't outlawed it.
err_out.reset | ||
|
||
reporter.WARNING.count = 3 | ||
reporter.ERROR.count = 10 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably when the reporter API is nailed down some more, this should be disallowed. Maybe Reporter should have protected increment(severity)
.
Pardon me @som-snytt , I didn't know you were my assigned reviewer. I will make the changes as suggested but in the meanwhile, my midterms are around the corner. Is it okay if this can wait for some days? |
Absolutely, reviewing and updating are on a volunteer basis! |
Hey @som-snytt, I made the changes. Could you review and suggest further changes if needed. |
@Test | ||
def unitTest: Unit = { | ||
val noPos = NoPosition | ||
val path = "test/junit/scala/tools/nsc/reporters/file_ConsoleReporterTest.txt" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not clear on why a file is needed. Source can be just a byte array.
// printMessage test | ||
reporter.printMessage("Hello World!") | ||
assertEquals("Hello World!\n", err_out.toString) | ||
err_out.reset |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could refactor this pattern to a method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure that I get you correctly. Do you want me to group the related tests inside a method, for example the tests for printMessage inside a single method?
Made the changes. Still not sure, if it's exactly what you wanted. |
Hey @som-snytt, could you review the changes? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a couple of small comments. I'm trying out the "review" button for the first time, which really complicates the workflow. (note to github)
You need to rebase and clean up the git history, which includes spurious merge commits. They want to see your one squashed commit before they merge. (as a rule)
val input = new StringReader("s\n") | ||
val input_reader = new BufferedReader(input) | ||
val setting = new Settings() | ||
setting.maxerrs.tryToSet(List("50")) //changing maxerrs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
settings.maxerrs.value = 50
def printMessageTest(): Unit = { | ||
reporter.printMessage("Hello World!") | ||
assertEquals("Hello World!\n", err_out.toString) | ||
err_out.reset |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could capture this repeated pattern in a routine that performs the assert and the reset. I often see simple helpers like that in unit tests.
|
||
// printColumnMarkerTest test with DefinedPosition | ||
reporter.printColumnMarker(posWithSource) | ||
assertEquals(" ^\n", err_out.toString) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This assumes the platform line ending, perhaps. text.lines
converts to lines.
@Test | ||
def displayPromptTest(): Unit = { | ||
val stack = new ByteArrayOutputStream | ||
System.setErr(new PrintStream(stack)) // used for checking the stack trace of displayPrompt() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Console.withErr
. Again, it's easier to encapsulate with a method that does the setup. Allocating a BAOS for every test is easier than stack.reset
. As a style matter, maybe the idea is that it's worth reusing a heavyweight object?
val input = new StringReader("r\n") | ||
val input_reader = new BufferedReader(input) | ||
val reporter = new ConsoleReporter(new Settings(), input_reader, output_writer) | ||
reporter.displayPrompt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a huge deal, but I'd expect parens to demonstrate a side-effecting application. That's the standard advice. This looks like it just accesses a value.
/rebuild |
You have to fix the git history. Your PR should show your one commit. |
I didn't push form the '2.12.x' branch after rebasing it, think that was the root of the problem. Thanks @som-snytt ! I added the protected increment and reset severity functions in ConsoleReporter and also modified the tests. Hope you can take a look at it. |
@piyush-jaiswal, note that you seem to have accidentally committed a bunch of unrelated files. Please also review our guidelines on how to format a good commit message. As it stands, your commit title is too long, is not in the present tense, and there's no elaboration in the commit message itself (for example: what does this do? why? what was wrong before?) Thanks for reviewing @som-snytt! When you feel this PR is ready, feel free to merge. |
Made the changes. Kindly point out other issues if present. |
Sorry, just a busy time, albeit not midterms. If I suggested adding API to ConsoleReporter just for a test, don't listen to that guy. Also, there was just a commit to let it take two writers, for error and echo. That might affect your test. You can actually fix something by changing it to use |
Okay, I've changed my tests according to the commit and yeah I don't think it's possible to test the abort option too. |
review @som-snytt ? |
Is there any further issue present? I am finding it difficult to spotting them on my own. |
if(echoWriterOut == null) | ||
new ConsoleReporter(new Settings(), reader, writer) | ||
else | ||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Repo style is space after if if (
and open brace on same line else {
.
|
||
|
||
def testHelper(checkBlank: Boolean, hasPos: Boolean, message: String, severity: String): Unit = { | ||
if(checkBlank) assertEquals("", writerOut.toString) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the flag is redundant with message = ""
. Possibly message.isEmpty && severity.isEmpty
.
} | ||
} | ||
writerOut.reset | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test rig could be: testHelper(pos: Position = NoPosition, msg: String, severity: String = "")(test: Position => Unit)
.
testHelper(msg = "hello, world")(_ => reporter.printMessage("hello, world"))
.
testHelper(myPos, "test")(reporter.print(_, "test", INFO))
or similar.
The hasPos
flag is pos.isDefined
.
I lose track of the true, false
pairs in the tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if we require Position
as an argument of the function stored in the second parameter, test
of testHelper
.
We could just do:
def testHelper(pos: Position = NoPosition, msg: String, severity: String = "")(test: () => Unit)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I was trying to avoid repeating the pos info. My second example reads well; you'd only need arrow syntax to ignore the pos in the test function.
But yes, you could just:
testHelper(myPos, "test")(reporter.print(myPos, "test", INFO))
with by-name param instead of a function:
def testHelper(...)(test: => Unit)
Either way, I think it's worth the trouble, because they want to do more tricks with reporters, like filtering, so it's likely your test will get exercised and expanded.
testHelper(false, false, "test", "") | ||
|
||
reporter.print(noPos, "test", reporter.WARNING) | ||
testHelper(false, false, "test", "warning: ") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The false, false
, which I've forgotten what it means, is noise.
Sometimes a little table of truth values in code is tidy, but not as args. It can help to name them, f(hasPos = false, isBlank = false, x, y)
, and in non-test code the repo requires named boolean args for this reason.
Eliminating the noise would take this to another level.
@@ -91,4 +91,4 @@ class ConsoleReporter(val settings: Settings, reader: BufferedReader, writer: Pr | |||
override def flush() = writer.flush() | |||
|
|||
override def finish() = printSummary() | |||
} | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably restore terminal NL.
|
||
reporter.WARNING.count = 26 | ||
reporter.display(posWithSource, "Testing display for maxwarns to fail", reporter.WARNING) | ||
testHelper(true, false, "", "") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The one thing tested by test/files/neg/maxerrs.scala
is that output is suppressed but the error or warning over the max to display is still counted, and not simply ignored. Here, the count is bumped.
I've tried to make the changes. Please review. Thanks! |
Option(echoWriterOut) match { | ||
case None => new ConsoleReporter(new Settings(), reader, writer) | ||
case Some(_) => new ConsoleReporter(new Settings(), reader, writer, new PrintWriter(echoWriterOut)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an idiom you'll see nowhere. I won't nitpick default to null, but you can just case null =>
or just val echo = if (out != null) new PrintWriter(out) else writer
. You might as well name the params errOut
and echoOut
since they aren't Writers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I read somewhere that null
was provided in scala for java interop and that Option
is better to use in scala. As it may be, I think I'll use null =>
as it utilizes one of the constructors in ConsoleReporter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To avoid both null
and boxing, method overload: f(out)
calls f(out, out)
. Sometimes the default arg can be an empty value of the desired type.
testHelper(msg = "test")(_ => reporter.print(NoPosition, "test", reporter.INFO)) | ||
testHelper(msg = "test", severity = "warning: ")(_ => reporter.print(NoPosition, "test", reporter.WARNING)) | ||
testHelper(msg = "test", severity = "error: ")(_ => reporter.print(NoPosition, "test", reporter.ERROR)) | ||
testHelper(posWithSource, msg = "test")(_ => reporter.print(posWithSource, "test", reporter.INFO)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since your helper takes Pos => Unit
, this would be
testHelper(posWithSource, msg = "test")(reporter.print(_, "test", reporter.INFO))
If you find that finicky, then helper could just take (body: => Unit)
, and maybe that's easier to read, too:
testHelper(posWithSource, msg = "test")(reporter.print(posWithSource, "test", reporter.INFO))
reporter.ERROR.count += 1 | ||
testHelper(posWithSource, msg = "Testing display for maxerrs to pass", severity = "error: ")(_ => reporter.display(posWithSource, "Testing display for maxerrs to pass", reporter.ERROR)) | ||
reporter.ERROR.count += 1 | ||
testHelper(msg = "")(_ => reporter.display(posWithSource, "Testing display for maxerrs to fail", reporter.ERROR)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you're testing display
(and not reporter.error
), I'd set maxerrs = 1
and ERROR.count = 0
explicitly in the test so we can see the conditions of the test. I don't know what the current count is, does it depend on order tests are run? etc.
assertEquals("three warnings found", it.next) | ||
assertEquals("10 errors found", it.next) | ||
writerOut.reset | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The tests assume test isolation. Probably I wouldn't have used a shared reporter, since it's cheap to construct. Each test could use a throw-away reporter. Here, for instance, the counts are bumped up and other tests could see that, depending on how the test is run (one Test instance per test method or one instance for all, test order, etc).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should I use a separate BAOS
for each test as well and pass it as an argument in testHelper
or let it remain a global as it is now?
Just a couple of small comments to push it across. It's rude at this point to ask not to use a shared reporter across test methods, so I'll leave that to you, so long as the tests actually pass. For future reference, I avoid sharing the "system under test" unless it's expensive to construct. |
Good work, @piyush-jaiswal -- thanks. Thank you for the in-depth reviewing, @som-snytt! |
I'm pretty sure this PR hit all of the hardest problems in computer science, or I might be off by one. This test will be so useful when someone adds reporter features. 👍 |
Updated. I've used the same |
assertEquals(" ^", it.next) | ||
} | ||
} | ||
writerOut.reset |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, we should have put the reset in a finally block. If it fails, it throws, so the next test to run could see the dirty buffer. Probably the test class is reinstantiated; I think junit does that.
LGTM |
Thanks @adriaanm and thanks @som-snytt for taking the time to review this PR. This definitely was a great learning experience for me! |
no interesting merge conflicts. versions.properties is always a conflict factory, and HashMap.scala was because of parallel collections removal. % export mb=$(git merge-base origin/2.12.x origin/2.13.x) % git log --graph --oneline --decorate $mb..origin/2.12.x | cat * 96cdfb4 (origin/HEAD, origin/2.12.x) Merge pull request scala#5741 from monkey-mas/bump-up-sbt-jmh-to-0.2.21 |\ | * 08f753e Bump up sbt-jmh to 0.2.21 * 38baf2b Merge pull request scala#5771 from som-snytt/issue/regex-doc-err |\ | * cc1b8f3 Fix and improve Regex doc * | 6f905fd Merge pull request scala#5747 from dwijnand/fix-root-package-task |\ \ | * | 4c1c8de Rewire package to osgiBundle for OSGi-enabled projects | / * | 57948c8 Merge pull request scala#5791 from SethTisue/cruft-begone |\ \ | * | 4b98161 remove test/pending directory too | * | 25048bc (SethTisue/cruft-begone) rm -r test/{flaky,disabled*,checker-tests,support,debug} | * | 0563c4b remove orphaned checkfiles | * | 36357f3 remove two empty source files | * | 8690809 fix typos | * | 8177b99 unset a stray execute bit * | | c7c2152 Merge pull request scala#5776 from lrytz/numbersCleanup |\ \ \ | * | | 77e0602 cleanups and clarifications in versions.properties | / / * | | 95a263e Merge pull request scala#5789 from ceeph/patch-1 |\ \ \ | |/ / |/| | | * | a9ba3e6 Fix table formatting |/ / * | 6048c66 Merge pull request scala#5780 from lrytz/bootstrapOverwrite |\ \ | * | 6ff3891 Use a single repository in the bootstrap job |/ / * | 0dab108 Merge pull request scala#5777 from som-snytt/issue/10226 |\ \ | * | c77b420 SI-10226 REPL handles paste when colorized |/ / * | d0c2620 Merge pull request scala#5756 from rorygraves/2.12.x_depthboxing |\ \ | * | f7cd76b Reduce boxing of scala.reflect.internal.Depth | / * | 17e057b Merge pull request scala#5755 from rorygraves/2.12.x_map4 |\ \ | * | 0c6d4e5 Performance improvements for Map4 to HashMap nad Set4 to HashSet transitions | * | aefc8f4 Add benchmarks for Map4 to HashMap and Set4 to HashSet transitions | * | fad8b95 Fix compile error on existing ListBenchmark | / * | 3fadf69 Merge pull request scala#5675 from piyush-jaiswal/issue/9729 |\ \ | |/ |/| | * cc99026 Add tests for ConsoleReporter. * 6e9268b Merge pull request scala#5761 from lrytz/sd329 |\ | * 6abb6ba Don't use `equals` for comparing java.lang.Double/Float * 680d866 Merge pull request scala#5719 from retronym/ticket/10187 |\ | * 898fa00 SI-10187 Support mutation of mutable.HashMap in getOrElseUpdate * 0e38f28 Merge pull request scala#5767 from som-snytt/issue/5621 |\ | * dea2171 SI-5621 Missing implicits are supplied by defaults * 482879f Merge pull request scala#5769 from som-snytt/issue/8969 |\ | * 050811b SI-8969 Accept poly+implicit for assignment syntax * cba77ce Merge pull request scala#5766 from lrytz/versionsReadme * 8fcb9f1 Adapt README to new version numbers % git merge origin/2.12.x % git status ... both modified: src/library/scala/collection/mutable/HashMap.scala deleted by them: test/pending/shootout/fasta.scala both modified: versions.properties % git rm --force test/pending/shootout/fasta.scala % emacs versions.properties % git add -u versions.properties % emacs src/library/scala/collection/mutable/HashMap.scala % git add -u src/library/scala/collection/mutable/HashMap.scala
This commit adds tests for the ConsoleReporter which includes tests for the feature added by #5667.