diff --git a/WORKSPACE b/WORKSPACE index 426187e3a..ac4f866a8 100644 --- a/WORKSPACE +++ b/WORKSPACE @@ -64,10 +64,6 @@ maven_install( ], ) -# To update maven_install.json, run this command to re-pin the unpinned repository: -# -# bazel run @unpinned_maven//:pin -# load("@maven//:defs.bzl", "pinned_maven_install") pinned_maven_install() diff --git a/jflex/pom.xml b/jflex/pom.xml index ad26a63dc..cd5f563d2 100644 --- a/jflex/pom.xml +++ b/jflex/pom.xml @@ -81,6 +81,24 @@ truth test + + com.pholser + junit-quickcheck-core + 0.9 + test + + + com.pholser + junit-quickcheck-generators + 0.9 + test + + + org.slf4j + slf4j-simple + 1.7.28 + test + @@ -91,6 +109,7 @@ **/*Test.java **/*Tests.java + **/*Quickcheck.java diff --git a/jflex/src/main/java/jflex/core/IntCharSet.java b/jflex/src/main/java/jflex/core/IntCharSet.java index 1033d83af..5969788c6 100644 --- a/jflex/src/main/java/jflex/core/IntCharSet.java +++ b/jflex/src/main/java/jflex/core/IntCharSet.java @@ -138,6 +138,11 @@ private int indexOf(int c) { /** Merges the given set into this one. */ public void add(IntCharSet set) { + if (DEBUG) { + assert invariants(); + assert set.invariants(); + assert this != set; + } for (Interval interval : set.intervals) { add(interval); } @@ -372,6 +377,7 @@ public void sub(IntCharSet set) { // not asserting non-null, because we'll already get an exception and it confuses lgtm.com assert set.invariants(); assert isSubSet(set, this); + assert set != this; } int i = 0; // index in this.intervals diff --git a/jflex/src/test/java/jflex/core/BUILD b/jflex/src/test/java/jflex/core/BUILD index 341ec8181..7f02b145e 100644 --- a/jflex/src/test/java/jflex/core/BUILD +++ b/jflex/src/test/java/jflex/core/BUILD @@ -8,6 +8,20 @@ java_test( ], ) +java_test( + name = "IntCharSetQuickcheck", + srcs = [ + "IntCharSetGen.java", + "IntCharSetQuickcheck.java", + ], + deps = [ + "//jflex/src/main/java/jflex/chars", + "//jflex/src/main/java/jflex/core", + "//third_party/com/google/truth", + "//third_party/com/pholser/quickcheck", + ], +) + java_test( name = "IntCharSetTest", srcs = ["IntCharSetTest.java"], diff --git a/jflex/src/test/java/jflex/core/IntCharSetGen.java b/jflex/src/test/java/jflex/core/IntCharSetGen.java new file mode 100644 index 000000000..5989a517c --- /dev/null +++ b/jflex/src/test/java/jflex/core/IntCharSetGen.java @@ -0,0 +1,89 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * JFlex 1.8.0-SNAPSHOT * + * Copyright (C) 1998-2019 Gerwin Klein * + * All rights reserved. * + * * + * License: BSD * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +package jflex.core; + +import com.pholser.junit.quickcheck.generator.GenerationStatus; +import com.pholser.junit.quickcheck.generator.Generator; +import com.pholser.junit.quickcheck.generator.InRange; +import com.pholser.junit.quickcheck.generator.Size; +import com.pholser.junit.quickcheck.random.SourceOfRandomness; +import jflex.chars.Interval; + +/** + * Generator for random {@link IntCharSet} instances. + * + * @author Gerwin Klein + * @version JFlex 1.8.0-SNAPSHOT + * @see IntCharSet + */ +public class IntCharSetGen extends Generator { + + /** Min bound for intervals */ + private int minChar = 0; + /** Max bound for intervals. Small for speed, and more likely edge cases. */ + private int maxChar = 50; + + /** Min bound for number of intervals (0 = empty set) */ + private int minSize = 0; + /** Max bound for number of intervals */ + private int maxSize = 5; + + /** Constructs generator for IntCharSet */ + public IntCharSetGen() { + super(IntCharSet.class); + } + + @Override + public IntCharSet generate(SourceOfRandomness r, GenerationStatus status) { + IntCharSet result = new IntCharSet(); + + int numIntervals = r.nextInt(minSize, maxSize); + for (int i = 0; i < numIntervals; i++) { + int start = r.nextInt(minChar, maxChar); + int end = r.nextInt(start, maxChar); + + // pick default with higher probability + switch (r.nextInt(0, 4)) { + case 0: + result.add(IntCharSet.ofCharacter(start)); + break; + case 1: + result.add(start); + break; + default: + result.add(new Interval(start, end)); + break; + } + } + + return result; + } + + /** + * Configure this generator to only produce intervals in the given range. + * + * @param range annotation that contains the intervals constraints + */ + public void configure(InRange range) { + minChar = Math.max(0, range.minInt()); + maxChar = Math.min(range.maxInt(), CharClasses.maxChar); + } + + /** + * Configure this generator to only produce IntCharSets with a given range of number of intervals. + * + * @param size annotation that contains how many intervals the IntCharSet should contain at least + * and at most + */ + public void configure(Size size) { + minSize = size.min(); + maxSize = size.max(); + } +} diff --git a/jflex/src/test/java/jflex/core/IntCharSetQuickcheck.java b/jflex/src/test/java/jflex/core/IntCharSetQuickcheck.java new file mode 100644 index 000000000..e8783b68c --- /dev/null +++ b/jflex/src/test/java/jflex/core/IntCharSetQuickcheck.java @@ -0,0 +1,171 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * JFlex 1.8.0-SNAPSHOT * + * Copyright (C) 1998-2019 Gerwin Klein * + * All rights reserved. * + * * + * License: BSD * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +package jflex.core; + +import static com.google.common.truth.Truth.assertThat; + +import com.pholser.junit.quickcheck.Property; +import com.pholser.junit.quickcheck.generator.InRange; +import com.pholser.junit.quickcheck.runner.JUnitQuickcheck; +import org.junit.runner.RunWith; + +/** + * Property-based tests for {@link IntCharSet} + * + * @author Gerwin Klein + * @version JFlex 1.8.0-SNAPSHOT + * @see IntCharSet + */ +@RunWith(JUnitQuickcheck.class) +public class IntCharSetQuickcheck { + + @Property + public void addIsUnion(IntCharSet s1, IntCharSet s2) { + IntCharSet union = IntCharSet.copyOf(s1); + union.add(s2); + + assertThat(union.invariants()).isTrue(); + + assertThat(IntCharSet.isSubSet(s1, union)).isTrue(); + assertThat(IntCharSet.isSubSet(s2, union)).isTrue(); + + for (int i : union) { + assertThat(s1.contains(i) || s2.contains(i)).isTrue(); + } + } + + @Property + public void andIsIntersection( + @InRange(maxInt = 100) IntCharSet s1, @InRange(maxInt = 100) IntCharSet s2) { + IntCharSet inter = s1.and(s2); + + assertThat(inter.invariants()).isTrue(); + + assertThat(IntCharSet.isSubSet(inter, s1)).isTrue(); + assertThat(IntCharSet.isSubSet(inter, s2)).isTrue(); + + for (int i : s1) { + assertThat(!s2.contains(i) || inter.contains(i)).isTrue(); + } + } + + @Property + public void andCommutes(IntCharSet s1, IntCharSet s2) { + assertThat(s1.and(s2)).isEqualTo(s2.and(s1)); + } + + @Property + public void addSelf(IntCharSet set) { + IntCharSet setPre = IntCharSet.copyOf(set); + set.add(setPre); + assertThat(set).isEqualTo(setPre); + } + + @Property + public void addIdemPotent(IntCharSet s1, IntCharSet s2) { + IntCharSet union1 = IntCharSet.copyOf(s1); + union1.add(s2); + IntCharSet union2 = IntCharSet.copyOf(union1); + union2.add(s2); + assertThat(union2).isEqualTo(union1); + } + + @Property + public void subIsDifference(IntCharSet s1, IntCharSet s2) { + IntCharSet diff = IntCharSet.copyOf(s1); + // use intersection to ensure that argument of sub is contained in s1 + diff.sub(s1.and(s2)); + + assertThat(diff.invariants()).isTrue(); + + assertThat(IntCharSet.isSubSet(diff, s1)).isTrue(); + assertThat(diff.and(s2).containsElements()).isFalse(); + + // union of the diff and s2 should be equal to union of s1 and s2 + diff.add(s2); + IntCharSet s3 = IntCharSet.copyOf(s1); + s3.add(s2); + assertThat(diff).isEqualTo(s3); + } + + @Property + public void containsItsElements(IntCharSet set) { + for (int i : set) assertThat(set.contains(i)).isTrue(); + } + + @Property + public void allCharsContainsEverything(IntCharSet set) { + assertThat(IntCharSet.allChars().contains(set)).isTrue(); + } + + @Property + public void addSubEq(IntCharSet s1, IntCharSet s2) { + IntCharSet s1Pre = IntCharSet.copyOf(s1); + IntCharSet inter = s1.and(s2); + + s1.sub(inter); + s1.add(inter); + + assertThat(s1).isEqualTo(s1Pre); + } + + @Property + public void addEmpty(IntCharSet set) { + IntCharSet setPre = IntCharSet.copyOf(set); + set.add(new IntCharSet()); + assertThat(set).isEqualTo(setPre); + } + + @Property + public void subEmpty(IntCharSet set) { + IntCharSet setPre = IntCharSet.copyOf(set); + set.sub(new IntCharSet()); + assertThat(set).isEqualTo(setPre); + } + + @Property + public void andEmpty(IntCharSet set) { + assertThat(set.and(new IntCharSet())).isEqualTo(new IntCharSet()); + } + + @Property + public void addAll(IntCharSet set) { + set.add(IntCharSet.allChars()); + assertThat(set).isEqualTo(IntCharSet.allChars()); + } + + @Property + public void subSelf(IntCharSet set) { + set.sub(IntCharSet.copyOf(set)); + assertThat(set).isEqualTo(new IntCharSet()); + } + + @Property + public void andAll(IntCharSet set) { + assertThat(set.and(IntCharSet.allChars())).isEqualTo(set); + } + + @Property + public void andSelf(IntCharSet set) { + assertThat(set.and(set)).isEqualTo(set); + } + + @Property + public void complement(IntCharSet set) { + IntCharSet comp = IntCharSet.allChars(); + comp.sub(set); + + assertThat(comp.invariants()).isTrue(); + assertThat(comp.and(set).containsElements()).isFalse(); + + comp.add(set); + assertThat(comp).isEqualTo(IntCharSet.allChars()); + } +} diff --git a/third_party/com/google/auto_value/BUILD b/third_party/com/google/auto_value/BUILD index 701db3f82..4f9fc88df 100644 --- a/third_party/com/google/auto_value/BUILD +++ b/third_party/com/google/auto_value/BUILD @@ -1,3 +1,5 @@ +# Google AutoValue + package(default_visibility = ["//visibility:public"]) licenses(["notice"]) # Apache License 2.0 diff --git a/third_party/com/pholser/quickcheck/BUILD b/third_party/com/pholser/quickcheck/BUILD new file mode 100644 index 000000000..c9a912d69 --- /dev/null +++ b/third_party/com/pholser/quickcheck/BUILD @@ -0,0 +1,17 @@ +# junit-quickcheck +# junit-quickcheck is a library that supports writing and running property-based tests in JUnit, +# inspired by QuickCheck for Haskell. +# https://github.com/pholser/junit-quickcheck + +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) # MIT License + +java_library( + name = "quickcheck", + testonly = True, + exports = [ + "@maven//:com_pholser_junit_quickcheck_core", + "@maven//:com_pholser_junit_quickcheck_generators", + ], +) diff --git a/third_party/deps.bzl b/third_party/deps.bzl index aa95a92ce..a240e7fec 100644 --- a/third_party/deps.bzl +++ b/third_party/deps.bzl @@ -1,4 +1,8 @@ # Please keep deps in alphabetical order +# After a change in deps, run this command to re-pin the unpinned repository: +# +# bazel run @unpinned_maven//:pin +# ARTIFACTS = [ "com.google.code.findbugs:jsr305:3.0.2", "org.apache.ant:ant:1.7.0", @@ -11,5 +15,7 @@ ARTIFACTS = [ "com.google.flogger:flogger-system-backend:0.4", "com.google.guava:guava:jar:26.0-jre", "com.google.truth:truth:0.36", + "com.pholser:junit-quickcheck-core:0.9", + "com.pholser:junit-quickcheck-generators:0.9", "junit:junit:jar:4.12", ] diff --git a/third_party/maven_install.json b/third_party/maven_install.json index 80b10da66..52f63d138 100644 --- a/third_party/maven_install.json +++ b/third_party/maven_install.json @@ -1,6 +1,6 @@ { "dependency_tree": { - "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": -185863427, + "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": 1430077768, "conflict_resolution": {}, "dependencies": [ { @@ -155,6 +155,61 @@ "sha256": "aa19c5987eb52a9d7fb954823e8ea70d36308a5bde309c2020abe5e329c17527", "url": "https://jcenter.bintray.com/com/google/truth/truth/0.36/truth-0.36.jar" }, + { + "coord": "com.pholser:junit-quickcheck-core:0.9", + "dependencies": [ + "org.javaruntype:javaruntype:1.3", + "org.javassist:javassist:3.20.0-GA", + "junit:junit:4.12", + "org.hamcrest:hamcrest-core:1.3", + "org.slf4j:slf4j-api:1.7.25", + "ognl:ognl:3.1.12", + "org.antlr:antlr-runtime:3.1.2", + "ru.vyarus:generics-resolver:2.0.1" + ], + "directDependencies": [ + "org.javaruntype:javaruntype:1.3", + "junit:junit:4.12", + "org.hamcrest:hamcrest-core:1.3", + "org.slf4j:slf4j-api:1.7.25", + "ognl:ognl:3.1.12", + "ru.vyarus:generics-resolver:2.0.1" + ], + "file": "v1/https/jcenter.bintray.com/com/pholser/junit-quickcheck-core/0.9/junit-quickcheck-core-0.9.jar", + "mirror_urls": [ + "https://jcenter.bintray.com/com/pholser/junit-quickcheck-core/0.9/junit-quickcheck-core-0.9.jar", + "https://maven.google.comcom/pholser/junit-quickcheck-core/0.9/junit-quickcheck-core-0.9.jar", + "https://repo1.maven.org/maven2com/pholser/junit-quickcheck-core/0.9/junit-quickcheck-core-0.9.jar" + ], + "sha256": "1d806901f9c8cc561ce57e15f39bd4c45530ad11e7ca638e2003ae3a9d982dc4", + "url": "https://jcenter.bintray.com/com/pholser/junit-quickcheck-core/0.9/junit-quickcheck-core-0.9.jar" + }, + { + "coord": "com.pholser:junit-quickcheck-generators:0.9", + "dependencies": [ + "org.javaruntype:javaruntype:1.3", + "org.javassist:javassist:3.20.0-GA", + "junit:junit:4.12", + "org.hamcrest:hamcrest-core:1.3", + "org.slf4j:slf4j-api:1.7.25", + "ognl:ognl:3.1.12", + "org.antlr:antlr-runtime:3.1.2", + "ru.vyarus:generics-resolver:2.0.1", + "com.pholser:junit-quickcheck-core:0.9" + ], + "directDependencies": [ + "com.pholser:junit-quickcheck-core:0.9", + "junit:junit:4.12" + ], + "file": "v1/https/jcenter.bintray.com/com/pholser/junit-quickcheck-generators/0.9/junit-quickcheck-generators-0.9.jar", + "mirror_urls": [ + "https://jcenter.bintray.com/com/pholser/junit-quickcheck-generators/0.9/junit-quickcheck-generators-0.9.jar", + "https://maven.google.comcom/pholser/junit-quickcheck-generators/0.9/junit-quickcheck-generators-0.9.jar", + "https://repo1.maven.org/maven2com/pholser/junit-quickcheck-generators/0.9/junit-quickcheck-generators-0.9.jar" + ], + "sha256": "238fb3143c27255bb33f86ff96f548671e1799288107baae3ce867ce04fdfd46", + "url": "https://jcenter.bintray.com/com/pholser/junit-quickcheck-generators/0.9/junit-quickcheck-generators-0.9.jar" + }, { "coord": "commons-collections:commons-collections:3.2.1", "dependencies": [], @@ -198,6 +253,39 @@ "sha256": "59721f0805e223d84b90677887d9ff567dc534d7c502ca903c0c2b17f05c116a", "url": "https://jcenter.bintray.com/junit/junit/4.12/junit-4.12.jar" }, + { + "coord": "ognl:ognl:3.1.12", + "dependencies": [ + "org.javassist:javassist:3.20.0-GA" + ], + "directDependencies": [ + "org.javassist:javassist:3.20.0-GA" + ], + "file": "v1/https/jcenter.bintray.com/ognl/ognl/3.1.12/ognl-3.1.12.jar", + "mirror_urls": [ + "https://jcenter.bintray.com/ognl/ognl/3.1.12/ognl-3.1.12.jar", + "https://maven.google.comognl/ognl/3.1.12/ognl-3.1.12.jar", + "https://repo1.maven.org/maven2ognl/ognl/3.1.12/ognl-3.1.12.jar" + ], + "sha256": "74b63fa0cdb1d4718e6807f2ed1005ac2f15a513910d68039af9a559196195e9", + "url": "https://jcenter.bintray.com/ognl/ognl/3.1.12/ognl-3.1.12.jar" + }, + { + "coord": "org.antlr:antlr-runtime:3.1.2", + "dependencies": [], + "directDependencies": [], + "exclusions": [ + "org.antlr:stringtemplate" + ], + "file": "v1/https/jcenter.bintray.com/org/antlr/antlr-runtime/3.1.2/antlr-runtime-3.1.2.jar", + "mirror_urls": [ + "https://jcenter.bintray.com/org/antlr/antlr-runtime/3.1.2/antlr-runtime-3.1.2.jar", + "https://maven.google.comorg/antlr/antlr-runtime/3.1.2/antlr-runtime-3.1.2.jar", + "https://repo1.maven.org/maven2org/antlr/antlr-runtime/3.1.2/antlr-runtime-3.1.2.jar" + ], + "sha256": "5b0339a0a50f69cd50f1911e05d4ca12f1974374d8a6db092968f25ffe38aad2", + "url": "https://jcenter.bintray.com/org/antlr/antlr-runtime/3.1.2/antlr-runtime-3.1.2.jar" + }, { "coord": "org.apache.ant:ant-launcher:1.7.0", "dependencies": [], @@ -285,6 +373,62 @@ ], "sha256": "66fdef91e9739348df7a096aa384a5685f4e875584cce89386a7a47251c4d8e9", "url": "https://jcenter.bintray.com/org/hamcrest/hamcrest-core/1.3/hamcrest-core-1.3.jar" + }, + { + "coord": "org.javaruntype:javaruntype:1.3", + "dependencies": [ + "org.antlr:antlr-runtime:3.1.2" + ], + "directDependencies": [ + "org.antlr:antlr-runtime:3.1.2" + ], + "file": "v1/https/jcenter.bintray.com/org/javaruntype/javaruntype/1.3/javaruntype-1.3.jar", + "mirror_urls": [ + "https://jcenter.bintray.com/org/javaruntype/javaruntype/1.3/javaruntype-1.3.jar", + "https://maven.google.comorg/javaruntype/javaruntype/1.3/javaruntype-1.3.jar", + "https://repo1.maven.org/maven2org/javaruntype/javaruntype/1.3/javaruntype-1.3.jar" + ], + "sha256": "84620f4cbe1838f04712e3a7a22cc659e2bb942e9cdbb8b54d7f2e46b17d43e8", + "url": "https://jcenter.bintray.com/org/javaruntype/javaruntype/1.3/javaruntype-1.3.jar" + }, + { + "coord": "org.javassist:javassist:3.20.0-GA", + "dependencies": [], + "directDependencies": [], + "file": "v1/https/jcenter.bintray.com/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar", + "mirror_urls": [ + "https://jcenter.bintray.com/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar", + "https://maven.google.comorg/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar", + "https://repo1.maven.org/maven2org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar" + ], + "sha256": "d7691062fb779c2381640c8f72acba2c23873b01c243866d41c15dc4c8848ea2", + "url": "https://jcenter.bintray.com/org/javassist/javassist/3.20.0-GA/javassist-3.20.0-GA.jar" + }, + { + "coord": "org.slf4j:slf4j-api:1.7.25", + "dependencies": [], + "directDependencies": [], + "file": "v1/https/jcenter.bintray.com/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar", + "mirror_urls": [ + "https://jcenter.bintray.com/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar", + "https://maven.google.comorg/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar", + "https://repo1.maven.org/maven2org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar" + ], + "sha256": "18c4a0095d5c1da6b817592e767bb23d29dd2f560ad74df75ff3961dbde25b79", + "url": "https://jcenter.bintray.com/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar" + }, + { + "coord": "ru.vyarus:generics-resolver:2.0.1", + "dependencies": [], + "directDependencies": [], + "file": "v1/https/jcenter.bintray.com/ru/vyarus/generics-resolver/2.0.1/generics-resolver-2.0.1.jar", + "mirror_urls": [ + "https://jcenter.bintray.com/ru/vyarus/generics-resolver/2.0.1/generics-resolver-2.0.1.jar", + "https://maven.google.comru/vyarus/generics-resolver/2.0.1/generics-resolver-2.0.1.jar", + "https://repo1.maven.org/maven2ru/vyarus/generics-resolver/2.0.1/generics-resolver-2.0.1.jar" + ], + "sha256": "2d3ecff6064b22349395555c09940949371a70cb7c0e0fdedb711566b13f2931", + "url": "https://jcenter.bintray.com/ru/vyarus/generics-resolver/2.0.1/generics-resolver-2.0.1.jar" } ], "version": "0.1.0"