import java.util.*; /** * Unit test for erpnext-0002: serial_batch_bundle.get_serial_batch_list_from_item O(N^2) * * Simulates serial number dedup where each serial_no is checked via * list scan (defect) vs set lookup (fix). * * Defect: serial_batch_bundle.py lines 1567-1571 — "if row.serial_no not in serial_list" * where serial_list is a Python list, giving O(N) per check and O(N^2) overall. * * Fix: maintain a parallel set for O(1) membership checks. */ public class test_erpnext_0002 { // --- Defect: list-only dedup --- static List dedupSerialDefect(List serials) { List serialList = new ArrayList<>(); for (String sn : serials) { if (sn != null && !serialList.contains(sn)) { // O(N) per check serialList.add(sn); } } return serialList; } // --- Fix: set-backed dedup --- static List dedupSerialFixed(List serials) { List serialList = new ArrayList<>(); Set serialSet = new HashSet<>(); for (String sn : serials) { if (sn != null && !serialSet.contains(sn)) { // O(1) per check serialList.add(sn); serialSet.add(sn); } } return serialList; } static List generateSerials(int n) { List serials = new ArrayList<>(n); for (int i = 0; i < n; i++) { serials.add("SN-" + String.format("%06d", i % (n / 2 + 1))); // ~50% duplicates } return serials; } public static void main(String[] args) { System.out.println("=== erpnext-0002: serial_batch_bundle dedup O(N^2) ===\n"); // Correctness test List input = Arrays.asList("SN-001", "SN-002", "SN-001", "SN-003", "SN-002"); List expected = Arrays.asList("SN-001", "SN-002", "SN-003"); List defectResult = dedupSerialDefect(input); List fixedResult = dedupSerialFixed(input); assert defectResult.equals(expected) : "Defect result wrong: " + defectResult; assert fixedResult.equals(expected) : "Fixed result wrong: " + fixedResult; System.out.println("Correctness: PASS"); // Performance test: 5000 serial numbers int N = 5000; List serials = generateSerials(N); System.out.println("Serial count: " + N + " (~50% duplicates)"); // Warmup for (int i = 0; i < 5; i++) { dedupSerialDefect(serials); dedupSerialFixed(serials); } int iterations = 50; long t0 = System.nanoTime(); for (int i = 0; i < iterations; i++) { dedupSerialDefect(serials); } long defectNs = System.nanoTime() - t0; t0 = System.nanoTime(); for (int i = 0; i < iterations; i++) { dedupSerialFixed(serials); } long fixedNs = System.nanoTime() - t0; double ratio = (double) defectNs / fixedNs; System.out.printf("Defect: %,d ns / %d iters%n", defectNs, iterations); System.out.printf("Fixed: %,d ns / %d iters%n", fixedNs, iterations); System.out.printf("Ratio: %.1fx%n", ratio); boolean pass = ratio > 3.0; System.out.println("\nResult: " + (pass ? "PASS" : "FAIL") + " (ratio=" + String.format("%.1f", ratio) + "x)"); assert pass : "Expected speedup > 3x, got " + ratio; } }