Skip to content

Commit 06bcb7c

Browse files
committed
Add assertEquals-signed-zero.ql
1 parent 0f73bcb commit 06bcb7c

File tree

1 file changed

+58
-0
lines changed

1 file changed

+58
-0
lines changed
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* Finds calls to `assertEquals` methods where one argument is a floating point zero with
3+
* explicit sign, that is `-0` or `+0`, but where the `assertEquals` method ignores the
4+
* sign of zero.
5+
*
6+
* Take for example this usage of a JUnit assertion method:
7+
* ```java
8+
* assertEquals(-0.0, value, 0.0);
9+
* ```
10+
* Here the intention might have been to verify that the value is `-0` (and not `+0`),
11+
* however this assertion method with additional 'delta' parameter ignores the sign of
12+
* zero, so it would pass even if the value is unexpectedly `+0`.
13+
*
14+
* @kind problem
15+
*/
16+
17+
import java
18+
19+
/**
20+
* `float` or `double` literal 0 with explicit `-` or `+` sign.
21+
*/
22+
class SignedZeroExpr extends UnaryExpr {
23+
SignedZeroExpr() {
24+
(
25+
this instanceof MinusExpr
26+
or this instanceof PlusExpr
27+
)
28+
and (
29+
this.getExpr().(FloatLiteral).getFloatValue() = 0
30+
or this.getExpr().(DoubleLiteral).getDoubleValue() = 0
31+
)
32+
}
33+
}
34+
35+
// TODO: Maybe use classes from AssertLib.qll?
36+
from MethodAccess assertCall, Method assertMethod, SignedZeroExpr signedZero, int floatingPointParamCount
37+
where
38+
assertMethod = assertCall.getMethod()
39+
and assertMethod.hasName("assertEquals")
40+
and floatingPointParamCount = count(Parameter p | p = assertMethod.getAParameter() and p.getType() instanceof FloatingPointType)
41+
and (
42+
assertMethod.getDeclaringType().getQualifiedName() = [
43+
"org.junit.Assert", // JUnit 4
44+
"org.junit.jupiter.api.Assertions", // JUnit 5
45+
]
46+
// For JUnit only assertion methods with additional 'delta' parameter are affected (i.e. 3 floating point parameters)
47+
// Note: JUnit 4 has undocumented behavior where a negative delta causes exact equality check considering the sign,
48+
// but not going to check for this here
49+
and floatingPointParamCount = 3
50+
or
51+
// TestNG
52+
assertMethod.getDeclaringType().hasQualifiedName("org.testng", "Assert")
53+
// For TestNG both regular 2 param method and method with additional 'delta' parameter are affected
54+
and floatingPointParamCount >= 2
55+
)
56+
// Ideally verify that this is the 'actual' or 'expected' parameter, but rather unlikely that signed zero is used as 'delta'
57+
and assertCall.getAnArgument() = signedZero
58+
select assertCall, "Assertion method ignores sign of $@", signedZero, "this expression"

0 commit comments

Comments
 (0)