Java: Question on assert-behaviour - java

I have this code snippet
import java.util.ArrayList;
import java.util.List;
public class AssertTest {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
assert(list.add("test")); //<-- adds an element
System.out.println(list.size());
}
}
Output:
0
Why is the output list empty? How does assert behave here?
Thank you in advance!

You should enable assertion with -ea flag... such as;
java -ea -cp . AssertTest
Also using assertion is worst place for side effects..

Never assert on anything with side effects. When you run without asserts enabled (enabled with -ea), list.add("test") will not be executed.
It's a good habit to never assert anything but false, as follows:
if (!list.add("test")) {
assert false;
// Handle the problem
}

you have to enable assert. ie run as java -ea AssertTest

Incidental to your question - assertions should not contain code that is needed for the correct operation of your program, since this causes that correct operation to be dependent on whether assertions are enabled or not.

Assertions needs to be enabled. Enable them using the -ea switch.
See the Java application launcher docs.

assert method that checks whether a Boolean expression is true or false. If the expression evaluates to true, then there is no effect. But if it evaluates to false, the assert method prints the stack trace and the program aborts. In this sample implementation, a second argument for a string is used so that the cause of error can be printed.

Related

Why mockito will trigger the verify twice?

I notice this problem during the following test:
verify(mockedObject).functionCall(argThat(inputStream -> {
final String content = ... // read the inputStream
assertEquals(expectedContent, content);
return true;
}));
It will actually fail although the assertEquals assertion is true. I debug the test, find that the lambda function is reached twice, and at the second time, the cursor of the stream is at the end of the stream. That's why it fails.
So I have to reset the stream first:
verify(mockedObject).functionCall(argThat(inputStream -> {
inputStream.reset();
final String content = ... // read the inputStream
assertEquals(expectedContent, content);
return true;
}));
The question is, why the lambda is triggered twice? Is this by design? Does it have a document?
Mockito version: 2.22
Junit version: 5.6.0
Java version: 1.8
Update
The method is called exactly once, and the inputs of two lambda calls are exactly the same input. Actually, they are the same object. The only thing I have to do is to reset the stream, as it has been exhausted by the first lambda call.
I wouldn't say it's "by design", rather that it's what the current implementation does. The Mockito Times class which performs your assertions has the following method (I'm on a pretty recent version so YMMV):
public void verify(VerificationData data) {
List<Invocation> invocations = data.getAllInvocations();
MatchableInvocation wanted = data.getTarget();
if (wantedCount > 0) {
checkMissingInvocation(data.getAllInvocations(), data.getTarget());
}
checkNumberOfInvocations(invocations, wanted, wantedCount);
}
Both checkMissingInvocation and checkNumberOfInvocations perform independent filtering on the list of all invocations to retain the relevant ones, so any matcher you declare ends up being executed twice for each invocation. It's actually exactly the same call:
List<Invocation> actualInvocations = findInvocations(invocations, wanted);
Maybe the filtered list could be cached, but the point is that unless otherwise specified in the documentation, you cannot assume that the function you supply will be executed only once. Also, predicate functions are generally expected to be free of side-effects.

Assert the String has certain length (Java)

Is there any way to assert in a method that input String has certain length?
I tried assert stringName[4]; but seems like it doesn't work
If you just want to use the Java's assert keyword and not any library like JUnit, then you can probably use:
String myStr = "hello";
assert myStr.length() == 5 : "String length is incorrect";
From the official docs:
The assertion statement has two forms. The first, simpler form is:
assert Expression1;
where Expression1 is a boolean expression. When
the system runs the assertion, it evaluates Expression1 and if it is
false throws an AssertionError with no detail message.
The second form of the assertion statement is:
assert Expression1 : Expression2 ;
where:
Expression1 is a boolean expression. Expression2 is an expression that
has a value. (It cannot be an invocation of a method that is declared
void.)
You can use the following if you're using a testing library like JUnit:
String myStr = "hello";
assertEquals(5, myStr.length());
Update:
As correctly pointed out in the comments by AxelH, after compilation, you run the first solution as java -ea AssertionTest. The -ea flag enables assertions.
Instead of using assert, I'd recommend using Exception to check the state of the variables as a simple demo:
String[] arr = new String[3];
if (arr.length != 4) {
throw new IllegalStateException("Array length is not expected");
}
This will directly give the hint by exceptions and you don't need to bother with assert in jvm options.
Exception in thread "main" java.lang.IllegalStateException: Array length is not expected
at basic.AssertListLength.main(AssertListLength.java:7)
If you are using hamcrest, then you can do:
assertThat("text", hasLength(4))
See http://hamcrest.org/JavaHamcrest/javadoc/2.2/ > CharSequenceLength
Good thing about this is that it will have a proper error message, among others including the string itself.
Use AssertJ hasSize():
assertThat(stringName).hasSize(4)

why false if will execute?

Here is a code snippet from SAMLSSORelyingPartyObject in WSO2 org.wso2.carbon.hostobjects.sso package.
if (argLength != 1 || !(args[0] instanceof String)) {
String errorMsg = "Invalid argument. SAML response is missing.";
log.error(errorMsg);
throw new ScriptException(errorMsg);
}
when I was debugging this I saw even though this if expression evaluate to false, ScriptException will execute. anyone has explanation for that?
EDIT
The reason was I was debugging in wrong jar in eclipse IDE. server jar version is different was from the jar version I was debugging. even though IDE shows debug was on that line. actually debug was outside of if block
You must be misinterpreting what you saw in debug. If the complete logical expression in the if() evaluates to false, then the code inside the brackets shown will not execute. Perhaps the exception was thrown from elsewhere, or else the complete logical expression actually evaluated to true.

How to use assert in android?

I want to use assert obj != null : "object cannot be null" on Android device. The assert doesn't seem to work, so I searched online and I found this local solution:
adb shell setprop debug.assert 1
it does work on my local machine.
I want to run this command using my Eclipse project(so it would be in the source control).
How can I do it?
Assert won't work in Android because most of the time a person isn't running in debug mode, but rather some optimized code. Thus, the proper solution is to manually throw an exception, with code like this:
if (obj==null) throw new AssertionError("Object cannot be null");
It should be noted that by design, Asserts are intended for debug code, and not for release time code. So this might not be the best use of throwing an Assert. But this is how you can do it still, so...
Tested on Android 4.x device, it is possible to use Java assert on Android device:
Edit /system/build.prop (for example by X-plore), add line at end of file: debug.assert=1
Reboot phone
Now your Android device is sensible to assert checks, and will throw AssertionError when assert check fails.
EDIT:
Another easy approach, enabling asserts from PC until device is restarted:
platform-tools\adb shell setprop debug.assert 1
You may for example create a .bat file (on Windows) and run it when device is attached.
Create your own assert method:
public static <T> T assertNotNull(T object) {
if (object == null)
throw new AssertionError("Object cannot be null");
return object;
}
Returning same object allows for using this in assignments for brevity.
if (somevar == null) throw new RuntimeException();
Replace RuntimeException() with an appropriate exception subtype.
Sharing my class which I use for assertions on Android, its simpler, has nice naming and very elegant because it allows you to write asserts like this:
Assert.that(obj!=null, "Object should not be null");
Here's the code for the class:
public class Assert {
public static void that(boolean condition, String message) {
if (!condition) {
throw new AssertionError(message);
}
}
}
Hope it helps!
To make assertion available in Java Virtual Machine, using -enableassertions or -ea command-line options
on Window's Command prompt,
java –ea YourApp
on Android Studio 3.0, on Tools/Edit Configurations/VM options, input -enableassertions or -ea

Stackoverflow calling metaClass method on Map

This piece of code is causing a stackOverflow exception:
ISerializer serializer = buildSerializer(TestDataProvider.getAuthor());
ASObject result = (ASObject) serializer.serialize();
assert result.isNotLazyProxy
The StackOverflow is being thrown on this line: assert result.isNotLazyProxy. Note, the isNotLazyProxy method never actually gets called.
isNotLazyProxy is a extension method (what are these called in groovy?) defined as follows:
/**
* Asserts that this ASObject is not a lazy loaded proxy,
* ie - that all of it's properties' values have been included
*/
ASObject.metaClass.isNotLazyProxy = { ->
assert delegate[HibernateProxyConstants.PROXYINITIALIZED] == true
return true;
}
However, setting a breakpoint on the first line of that closure shows that it never gets called.
Instead, there's a StackOverflow thrown:
java.lang.StackOverflowError
at java.lang.System.arraycopy(Native Method)
at java.lang.String.getChars(String.java:855)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:391)
at java.lang.StringBuffer.append(StringBuffer.java:224)
at java.lang.StringBuffer.<init>(StringBuffer.java:104)
at org.codehaus.groovy.runtime.InvokerHelper.formatMap(InvokerHelper.java:557)
at org.codehaus.groovy.runtime.InvokerHelper.format(InvokerHelper.java:530)
at org.codehaus.groovy.runtime.InvokerHelper.formatList(InvokerHelper.java:602)
at org.codehaus.groovy.runtime.InvokerHelper.format(InvokerHelper.java:527)
at org.codehaus.groovy.runtime.InvokerHelper.formatMap(InvokerHelper.java:575)
snip
I'm not sure if it's relevant, but ASObject is a subclass of a Map, and it's contents may have properties that refer to other keys within itself.
I would've have thought it was relevant, except the StackOverflow appears to indicate that groovy is traversing the members of the map.
What's going on? Why is this stackoverflow occurring?
assert result.isNotLazyProxy is probably not doing what you want to do.
In groovy map.somehing is translated to map.get(something). See http://groovy.codehaus.org/JN1035-Maps :
assert map2.class == null
//field syntax always refers to value of key, even if it doesn't exist
//use getClass() instead of class for maps...
assert map2.getClass() == LinkedHashMap //the kind of Map being used
So use assert result.isNotLazyProxy().
Of course result.isNotLazyProxy should return null in your case, and the assert result.isNotLazyProxy assertion should fail. When this assertion fails groovy will display an assertion error, and the map. In your case formatting the map fails for some reason.
Reason it fails:
It is a known bug, see example. As I see, it has nothing to do with ASObject, as it uses no lists.
At first glance, it looks like something else is causing the endless recursion...
Does ASObject have any other metaClass methods? Especially those overriding the getAt( key ) method of Map
I came up with this quick test script, and it seems to work fine as I'd expect (and I think it does the same as what you say you're doing)
class ASObject {
#Delegate Map map = [ 'PROXYINITIALIZED' : true ]
}
ASObject.metaClass.isNotLazyProxy = { ->
assert delegate[ 'PROXYINITIALIZED' ] == true
return true
}
assert new ASObject().isNotLazyProxy()

Categories