defects4j icon indicating copy to clipboard operation
defects4j copied to clipboard

is D4J missing two triggering test cases?

Open jose opened this issue 8 years ago • 6 comments

Hi René,

I've been running a sanity check on all test methods using $D4J_HOME/framework/lib/formatter.jar and $D4J_HOME/framework/bin/defects4j test -t ..., and there are two test methods to which the outcome of each tool is different:

Lang,64,org.apache.commons.lang.enums.ValuedEnumTest::testCompareTo_classloader_different
Lang,64,org.apache.commons.lang.enums.ValuedEnumTest::testCompareTo_classloader_equal

for example, the test method testCompareTo_classloader_different passes with $D4J_HOME/framework/bin/defects4j test -t

$ $D4J_HOME/framework/bin/defects4j checkout -p Lang -v 64b -w Lang-64b
$ cd Lang-64b
$ $D4J_HOME/framework/bin/defects4j compile
$ $D4J_HOME/framework/bin/defects4j test -t org.apache.commons.lang.enums.ValuedEnumTest::testCompareTo_classloader_different

however, it fails if I use $D4J_HOME/framework/lib/formatter.jar:

$ $D4J_HOME/framework/bin/defects4j checkout -p Lang -v 64b -w Lang-64b
$ cd Lang-64b
$ CP=$($D4J_HOME/framework/bin/defects4j export -p cp.test)
$ $D4J_HOME/framework/bin/defects4j compile
java -cp "$CP:$D4J_HOME/framework/lib/formatter.jar" edu.washington.cs.mut.testrunner.SingleTestRunner org.apache.commons.lang.enums.ValuedEnumTest::testCompareTo_classloader_different

any clue why the custom JUnit runner reports a failing test method and the other approach not?

Extra

What about running the test class from the command line with org.junit.runner.JUnitCore?

$ $D4J_HOME/framework/bin/defects4j checkout -p Lang -v 64b -w Lang-64b
$ cd Lang-64b
$ CP=$($D4J_HOME/framework/bin/defects4j export -p cp.test)
$ $D4J_HOME/framework/bin/defects4j compile
$ java -cp "$CP" org.junit.runner.JUnitCore org.apache.commons.lang.enums.ValuedEnumTest

well, it seems that there are indeed 3 failing test cases and not just 1 as reported by $D4J_HOME/framework/projects/Lang/trigger_tests/64.

and actually, those 3 failing test cases seem to be triggering test cases, as they do not fail on the fixed version, i.e., Lang-64f.

jose avatar Sep 13 '16 22:09 jose

Hi José,

It seems that the difference is caused by an instanceof check on the class loader:

   public void testCompareTo_classloader_equal() throws Exception {                          
        ClassLoader cl = ValuedColorEnum.class.getClassLoader();                              
        if (cl instanceof URLClassLoader) {                                                   
            URLClassLoader urlCL = (URLClassLoader) cl;                                       
            URLClassLoader urlCL1 = new URLClassLoader(urlCL.getURLs(), null);                
            URLClassLoader urlCL2 = new URLClassLoader(urlCL.getURLs(), null);                
            Class otherEnumClass1 = urlCL1.loadClass("org.apache.commons.lang.enums.ValuedColorEnum");
            Class otherEnumClass2 = urlCL2.loadClass("org.apache.commons.lang.enums.ValuedColorEnum");
            Object blue1 = otherEnumClass1.getDeclaredField("BLUE").get(null);                
            Object blue2 = otherEnumClass2.getDeclaredField("BLUE").get(null);                
            assertTrue(((Comparable) blue1).compareTo(blue2) == 0);                           
        }                                                                                     
    }  

The two tests that fail do essentially nothing when executed with Ant.

Executing tests using JUnitCore seems generally reasonable, but this requires more thought as a project's test suite is defined within its build file. What about the following: Let's call JUnitCore from within the run.dev.tests target, for testing purposes, to see whether all defects are still reproducible and whether we observe any more unexpected failing tests. This will give us a better idea of how much effort this change would be.

rjust avatar Oct 20 '16 06:10 rjust

What about the following: Let's call JUnitCore from within the run.dev.tests target, for testing purposes, to see whether all defects are still reproducible and whether we observe any more unexpected failing tests. This will give us a better idea of how much effort this change would be.

Ok, how do we do that?

Cheers, Jose

jose avatar Oct 20 '16 11:10 jose

Currently, the run.dev.tests target calls Ant's junit task with proper classpath settings and the list of tests. We can (for testing purposes) replace the junit task with a call to an exec task that invokes JUnitCore. Converting the classpath and list of tests into the right format should be doable with Ant's filterchains.

What do you think?

rjust avatar Nov 04 '16 13:11 rjust

It sounds reasonable (at least for testing purposes). However, be aware that a solution like that would break $D4J_HOME/framework/bin/defects4j test -t functionality, as org.junit.runner.JUnitCore does not run test methods. (Well, instead of using org.junit.runner.JUnitCore we could use edu.washington.cs.mut.testrunner.SingleTestRunner from $D4J_HOME/framework/lib/formatter.jar, which runs JUnit test classes and/or test methods)

jose avatar Nov 11 '16 02:11 jose

José,

Any chance that you could implement this change so that we can try to reproduce all defects with JUnitCore? Seems like this "only" requires some changes in the top-level build file.

Thanks, René

rjust avatar Mar 05 '17 02:03 rjust

Hi!

I just came across this issue lately. It is indeed a configuration/execution environment related problem. And, by the way, it can even happen using Ant. One just has to fiddle around a bit with the params of the JUnit Ant task.

I was trying to pass some arguments to the JVM inside the JUnit task therefore I had to make Ant respect my <jvmarg /> tags by setting fork to true (the default case is fork="false").

In the default case, or when you use test with -t then the class loader hierarchy is the following:

  • sun.misc.Launcher$ExtClassLoader
  • sun.misc.Launcher$AppClassLoader
  • AntClassLoader

When you use JUnitCore, or fork is true then the class loader hierarchy is the following:

  • sun.misc.Launcher$ExtClassLoader
  • sun.misc.Launcher$AppClassLoader

ExtClassLoader and AppClassLoader are URLClassloaders, however AntClassLoader is not, hence both testCompareTo_classloader_different and testCompareTo_classloader_equal will eventually pass in the default case, because the cl instanceof URLClassLoader condition will be false, so the main part of the test will be skipped.

Frenkymd avatar Aug 30 '19 10:08 Frenkymd