package unit; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; /** * CWE-407 unit test: opensearch-001 * ImmutableCacheStatsHolder.java:232-235 — Arrays.asList(levels).contains() inside * a loop over dimensionNames — O(n²) level filtering. * * Slow path: Arrays.asList().contains() — O(L) per iteration. * Fast path: HashSet.contains() — O(1) per iteration. * * Compile: javac -d . CacheStatsLevelsContains.java * Run: java -ea unit.CacheStatsLevelsContains */ public class CacheStatsLevelsContains { /** * Simulates the defective filterLevels(). * Returns the number of element comparisons performed. */ static long slowFilterLevels(String[] levels, List dimensionNames) { if (levels == null) return 0; List levelsList = Arrays.asList(levels); // O(n) contains() scan List result = new ArrayList<>(); long comparisons = 0; for (String dimensionName : dimensionNames) { // charge the linear scan cost comparisons += levelsList.size(); if (levelsList.contains(dimensionName)) { result.add(dimensionName); } } return comparisons; } /** * Simulates the fixed filterLevels() using HashSet. * Returns the number of hash lookups performed. */ static long fastFilterLevels(String[] levels, List dimensionNames) { if (levels == null) return 0; Set levelsSet = new HashSet<>(Arrays.asList(levels)); List result = new ArrayList<>(); long operations = 0; for (String dimensionName : dimensionNames) { operations++; // O(1) hash lookup if (levelsSet.contains(dimensionName)) { result.add(dimensionName); } } return operations; } /** Run both paths and return filtered list (for correctness check). */ static List filterSlow(String[] levels, List dimensionNames) { if (levels == null) return new ArrayList<>(dimensionNames); List levelsList = Arrays.asList(levels); List result = new ArrayList<>(); for (String d : dimensionNames) { if (levelsList.contains(d)) result.add(d); } return result; } static List filterFast(String[] levels, List dimensionNames) { if (levels == null) return new ArrayList<>(dimensionNames); Set levelsSet = new HashSet<>(Arrays.asList(levels)); List result = new ArrayList<>(); for (String d : dimensionNames) { if (levelsSet.contains(d)) result.add(d); } return result; } public static void main(String[] args) { int passed = 0; int total = 0; // Test 1: correctness — same output from both paths { total++; String[] levels = {"shard", "node"}; List dims = new ArrayList<>(Arrays.asList("index", "shard", "node", "tier")); List slowResult = filterSlow(levels, dims); List fastResult = filterFast(levels, dims); assert slowResult.equals(fastResult) : "Results differ: slow=" + slowResult + " fast=" + fastResult; assert slowResult.size() == 2 : "Expected 2, got " + slowResult.size(); System.out.printf("Test 1 (correctness): both = %s%n", slowResult); passed++; } // Test 2: null levels — pass-through { total++; List dims = new ArrayList<>(Arrays.asList("a", "b", "c")); long slowCost = slowFilterLevels(null, dims); long fastCost = fastFilterLevels(null, dims); assert slowCost == 0 && fastCost == 0; System.out.printf("Test 2 (null levels): slow=%d fast=%d%n", slowCost, fastCost); passed++; } // Test 3: cost ratio — medium scale { total++; int D = 100; // dimension names (like cache dimension keys in a large cluster) int L = 50; // levels requested List dimensionNames = new ArrayList<>(); for (int i = 0; i < D; i++) dimensionNames.add("dim" + i); String[] levels = new String[L]; for (int i = 0; i < L; i++) levels[i] = "dim" + (i * 2); // every other dim long slowCost = slowFilterLevels(levels, dimensionNames); long fastCost = fastFilterLevels(levels, dimensionNames); assert slowCost > fastCost : String.format("Expected slow > fast: slow=%d fast=%d", slowCost, fastCost); System.out.printf("Test 3 (D=%d L=%d): slow=%d, fast=%d, ratio=%.1fx%n", D, L, slowCost, fastCost, (double) slowCost / fastCost); passed++; } // Test 4: large scale — verify significant speedup { total++; int D = 500; int L = 200; List dimensionNames = new ArrayList<>(); for (int i = 0; i < D; i++) dimensionNames.add("dim" + i); String[] levels = new String[L]; for (int i = 0; i < L; i++) levels[i] = "dim" + i; long slowCost = slowFilterLevels(levels, dimensionNames); long fastCost = fastFilterLevels(levels, dimensionNames); double ratio = (double) slowCost / fastCost; assert ratio > 10.0 : String.format("Expected >10x speedup at D=%d L=%d, got %.1fx", D, L, ratio); System.out.printf("Test 4 (D=%d L=%d): slow=%d, fast=%d, speedup=%.1fx%n", D, L, slowCost, fastCost, ratio); passed++; } System.out.printf("%n%d/%d PASS%n", passed, total); } }