diff --git a/benchmarks/src/main/kotlin/org/Performance.kt b/benchmarks/src/main/kotlin/org/Performance.kt new file mode 100644 index 000000000..9d886c027 --- /dev/null +++ b/benchmarks/src/main/kotlin/org/Performance.kt @@ -0,0 +1,403 @@ +package org + +import org.ucfs.input.LinearInputLabel +import org.ucfs.sppf.node.SppfNode + +class Performance {} +val code = + """package org.junit.experimental.categories; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +import org.junit.runner.Description; +import org.junit.runner.manipulation.Filter; +import org.junit.runner.manipulation.NoTestsRemainException; +import org.junit.runners.Suite; +import org.junit.runners.model.InitializationError; +import org.junit.runners.model.RunnerBuilder; + +/** + * From a given set of test classes, runs only the classes and methods that are + * annotated with either the category given with the @IncludeCategory + * annotation, or a subtype of that category. + *

+ * Note that, for now, annotating suites with {@code @Category} has no effect. + * Categories must be annotated on the direct method or class. + *

+ * Example: + *

+ * public interface FastTests {
+ * }
+ *
+ * public interface SlowTests {
+ * }
+ *
+ * public interface SmokeTests
+ * }
+ *
+ * public static class A {
+ *     @Test
+ *     public void a() {
+ *         fail();
+ *     }
+ *
+ *     @Category(SlowTests.class)
+ *     @Test
+ *     public void b() {
+ *     }
+ *
+ *     @Category({FastTests.class, SmokeTests.class})
+ *     @Test
+ *     public void c() {
+ *     }
+ * }
+ *
+ * @Category({SlowTests.class, FastTests.class})
+ * public static class B {
+ *     @Test
+ *     public void d() {
+ *     }
+ * }
+ *
+ * @RunWith(Categories.class)
+ * @IncludeCategory(SlowTests.class)
+ * @SuiteClasses({A.class, B.class})
+ * // Note that Categories is a kind of Suite
+ * public static class SlowTestSuite {
+ *     // Will run A.b and B.d, but not A.a and A.c
+ * }
+ * 
+ *

+ * Example to run multiple categories: + *

+ * @RunWith(Categories.class)
+ * @IncludeCategory({FastTests.class, SmokeTests.class})
+ * @SuiteClasses({A.class, B.class})
+ * public static class FastOrSmokeTestSuite {
+ *     // Will run A.c and B.d, but not A.b because it is not any of FastTests or SmokeTests
+ * }
+ * 
+ * + * @version 4.12 + * @see Categories at JUnit wiki + */ +public class Categories extends Suite { + + @Retention(RetentionPolicy.RUNTIME) + public @interface IncludeCategory { + /** + * Determines the tests to run that are annotated with categories specified in + * the value of this annotation or their subtypes unless excluded with {@link ExcludeCategory}. + */ + public Class[] value() default {}; + + /** + * If true, runs tests annotated with any of the categories in + * {@link IncludeCategory#value()}. Otherwise, runs tests only if annotated with all of the categories. + */ + public boolean matchAny() default true; + } + + @Retention(RetentionPolicy.RUNTIME) + public @interface ExcludeCategory { + /** + * Determines the tests which do not run if they are annotated with categories specified in the + * value of this annotation or their subtypes regardless of being included in {@link IncludeCategory#value()}. + */ + public Class[] value() default {}; + + /** + * If true, the tests annotated with any of the categories in {@link ExcludeCategory#value()} + * do not run. Otherwise, the tests do not run if and only if annotated with all categories. + */ + public boolean matchAny() default true; + } + + public static class CategoryFilter extends Filter { + private final Set> included; + private final Set> excluded; + private final boolean includedAny; + private final boolean excludedAny; + + public static CategoryFilter include(boolean matchAny, Class... categories) { + if (hasNull(categories)) { + throw new NullPointerException("has null category"); + } + return categoryFilter(matchAny, createSet(categories), true, null); + } + + public static CategoryFilter include(Class category) { + return include(true, category); + } + + public static CategoryFilter include(Class... categories) { + return include(true, categories); + } + + public static CategoryFilter exclude(boolean matchAny, Class... categories) { + if (hasNull(categories)) { + throw new NullPointerException("has null category"); + } + return categoryFilter(true, null, matchAny, createSet(categories)); + } + + public static CategoryFilter exclude(Class category) { + return exclude(true, category); + } + + public static CategoryFilter exclude(Class... categories) { + return exclude(true, categories); + } + + public static CategoryFilter categoryFilter(boolean matchAnyInclusions, Set> inclusions, + boolean matchAnyExclusions, Set> exclusions) { + return new CategoryFilter(matchAnyInclusions, inclusions, matchAnyExclusions, exclusions); + } + + protected CategoryFilter(boolean matchAnyIncludes, Set> includes, + boolean matchAnyExcludes, Set> excludes) { + includedAny = matchAnyIncludes; + excludedAny = matchAnyExcludes; + included = copyAndRefine(includes); + excluded = copyAndRefine(excludes); + } + + /** + * @see #toString() + */ + @Override + public String describe() { + return toString(); + } + + /** + * Returns string in the form "[included categories] - [excluded categories]", where both + * sets have comma separated names of categories. + * + * @return string representation for the relative complement of excluded categories set + * in the set of included categories. Examples: + *
    + *
  • "categories [all]" for all included categories and no excluded ones; + *
  • "categories [all] - [A, B]" for all included categories and given excluded ones; + *
  • "categories [A, B] - [C, D]" for given included categories and given excluded ones. + *
+ * @see Class#toString() name of category + */ + @Override public String toString() { + StringBuilder description= new StringBuilder("categories ") + .append(included.isEmpty() ? "[all]" : included); + if (!excluded.isEmpty()) { + description.append(" - ").append(excluded); + } + return description.toString(); + } + + @Override + public boolean shouldRun(Description description) { + if (hasCorrectCategoryAnnotation(description)) { + return true; + } + + for (Description each : description.getChildren()) { + if (shouldRun(each)) { + return true; + } + } + + return false; + } + + private boolean hasCorrectCategoryAnnotation(Description description) { + final Set> childCategories= categories(description); + + // If a child has no categories, immediately return. + if (childCategories.isEmpty()) { + return included.isEmpty(); + } + + if (!excluded.isEmpty()) { + if (excludedAny) { + if (matchesAnyParentCategories(childCategories, excluded)) { + return false; + } + } else { + if (matchesAllParentCategories(childCategories, excluded)) { + return false; + } + } + } + + if (included.isEmpty()) { + // Couldn't be excluded, and with no suite's included categories treated as should run. + return true; + } else { + if (includedAny) { + return matchesAnyParentCategories(childCategories, included); + } else { + return matchesAllParentCategories(childCategories, included); + } + } + } + + /** + * @return true if at least one (any) parent category match a child, otherwise false. + * If empty parentCategories, returns false. + */ + private boolean matchesAnyParentCategories(Set> childCategories, Set> parentCategories) { + for (Class parentCategory : parentCategories) { + if (hasAssignableTo(childCategories, parentCategory)) { + return true; + } + } + return false; + } + + /** + * @return false if at least one parent category does not match children, otherwise true. + * If empty parentCategories, returns true. + */ + private boolean matchesAllParentCategories(Set> childCategories, Set> parentCategories) { + for (Class parentCategory : parentCategories) { + if (!hasAssignableTo(childCategories, parentCategory)) { + return false; + } + } + return true; + } + + private static Set> categories(Description description) { + Set> categories= new HashSet>(); + Collections.addAll(categories, directCategories(description)); + Collections.addAll(categories, directCategories(parentDescription(description))); + return categories; + } + + private static Description parentDescription(Description description) { + Class testClass= description.getTestClass(); + return testClass == null ? null : Description.createSuiteDescription(testClass); + } + + private static Class[] directCategories(Description description) { + if (description == null) { + return new Class[0]; + } + + Category annotation= description.getAnnotation(Category.class); + return annotation == null ? new Class[0] : annotation.value(); + } + + private static Set> copyAndRefine(Set> classes) { + HashSet> c= new HashSet>(); + if (classes != null) { + c.addAll(classes); + } + c.remove(null); + return c; + } + + private static boolean hasNull(Class... classes) { + if (classes == null) return false; + for (Class clazz : classes) { + if (clazz == null) { + return true; + } + } + return false; + } + } + + public Categories(Class klass, RunnerBuilder builder) throws InitializationError { + super(klass, builder); + try { + Set> included= getIncludedCategory(klass); + Set> excluded= getExcludedCategory(klass); + boolean isAnyIncluded= isAnyIncluded(klass); + boolean isAnyExcluded= isAnyExcluded(klass); + + filter(CategoryFilter.categoryFilter(isAnyIncluded, included, isAnyExcluded, excluded)); + } catch (NoTestsRemainException e) { + throw new InitializationError(e); + } + assertNoCategorizedDescendentsOfUncategorizeableParents(getDescription()); + } + + private static Set> getIncludedCategory(Class klass) { + IncludeCategory annotation= klass.getAnnotation(IncludeCategory.class); + return createSet(annotation == null ? null : annotation.value()); + } + + private static boolean isAnyIncluded(Class klass) { + IncludeCategory annotation= klass.getAnnotation(IncludeCategory.class); + return annotation == null || annotation.matchAny(); + } + + private static Set> getExcludedCategory(Class klass) { + ExcludeCategory annotation= klass.getAnnotation(ExcludeCategory.class); + return createSet(annotation == null ? null : annotation.value()); + } + + private static boolean isAnyExcluded(Class klass) { + ExcludeCategory annotation= klass.getAnnotation(ExcludeCategory.class); + return annotation == null || annotation.matchAny(); + } + + private static void assertNoCategorizedDescendentsOfUncategorizeableParents(Description description) throws InitializationError { + if (!canHaveCategorizedChildren(description)) { + assertNoDescendantsHaveCategoryAnnotations(description); + } + for (Description each : description.getChildren()) { + assertNoCategorizedDescendentsOfUncategorizeableParents(each); + } + } + + private static void assertNoDescendantsHaveCategoryAnnotations(Description description) throws InitializationError { + for (Description each : description.getChildren()) { + if (each.getAnnotation(Category.class) != null) { + throw new InitializationError("Category annotations on Parameterized classes are not supported on individual methods."); + } + assertNoDescendantsHaveCategoryAnnotations(each); + } + } + + // If children have names like [0], our current magical category code can't determine their parentage. + private static boolean canHaveCategorizedChildren(Description description) { + for (Description each : description.getChildren()) { + if (each.getTestClass() == null) { + return false; + } + } + return true; + } + + private static boolean hasAssignableTo(Set> assigns, Class to) { + for (final Class from : assigns) { + if (to.isAssignableFrom(from)) { + return true; + } + } + return false; + } + + private static Set> createSet(Class... t) { + final Set> set= new HashSet>(); + if (t != null) { + Collections.addAll(set, t); + } + return set; + } +} +""" +fun main() { + for (i in 0..2_000) + parse(code) +} + +fun parse(code: String): SppfNode? { + val parser = org.ucfs.Java8Parser() + parser.setInput(getTokenStream(code)) + return parser.parse().first +} \ No newline at end of file diff --git a/scripts/generate_all.sh b/scripts/generate_all.sh index 2dd7e7437..26d67f426 100755 --- a/scripts/generate_all.sh +++ b/scripts/generate_all.sh @@ -3,7 +3,7 @@ shopt -s nullglob #ingore failed patterns rootPrj=$(pwd) parserDest="../benchmarks/src/main/kotlin/" antlrSrc="benchmarks/src/main/java/org/antlr" -lexerSrc="examples/src/main/java/java7" +lexerSrc="examples/src/main/java/java8" printf "\n\nINSTALL PACKAGES\n" apt-get install jflex