diff --git a/README.md b/README.md index 6ee060ba..c9d06b8a 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,12 @@ There are command line options that can be used: | jcg.includeExceptionBasicBlocks | Set to "true" to included exception basic blocks, otherwise these will be excluded by default | -Djcg.includeExceptionBasicBlocks=true | +#### Heuristic +The "test" phase has been updated to calculate and append a heuristic value to each node. The heuristic value represents the likelihood that a property could be improved +through altering the generator and/or test case. A higher value indicates greater chance of improvement, so the paths with the top three values should be explored first. +The "test" phase will generate another dot file that has the heuristic value prepended to the name of each node. + + ## Known Restrictions * The static call graph generator does not account for methods invoked via reflection. @@ -84,6 +90,7 @@ There are command line options that can be used: Georgios Gousios Will Cygan +Jesse Coultas ### License diff --git a/artifacts/configs/convex-fixed/convex-fixed.patch b/artifacts/configs/convex-fixed/convex-fixed.patch new file mode 100644 index 00000000..0f57b637 --- /dev/null +++ b/artifacts/configs/convex-fixed/convex-fixed.patch @@ -0,0 +1,156 @@ +diff --git a/convex-core/pom.xml b/convex-core/pom.xml +index 471f81bf..3f83db91 100644 +--- a/convex-core/pom.xml ++++ b/convex-core/pom.xml +@@ -32,6 +32,59 @@ + + + ++ ++ org.jacoco ++ jacoco-maven-plugin ++ 0.8.6 ++ ++ ++ default-prepare-agent ++ ++ prepare-agent ++ ++ ++ ++ jacoco-report ++ test ++ ++ report ++ ++ ++ ++ ++ ++ org.apache.maven.plugins ++ maven-assembly-plugin ++ 3.3.0 ++ ++ ++ ++ jar-with-dependencies ++ ++ ++ ++ ++ ++ make-assembly ++ package ++ ++ single ++ ++ ++ ++ ++ ++ org.apache.maven.plugins ++ maven-jar-plugin ++ 3.2.0 ++ ++ ++ ++ test-jar ++ ++ ++ ++ + + + +@@ -44,6 +97,22 @@ + + + ++ ++ ++ ++ org.jacoco ++ jacoco-maven-plugin ++ ++ ++ ++ report ++ ++ ++ ++ ++ ++ ++ + + + org.bouncycastle +diff --git a/convex-core/src/test/java/convex/test/generators/PrimitiveGen.java b/convex-core/src/test/java/convex/test/generators/PrimitiveGen.java +index 1eba23e1..045f17d6 100644 +--- a/convex-core/src/test/java/convex/test/generators/PrimitiveGen.java ++++ b/convex-core/src/test/java/convex/test/generators/PrimitiveGen.java +@@ -5,6 +5,7 @@ import com.pholser.junit.quickcheck.generator.Generator; + import com.pholser.junit.quickcheck.random.SourceOfRandomness; + + import convex.core.data.ACell; ++import convex.core.data.Blob; + import convex.core.data.prim.CVMBool; + import convex.core.data.prim.CVMByte; + import convex.core.data.prim.CVMChar; +@@ -16,6 +17,8 @@ import convex.core.data.prim.CVMLong; + */ + public class PrimitiveGen extends Generator { + public final static PrimitiveGen INSTANCE = new PrimitiveGen(); ++ private static final int ONE_KB = 1024; ++ private static final int ONE_MB = ONE_KB * 1024; + + // public final Generator BYTE = gen().type(byte.class); + +@@ -25,7 +28,7 @@ public class PrimitiveGen extends Generator { + + @Override + public ACell generate(SourceOfRandomness r, GenerationStatus status) { +- int type = r.nextInt(6); ++ int type = r.nextInt(7); + switch (type) { + case 0: + return null; +@@ -39,8 +42,38 @@ public class PrimitiveGen extends Generator { + return CVMDouble.create(r.nextDouble()); + case 5: + return CVMBool.create(r.nextBoolean()); ++ case 6: ++ return Blob.create(r.nextBytes(getByteSize(r))); + default: + throw new Error("Unexpected type: " + type); + } + } ++ ++ private static int getByteSize(SourceOfRandomness r) { ++ int rnd = r.nextInt(1, 100); ++ ++ // 1% change of getting number 0 ++ if (rnd == 1) { ++ return 0; ++ } ++ ++ // 1% change of getting number 1 ++ if (rnd == 2) { ++ return 1; ++ } ++ ++ // 15% chance of getting a "larger" size ++ if (rnd >= 3 && rnd <= 17) { ++ return r.nextInt(ONE_KB * 4, ONE_KB * 100); ++ } ++ ++ // 5% chance of getting a "huge" size ++ if (rnd >= 18 && rnd <= 22) { ++ return r.nextInt(ONE_KB * 100, ONE_MB); ++ } ++ ++ // 78% - normalish size ++ return r.nextInt(2, ONE_KB * 4); ++ } ++ + } diff --git a/artifacts/configs/convex-fixed/convex-fixed.yaml b/artifacts/configs/convex-fixed/convex-fixed.yaml new file mode 100644 index 00000000..2b602d3a --- /dev/null +++ b/artifacts/configs/convex-fixed/convex-fixed.yaml @@ -0,0 +1,14 @@ +name: convex-fixed +URL: https://github.com/Convex-Dev/convex.git +checkoutID: e6db05a611cd4a1fb51f959e20d246637bb7744a +patchName: artifacts/configs/convex-fixed/convex-fixed.patch +subProject: convex-core +#mvnOptions: -DfailIfNoTests=false -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000" +mvnOptions: -DfailIfNoTests=false +properties: + - name: GenTestFormat#messageRoundTrip + entryPoint: "convex.comms.GenTestFormat.messageRoundTrip(Ljava/lang/String;)V" + - name: GenTestFormat#primitiveRoundTrip + entryPoint: "convex.comms.GenTestFormat.primitiveRoundTrip(Lconvex/core/data/ACell;)V" + - name: GenTestFormat#dataRoundTrip + entryPoint: "convex.comms.GenTestFormat.dataRoundTrip(Lconvex/core/data/ACell;)V" diff --git a/artifacts/configs/convex/convex.yaml b/artifacts/configs/convex/convex.yaml index dbccb339..3f8be2c4 100644 --- a/artifacts/configs/convex/convex.yaml +++ b/artifacts/configs/convex/convex.yaml @@ -6,9 +6,9 @@ subProject: convex-core #mvnOptions: -DfailIfNoTests=false -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000" mvnOptions: -DfailIfNoTests=false properties: -# - name: GenTestFormat#messageRoundTrip -# entryPoint: "convex.comms.GenTestFormat.messageRoundTrip(Ljava/lang/String;)V" + - name: GenTestFormat#messageRoundTrip + entryPoint: "convex.comms.GenTestFormat.messageRoundTrip(Ljava/lang/String;)V" - name: GenTestFormat#primitiveRoundTrip entryPoint: "convex.comms.GenTestFormat.primitiveRoundTrip(Lconvex/core/data/ACell;)V" -# - name: GenTestFormat#dataRoundTrip -# entryPoint: "convex.comms.GenTestFormat.dataRoundTrip(Lconvex/core/data/ACell;)V" + - name: GenTestFormat#dataRoundTrip + entryPoint: "convex.comms.GenTestFormat.dataRoundTrip(Lconvex/core/data/ACell;)V" diff --git a/artifacts/configs/jflex-fixed/jflex-fixed.patch b/artifacts/configs/jflex-fixed/jflex-fixed.patch new file mode 100644 index 00000000..91e11ac4 --- /dev/null +++ b/artifacts/configs/jflex-fixed/jflex-fixed.patch @@ -0,0 +1,501 @@ +diff --git a/jflex/pom.xml b/jflex/pom.xml +index 47904b61..185a3790 100644 +--- a/jflex/pom.xml ++++ b/jflex/pom.xml +@@ -51,6 +51,21 @@ + +1 + + ++ ++ ++ ++ org.jacoco ++ jacoco-maven-plugin ++ ++ ++ ++ report ++ ++ ++ ++ ++ ++ + + + com.github.vbmacher +@@ -156,6 +171,34 @@ + + + ++ ++ ++ ++ test-jar ++ ++ ++ ++ ++ ++ org.apache.maven.plugins ++ maven-assembly-plugin ++ 3.3.0 ++ ++ ++ ++ jar-with-dependencies ++ ++ ++ ++ ++ ++ make-assembly ++ package ++ ++ single ++ ++ ++ + + + org.apache.maven.plugins +@@ -231,6 +274,13 @@ + + + ++ ++ jacoco-report ++ test ++ ++ report ++ ++ + + + +diff --git a/jflex/src/test/java/jflex/core/unicode/BUILD.bazel b/jflex/src/test/java/jflex/core/unicode/BUILD.bazel +index 109146e2..4af8ce29 100644 +--- a/jflex/src/test/java/jflex/core/unicode/BUILD.bazel ++++ b/jflex/src/test/java/jflex/core/unicode/BUILD.bazel +@@ -49,9 +49,14 @@ java_test( + java_library( + name = "IntCharSetGen", + testonly = True, +- srcs = ["IntCharSetGen.java"], ++ srcs = [ ++ "IntCharGen.java", ++ "IntCharSetGen.java", ++ ], + deps = [ ++ "//jflex/src/main/java/jflex/chars", + "//jflex/src/main/java/jflex/core/unicode", ++ "//jflex/src/main/java/jflex/logging", + "//jflex/src/test/java/jflex/chars", + "//third_party/com/google/truth", + "//third_party/com/pholser/quickcheck", +diff --git a/jflex/src/test/java/jflex/core/unicode/CharClassesQuickcheck.java b/jflex/src/test/java/jflex/core/unicode/CharClassesQuickcheck.java +index 876f0387..22be04d6 100644 +--- a/jflex/src/test/java/jflex/core/unicode/CharClassesQuickcheck.java ++++ b/jflex/src/test/java/jflex/core/unicode/CharClassesQuickcheck.java +@@ -12,6 +12,7 @@ package jflex.core.unicode; + import static com.google.common.truth.Truth.assertThat; + import static org.junit.Assume.assumeTrue; + ++import com.pholser.junit.quickcheck.From; + import com.pholser.junit.quickcheck.Property; + import com.pholser.junit.quickcheck.generator.InRange; + import com.pholser.junit.quickcheck.generator.Size; +@@ -31,6 +32,7 @@ import org.junit.runner.RunWith; + */ + @RunWith(JUnitQuickcheck.class) + public class CharClassesQuickcheck { ++ UnicodeProperties unicodeProperties; + + // TODO(lsf): add testing for caseless; needs UnicodeProperties + +@@ -48,17 +50,24 @@ public class CharClassesQuickcheck { + @Property + public void addSingle( + CharClasses classes, +- @InRange(minInt = 0, maxInt = CharClasses.maxChar) int c1, +- @InRange(minInt = 0, maxInt = CharClasses.maxChar) int c2) { ++ @From(IntCharGen.class) int c1, ++ @From(IntCharGen.class) int c2, ++ boolean caseless) ++ throws UnicodeProperties.UnsupportedUnicodeVersionException { ++ + assumeTrue(c1 != c2); +- classes.makeClass(c1, false); ++ ++ if (caseless) { ++ classesInit(classes); ++ } ++ ++ classes.makeClass(c1, caseless); + assertThat(classes.invariants()).isTrue(); + assertThat(classes.getClassCode(c1)).isNotEqualTo(classes.getClassCode(c2)); + } + + @Property +- public void addSingleSingleton( +- CharClasses classes, @InRange(minInt = 0, maxInt = CharClasses.maxChar) int c) { ++ public void addSingleSingleton(CharClasses classes, @From(IntCharGen.class) int c) { + classes.makeClass(c, false); + IntCharSet set = classes.getCharClass(classes.getClassCode(c)); + assertThat(set).isEqualTo(IntCharSet.ofCharacter(c)); +@@ -68,11 +77,17 @@ public class CharClassesQuickcheck { + public void addSet( + CharClasses classes, + @InRange(maxInt = CharClasses.maxChar) IntCharSet set, +- @InRange(minInt = 0, maxInt = CharClasses.maxChar) int c) { ++ @From(IntCharGen.class) int c, ++ boolean caseless) ++ throws UnicodeProperties.UnsupportedUnicodeVersionException { + + assumeTrue(!set.contains(c)); + +- classes.makeClass(set, false); ++ if (caseless) { ++ classesInit(classes); ++ } ++ ++ classes.makeClass(set, caseless); + assertThat(classes.invariants()).isTrue(); + + int[] classCodes = classes.getClassCodes(set, false); +@@ -84,9 +99,15 @@ public class CharClassesQuickcheck { + + @Property + public void addSetParts( +- CharClasses classes, @InRange(maxInt = CharClasses.maxChar) IntCharSet set) { ++ CharClasses classes, @InRange(maxInt = CharClasses.maxChar) IntCharSet set, boolean caseless) ++ throws UnicodeProperties.UnsupportedUnicodeVersionException { + +- classes.makeClass(set, false); ++ if (caseless) { ++ classesInit(classes); ++ set = set.getCaseless(unicodeProperties); ++ } ++ ++ classes.makeClass(set, caseless); + + int[] classCodes = classes.getClassCodes(set, false); + IntCharSet allParts = new IntCharSet(); +@@ -98,9 +119,15 @@ public class CharClassesQuickcheck { + + @Property + public void addSetComplement( +- CharClasses classes, @InRange(maxInt = CharClasses.maxChar) IntCharSet set) { ++ CharClasses classes, @InRange(maxInt = CharClasses.maxChar) IntCharSet set, boolean caseless) ++ throws UnicodeProperties.UnsupportedUnicodeVersionException { ++ ++ if (caseless) { ++ classesInit(classes); ++ set = set.getCaseless(unicodeProperties); ++ } + +- classes.makeClass(set, false); ++ classes.makeClass(set, caseless); + + int[] notCodes = classes.getClassCodes(set, true); + IntCharSet others = new IntCharSet(); +@@ -112,11 +139,16 @@ public class CharClassesQuickcheck { + + @Property + public void addString( +- CharClasses classes, String s, @InRange(minInt = 0, maxInt = CharClasses.maxChar) int c) { ++ CharClasses classes, String s, @From(IntCharGen.class) int c, boolean caseless) ++ throws UnicodeProperties.UnsupportedUnicodeVersionException { + + assumeTrue(s.indexOf(c) < 0); + +- classes.makeClass(s, false); ++ if (caseless) { ++ classesInit(classes); ++ } ++ ++ classes.makeClass(s, caseless); + assertThat(classes.invariants()).isTrue(); + + int cCode = classes.getClassCode(c); +@@ -203,4 +235,18 @@ public class CharClassesQuickcheck { + assertThat(intervals[i].end + 1).isEqualTo(intervals[i + 1].start); + } + } ++ ++ private void classesInit(CharClasses classes) ++ throws UnicodeProperties.UnsupportedUnicodeVersionException { ++ // init classes ++ unicodeProperties = new UnicodeProperties(); ++ classes.init( ++ CharClasses.maxChar, ++ new ILexScan() { ++ @Override ++ public UnicodeProperties getUnicodeProperties() { ++ return unicodeProperties; ++ } ++ }); ++ } + } +diff --git a/jflex/src/test/java/jflex/core/unicode/IntCharGen.java b/jflex/src/test/java/jflex/core/unicode/IntCharGen.java +new file mode 100644 +index 00000000..45e47ee8 +--- /dev/null ++++ b/jflex/src/test/java/jflex/core/unicode/IntCharGen.java +@@ -0,0 +1,47 @@ ++package jflex.core.unicode; ++ ++import com.pholser.junit.quickcheck.generator.GenerationStatus; ++import com.pholser.junit.quickcheck.generator.Generator; ++import com.pholser.junit.quickcheck.random.SourceOfRandomness; ++import java.util.List; ++import jflex.chars.Interval; ++import jflex.logging.Out; ++ ++/** ++ * Generator for random Integer values that ensure to sometimes generate a cased character ++ * ++ * @author Jesse Coultas ++ * @version JFlex 1.8.2 ++ */ ++public class IntCharGen extends Generator { ++ /** Constructs generator for CharClasses */ ++ public IntCharGen() throws UnicodeProperties.UnsupportedUnicodeVersionException { ++ super(Integer.class); ++ } ++ ++ @Override ++ public Integer generate(SourceOfRandomness r, GenerationStatus status) { ++ // ensure we sometimes generate an int that has case options ++ if (r.nextBoolean()) { ++ try { ++ return getRandomCased(r); ++ } catch (UnicodeProperties.UnsupportedUnicodeVersionException e) { ++ Out.warning("Unable to fetch a random cased value - " + e.getMessage()); ++ } ++ } ++ ++ return r.nextInt(0, CharClasses.maxChar); ++ } ++ ++ public static Integer getRandomCased(SourceOfRandomness r) ++ throws UnicodeProperties.UnsupportedUnicodeVersionException { ++ // get list of casedIntervals ++ List casedIntervals = (new UnicodeProperties()).getIntCharSet("cased").getIntervals(); ++ ++ // randomly pick an interval ++ Interval interval = casedIntervals.get(r.nextInt(0, casedIntervals.size() - 1)); ++ ++ // return a value between start and end of interval ++ return r.nextInt(interval.start, interval.end); ++ } ++} +diff --git a/jflex/src/test/java/jflex/core/unicode/IntCharSetGen.java b/jflex/src/test/java/jflex/core/unicode/IntCharSetGen.java +index 7ff19e45..9d80976a 100644 +--- a/jflex/src/test/java/jflex/core/unicode/IntCharSetGen.java ++++ b/jflex/src/test/java/jflex/core/unicode/IntCharSetGen.java +@@ -15,6 +15,7 @@ import com.pholser.junit.quickcheck.generator.InRange; + import com.pholser.junit.quickcheck.generator.Size; + import com.pholser.junit.quickcheck.random.SourceOfRandomness; + import jflex.chars.IntervalGen; ++import jflex.logging.Out; + + /** + * Generator for random {@link IntCharSet} instances. +@@ -48,6 +49,15 @@ public class IntCharSetGen extends Generator { + result.add(intervals.generate(r, status)); + } + ++ // randomly add possible additional cased character ++ if (numIntervals < maxSize && r.nextBoolean()) { ++ try { ++ result.add(IntCharGen.getRandomCased(r)); ++ } catch (UnicodeProperties.UnsupportedUnicodeVersionException e) { ++ Out.warning("Unable to fetch a random cased value - " + e.getMessage()); ++ } ++ } ++ + return result; + } + +diff --git a/jflex/src/test/java/jflex/state/BUILD.bazel b/jflex/src/test/java/jflex/state/BUILD.bazel +index 936249c8..7481ca43 100644 +--- a/jflex/src/test/java/jflex/state/BUILD.bazel ++++ b/jflex/src/test/java/jflex/state/BUILD.bazel +@@ -3,6 +3,7 @@ java_test( + size = "small", + timeout = "short", + srcs = [ ++ "OffsetGen.java", + "StateSetGen.java", + "StateSetQuickcheck.java", + ], +diff --git a/jflex/src/test/java/jflex/state/OffsetGen.java b/jflex/src/test/java/jflex/state/OffsetGen.java +new file mode 100644 +index 00000000..fd9d5ab3 +--- /dev/null ++++ b/jflex/src/test/java/jflex/state/OffsetGen.java +@@ -0,0 +1,45 @@ ++package jflex.state; ++ ++import com.pholser.junit.quickcheck.generator.GenerationStatus; ++import com.pholser.junit.quickcheck.generator.Generator; ++import com.pholser.junit.quickcheck.random.SourceOfRandomness; ++ ++/** Generator for Offset data values */ ++public class OffsetGen extends Generator { ++ public OffsetGen() { ++ super(Integer.class); ++ } ++ ++ @Override ++ public Integer generate(SourceOfRandomness r, GenerationStatus status) { ++ int rnd = r.nextInt(1, 100); ++ ++ // 5% change of getting number 0 ++ if (rnd >= 1 && rnd <= 5) { ++ return 0; ++ } ++ ++ // 5% change of getting number 1 ++ if (rnd >= 6 && rnd <= 10) { ++ return 1; ++ } ++ ++ // 5% change of getting Integer.MAX_VALUE ++ if (rnd >= 11 && rnd <= 15) { ++ return Integer.MAX_VALUE; ++ } ++ ++ // 15% chance of getting a "larger" size ++ if (rnd >= 16 && rnd <= 30) { ++ return r.nextInt(200_001, 10_000_000); ++ } ++ ++ // 5% chance of getting a "huge" size ++ if (rnd >= 31 && rnd <= 35) { ++ return r.nextInt(10_000_001, Integer.MAX_VALUE); ++ } ++ ++ // 77% - normalish size ++ return r.nextInt(100, 20_000); ++ } ++} +diff --git a/jflex/src/test/java/jflex/state/StateSetGen.java b/jflex/src/test/java/jflex/state/StateSetGen.java +index e9962397..1f4d2443 100644 +--- a/jflex/src/test/java/jflex/state/StateSetGen.java ++++ b/jflex/src/test/java/jflex/state/StateSetGen.java +@@ -50,6 +50,11 @@ public class StateSetGen extends Generator { + result.addState(r.nextInt(minRange, maxRange)); + } + ++ // add large value 20% of the time ++ if (r.nextInt(1, 5) == 5) { ++ result.addState(r.nextInt(minRange + 100_000, maxRange + 100_000)); ++ } ++ + return result; + } + +diff --git a/jflex/src/test/java/jflex/state/StateSetQuickcheck.java b/jflex/src/test/java/jflex/state/StateSetQuickcheck.java +index 2537700d..0ac0e12c 100644 +--- a/jflex/src/test/java/jflex/state/StateSetQuickcheck.java ++++ b/jflex/src/test/java/jflex/state/StateSetQuickcheck.java +@@ -11,9 +11,13 @@ package jflex.state; + + import static com.google.common.truth.Truth.assertThat; + import static com.google.common.truth.Truth.assertWithMessage; ++import static org.hamcrest.core.IsEqual.equalTo; ++import static org.junit.Assume.assumeThat; + import static org.junit.Assume.assumeTrue; + ++import com.pholser.junit.quickcheck.From; + import com.pholser.junit.quickcheck.Property; ++import com.pholser.junit.quickcheck.generator.Also; + import com.pholser.junit.quickcheck.generator.InRange; + import com.pholser.junit.quickcheck.generator.Size; + import com.pholser.junit.quickcheck.runner.JUnitQuickcheck; +@@ -157,7 +161,8 @@ public class StateSetQuickcheck { + @Property + public void removeAdd( + @Size(max = 90) @InRange(minInt = 0, maxInt = 100) StateSet s, +- @InRange(minInt = 0, maxInt = 100) int e) { ++ @InRange(minInt = 0, maxInt = 100) int e, ++ @From(OffsetGen.class) int largeOffset) { + assumeTrue(s.hasElement(e)); + StateSet sPre = new StateSet(s); + s.remove(e); +@@ -165,6 +170,17 @@ public class StateSetQuickcheck { + assertThat(s).isNotEqualTo(sPre); + s.addState(e); + assertThat(s).isEqualTo(sPre); ++ ++ // add larger state value to force resize ++ if ((Integer.MAX_VALUE - largeOffset) <= s.bits.length) { // avoid overrun wrap ++ largeOffset = Integer.MAX_VALUE - s.bits.length; ++ } ++ int largerState = ++ ((s.bits.length + largeOffset) << StateSet.BITS) & Integer.MAX_VALUE; // & resets sign bit ++ s.addState(largerState); ++ assertThat(s).contains(largerState); ++ s.remove(largerState); ++ assertThat(s).isEqualTo(sPre); + } + + @Property +@@ -181,10 +197,27 @@ public class StateSetQuickcheck { + } + + @Property +- public void addStateDoesNotRemove(StateSet set, @InRange(minInt = 0, maxInt = 34) int e) { ++ public void addStateDoesNotRemove( ++ StateSet set, @Also("2147483647") @InRange(minInt = 0, maxInt = 34) int e) { + StateSet setPre = new StateSet(set); + set.addState(e); + assertThat(set.contains(setPre)).isTrue(); ++ assertThat(set.hasElement(e)).isTrue(); ++ ++ // add an out of range value to increase coverage of contains ++ ++ // offset to StateSetGen.maxRange + 1 ++ int offset = ++ 1001; // note this effected by InRange, so this needs to be adjusted based on annotations ++ // on set, default is set ++ ++ // if no overflow then offset + e, else overflow so use MAX_VALUE ++ int newValue = (Integer.MAX_VALUE - offset) >= e ? offset + e : Integer.MAX_VALUE; ++ assumeThat(set.hasElement(newValue), equalTo(false)); ++ set.addState(newValue); ++ assertThat(set.contains(setPre)).isTrue(); ++ assertThat(set.hasElement(newValue)).isTrue(); ++ assertThat(setPre.contains(set)).isFalse(); + } + + @Property +@@ -208,6 +241,12 @@ public class StateSetQuickcheck { + StateSet comp = s1.complement(s2); + // only elements of s2 are in the complement + assertThat(s2.contains(comp)).isTrue(); ++ ++ // ensure that comp does not contain s1 ++ StateSet empty = new StateSet(); ++ if (!empty.contains(s1)) { // if s1 is {}, then it will always be contained in comp ++ assertThat(comp.contains(s1)).isFalse(); ++ } + } + + @Property +@@ -228,6 +267,13 @@ public class StateSetQuickcheck { + public void containsElements(StateSet s, @InRange(minInt = 0, maxInt = 34) int e) { + s.addState(e); + assertThat(s.containsElements()).isTrue(); ++ ++ // remove each added element, ot ensure containsElements continues to work as elements are ++ // removed ++ while (s.containsElements()) { ++ s.getAndRemoveElement(); ++ } ++ assertThat(s.containsElements()).isFalse(); + } + + @Property \ No newline at end of file diff --git a/artifacts/configs/jflex-fixed/jflex-fixed.yaml b/artifacts/configs/jflex-fixed/jflex-fixed.yaml new file mode 100644 index 00000000..893ae1ca --- /dev/null +++ b/artifacts/configs/jflex-fixed/jflex-fixed.yaml @@ -0,0 +1,98 @@ +name: jflex-fixed +URL: https://github.com/jflex-de/jflex.git +checkoutID: e6d1752bd48a7ccb2a2b78479dc5a73ac475bbb9 +patchName: artifacts/configs/jflex-fixed/jflex-fixed.patch +subProject: jflex +#mvnOptions: -DfailIfNoTests=false -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000" +mvnOptions: -DfailIfNoTests=false +properties: + - name: StateSetQuickcheck#size2nbits + entryPoint: "jflex.state.StateSetQuickcheck.size2nbits(I)V" + - name: StateSetQuickcheck#containsIsSubset + entryPoint: "jflex.state.StateSetQuickcheck.containsIsSubset(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#addIsUnion + entryPoint: "jflex.state.StateSetQuickcheck.addIsUnion(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#addCommutes + entryPoint: "jflex.state.StateSetQuickcheck.addCommutes(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#addEmpty + entryPoint: "jflex.state.StateSetQuickcheck.addEmpty(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#addSelf + entryPoint: "jflex.state.StateSetQuickcheck.addSelf(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#addIdemPotent + entryPoint: "jflex.state.StateSetQuickcheck.addIdemPotent(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#intersect + entryPoint: "jflex.state.StateSetQuickcheck.intersect(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#intersectUnchanged + entryPoint: "jflex.state.StateSetQuickcheck.intersectUnchanged(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#intersectCommutes + entryPoint: "jflex.state.StateSetQuickcheck.intersectCommutes(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#intersectEmpty + entryPoint: "jflex.state.StateSetQuickcheck.intersectEmpty(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#intersectSelf + entryPoint: "jflex.state.StateSetQuickcheck.intersectSelf(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#containsItsElements + entryPoint: "jflex.state.StateSetQuickcheck.containsItsElements(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#removeRemoves + entryPoint: "jflex.state.StateSetQuickcheck.removeRemoves(Ljflex/state/StateSet;I)V" + - name: StateSetQuickcheck#removeAdd + entryPoint: "jflex.state.StateSetQuickcheck.removeAdd(Ljflex/state/StateSet;II)V" + - name: StateSetQuickcheck#clearMakesEmpty + entryPoint: "jflex.state.StateSetQuickcheck.clearMakesEmpty(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#addStateAdds + entryPoint: "jflex.state.StateSetQuickcheck.addStateAdds(Ljflex/state/StateSet;I)V" + - name: StateSetQuickcheck#addStateDoesNotRemove + entryPoint: "jflex.state.StateSetQuickcheck.addStateDoesNotRemove(Ljflex/state/StateSet;I)V" + - name: StateSetQuickcheck#addStateAdd + entryPoint: "jflex.state.StateSetQuickcheck.addStateAdd(Ljflex/state/StateSet;I)V" + - name: StateSetQuickcheck#complementNoOriginalElements + entryPoint: "jflex.state.StateSetQuickcheck.complementNoOriginalElements(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#complementElements + entryPoint: "jflex.state.StateSetQuickcheck.complementElements(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#complementUnion + entryPoint: "jflex.state.StateSetQuickcheck.complementUnion(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#containsElements + entryPoint: "jflex.state.StateSetQuickcheck.containsElements(Ljflex/state/StateSet;I)V" + - name: StateSetQuickcheck#containsNoElements + entryPoint: "jflex.state.StateSetQuickcheck.containsNoElements(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#copy + entryPoint: "jflex.state.StateSetQuickcheck.copy(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#copyInto + entryPoint: "jflex.state.StateSetQuickcheck.copyInto(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#hashCode + entryPoint: "jflex.state.StateSetQuickcheck.hashCode(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#getAndRemoveRemoves + entryPoint: "jflex.state.StateSetQuickcheck.getAndRemoveRemoves(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#getAndRemoveIsElement + entryPoint: "jflex.state.StateSetQuickcheck.getAndRemoveIsElement(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#getAndRemoveAdd + entryPoint: "jflex.state.StateSetQuickcheck.getAndRemoveAdd(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#enumerator + entryPoint: "jflex.state.StateSetQuickcheck.enumerator(Ljflex/state/StateSet;)V" + - name: CharClassesQuickcheck#invariants + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.invariants(Ljflex/core/unicode/CharClasses;)V" + - name: CharClassesQuickcheck#maxCharCode + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.maxCharCode(Ljflex/core/unicode/CharClasses;)V" + - name: CharClassesQuickcheck#addSingle + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.addSingle(Ljflex/core/unicode/CharClasses;IIZ)V" + - name: CharClassesQuickcheck#addSingleSingleton + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.addSingleSingleton(Ljflex/core/unicode/CharClasses;I)V" + - name: CharClassesQuickcheck#addSet + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.addSet(Ljflex/core/unicode/CharClasses;Ljflex/core/unicode/IntCharSet;IZ)V" + - name: CharClassesQuickcheck#addSetParts + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.addSetParts(Ljflex/core/unicode/CharClasses;Ljflex/core/unicode/IntCharSet;Z)V" + - name: CharClassesQuickcheck#addSetComplement + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.addSetComplement(Ljflex/core/unicode/CharClasses;Ljflex/core/unicode/IntCharSet;Z)V" + - name: CharClassesQuickcheck#addString + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.addString(Ljflex/core/unicode/CharClasses;Ljava/lang/String;IZ)V" + - name: CharClassesQuickcheck#normaliseSingle + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.normaliseSingle(Ljflex/core/unicode/CharClasses;I)V" + - name: CharClassesQuickcheck#computeTablesEq + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.computeTablesEq(Ljflex/core/unicode/CharClasses;Ljava/util/ArrayList;)V" + - name: CharClassesQuickcheck#getTablesEq + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.getTablesEq(Ljflex/core/unicode/CharClasses;Ljava/util/ArrayList;)V" + - name: CharClassesQuickcheck#classCodesUnion + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.classCodesUnion(Ljflex/core/unicode/CharClasses;)V" + - name: CharClassesQuickcheck#classCodesCode + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.classCodesCode(Ljflex/core/unicode/CharClasses;)V" + - name: CharClassesQuickcheck#classCodesDisjointOrdered + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.classCodesDisjointOrdered(Ljflex/core/unicode/CharClasses;)V" diff --git a/artifacts/configs/jflex/jflex.patch b/artifacts/configs/jflex/jflex.patch index e7ca97d0..5048f75b 100644 --- a/artifacts/configs/jflex/jflex.patch +++ b/artifacts/configs/jflex/jflex.patch @@ -73,23 +73,3 @@ index 47904b61..185a3790 100644 - -diff --git a/jflex/src/test/java/jflex/state/StateSetQuickcheck.java b/jflex/src/test/java/jflex/state/StateSetQuickcheck.java -index c3ac7e67..35c34f32 100644 ---- a/jflex/src/test/java/jflex/state/StateSetQuickcheck.java -+++ b/jflex/src/test/java/jflex/state/StateSetQuickcheck.java -@@ -165,6 +165,13 @@ public class StateSetQuickcheck { - assertThat(s).isNotEqualTo(sPre); - s.addState(e); - assertThat(s).isEqualTo(sPre); -+ -+ // remove with add larger to force resize -+ s.remove(e); -+ assertThat(sPre.contains(s)).isTrue(); -+ assertThat(s).isNotEqualTo(sPre); -+ s.addState(e + 384); -+ assertThat(s).contains(e + 384); - } - - @Property - diff --git a/artifacts/configs/jflex/jflex.yaml b/artifacts/configs/jflex/jflex.yaml index d87b90aa..b9a249a4 100644 --- a/artifacts/configs/jflex/jflex.yaml +++ b/artifacts/configs/jflex/jflex.yaml @@ -6,65 +6,93 @@ subProject: jflex #mvnOptions: -DfailIfNoTests=false -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000" mvnOptions: -DfailIfNoTests=false properties: - # - name: StateSetQuickcheck#size2nbits - # entryPoint: "jflex.state.StateSetQuickcheck.size2nbits(I)V" - # - name: StateSetQuickcheck#containsIsSubset - # entryPoint: "jflex.state.StateSetQuickcheck.containsIsSubset(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#addIsUnion - # entryPoint: "jflex.state.StateSetQuickcheck.addIsUnion(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#addCommutes - # entryPoint: "jflex.state.StateSetQuickcheck.addCommutes(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#addEmpty - # entryPoint: "jflex.state.StateSetQuickcheck.addEmpty(Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#addSelf - # entryPoint: "jflex.state.StateSetQuickcheck.addSelf(Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#addIdemPotent - # entryPoint: "jflex.state.StateSetQuickcheck.addIdemPotent(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#intersect - # entryPoint: "jflex.state.StateSetQuickcheck.intersect(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#intersectUnchanged - # entryPoint: "jflex.state.StateSetQuickcheck.intersectUnchanged(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#intersectCommutes - # entryPoint: "jflex.state.StateSetQuickcheck.intersectCommutes(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#intersectEmpty - # entryPoint: "jflex.state.StateSetQuickcheck.intersectEmpty(Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#intersectSelf - # entryPoint: "jflex.state.StateSetQuickcheck.intersectSelf(Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#containsItsElements - # entryPoint: "jflex.state.StateSetQuickcheck.containsItsElements(Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#removeRemoves - # entryPoint: "jflex.state.StateSetQuickcheck.removeRemoves(Ljflex/state/StateSet;I)V" + - name: StateSetQuickcheck#size2nbits + entryPoint: "jflex.state.StateSetQuickcheck.size2nbits(I)V" + - name: StateSetQuickcheck#containsIsSubset + entryPoint: "jflex.state.StateSetQuickcheck.containsIsSubset(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#addIsUnion + entryPoint: "jflex.state.StateSetQuickcheck.addIsUnion(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#addCommutes + entryPoint: "jflex.state.StateSetQuickcheck.addCommutes(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#addEmpty + entryPoint: "jflex.state.StateSetQuickcheck.addEmpty(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#addSelf + entryPoint: "jflex.state.StateSetQuickcheck.addSelf(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#addIdemPotent + entryPoint: "jflex.state.StateSetQuickcheck.addIdemPotent(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#intersect + entryPoint: "jflex.state.StateSetQuickcheck.intersect(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#intersectUnchanged + entryPoint: "jflex.state.StateSetQuickcheck.intersectUnchanged(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#intersectCommutes + entryPoint: "jflex.state.StateSetQuickcheck.intersectCommutes(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#intersectEmpty + entryPoint: "jflex.state.StateSetQuickcheck.intersectEmpty(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#intersectSelf + entryPoint: "jflex.state.StateSetQuickcheck.intersectSelf(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#containsItsElements + entryPoint: "jflex.state.StateSetQuickcheck.containsItsElements(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#removeRemoves + entryPoint: "jflex.state.StateSetQuickcheck.removeRemoves(Ljflex/state/StateSet;I)V" - name: StateSetQuickcheck#removeAdd entryPoint: "jflex.state.StateSetQuickcheck.removeAdd(Ljflex/state/StateSet;I)V" - # - name: StateSetQuickcheck#clearMakesEmpty - # entryPoint: "jflex.state.StateSetQuickcheck.clearMakesEmpty(Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#addStateAdds - # entryPoint: "jflex.state.StateSetQuickcheck.addStateAdds(Ljflex/state/StateSet;I)V" - # - name: StateSetQuickcheck#addStateDoesNotRemove - # entryPoint: "jflex.state.StateSetQuickcheck.addStateDoesNotRemove(Ljflex/state/StateSet;I)V" - # - name: StateSetQuickcheck#addStateAdd - # entryPoint: "jflex.state.StateSetQuickcheck.addStateAdd(Ljflex/state/StateSet;I)V" - # - name: StateSetQuickcheck#complementNoOriginalElements - # entryPoint: "jflex.state.StateSetQuickcheck.complementNoOriginalElements(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#complementElements - # entryPoint: "jflex.state.StateSetQuickcheck.complementElements(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#complementUnion - # entryPoint: "jflex.state.StateSetQuickcheck.complementUnion(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#containsElements - # entryPoint: "jflex.state.StateSetQuickcheck.containsElements(Ljflex/state/StateSet;I)V" - # - name: StateSetQuickcheck#containsNoElements - # entryPoint: "jflex.state.StateSetQuickcheck.containsNoElements(Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#copy - # entryPoint: "jflex.state.StateSetQuickcheck.copy(Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#copyInto - # entryPoint: "jflex.state.StateSetQuickcheck.copyInto(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#hashCode - # entryPoint: "jflex.state.StateSetQuickcheck.hashCode(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#getAndRemoveRemoves - # entryPoint: "jflex.state.StateSetQuickcheck.getAndRemoveRemoves(Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#getAndRemoveIsElement - # entryPoint: "jflex.state.StateSetQuickcheck.getAndRemoveIsElement(Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#getAndRemoveAdd - # entryPoint: "jflex.state.StateSetQuickcheck.getAndRemoveAdd(Ljflex/state/StateSet;)V" - # - name: StateSetQuickcheck#enumerator - # entryPoint: "jflex.state.StateSetQuickcheck.enumerator(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#clearMakesEmpty + entryPoint: "jflex.state.StateSetQuickcheck.clearMakesEmpty(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#addStateAdds + entryPoint: "jflex.state.StateSetQuickcheck.addStateAdds(Ljflex/state/StateSet;I)V" + - name: StateSetQuickcheck#addStateDoesNotRemove + entryPoint: "jflex.state.StateSetQuickcheck.addStateDoesNotRemove(Ljflex/state/StateSet;I)V" + - name: StateSetQuickcheck#addStateAdd + entryPoint: "jflex.state.StateSetQuickcheck.addStateAdd(Ljflex/state/StateSet;I)V" + - name: StateSetQuickcheck#complementNoOriginalElements + entryPoint: "jflex.state.StateSetQuickcheck.complementNoOriginalElements(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#complementElements + entryPoint: "jflex.state.StateSetQuickcheck.complementElements(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#complementUnion + entryPoint: "jflex.state.StateSetQuickcheck.complementUnion(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#containsElements + entryPoint: "jflex.state.StateSetQuickcheck.containsElements(Ljflex/state/StateSet;I)V" + - name: StateSetQuickcheck#containsNoElements + entryPoint: "jflex.state.StateSetQuickcheck.containsNoElements(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#copy + entryPoint: "jflex.state.StateSetQuickcheck.copy(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#copyInto + entryPoint: "jflex.state.StateSetQuickcheck.copyInto(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#hashCode + entryPoint: "jflex.state.StateSetQuickcheck.hashCode(Ljflex/state/StateSet;Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#getAndRemoveRemoves + entryPoint: "jflex.state.StateSetQuickcheck.getAndRemoveRemoves(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#getAndRemoveIsElement + entryPoint: "jflex.state.StateSetQuickcheck.getAndRemoveIsElement(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#getAndRemoveAdd + entryPoint: "jflex.state.StateSetQuickcheck.getAndRemoveAdd(Ljflex/state/StateSet;)V" + - name: StateSetQuickcheck#enumerator + entryPoint: "jflex.state.StateSetQuickcheck.enumerator(Ljflex/state/StateSet;)V" + - name: CharClassesQuickcheck#invariants + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.invariants(Ljflex/core/unicode/CharClasses;)V" + - name: CharClassesQuickcheck#maxCharCode + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.maxCharCode(Ljflex/core/unicode/CharClasses;)V" + - name: CharClassesQuickcheck#addSingle + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.addSingle(Ljflex/core/unicode/CharClasses;II)V" + - name: CharClassesQuickcheck#addSingleSingleton + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.addSingleSingleton(Ljflex/core/unicode/CharClasses;I)V" + - name: CharClassesQuickcheck#addSet + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.addSet(Ljflex/core/unicode/CharClasses;Ljflex/core/unicode/IntCharSet;I)V" + - name: CharClassesQuickcheck#addSetParts + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.addSetParts(Ljflex/core/unicode/CharClasses;Ljflex/core/unicode/IntCharSet;)V" + - name: CharClassesQuickcheck#addSetComplement + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.addSetComplement(Ljflex/core/unicode/CharClasses;Ljflex/core/unicode/IntCharSet;)V" + - name: CharClassesQuickcheck#addString + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.addString(Ljflex/core/unicode/CharClasses;Ljava/lang/String;I)V" + - name: CharClassesQuickcheck#normaliseSingle + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.normaliseSingle(Ljflex/core/unicode/CharClasses;I)V" + - name: CharClassesQuickcheck#computeTablesEq + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.computeTablesEq(Ljflex/core/unicode/CharClasses;Ljava/util/ArrayList;)V" + - name: CharClassesQuickcheck#getTablesEq + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.getTablesEq(Ljflex/core/unicode/CharClasses;Ljava/util/ArrayList;)V" + - name: CharClassesQuickcheck#classCodesUnion + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.classCodesUnion(Ljflex/core/unicode/CharClasses;)V" + - name: CharClassesQuickcheck#classCodesCode + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.classCodesCode(Ljflex/core/unicode/CharClasses;)V" + - name: CharClassesQuickcheck#classCodesDisjointOrdered + entryPoint: "jflex.core.unicode.CharClassesQuickcheck.classCodesDisjointOrdered(Ljflex/core/unicode/CharClasses;)V" diff --git a/artifacts/configs/mph-table-fixed/mph-table-fixed.patch b/artifacts/configs/mph-table-fixed/mph-table-fixed.patch new file mode 100644 index 00000000..2c55cfeb --- /dev/null +++ b/artifacts/configs/mph-table-fixed/mph-table-fixed.patch @@ -0,0 +1,161 @@ +diff --git a/pom.xml b/pom.xml +--- a/pom.xml (revision dbd5413df33bf8f0a995822eeefe94df50f3c5a7) ++++ b/pom.xml (date 1655257746259) +@@ -40,8 +40,75 @@ + 1.8 + + ++ ++ org.jacoco ++ jacoco-maven-plugin ++ 0.8.6 ++ ++ ++ default-prepare-agent ++ ++ prepare-agent ++ ++ ++ ++ jacoco-report ++ test ++ ++ report ++ ++ ++ ++ ++ ++ org.apache.maven.plugins ++ maven-jar-plugin ++ 3.2.0 ++ ++ ++ ++ test-jar ++ ++ ++ ++ ++ ++ org.apache.maven.plugins ++ maven-assembly-plugin ++ 3.3.0 ++ ++ ++ jar-with-dependencies ++ ++ ++ ++ ++ make-assembly ++ package ++ ++ single ++ ++ ++ ++ + + ++ ++ ++ ++ ++ org.jacoco ++ jacoco-maven-plugin ++ ++ ++ ++ report ++ ++ ++ ++ ++ ++ + + + +diff --git a/src/test/java/com/indeed/mph/generators/IntListGenerator.java b/src/test/java/com/indeed/mph/generators/IntListGenerator.java +new file mode 100644 +index 0000000..33b6870 +--- /dev/null ++++ b/src/test/java/com/indeed/mph/generators/IntListGenerator.java +@@ -0,0 +1,36 @@ ++package com.indeed.mph.generators; ++import com.pholser.junit.quickcheck.generator.ComponentizedGenerator; ++import com.pholser.junit.quickcheck.generator.GenerationStatus; ++import com.pholser.junit.quickcheck.random.SourceOfRandomness; ++import java.util.ArrayList; ++import java.util.List; ++import java.util.stream.Collectors; ++import java.util.stream.IntStream; ++ ++public class IntListGenerator extends ComponentizedGenerator { ++ public IntListGenerator() { ++ super(List.class); ++ } ++ boolean generatedEmptyList = false; ++ @Override ++ public List generate(SourceOfRandomness sourceOfRandomness, GenerationStatus generationStatus) { ++ if (!generatedEmptyList) { ++ generatedEmptyList = true; ++ return new ArrayList(); ++ } ++ int rng = sourceOfRandomness.nextInt(0, 20); ++ int listSize = 0; ++ if (rng >= 0 && rng <= 16) { ++ listSize = sourceOfRandomness.nextInt(0, 100); ++ } else if (rng >= 17 && rng <= 18) { ++ listSize = sourceOfRandomness.nextInt(1000, 10000); ++ } else if (rng >= 19 && rng <= 20) { ++ listSize = sourceOfRandomness.nextInt(100000, 10000000); ++ } ++ return IntStream.range(0, listSize).mapToObj(i -> sourceOfRandomness.nextInt(Integer.MIN_VALUE, Integer.MAX_VALUE)).collect(Collectors.toList()); ++ } ++ @Override ++ public int numberOfNeededComponents() { ++ return 1; ++ } ++} +diff --git a/src/test/java/com/indeed/mph/serializers/TestSmartListSerializer.java b/src/test/java/com/indeed/mph/serializers/TestSmartListSerializer.java +index 8312fe2..e898509 100644 +--- a/src/test/java/com/indeed/mph/serializers/TestSmartListSerializer.java ++++ b/src/test/java/com/indeed/mph/serializers/TestSmartListSerializer.java +@@ -1,9 +1,9 @@ + package com.indeed.mph.serializers; +- ++import com.pholser.junit.quickcheck.From; + import com.pholser.junit.quickcheck.Property; + import com.pholser.junit.quickcheck.runner.JUnitQuickcheck; + import org.junit.runner.RunWith; +- ++import com.indeed.mph.generators.IntListGenerator; + import java.io.IOException; + import java.util.List; + +@@ -23,7 +23,23 @@ public class TestSmartListSerializer { + final SmartListSerializer bytesSerializer = new SmartListSerializer<>(new SmartByteSerializer()); + assertRoundTrip(bytesSerializer, byteTarget); + ++ final SmartListSerializer stringsSerializer = new SmartListSerializer<>(new SmartStringSerializer()); ++ assertRoundTrip(stringsSerializer, stringTarget); ++ } ++ @Property ++ public void canRoundTripSerializableListsWithGenerator( ++ @From(IntListGenerator.class) final List intTarget, ++ final List byteTarget, ++ final List stringTarget ++ ) throws IOException { ++ final SmartListSerializer intsSerializer = new SmartListSerializer<>(new SmartIntegerSerializer()); ++ assertRoundTrip(intsSerializer, intTarget); ++ ++ final SmartListSerializer bytesSerializer = new SmartListSerializer<>(new SmartByteSerializer()); ++ assertRoundTrip(bytesSerializer, byteTarget); ++ + final SmartListSerializer stringsSerializer = new SmartListSerializer<>(new SmartStringSerializer()); + assertRoundTrip(stringsSerializer, stringTarget); + } + } ++ diff --git a/artifacts/configs/mph-table-fixed/mph-table-fixed.yaml b/artifacts/configs/mph-table-fixed/mph-table-fixed.yaml new file mode 100644 index 00000000..ba32d3fc --- /dev/null +++ b/artifacts/configs/mph-table-fixed/mph-table-fixed.yaml @@ -0,0 +1,24 @@ +name: mph-table-fixed +URL: https://github.com/indeedeng/mph-table.git +checkoutID: dbd5413df33bf8f0a995822eeefe94df50f3c5a7 +patchName: artifacts/configs/mph-table-fixed/mph-table-fixed.patch +#mvnOptions: -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000" +properties: + - name: TestSmartListSerializer#canRoundTripSerializableLists + entryPoint: "com.indeed.mph.serializers.TestSmartListSerializer.canRoundTripSerializableLists(Ljava/util/List;Ljava/util/List;Ljava/util/List;)V" + - name: TestSmartListSerializer#canRoundTripSerializableListsWithGenerator + entryPoint: "com.indeed.mph.serializers.TestSmartListSerializer.canRoundTripSerializableListsWithGenerator(Ljava/util/List;Ljava/util/List;Ljava/util/List;)V" + - name: TestSmartShortSerializer#canRoundTripShort + entryPoint: "com.indeed.mph.serializers.TestSmartShortSerializer.canRoundTripShort(S)V" + - name: TestSmartIntegerSerializer#canRoundTripIntegers + entryPoint: "com.indeed.mph.serializers.TestSmartIntegerSerializer.canRoundTripIntegers(I)V" + - name: TestSmartStringSerializer#canRoundTripStrings + entryPoint: "com.indeed.mph.serializers.TestSmartStringSerializer.canRoundTripStrings(Ljava/lang/String;)V" + - name: TestSmartByteSerializer#canRoundTripBytes + entryPoint: "com.indeed.mph.serializers.TestSmartByteSerializer.canRoundTripBytes(B)V" + - name: TestSmartLongSerializer#canRoundTripLongs + entryPoint: "com.indeed.mph.serializers.TestSmartLongSerializer.canRoundTripLongs(J)V" + - name: TestSmartPairSerializer#canRoundTripPairs + entryPoint: "com.indeed.mph.serializers.TestSmartPairSerializer.canRoundTripPairs(Lcom/indeed/util/core/Pair;)V" + - name: TestSmartOptionalSerializer#java#canRoundTripPresentOptionals + entryPoint: "com.indeed.mph.serializers.TestSmartOptionalSerializer.java.canRoundTripPresentOptionals(J)V" diff --git a/artifacts/configs/mph-table/mph-table.patch b/artifacts/configs/mph-table/mph-table.patch index a4a7dc76..71f0002c 100644 --- a/artifacts/configs/mph-table/mph-table.patch +++ b/artifacts/configs/mph-table/mph-table.patch @@ -1,8 +1,7 @@ diff --git a/pom.xml b/pom.xml -index 65f0f80..508b290 100644 ---- a/pom.xml -+++ b/pom.xml -@@ -40,9 +40,57 @@ +--- a/pom.xml (revision dbd5413df33bf8f0a995822eeefe94df50f3c5a7) ++++ b/pom.xml (date 1655257746259) +@@ -40,8 +40,75 @@ 1.8 @@ -37,10 +36,29 @@ index 65f0f80..508b290 100644 + + + ++ ++ ++ org.apache.maven.plugins ++ maven-assembly-plugin ++ 3.3.0 ++ ++ ++ jar-with-dependencies ++ ++ ++ ++ ++ make-assembly ++ package ++ ++ single ++ ++ ++ + - ++ + + + @@ -56,89 +74,7 @@ index 65f0f80..508b290 100644 + + + -+ - - - -diff --git a/src/test/java/com/indeed/mph/generators/IntListGenerator.java b/src/test/java/com/indeed/mph/generators/IntListGenerator.java -new file mode 100644 -index 0000000..33b6870 ---- /dev/null -+++ b/src/test/java/com/indeed/mph/generators/IntListGenerator.java -@@ -0,0 +1,36 @@ -+package com.indeed.mph.generators; -+import com.pholser.junit.quickcheck.generator.ComponentizedGenerator; -+import com.pholser.junit.quickcheck.generator.GenerationStatus; -+import com.pholser.junit.quickcheck.random.SourceOfRandomness; -+import java.util.ArrayList; -+import java.util.List; -+import java.util.stream.Collectors; -+import java.util.stream.IntStream; -+ -+public class IntListGenerator extends ComponentizedGenerator { -+ public IntListGenerator() { -+ super(List.class); -+ } -+ boolean generatedEmptyList = false; -+ @Override -+ public List generate(SourceOfRandomness sourceOfRandomness, GenerationStatus generationStatus) { -+ if (!generatedEmptyList) { -+ generatedEmptyList = true; -+ return new ArrayList(); -+ } -+ int rng = sourceOfRandomness.nextInt(0, 20); -+ int listSize = 0; -+ if (rng >= 0 && rng <= 16) { -+ listSize = sourceOfRandomness.nextInt(0, 100); -+ } else if (rng >= 17 && rng <= 18) { -+ listSize = sourceOfRandomness.nextInt(1000, 10000); -+ } else if (rng >= 19 && rng <= 20) { -+ listSize = sourceOfRandomness.nextInt(100000, 10000000); -+ } -+ return IntStream.range(0, listSize).mapToObj(i -> sourceOfRandomness.nextInt(Integer.MIN_VALUE, Integer.MAX_VALUE)).collect(Collectors.toList()); -+ } -+ @Override -+ public int numberOfNeededComponents() { -+ return 1; -+ } -+} -diff --git a/src/test/java/com/indeed/mph/serializers/TestSmartListSerializer.java b/src/test/java/com/indeed/mph/serializers/TestSmartListSerializer.java -index 8312fe2..e898509 100644 ---- a/src/test/java/com/indeed/mph/serializers/TestSmartListSerializer.java -+++ b/src/test/java/com/indeed/mph/serializers/TestSmartListSerializer.java -@@ -1,9 +1,9 @@ - package com.indeed.mph.serializers; -- -+import com.pholser.junit.quickcheck.From; - import com.pholser.junit.quickcheck.Property; - import com.pholser.junit.quickcheck.runner.JUnitQuickcheck; - import org.junit.runner.RunWith; -- -+import com.indeed.mph.generators.IntListGenerator; - import java.io.IOException; - import java.util.List; -@@ -23,7 +23,23 @@ public class TestSmartListSerializer { - final SmartListSerializer bytesSerializer = new SmartListSerializer<>(new SmartByteSerializer()); - assertRoundTrip(bytesSerializer, byteTarget); + -+ final SmartListSerializer stringsSerializer = new SmartListSerializer<>(new SmartStringSerializer()); -+ assertRoundTrip(stringsSerializer, stringTarget); -+ } -+ @Property -+ public void canRoundTripSerializableListsWithGenerator( -+ @From(IntListGenerator.class) final List intTarget, -+ final List byteTarget, -+ final List stringTarget -+ ) throws IOException { -+ final SmartListSerializer intsSerializer = new SmartListSerializer<>(new SmartIntegerSerializer()); -+ assertRoundTrip(intsSerializer, intTarget); -+ -+ final SmartListSerializer bytesSerializer = new SmartListSerializer<>(new SmartByteSerializer()); -+ assertRoundTrip(bytesSerializer, byteTarget); -+ - final SmartListSerializer stringsSerializer = new SmartListSerializer<>(new SmartStringSerializer()); - assertRoundTrip(stringsSerializer, stringTarget); - } - } -+ + diff --git a/artifacts/configs/mph-table/mph-table.yaml b/artifacts/configs/mph-table/mph-table.yaml index a5ec300a..b8b1f72b 100644 --- a/artifacts/configs/mph-table/mph-table.yaml +++ b/artifacts/configs/mph-table/mph-table.yaml @@ -2,11 +2,10 @@ name: mph-table URL: https://github.com/indeedeng/mph-table.git checkoutID: dbd5413df33bf8f0a995822eeefe94df50f3c5a7 patchName: artifacts/configs/mph-table/mph-table.patch +#mvnOptions: -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000" properties: - name: TestSmartListSerializer#canRoundTripSerializableLists entryPoint: "com.indeed.mph.serializers.TestSmartListSerializer.canRoundTripSerializableLists(Ljava/util/List;Ljava/util/List;Ljava/util/List;)V" - - name: TestSmartListSerializer#canRoundTripSerializableListsWithGenerator - entryPoint: "com.indeed.mph.serializers.TestSmartListSerializer.canRoundTripSerializableListsWithGenerator(Ljava/util/List;Ljava/util/List;Ljava/util/List;)V" - name: TestSmartShortSerializer#canRoundTripShort entryPoint: "com.indeed.mph.serializers.TestSmartShortSerializer.canRoundTripShort(S)V" - name: TestSmartIntegerSerializer#canRoundTripIntegers @@ -19,10 +18,5 @@ properties: entryPoint: "com.indeed.mph.serializers.TestSmartLongSerializer.canRoundTripLongs(J)V" - name: TestSmartPairSerializer#canRoundTripPairs entryPoint: "com.indeed.mph.serializers.TestSmartPairSerializer.canRoundTripPairs(Lcom/indeed/util/core/Pair;)V" - - name: TestSmartListSerializer#canRoundTripSerializableLists - entryPoint: "com.indeed.mph.serializers.TestSmartListSerializer.canRoundTripSerializableLists(Ljava/util/List;Ljava/util/List;Ljava/util/List;)V" - - name: TestSmartListSerializer#canRoundTripSerializableListsWithGenerator - entryPoint: "com.indeed.mph.serializers.TestSmartListSerializer.canRoundTripSerializableListsWithGenerator(Ljava/util/List;Ljava/util/List;Ljava/util/List;)V" - - name: TestSmartShortSerializer#canRoundTripShort - entryPoint: "com.indeed.mph.serializers.TestSmartShortSerializer.canRoundTripShort(S)V" - + - name: TestSmartOptionalSerializer#java#canRoundTripPresentOptionals + entryPoint: "com.indeed.mph.serializers.TestSmartOptionalSerializer.java.canRoundTripPresentOptionals(J)V" diff --git a/buildsvg.sh b/buildsvg.sh new file mode 100755 index 00000000..8edeb22e --- /dev/null +++ b/buildsvg.sh @@ -0,0 +1,3 @@ +for i in `ls *-reachability.dot`; do echo -n Processing $i...; dot -Tsvg -o ${i::-4}.svg $i; echo Done; done; +for i in `ls *-annotated.dot`; do echo -n Processing $i...; dot -Tsvg -o ${i::-4}.svg $i; echo Done; done; + diff --git a/runall.sh b/runall.sh new file mode 100755 index 00000000..88a3bb75 --- /dev/null +++ b/runall.sh @@ -0,0 +1,61 @@ +#!/bin/bash + +# SET JCG_HOME based on the directory where this script resides +JCG_HOME="$(pwd)/$( dirname -- "$0"; )"; + +declare -A mainjar +mainjar[convex]=convex-core-0.7.1-jar-with-dependencies.jar +mainjar[jflex]=jflex-1.8.2-jar-with-dependencies.jar +mainjar[mph-table]=mph-table-1.0.6-SNAPSHOT-jar-with-dependencies.jar + +declare -A testjar +testjar[convex]=convex-core-0.7.1-tests.jar +testjar[jflex]=jflex-1.8.2-tests.jar +testjar[mph-table]=mph-table-1.0.6-SNAPSHOT-tests.jar + + +cd $JCG_HOME || exit + +mkdir -p serializedGraphs + + +for type in original fixed +do + for project in convex jflex mph-table + do + echo $type for $project + + if [[ "$type" == "original" ]] + then + projectName=$project + else + projectName=$project-$type + fi + + # clean project + rm -rf $projectName + + # clean output + rm -rf output + mkdir output + + # git project + java -jar ./target/javacg-0.1-SNAPSHOT-jar-with-dependencies.jar git -c $projectName + + # build project + java -jar ./target/javacg-0.1-SNAPSHOT-jar-with-dependencies.jar build -j ./artifacts/output/${mainjar[$project]} -t ./artifacts/output/${testjar[$project]} -o serializedGraphs/$projectName + + # test project + java -jar ./target/javacg-0.1-SNAPSHOT-jar-with-dependencies.jar test -c $projectName -f serializedGraphs/$projectName + + # copy output + rm -rf output-$projectName + mv output output-$projectName + + cd output-$projectName || exit + ../buildsvg.sh + cd .. + done +done + + diff --git a/src/main/java/edu/uic/bitslab/callgraph/GetBest.java b/src/main/java/edu/uic/bitslab/callgraph/GetBest.java new file mode 100644 index 00000000..b0b1c3dc --- /dev/null +++ b/src/main/java/edu/uic/bitslab/callgraph/GetBest.java @@ -0,0 +1,342 @@ +package edu.uic.bitslab.callgraph; + +import gr.gousiosg.javacg.stat.JCallGraph; +import gr.gousiosg.javacg.stat.coverage.ColoredNode; +import gr.gousiosg.javacg.stat.graph.Utilities; +import org.jgrapht.Graph; +import org.jgrapht.GraphPath; +import org.jgrapht.alg.interfaces.ShortestPathAlgorithm; +import org.jgrapht.alg.shortestpath.BFSShortestPath; +import org.jgrapht.event.ConnectedComponentTraversalEvent; +import org.jgrapht.event.EdgeTraversalEvent; +import org.jgrapht.event.TraversalListenerAdapter; +import org.jgrapht.event.VertexTraversalEvent; +import org.jgrapht.graph.DefaultEdge; +import org.jgrapht.nio.Attribute; +import org.jgrapht.nio.DefaultAttribute; +import org.jgrapht.nio.dot.DOTExporter; +import org.jgrapht.traverse.DepthFirstIterator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.xml.bind.DatatypeConverter; +import java.io.*; +import java.nio.file.Path; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.*; +import java.util.stream.Collectors; + + +public class GetBest { + private static final Logger LOGGER = LoggerFactory.getLogger(GetBest.class); + private final Graph reachability; + private final String propertyName; + private final Map score = new HashMap<>(); + + /* Colors - Copied from gr.gousiosg.javacg.stat.coverage.ColoredNode */ + private static final String IMPLIED_COVERAGE_COLOR = "skyblue"; + private static final String LIGHT_GREEN = "greenyellow"; + private static final String MEDIUM_GREEN = "green1"; + private static final String MEDIUM_DARK_GREEN = "green3"; + private static final String DARK_GREEN = "green4"; + private static final String FIREBRICK = "lightpink"; + private static final String ENTRYPOINT_COLOR = "lightgoldenrod"; + private static final String NO_COLOR = "ghostwhite"; + private static final String TEST_NODE_COLOR = "plum"; + + private static final String DEFAULT_EDGE_COLOR = "black"; + private static final String FIRST_PATH_EDGE_COLOR = "green"; + private static final String SECOND_PATH_EDGE_COLOR = "yellow"; + private static final String THIRD_PATH_EDGE_COLOR = "red"; + + private static final int NUM_TOP_PATHS = 3; + + // color by type + private static final String UNCOVERED_COLOR = FIREBRICK; + + + + public static void main(String[] args) throws IOException, ClassNotFoundException { + String objectFileName = args[0]; + String propertyName; + + if (args.length == 2) { + propertyName = args[1]; + } else { + String filename = Path.of(args[0]).getFileName().toString(); + propertyName = filename.substring(0, filename.lastIndexOf('.')); + } + + LOGGER.info("----------GRAPH------------"); + LOGGER.info(objectFileName); + + GetBest o = new GetBest(objectFileName, propertyName); + o.run(); + } + + public GetBest(Graph reachability, String propertyName) { + this.reachability = reachability; + this.propertyName = propertyName; + } + + public GetBest(String objectFileName, String propertyName) throws IOException, ClassNotFoundException { + try (ObjectInput ois = new ObjectInputStream(new FileInputStream(objectFileName))) { + reachability = returnGraph(ois.readObject()); + } + this.propertyName = propertyName; + } + + @SuppressWarnings("unchecked") + private Graph returnGraph(Object o) { + if (o instanceof Graph) { + return (Graph) o; + } + + LOGGER.error("Expected instanceof Graph, but received " + o.getClass().getName() + " instead."); + return null; + } + + public void run() { + // we don't have a graph to reason about! + if (reachability == null) { + return; + } + + ColoredNode entryPoint = getEntryPoint(); + + if (entryPoint == null) { + LOGGER.error("Unable to find entry point"); + return; + } + + DepthFirstIterator iter = new DepthFirstIterator<>(reachability, entryPoint); + iter.addTraversalListener(new GetBestTraversalListener(reachability, score)); + + // traverse the graph to set the scores + while (iter.hasNext()) { + iter.next(); + } + + // get all of the paths + List pathWeights = new ArrayList<>(); + BFSShortestPath bfsShortestPath = new BFSShortestPath<>(reachability); + ShortestPathAlgorithm.SingleSourcePaths allPaths = bfsShortestPath.getPaths(entryPoint); + HashSet sinkSet = reachability.vertexSet().stream().filter(vertex -> reachability.outDegreeOf(vertex) == 0).collect(Collectors.toCollection(HashSet::new)); + sinkSet.forEach( sinkVertex -> { + GraphPath executionPath = allPaths.getPath(sinkVertex); + + double pathSum = executionPath.getEdgeList().stream().map(reachability::getEdgeTarget).mapToDouble(score::get).filter( (d) -> !Double.isNaN(d)).sum(); + pathWeights.add(new PathWeight(executionPath, pathSum)); + }); + + // output sorted paths + Comparator comparator = Comparator.comparingDouble(p -> p.weight); + pathWeights.sort(comparator.reversed()); + + String outputPaths = JCallGraph.OUTPUT_DIRECTORY + propertyName + "-paths.csv"; + try { + Writer writer = new FileWriter(outputPaths); + for(PathWeight pathWeight : pathWeights) { + String pathString = pathWeight.path + .getVertexList() + .stream() + .map(p -> '"' + p.toString() + '"') + .collect(Collectors.joining(",")); + + MessageDigest md = MessageDigest.getInstance("md5"); + md.update(pathString.getBytes()); + byte[] digest = md.digest(); + String pathHash = DatatypeConverter.printHexBinary(digest).toUpperCase(); + + writer.write( + pathWeight.weight + "," + + pathHash + "," + + pathString + + System.lineSeparator()); + } + + writer.close(); + } catch (IOException | NoSuchAlgorithmException e) { + LOGGER.error("Unable to write paths to " + outputPaths); + } + + String[] edgeStringColor = { + FIRST_PATH_EDGE_COLOR, + SECOND_PATH_EDGE_COLOR, + THIRD_PATH_EDGE_COLOR + }; + + Map> edgePathNumber = new HashMap<>(); + + // color the edges based on the top three paths + for (int pathIndex = 0; pathIndex < NUM_TOP_PATHS && pathIndex < pathWeights.size(); pathIndex++) { + for (DefaultEdge edge : pathWeights.get(pathIndex).path.getEdgeList()) { + if (edgePathNumber.containsKey(edge)) { + edgePathNumber.get(edge).add(pathIndex); + } else { + edgePathNumber.put(edge, new ArrayList<>(List.of(pathIndex))); + } + } + } + + /* annotated graph - Write to .dot file in output directory */ + String path = JCallGraph.OUTPUT_DIRECTORY + propertyName + "-annotated.dot"; + try { + Writer writer = new FileWriter(path); + DOTExporter exporter = Utilities.coloredExporter(); + exporter.setVertexAttributeProvider( + (v) -> { + Map map = new LinkedHashMap<>(); + map.put("label", DefaultAttribute.createAttribute(score.get(v).toString() + " - " + dotFormat(v.toString()))); + map.put("style", DefaultAttribute.createAttribute("filled")); + map.put("fillcolor", DefaultAttribute.createAttribute(v.getColor())); + return map; + }); + exporter.setEdgeAttributeProvider( + (edge) -> { + Map map = new LinkedHashMap<>(); + + if (edgePathNumber.containsKey(edge)) { + List pathSet = edgePathNumber.get(edge); + + + int pathNumber = pathSet.get(0); + map.put("color", DefaultAttribute.createAttribute(edgeStringColor[pathNumber])); + + map.put("penwidth", DefaultAttribute.createAttribute(2.0)); + + String stringPathNumbers = pathSet.stream().map(String::valueOf).collect(Collectors.joining("/")); + map.put("label", DefaultAttribute.createAttribute("P" + stringPathNumbers)); + } + + return map; + } + ); + exporter.exportGraph(reachability, writer); + LOGGER.info("Graph written to " + path + "!"); + } catch (IOException e) { + LOGGER.error("Unable to write callgraph to " + path); + } + } + + private ColoredNode getEntryPoint() { + Set vertexSet = reachability.vertexSet(); + + for (ColoredNode v : vertexSet) { + if (reachability.inDegreeOf(v) == 0) { + return v; + } + } + + return null; + } + + private static String dotFormat(String vertex) { + return "\"" + vertex + "\""; + } + + static class PathWeight { + public final GraphPath path; + public final Double weight; + + PathWeight(GraphPath path, Double weight) { + this.path = path; + this.weight = weight; + } + } + + static class GetBestTraversalListener extends TraversalListenerAdapter { + Graph graph; + Map score; + + GetBestTraversalListener(Graph graph, Map score) { + super(); + + this.graph = graph; + this.score = score; + } + + @Override + public void connectedComponentFinished(ConnectedComponentTraversalEvent connectedComponentTraversalEvent) { + + } + + @Override + public void connectedComponentStarted(ConnectedComponentTraversalEvent connectedComponentTraversalEvent) { + + } + + @Override + public void edgeTraversed(EdgeTraversalEvent edgeTraversalEvent) { + + } + + @Override + public void vertexTraversed(VertexTraversalEvent vertexTraversalEvent) { + + } + + @Override + public void vertexFinished(VertexTraversalEvent vertexTraversalEvent) { + ColoredNode parentVertex = vertexTraversalEvent.getVertex(); + score.put(parentVertex, Score(parentVertex)); + } + + private double vertexColorToInt(String color) { + switch (color) { + case UNCOVERED_COLOR: + return 1.00; + + case LIGHT_GREEN: + return 0.80; + + case MEDIUM_GREEN: + return 0.60; + + case MEDIUM_DARK_GREEN: + return 0.40; + + case DARK_GREEN: + return 0.20; + + default: + return 0.00; + } + } + + private double Score(ColoredNode vertex) { + final double weightParentScore = 1; + final double weightChildrenScore = .5; + //final double weightUncoveredChildren = .5; + + // parent score (note: high score is better) + double parentScore = vertexColorToInt(vertex.getColor()); + +// double maxChildrenScore = graph.outgoingEdgesOf(vertex) +// .stream() +// .mapToDouble( e -> score.get(graph.getEdgeTarget(e)) ) +// .max() +// .orElse(0.00); + + double totalChildrenScore = graph.outgoingEdgesOf(vertex) + .stream() + .mapToDouble( e -> score.getOrDefault(graph.getEdgeTarget(e), 0.00) ) + .sum(); + + return (weightParentScore * parentScore) + + (weightChildrenScore * totalChildrenScore); + + // get uncovered children +// long countUncoveredChildren = graph.outgoingEdgesOf(vertex) +// .stream() +// .map( e -> graph.getEdgeTarget(e).getColor() ) +// .filter( color -> color.equals(UNCOVERED_COLOR)) +// .count(); +// +// return (weightParentScore * parentScore) + +// (parentScore * (weightUncoveredChildren * countUncoveredChildren)); + } + } +} + diff --git a/src/main/java/gr/gousiosg/javacg/stat/JCallGraph.java b/src/main/java/gr/gousiosg/javacg/stat/JCallGraph.java index 069e391d..3722a959 100644 --- a/src/main/java/gr/gousiosg/javacg/stat/JCallGraph.java +++ b/src/main/java/gr/gousiosg/javacg/stat/JCallGraph.java @@ -28,6 +28,7 @@ package gr.gousiosg.javacg.stat; +import edu.uic.bitslab.callgraph.GetBest; import gr.gousiosg.javacg.dyn.Pair; import gr.gousiosg.javacg.stat.coverage.ColoredNode; import gr.gousiosg.javacg.stat.coverage.CoverageStatistics; @@ -81,6 +82,7 @@ public class JCallGraph { private static final String DELIMITER = "-"; private static final String DOT_SUFFIX = ".dot"; private static final String CSV_SUFFIX = ".csv"; + private static final String SER_SUFFIX = ".ser"; public static void main(String[] args) { try { @@ -176,12 +178,17 @@ else if(s.second instanceof ArrayList){ Pruning.pruneOriginalGraph(callgraph, jacocoCoverage); // 4. Operate on the graph and write it to output maybeWriteGraph(callgraph.graph, JCallGraph.OUTPUT_DIRECTORY + propertyName); - maybeInspectReachability(callgraph, arguments.maybeDepth(), jacocoCoverage, s.second, JCallGraph.OUTPUT_DIRECTORY + propertyName); + Graph prunedReachability = maybeInspectReachability(callgraph, arguments.maybeDepth(), jacocoCoverage, s.second, JCallGraph.OUTPUT_DIRECTORY + propertyName); maybeInspectAncestry(callgraph, arguments, jacocoCoverage, Optional.of(s.second), Optional.of(propertyName)); rt.cleanTarget(); + + // write the best paths and annotated dot file + GetBest getBest = new GetBest(prunedReachability, propertyName); + getBest.run(); } break; } + default: LOGGER.error("Invalid argument provided!"); System.exit(1); @@ -272,7 +279,7 @@ public static ArrayList> fetchAllMethodSignaturesForyaml (J for(Method tempMethod : methods) if(Arrays.stream(tempMethod.getAnnotationEntries()) .map(e->e.getAnnotationType()) - .anyMatch(e->e.equals("Lorg/junit/Test;"))){ + .anyMatch(e->e.equals("Lcom/pholser/junit/quickcheck/Property;"))){ // .anyMatch(e->e.equals("Lorg/junit/Test;"))){ String methodDescriptor=tempMethod.getName() + tempMethod.getSignature(); signatureResults.add(new Pair<>(className+"#"+tempMethod.getName(),jc.getClassName() + "." + methodDescriptor)); } @@ -403,14 +410,14 @@ public static void manualMain(String[] args) { maybeInspectReachability(callgraph, depth, jacocoCoverage, entryPoint, output); -// maybeWriteGraph(callgraph.graph, args[4]); + // maybeWriteGraph(callgraph.graph, args[4]); } private static void maybeWriteGraph(Graph graph, String output) { Utilities.writeGraph(graph, Utilities.defaultExporter(), JCallGraph.asDot(output)); } - private static void maybeInspectReachability( + private static Graph maybeInspectReachability( StaticCallgraph callgraph, Optional depth, JacocoCoverage jacocoCoverage, String entryPoint, String outputFile) { /* Fetch reachability */ @@ -424,21 +431,38 @@ private static void maybeInspectReachability( Pruning.pruneReachabilityGraph(reachability, callgraph.metadata, jacocoCoverage); /* Should we write the graph to a file? */ - String outputName = outputFile + DELIMITER + REACHABILITY; - - /* Attach depth to name if present */ - if (depth.isPresent()) { - outputName = outputName + DELIMITER + depth.get(); - } + String outputName = getCompleteOutputName(depth, outputFile); /* Store reachability in file? */ Utilities.writeGraph( reachability, Utilities.coloredExporter(), JCallGraph.asDot(outputName)); + try { + writeSerializeReachabilityGraph(reachability, asSer(outputName)); + } catch (IOException e) { + LOGGER.error("Error writing serialized reachability graph."); + LOGGER.error(e.getMessage()); + } + + /* Analyze reachability coverage? */ if (jacocoCoverage.hasCoverage()) { CoverageStatistics.analyze( reachability, Optional.of(asCsv(outputName + DELIMITER + COVERAGE))); } + + return reachability; + } + + private static String getCompleteOutputName(Optional depth, String outputFile) { + /* Should we write the graph to a file? */ + String outputName = outputFile + DELIMITER + REACHABILITY; + + /* Attach depth to name if present */ + if (depth.isPresent()) { + outputName = outputName + DELIMITER + depth.get(); + } + + return outputName; } private static void maybeInspectAncestry( @@ -469,6 +493,10 @@ private static String asDot(String name) { return name.endsWith(DOT_SUFFIX) ? name : (name + DOT_SUFFIX); } + private static String asSer(String name) { + return name.endsWith(SER_SUFFIX) ? name : (name + SER_SUFFIX); + } + private static String asCsv(String name) { return name.endsWith(CSV_SUFFIX) ? name : (name + CSV_SUFFIX); } @@ -487,6 +515,15 @@ private static void maybeSerializeStaticCallGraph(StaticCallgraph callgraph, Bui } } + private static void writeSerializeReachabilityGraph(Graph reachability, String pathname) throws IOException { + File filename = new File(pathname); + FileOutputStream file = new FileOutputStream(filename); + ObjectOutputStream out = new ObjectOutputStream(file); + out.writeObject(reachability); + out.close(); + file.close(); + } + // // deserializeStaticCallGraph reads bytecode and creates a StaticCallgraph object to be returned // Throws: IOException when file cannot be read diff --git a/src/main/java/gr/gousiosg/javacg/stat/coverage/ColoredNode.java b/src/main/java/gr/gousiosg/javacg/stat/coverage/ColoredNode.java index 77a6fbab..8da549c1 100644 --- a/src/main/java/gr/gousiosg/javacg/stat/coverage/ColoredNode.java +++ b/src/main/java/gr/gousiosg/javacg/stat/coverage/ColoredNode.java @@ -1,6 +1,8 @@ package gr.gousiosg.javacg.stat.coverage; -public class ColoredNode { +import java.io.Serializable; + +public class ColoredNode implements Serializable { /* Colors */ private static final String IMPLIED_COVERAGE_COLOR = "skyblue"; @@ -30,6 +32,10 @@ public String getColor() { return color; } + public void setColor(String color) { + this.color = color; + } + public String getLabel() { return this.label; } @@ -131,7 +137,11 @@ public int getBranchesMissed() { return branchesMissed; } - private float lineRatio() { + public float lineRatio() { return (float) linesCovered / ((float) linesCovered + (float) linesMissed); } + + public String toString() { + return getLabel(); + } } diff --git a/src/main/java/gr/gousiosg/javacg/stat/coverage/CoverageStatistics.java b/src/main/java/gr/gousiosg/javacg/stat/coverage/CoverageStatistics.java index 79fc4a03..89c282cd 100644 --- a/src/main/java/gr/gousiosg/javacg/stat/coverage/CoverageStatistics.java +++ b/src/main/java/gr/gousiosg/javacg/stat/coverage/CoverageStatistics.java @@ -69,7 +69,7 @@ public static void analyze(Graph graph, Optional field.isAnnotationPresent(Writeable.class)) .forEach( diff --git a/src/main/java/gr/gousiosg/javacg/stat/graph/Constants.java b/src/main/java/gr/gousiosg/javacg/stat/graph/Constants.java index 1837d6b4..527190b8 100644 --- a/src/main/java/gr/gousiosg/javacg/stat/graph/Constants.java +++ b/src/main/java/gr/gousiosg/javacg/stat/graph/Constants.java @@ -10,4 +10,5 @@ public class Constants { protected static final String STYLE = "style"; protected static final String FILLCOLOR = "fillcolor"; protected static final String FILLED = "filled"; + protected static final String LINERATIO = "lineratio"; }