Commit aa9b8167 authored by Romain F. T's avatar Romain F. T
Browse files

Fix #633 and #634

parent ff4dd2b4
<?xml version="1.0" encoding="ASCII"?>
<java:Model xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:java="http://www.eclipse.org/MoDisco/Java/0.2.incubation/java" name="j-unit-test-contains-too-many-asserts">
<ownedElements name="(default package)">
<ownedElements xsi:type="java:ClassDeclaration" originalCompilationUnit="//@compilationUnits.0" name="FooTest633">
<modifier visibility="public"/>
<superClass type="//@ownedElements.1/@ownedPackages.0/@ownedElements.0"/>
<bodyDeclarations xsi:type="java:MethodDeclaration" originalCompilationUnit="//@compilationUnits.0" name="testWith1Assert">
<modifier visibility="public"/>
<body originalCompilationUnit="//@compilationUnits.0">
<statements xsi:type="java:AssertStatement" originalCompilationUnit="//@compilationUnits.0">
<expression xsi:type="java:BooleanLiteral" originalCompilationUnit="//@compilationUnits.0" value="true"/>
</statements>
</body>
<returnType type="//@orphanTypes.5"/>
</bodyDeclarations>
<bodyDeclarations xsi:type="java:MethodDeclaration" originalCompilationUnit="//@compilationUnits.0" name="testWith3Asserts">
<modifier visibility="public"/>
<body originalCompilationUnit="//@compilationUnits.0">
<statements xsi:type="java:AssertStatement" originalCompilationUnit="//@compilationUnits.0">
<expression xsi:type="java:BooleanLiteral" originalCompilationUnit="//@compilationUnits.0" value="true"/>
</statements>
<statements xsi:type="java:AssertStatement" originalCompilationUnit="//@compilationUnits.0">
<expression xsi:type="java:BooleanLiteral" originalCompilationUnit="//@compilationUnits.0" value="true"/>
</statements>
<statements xsi:type="java:AssertStatement" originalCompilationUnit="//@compilationUnits.0">
<expression xsi:type="java:BooleanLiteral" originalCompilationUnit="//@compilationUnits.0" value="true"/>
</statements>
</body>
<returnType type="//@orphanTypes.5"/>
</bodyDeclarations>
<bodyDeclarations xsi:type="java:MethodDeclaration" originalCompilationUnit="//@compilationUnits.0" name="notATestBut3Asserts">
<modifier visibility="public"/>
<body originalCompilationUnit="//@compilationUnits.0">
<statements xsi:type="java:AssertStatement" originalCompilationUnit="//@compilationUnits.0">
<expression xsi:type="java:BooleanLiteral" originalCompilationUnit="//@compilationUnits.0" value="true"/>
</statements>
<statements xsi:type="java:AssertStatement" originalCompilationUnit="//@compilationUnits.0">
<expression xsi:type="java:BooleanLiteral" originalCompilationUnit="//@compilationUnits.0" value="true"/>
</statements>
<statements xsi:type="java:AssertStatement" originalCompilationUnit="//@compilationUnits.0">
<expression xsi:type="java:BooleanLiteral" originalCompilationUnit="//@compilationUnits.0" value="true"/>
</statements>
</body>
<returnType type="//@orphanTypes.5"/>
</bodyDeclarations>
</ownedElements>
<ownedElements xsi:type="java:ClassDeclaration" originalCompilationUnit="//@compilationUnits.0" name="FooTest633_2">
<modifier visibility="public"/>
<bodyDeclarations xsi:type="java:MethodDeclaration" originalCompilationUnit="//@compilationUnits.0" name="testInvalidClass">
<modifier visibility="public"/>
<body originalCompilationUnit="//@compilationUnits.0"/>
<returnType type="//@orphanTypes.5"/>
</bodyDeclarations>
</ownedElements>
</ownedElements>
<ownedElements name="junit" proxy="true">
<ownedPackages name="framework" proxy="true">
<ownedElements xsi:type="java:ClassDeclaration" name="TestCase" proxy="true" usagesInTypeAccess="//@ownedElements.0/@ownedElements.0/@superClass">
</ownedElements>
</ownedPackages>
</ownedElements>
<orphanTypes xsi:type="java:PrimitiveTypeInt" name="int"/>
<orphanTypes xsi:type="java:PrimitiveTypeLong" name="long"/>
<orphanTypes xsi:type="java:PrimitiveTypeFloat" name="float"/>
<orphanTypes xsi:type="java:PrimitiveTypeDouble" name="double"/>
<orphanTypes xsi:type="java:PrimitiveTypeBoolean" name="boolean"/>
<orphanTypes xsi:type="java:PrimitiveTypeVoid" name="void" usagesInTypeAccess="//@ownedElements.0/@ownedElements.0/@bodyDeclarations.0/@returnType"/>
<orphanTypes xsi:type="java:PrimitiveTypeChar" name="char"/>
<orphanTypes xsi:type="java:PrimitiveTypeShort" name="short"/>
<orphanTypes xsi:type="java:PrimitiveTypeByte" name="byte"/>
<compilationUnits name="FooTest.java" originalFilePath="/home/roschan/Projets/Eclipse/eclipse-workspace3/ATL/j-unit-test-contains-too-many-asserts/src/FooTest.java" types="//@ownedElements.0/@ownedElements.0"/>
</java:Model>
<?xml version="1.0" encoding="ASCII"?>
<java:Model xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:java="http://www.eclipse.org/MoDisco/Java/0.2.incubation/java" name="j-unit-test-should-include-assert">
<ownedElements name="(default package)">
<ownedElements xsi:type="java:ClassDeclaration" originalCompilationUnit="//@compilationUnits.0" name="FooTest634">
<modifier visibility="public"/>
<superClass type="//@ownedElements.1/@ownedPackages.0/@ownedElements.0"/>
<bodyDeclarations xsi:type="java:MethodDeclaration" originalCompilationUnit="//@compilationUnits.0" name="testWithAssert">
<modifier visibility="public"/>
<body originalCompilationUnit="//@compilationUnits.0">
<statements xsi:type="java:AssertStatement" originalCompilationUnit="//@compilationUnits.0">
<expression xsi:type="java:BooleanLiteral" originalCompilationUnit="//@compilationUnits.0" value="true"/>
</statements>
</body>
<returnType type="//@orphanTypes.5"/>
</bodyDeclarations>
<bodyDeclarations xsi:type="java:MethodDeclaration" originalCompilationUnit="//@compilationUnits.0" name="testWithoutAssert">
<modifier visibility="public"/>
<body originalCompilationUnit="//@compilationUnits.0"/>
<returnType type="//@orphanTypes.5"/>
</bodyDeclarations>
<bodyDeclarations xsi:type="java:MethodDeclaration" originalCompilationUnit="//@compilationUnits.0" name="notATestAndNoAssert">
<modifier visibility="public"/>
<body originalCompilationUnit="//@compilationUnits.0"/>
<returnType type="//@orphanTypes.5"/>
</bodyDeclarations>
</ownedElements>
<ownedElements xsi:type="java:ClassDeclaration" originalCompilationUnit="//@compilationUnits.0" name="FooTest634_2">
<modifier visibility="public"/>
<bodyDeclarations xsi:type="java:MethodDeclaration" originalCompilationUnit="//@compilationUnits.0" name="testInvalidClass">
<modifier visibility="public"/>
<body originalCompilationUnit="//@compilationUnits.0"/>
<returnType type="//@orphanTypes.5"/>
</bodyDeclarations>
</ownedElements>
</ownedElements>
<ownedElements name="junit" proxy="true">
<ownedPackages name="framework" proxy="true">
<ownedElements xsi:type="java:ClassDeclaration" name="TestCase" proxy="true" usagesInTypeAccess="//@ownedElements.0/@ownedElements.0/@superClass">
</ownedElements>
</ownedPackages>
</ownedElements>
<orphanTypes xsi:type="java:PrimitiveTypeInt" name="int"/>
<orphanTypes xsi:type="java:PrimitiveTypeLong" name="long"/>
<orphanTypes xsi:type="java:PrimitiveTypeFloat" name="float"/>
<orphanTypes xsi:type="java:PrimitiveTypeDouble" name="double"/>
<orphanTypes xsi:type="java:PrimitiveTypeBoolean" name="boolean"/>
<orphanTypes xsi:type="java:PrimitiveTypeVoid" name="void" usagesInTypeAccess="//@ownedElements.0/@ownedElements.0/@bodyDeclarations.0/@returnType"/>
<orphanTypes xsi:type="java:PrimitiveTypeChar" name="char"/>
<orphanTypes xsi:type="java:PrimitiveTypeShort" name="short"/>
<orphanTypes xsi:type="java:PrimitiveTypeByte" name="byte"/>
<compilationUnits name="FooTest.java" originalFilePath="/home/roschan/Projets/Eclipse/eclipse-workspace3/ATL/j-unit-test-should-include-assert/src/FooTest.java" types="//@ownedElements.0/@ownedElements.0"/>
</java:Model>
......@@ -158,11 +158,15 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) =
thisModule.avoidReassigningParameters(),
thisModule.avoidStringBufferField(),
thisModule.forLoopVariableCount(),
thisModule.JUnitTestsShouldIncludeAssert(),
thisModule.JUnitTestContainsTooManyAsserts(1) -- TODO il s'agit d'une
-- règle paramétrée, je ne sais pas du tout où l'utilisateur indiquerait
-- sa préférence donc en attendant je mets 1 (valeur par défaut).
thisModule.oneDeclarationPerLine(),
thisModule.switchDensity(),
-- #FIXME: thisModule.unusedLocalVariable(),
thisModule.useAssertSameInsteadOfAssertTrue(),
thisModule.useAssertTrueInsteadOfAssertEquals()
thisModule.useAssertTrueInsteadOfAssertEquals(),
-- Bugged rules:
--
......@@ -179,15 +183,8 @@ helper def: allMeasures(project : java!Model): Set(smm!Measure) =
-- thisModule.dontUseFloatTypeForLoopIndices(),
-- thisModule.methodWithSameNameAsEnclosingClass(),
-- Best practicices rules
--
thisModule.avoidThrowingNewInstanceOfSameException(),
thisModule.switchDensity()
};
--- Creates an instance of Measure for the switch statement missing one or more break/return statements
rule MeasureMissingBreakInSwitch(ss: java!SwitchStatement) {
to
......@@ -219,13 +216,13 @@ rule MeasureAbstractClassWithoutAnyMethod(i : java!ClassDeclaration) {
),
noc: smm!DimensionalMeasure (
name <- 'AbstractClassWithoutAnyMethod',
shortDescription <- 'If an abstract class does not provides any methods, it may be acting as a simple data containerth...'
shortDescription <- 'If an abstract class does not provides any methods, it may be acting as a simple data containerth...'
),
measurement: smm!DirectMeasurement (
measurement: smm!DirectMeasurement (
error<-'The class anstract' + i.name + ' has not method.'
)
do {
noc;
noc;
}
}
......@@ -239,7 +236,7 @@ rule MeasureArrayIsStoredDirectly(s: java!MethodDeclaration){
),
noc: smm!DimensionalMeasure (
name <- 'ArrayIsStoredDirectly',
shortDescription <- 'Constructors and methods receiving arrays should clone objects and store the copy'
shortDescription <- 'Constructors and methods receiving arrays should clone objects and store the copy'
),
measurement: smm!DirectMeasurement (
error <- s.name + ' has an array parameter that is not cloned before use'
......@@ -265,7 +262,7 @@ rule MeasureAvoidCallingFinalize(methode : java!MethodInvocation) {
error <- 'finalize() is called in class' + methode.originalCompilationUnit.name
)
do {
noc;
noc;
}
}
......@@ -325,11 +322,11 @@ rule MeasureAvoidEnumAsIdentifier(w: java!VariableDeclaration) {
error <- ' class '+w.originalCompilationUnit.name+ ' has a variable named to enum witch is a reserved name'
)
do {
noc;
noc;
}
}
-- ------------------------------------------- AvoidInstantiatingObjectInLoops ---------------------------------------------
-- ---------------------------------------- AvoidInstantiatingObjectInLoops -------------------------------------------
--- creates a measure when an object is instantiated in a loop
rule MeasureAvoidInstantiatingObjectInLoops(s: java!Statement){
to
......@@ -470,10 +467,10 @@ rule measureAvoidThreadGroup(variable : java!VariableDeclarationStatement) {
}
}
-- ------------------------------------------- AvoidThrowingNewInstanceOfSameException ---------------------------------------------
-- ------------------------------------- AvoidThrowingNewInstanceOfSameException -----------------------------------------
--- A Measure instance if the class violates the rule 'AvoidThrowingNewInstanceOfSameException'.
rule MeasureAvoidThrowingNewInstanceOfSameException(catch : java!CatchClause) {
to
to
om: smm!ObservedMeasure (
measure <- noc,
measurements <- measurement
......@@ -486,7 +483,7 @@ rule MeasureAvoidThrowingNewInstanceOfSameException(catch : java!CatchClause) {
error <-'The class '+ catch.originalCompilationUnit.name + ' has a method that rethrows a caught exception wrapped inside a new instance of the same type.'
)
do {
noc;
noc;
}
}
......@@ -533,7 +530,7 @@ rule MeasureAvoidUsingShortType(typeShort : java!VariableDeclarationStatement) {
}
}
-- ----------------------------------------- AvoidUsingNativeCode ------------------------------------------------------------------------------------
-- ---------------------------------------- AvoidUsingNativeCode -------------------------------------------------------
---creates a new Measure when a Java Native Interface (JNI) calls unecessary reliance(s).
rule MeasureAvoidUsingNativeCode(classDeclaration : java!ClassDeclaration) {
......@@ -673,7 +670,7 @@ rule MeasureCommentRequired(element: java!BodyDeclaration, violatedProperties: S
}
}
-- ------------------------------------------- MeasureCompareObjectsWithEquals ---------------------------------------------
-- --------------------------------------- MeasureCompareObjectsWithEquals ---------------------------------------------
--- A measure instance if the class violates the rule MeasureCompareObjectsWithEquals.
rule MeasureCompareObjectsWithEquals(expression : java!InfixExpression) {
to
......@@ -686,16 +683,16 @@ rule MeasureCompareObjectsWithEquals(expression : java!InfixExpression) {
shortDescription <- 'Use equals() to compare object references; avoid comparing them with ==.'
),
measurement: smm!DirectMeasurement (
measurement: smm!DirectMeasurement (
error<-'The Class '+ expression.originalCompilationUnit.name + ' is using == instead of equals() to compare objects.'
)
do {
noc;
noc;
}
}
}
-- -----------------------------------------DoNotCallGarbageCollectionExplicitly----------------------------------------------
-- ------------------------------------- DoNotCallGarbageCollectionExplicitly ------------------------------------------
--- A Measure instance if the class violate the rule DoNotCallGarbageCollectionExplicitly
rule MeasureDoNotCallGarbageCollectionExplicitly(method : java!MethodInvocation) {
to
......@@ -715,7 +712,7 @@ rule MeasureDoNotCallGarbageCollectionExplicitly(method : java!MethodInvocation)
}
}
-- ----------------------------------------- DoNotCallSystemExit----------------------------------------------
-- ----------------------------------------- DoNotCallSystemExit ----------------------------------------------
--- A Measure instance if the class violates the rule DoNotCallSystemExit.
rule MeasureDoNotCallSystemExit(invocation : java!MethodInvocation) {
to
......@@ -728,7 +725,7 @@ rule MeasureDoNotCallSystemExit(invocation : java!MethodInvocation) {
shortDescription <- 'Applications should not call System.exit(), since only the web container or the application server should stop the JVM'
),
measurement: smm!DirectMeasurement (
measurement: smm!DirectMeasurement (
error<- 'Do not call ' + invocation.method.getMethodClassName() + '.' + invocation.method.name + ' in the file ' + invocation.originalCompilationUnit.name
)
do {
......@@ -1133,7 +1130,7 @@ rule MeasureFieldDeclarationsShouldBeAtStartOfClass(class: java!ClassDeclaration
name <- 'FieldDeclarationsShouldBeAtStartOfClass',
shortDescription <- 'Fields should be declared at the top of the class, before any method declarations, constructors, initializers or inner classes.'
),
measurement: smm!DirectMeasurement (
measurement: smm!DirectMeasurement (
error<- 'Some of the fields of the class ' + class.name + ' are not declared at the top'
)
do {
......@@ -1141,7 +1138,7 @@ rule MeasureFieldDeclarationsShouldBeAtStartOfClass(class: java!ClassDeclaration
}
}
-- ------------------------------------------- MeasureFinalFieldCouldBeStatic ---------------------------------------------
-- --------------------------------- MeasureFinalFieldCouldBeStatic ---------------------------------------------
--- A Measure instance if the class violates the rule MeasureFinalFieldCouldBeStatic.
rule MeasureFinalFieldCouldBeStatic(field : java!FieldDeclaration) {
to
......@@ -1163,7 +1160,7 @@ rule MeasureFinalFieldCouldBeStatic(field : java!FieldDeclaration) {
}
}
-- ----------------------------------------- ForLoopVariableCount----------------------------------------------
-- ----------------------------------------- ForLoopVariableCount ----------------------------------------------
--- A Measure instance if the class violates the rule ForLoopVariableCount.
rule MeasureForLoopVariableCount(forStatement: java!ForStatement) {
to
......@@ -1184,7 +1181,7 @@ rule MeasureForLoopVariableCount(forStatement: java!ForStatement) {
}
}
-- -----------------------------------------GenericsNaming----------------------------------------------
-- ---------------------------------------- GenericsNaming ---------------------------------------------
--- A Measure instance if the class violate the rule GenericsNaming
rule MeasureGenericsNaming(type :java!TypeParameter) {
to
......@@ -1314,9 +1311,9 @@ rule MeasureIntegerInstantiation(variable : java!CompilationUnit) {
),
noc: smm!DimensionalMeasure (
name <- 'IntegerInstantiation',
shortDescription <- 'Calling new Integer() causes memory allocation that can be avoided by the static Integer.valueOf(). It makes use of an internal cache that recycles earlier instances making it more memory efficient. Note that new Integer() is deprecated since JDK 9 for that reason.'
shortDescription <- 'Calling new Integer() causes memory allocation that can be avoided by the static Integer.valueOf(). It makes use of an internal cache that recycles earlier instances making it more memory efficient. Note that new Integer() is deprecated since JDK 9 for that reason.'
),
measurement: smm!DirectMeasurement (
measurement: smm!DirectMeasurement (
error<-'In the Class '+ variable.name + ' an instantiation of Integer must be Integer.ValueOf().'
)
......@@ -1346,6 +1343,46 @@ rule MeasureJUnitSpelling(i : java!MethodDeclaration) {
}
}
-- --------------------- JUnitTestsShouldIncludeAssert -------------------------
--- A measure instance if a JUnit test class violates the rule JUnitTestsShouldIncludeAssert
rule MeasureJUnitTestsShouldIncludeAssert(m: java!MethodDeclaration, c: java!ClassDeclaration) {
to
om: smm!ObservedMeasure (
measure <- noc,
measurements <- measurement
),
noc: smm!DimensionalMeasure (
name <- 'JUnitTestsShouldIncludeAssert',
shortDescription <- 'JUnit tests should include at least one assertion.'
),
measurement: smm!DirectMeasurement (
error<- 'The JUnit test ' + m.name + ' in the class ' + c.name + ' should include at least one assertion.'
)
do {
noc;
}
}
----------------------- JUnitTestContainsTooManyAsserts ------------------------
-- A measure instance if a JUnit test class violates the rule JUnitTestContainsTooManyAsserts
rule MeasureJUnitTestContainsTooManyAsserts(m: java!MethodDeclaration, c: java!ClassDeclaration, max: Integer) {
to
om: smm!ObservedMeasure (
measure <- noc,
measurements <- measurement
),
noc: smm!DimensionalMeasure (
name <- 'JUnitTestContainsTooManyAsserts',
shortDescription <- 'Unit tests should not contain too many asserts.'
),
measurement: smm!DirectMeasurement (
error<- 'The JUnit test ' + m.getName() + ' in the class ' + c.getName() + ' contains more than ' + max + ' assertions.'
)
do {
noc;
}
}
-- ------------------------------------------- LongInstantiation ---------------------------------------------
--- A Measure instance if the class violates the rule 'LongInstantiation'.
rule MeasureLongInstantiation(variable : java!CompilationUnit) {
......
......@@ -125,16 +125,68 @@ helper context java!VariableDeclarationExpression def: nbLocalVariableDeclaratio
self.fragments.size(); -- The fragments collection contains all the variable declarations of an initializer*
-- Initializer* : for(int x = 0; ...), "int x = 0" is the initializer part of the for loop
--- helper for the rule JUnitTestsShouldIncludeAssert
--TODO ne couvre pas du tout tous les cas possibles que fait le vrai PMD (mockito, etc.)
helper def: JUnitTestsShouldIncludeAssert() : Set(smm!Measure) =
java!ClassDeclaration.allInstances()
-> select(cl | cl.isTestClass())
-> iterate(i; res : Set(smm!Measure) = Set{} | i.bodyDeclarations
-> select(mtd |
mtd.oclIsTypeOf(java!MethodDeclaration)
and mtd.isTestMethod()
and mtd.numberOfAsserts() < 1
)
-> collect(mtd | thisModule.MeasureJUnitTestsShouldIncludeAssert(mtd, i))
)
;
-- counts the number of assertions in a method declaration
helper context java!MethodDeclaration def: numberOfAsserts() : Integer =
self.getBody().statements
-> select(sttm | sttm <> OclUndefined) -- utile?
-> select(sttm | sttm.oclIsTypeOf(java!AssertStatement))
-> size()
;
-- tells if a method is a test (assuming its class is a TestCase)
-- XXX we maybe could check the annotation too?
helper context java!MethodDeclaration def: isTestMethod() : Boolean =
self.name.substring(1, 4) = 'test'
;
-- tells if a class extends TestCase
helper context java!ClassDeclaration def: isTestClass() : Boolean =
if self.superClass <> OclUndefined then -- the condition is needed because
-- using "and" doesn't prevent the execution of the rest of the expression
-- for some reason, so an error occurs
self.superClass.type.name = 'junit.framework.TestCase' or self.superClass.type.name = 'TestCase'
else
false
endif
;
--- helper for the rule JUnitTestContainsTooManyAsserts
helper def: JUnitTestContainsTooManyAsserts(maximumAsserts : Integer) : Set(smm!Measure) =
java!ClassDeclaration.allInstances()
-> select(cl | cl.isTestClass())
-> iterate(i; res : Set(smm!Measure) = Set{} | i.bodyDeclarations
-> select(mtd |
mtd.oclIsTypeOf(java!MethodDeclaration)
and mtd.isTestMethod()
and mtd.numberOfAsserts() > maximumAsserts
)
-> collect(mtd | thisModule.MeasureJUnitTestContainsTooManyAsserts(mtd, i, maximumAsserts))
)
;
-- #TODO: Add comment
helper def: oneDeclarationPerLine(): Set(smm!Measure) =
java!VariableDeclarationStatement.allInstances()
->select(s | s.fragments.size()>1)
->collect(s | thisModule.MeasureOneDeclarationPerLine(s));
--- Rule for metrics SwitchDensity :
-- #TODO: Improve comment
-- #TODO: Improve comment
helper def: switchDensity() : Set (smm!Measure) =
-- Browse through all Switch Statements
java!SwitchStatement.allInstances()->iterate(switchCase; res : Set(smm!Measure) = Set{} |
......@@ -171,8 +223,6 @@ helper def: useAssertTrueInsteadOfAssertEquals() : Set(smm!Measure) =
->select(assert | thisModule.isWrongUseAssertTrueInsteadOfAssertEquals(assert))
->collect(assert | thisModule.MesureUseAssertTrueInsteadOfAssertEquals(assert));
-- Attention !!!
-- Before adding a rule to the end of file, ensure that you are respecting the
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment