-
Notifications
You must be signed in to change notification settings - Fork 937
Simplify java assertions and add messages to all #1027
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
Conversation
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.
Thanks, I like the idea. Please find my comments inline.
test/one/profiler/test/Assert.java
Outdated
|
|
||
| enum Comparison { | ||
| GT, GTE, LT, LTE, | ||
| } |
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.
Only one top-level class per file, please.
Make it a nested class or move to a separate file.
test/one/profiler/test/Assert.java
Outdated
| public class Assert { | ||
| private static final Logger log = Logger.getLogger(Assert.class.getName()); | ||
| private static final Map<Comparison, String> operator = new HashMap<>(); | ||
| private static final Map<Comparison, BiPredicate<Double, Double>> comparator = new HashMap<>(); |
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.
No need for maps - just store them directly in enum's fields.
Alternatively, enum may itself implement BiPredicate.
test/test/jfr/JfrTests.java
Outdated
| Assert.isGreater(eventsCount.get("jdk.ExecutionSample"), 50); | ||
| Assert.isGreater(eventsCount.get("jdk.JavaMonitorEnter"), 50); | ||
| Assert.isGreater(eventsCount.get("jdk.ObjectAllocationInNewTLAB"), 50); | ||
| Assert.isGreater(eventsCount.get("jdk.ExecutionSample"), 50, "jdk.ExecutionSample > 50"); |
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 a fan of repeating assertion in a message every time - this is more of a boilerplate that does not add much value. It's ok to leave it without a message. Or, given that stacktrace already contains line numbers, we may extract a line from the source code and show it to a user. Not sure it's worth doing, though.
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.
Added source parser, assertion failures looks like this now:
java.lang.AssertionError: Expected 0.13666666666666666 < 0.01
at test/test/recovery/RecoveryTests.java:42
:41 Output out = p.profile("-d 3 -e cpu -o collapsed");
:42 👉 Assert.isLess(out.ratio("vtable stub"), 0.01);
:43 Assert.isGreater(out.ratio("Numbers.loop"), 0.8);
at one.profiler.test.Assert.assertComparison(Assert.java:44)
at one.profiler.test.Assert.isLess(Assert.java:81)
at test.recovery.RecoveryTests.numbers(RecoveryTests.java:42)
before:
java.lang.AssertionError: Expected 0.13666666666666666 < 0.01
at one.profiler.test.Assert.assertComparison(Assert.java:44)
at one.profiler.test.Assert.isLess(Assert.java:81)
at test.recovery.RecoveryTests.numbers(RecoveryTests.java:42)
test/one/profiler/test/Assert.java
Outdated
|
|
||
|
|
||
| enum Comparison { | ||
| GT, GTE, LT, LTE, |
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.
Add EQ for completeness?
| @@ -0,0 +1,68 @@ | |||
| package one.profiler.test; | |||
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.
We badly need a linter for file headers.
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.
Can we merge #1016 if I remove the trailing whitespace checker for now(it is scanning .class files and giving false results)
| String className = element.getClassName(); | ||
|
|
||
| try { | ||
| Class<?> clazz = Class.forName(className); |
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.
Why do we need to instantiate a class just to convert its name to a path? Isn't className sufficient?
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.
We already had fileName with extension, simplifying this.
| } | ||
|
|
||
| private static String getFilePathFromClassLoader(String fileName, Class<?> clazz) { | ||
| String packagePath = clazz.getPackage().getName().replace('.', File.separatorChar); |
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 just use / for better readability. It works even on Windows.
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.
It also makes sense to cut everything after the last $ in case it's a nested class.
| return "Error reading source file: " + ex.getMessage(); | ||
| } | ||
|
|
||
| return sourceCode.toString().trim(); |
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.
Each line is already trimmed, isn't it?
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 was to remove the last \n.
| int startLine = Math.max(1, lineNumber - 1); | ||
| int endLine = lineNumber + 1; | ||
|
|
||
| // Read lines, and append the target lines (-1, 0, +1) |
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.
Do we need +1 line for assertions? The next assertion will not be executed.
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.
Agree - I'll just leave one line with the original assertion for simplicity. We're not going to replace IDE anyway )
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.
In case the assertion spans multiple lines. Will simplify to single line then.
| private static final Logger log = Logger.getLogger(Assert.class.getName()); | ||
|
|
||
| private static void assertComparison(Comparison comparison, double left, double right, String message) { | ||
| boolean asserted = !comparison.comparator.test(left, right); |
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.
Isn't assertionFailed going to be a better name?
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.
It didn't "fail" though, we are checking a value and we find it is "asserted". Here used as "asserted" vs. "unasserted". Can clarify further if necessary.
test/test/lock/LockTests.java
Outdated
| assert out.contains("sun/nio/ch/DatagramChannelImpl.send"); | ||
| } | ||
| @Test(mainClass = DatagramTest.class, debugNonSafepoints = true) // Fails on Alpine | ||
| public void datagramSocketLock(TestProcess p) throws Exception { |
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.
What's happened with the indentation?
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.
Fixing.
test/test/lock/LockTests.java
Outdated
| out = p.profile("-e lock -d 3 -o collapsed"); | ||
| assert out.contains("sun/nio/ch/DatagramChannelImpl.send"); | ||
| } | ||
| @Test(mainClass = DatagramTest.class, debugNonSafepoints = true) // Fails on Alpine |
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.
Btw, the test no longer fails on Alpine, the comment can be removed.
| sourceCode.append(filePath); | ||
| sourceCode.append(":"); | ||
| sourceCode.append(lineNumber); | ||
| sourceCode.append("\n"); |
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 we return just one line, StringBuilder is redundant; use regular string concatenation or String.format.
|
|
||
| while ((line = reader.readLine()) != null) { | ||
| if (currentLine == lineNumber) { | ||
| sourceCode.append(" 👉 ").append(line.trim()); |
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.
Just return <string>;
| } | ||
|
|
||
| private static String getFilePathFromClassLoader(String className) { | ||
| int dollar = className.lastIndexOf("$"); |
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.
nit: certain string methods (including lastIndexOf) have single-char variants - prefer them where possible.
| if (stackTrace.length > ignoreFrames) { | ||
| StackTraceElement element = stackTrace[ignoreFrames]; | ||
| String className = element.getClassName(); | ||
| String filePath = getFilePathFromClassLoader(className); |
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.
...FromClassName? ClassLoader is not involved here.
test/one/profiler/test/Assert.java
Outdated
| String operation = left + " " + comparison.operator + " " + right; | ||
|
|
||
| log.log(Level.FINE, "isAsserted " + asserted + ", " | ||
| + (message == null ? "" : "'" + message + "'") + ": " |
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.
A string won't look right when message == null, will it?
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.
Punctuation still looks wrong:
isAsserted false, : 0 < 1
^^^
test/one/profiler/test/Assert.java
Outdated
| String lines = "\n" + SourceLocator.tryGetFrom(new Exception(), 2); | ||
| String msg = message != null ? (": " + message + "\n" + lines) : lines; |
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.
Construction is a bit hard to read. There'll be an extra empty line if the message is not empty, is it intended?
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.
Fixed in message null and not-null cases, simplified the construct.
test/one/profiler/test/Assert.java
Outdated
| String operation = left + " " + comparison.operator + " " + right; | ||
|
|
||
| log.log(Level.FINE, "isAsserted " + asserted + ", " | ||
| + (message == null ? "" : "'" + message + "'") + ": " |
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.
Punctuation still looks wrong:
isAsserted false, : 0 < 1
^^^
|
|
||
| while ((line = reader.readLine()) != null) { | ||
| if (currentLine == lineNumber) { | ||
| return result + "\n\t👉 " + line.trim(); |
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.
Can you construct the entire string here? It will be easier to read comparing to when the first part of the message is somewhere else.
Also, let's avoid non-ASCII character. It does not make a big difference here, but who knows where it might go off.
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 it is a good idea to keep concerns separate, getting the source code line and building the assertion message are different responsibilities. Renamed methods and classes and further simplified Assert.java
Description
Improve
Assert.javareadability, maintainability and extensibility. Introduce a newisAssertedfunction whichisLessetc. calls with aComparisonenum. Logging and assertion is done in a single place.Motivation and context
Accept a
messageparameter in allAssert.javais*methods and move assertion checks to a single method.How has this been tested?
Sample fine logs:
Sample assertion failure:
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.