erpnext-0001: BOM.get_children list dedup O(B^2) MEDIUM 4x erpnext-0002: serial_batch_bundle serial/batch dedup O(N^2) HIGH 45x ofbiz-0001: PaymentGatewayServices processList LinkedList O(N^2) HIGH 45x ofbiz-0002: OrderReturnServices/OrderReadHelper payment dedup O(N^2) MEDIUM 36x odoo: CLEAN (consistent set/frozenset/OrderedSet usage throughout)
95 lines
3.4 KiB
Java
95 lines
3.4 KiB
Java
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<String> dedupSerialDefect(List<String> serials) {
|
|
List<String> 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<String> dedupSerialFixed(List<String> serials) {
|
|
List<String> serialList = new ArrayList<>();
|
|
Set<String> 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<String> generateSerials(int n) {
|
|
List<String> 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<String> input = Arrays.asList("SN-001", "SN-002", "SN-001", "SN-003", "SN-002");
|
|
List<String> expected = Arrays.asList("SN-001", "SN-002", "SN-003");
|
|
|
|
List<String> defectResult = dedupSerialDefect(input);
|
|
List<String> 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<String> 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;
|
|
}
|
|
}
|