import java.util.*; /** * CWE-407 unit tests for Crystal compiler defects. * * crystal-0001: parser.cr parse_type_vars — type_vars Array#includes? O(N²) * while parsing type params: type_vars.includes?(name) in inner loop * Fix: parallel Set for O(1) duplicate detection * * crystal-0002: restrictions.cr union restrict — discarded Array#includes? O(T×O) * nested loop: other_types × union_types, discarded.includes?(type) per iteration * Fix: discarded = Set(Type).new */ public class CrystalTest { // --- crystal-0001: type_vars includes? --- static List parseTypeVarsList(List input) { List typeVars = new ArrayList<>(); for (String name : input) { if (typeVars.contains(name)) { // O(N) — defect throw new IllegalArgumentException("duplicated: " + name); } typeVars.add(name); } return typeVars; } static List parseTypeVarsSet(List input) { List typeVars = new ArrayList<>(); Set seen = new HashSet<>(); // O(1) — fix for (String name : input) { if (seen.contains(name)) { throw new IllegalArgumentException("duplicated: " + name); } typeVars.add(name); seen.add(name); } return typeVars; } static void testCrystal0001() throws Exception { int N = 3000; List typeParams = new ArrayList<>(); for (int i = 0; i < N; i++) typeParams.add("T" + i); // correctness List r1 = parseTypeVarsList(typeParams); List r2 = parseTypeVarsSet(typeParams); assert r1.equals(r2) : "list and set paths must agree"; // duplicate detection List withDup = new ArrayList<>(typeParams); withDup.add("T0"); boolean threwList = false, threwSet = false; try { parseTypeVarsList(withDup); } catch (IllegalArgumentException e) { threwList = true; } try { parseTypeVarsSet(withDup); } catch (IllegalArgumentException e) { threwSet = true; } assert threwList && threwSet : "both must detect duplicate"; // performance long t0 = System.nanoTime(); for (int r = 0; r < 200; r++) parseTypeVarsList(typeParams); long tList = System.nanoTime() - t0; t0 = System.nanoTime(); for (int r = 0; r < 200; r++) parseTypeVarsSet(typeParams); long tSet = System.nanoTime() - t0; double ratio = (double) tList / tSet; System.out.printf("crystal-0001: list=%.3fs set=%.3fs ratio=%.1f×%n", tList / 1e9, tSet / 1e9, ratio); assert ratio > 10 : "Expected >10× speedup, got " + ratio; System.out.println("PASS crystal-0001"); } // --- crystal-0002: discarded includes? in union restrict loop --- static int restrictUnionList(int otherCount, int unionCount) { List discarded = new ArrayList<>(); int matched = 0; for (int o = 0; o < otherCount; o++) { for (int u = 0; u < unionCount; u++) { if (discarded.contains(u)) continue; // O(D) — defect if (u % (o + 1) == 0) { matched++; discarded.add(u); } } } return matched; } static int restrictUnionSet(int otherCount, int unionCount) { Set discarded = new HashSet<>(); int matched = 0; for (int o = 0; o < otherCount; o++) { for (int u = 0; u < unionCount; u++) { if (discarded.contains(u)) continue; // O(1) — fix if (u % (o + 1) == 0) { matched++; discarded.add(u); } } } return matched; } static void testCrystal0002() throws Exception { int O = 60, U = 200; // correctness int r1 = restrictUnionList(O, U); int r2 = restrictUnionSet(O, U); assert r1 == r2 : "list and set must match: " + r1 + " vs " + r2; // performance long t0 = System.nanoTime(); for (int r = 0; r < 200; r++) restrictUnionList(O, U); long tList = System.nanoTime() - t0; t0 = System.nanoTime(); for (int r = 0; r < 200; r++) restrictUnionSet(O, U); long tSet = System.nanoTime() - t0; double ratio = (double) tList / tSet; System.out.printf("crystal-0002: list=%.3fs set=%.3fs ratio=%.1f×%n", tList / 1e9, tSet / 1e9, ratio); assert ratio > 3 : "Expected >3× speedup, got " + ratio; System.out.println("PASS crystal-0002"); } public static void main(String[] args) throws Exception { testCrystal0001(); testCrystal0002(); System.out.println("ALL PASS"); } }