java-topology/defects/micronaut/unit/MicronautTest.java

283 lines
11 KiB
Java

package unit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Unit test for Micronaut CWE-407 defects:
* micronaut-0001: ClassUtils.resolveHierarchy — hierarchy.contains (ArrayList) in while loop
* micronaut-0002: MutableAnnotationMetadata — annotationList.contains (ArrayList) in for loop
* micronaut-0003: EnvironmentPropertySource — includes/excludes.contains (List) in env loop
*
* No JUnit. No external deps. Compile and run:
* javac -d . *.java && java -ea unit.MicronautTest
*/
public class MicronautTest {
// ---- micronaut-0001 simulation ----
// Simulates resolveHierarchy: builds hierarchy list while walking superclass chain,
// calling contains() to deduplicate. Also simulates populateHierarchyInterfaces recursion.
static long slowResolveHierarchy(int superclassCount, int interfacesPerClass) {
long ops = 0;
List<Integer> hierarchy = new ArrayList<>();
List<Integer> interfaces = new ArrayList<>();
// Walk superclass chain
for (int superclass = 0; superclass < superclassCount; superclass++) {
if (!hierarchy.contains(superclass)) { // O(H) ArrayList
ops += hierarchy.size() + 1;
hierarchy.add(superclass);
}
// Populate interfaces for this superclass
for (int iface = 0; iface < interfacesPerClass; iface++) {
int ifaceId = superclass * 100 + iface;
if (!interfaces.contains(ifaceId)) { // O(|interfaces|) ArrayList
ops += interfaces.size() + 1;
interfaces.add(ifaceId);
}
// Recursive: each interface may have parent interfaces
for (int parentIface = 0; parentIface < interfacesPerClass / 2; parentIface++) {
int parentId = ifaceId * 100 + parentIface;
if (!interfaces.contains(parentId)) { // O(|interfaces|)
ops += interfaces.size() + 1;
interfaces.add(parentId);
}
}
}
}
return ops;
}
static long fastResolveHierarchy(int superclassCount, int interfacesPerClass) {
long ops = 0;
Set<Integer> hierarchy = new LinkedHashSet<>();
Set<Integer> interfaces = new LinkedHashSet<>();
for (int superclass = 0; superclass < superclassCount; superclass++) {
if (!hierarchy.contains(superclass)) { // O(1) HashSet
ops += 1;
hierarchy.add(superclass);
}
for (int iface = 0; iface < interfacesPerClass; iface++) {
int ifaceId = superclass * 100 + iface;
if (!interfaces.contains(ifaceId)) { // O(1)
ops += 1;
interfaces.add(ifaceId);
}
for (int parentIface = 0; parentIface < interfacesPerClass / 2; parentIface++) {
int parentId = ifaceId * 100 + parentIface;
if (!interfaces.contains(parentId)) { // O(1)
ops += 1;
interfaces.add(parentId);
}
}
}
}
return ops;
}
// ---- micronaut-0002 simulation ----
// Simulates addRepeatableStereotype: for each parent in parents list,
// check annotationList.contains (ArrayList) before adding.
static long slowAddRepeatableStereotype(int parentCount, int existingAnnotations) {
long ops = 0;
List<String> annotationList = new ArrayList<>();
// Pre-populate with existingAnnotations
for (int i = 0; i < existingAnnotations; i++) {
annotationList.add("existing-" + i);
}
// Add parents
for (int i = 0; i < parentCount; i++) {
String parent = "parent-" + i;
if (!annotationList.contains(parent)) { // O(|annotationList|) ArrayList
ops += annotationList.size() + 1;
annotationList.add(parent);
}
}
return ops;
}
static long fastAddRepeatableStereotype(int parentCount, int existingAnnotations) {
long ops = 0;
Set<String> annotationSet = new LinkedHashSet<>();
for (int i = 0; i < existingAnnotations; i++) {
annotationSet.add("existing-" + i);
}
for (int i = 0; i < parentCount; i++) {
String parent = "parent-" + i;
if (!annotationSet.contains(parent)) { // O(1)
ops += 1;
annotationSet.add(parent);
}
}
return ops;
}
// ---- micronaut-0003 simulation ----
// Simulates getEnv: for each env var, check excludes.contains and includes.contains
static long slowEnvFilter(int envVarCount, int filterListSize) {
long ops = 0;
List<String> excludes = new ArrayList<>();
List<String> includes = new ArrayList<>();
for (int i = 0; i < filterListSize; i++) {
excludes.add("EXCLUDE_" + i);
includes.add("INCLUDE_" + i);
}
Map<String, String> env = new HashMap<>();
for (int i = 0; i < envVarCount; i++) {
env.put("ENV_VAR_" + i, "value");
}
for (String envVar : env.keySet()) {
if (excludes.contains(envVar)) { // O(filterListSize) ArrayList
ops += filterListSize;
continue;
}
if (!includes.contains(envVar)) { // O(filterListSize) ArrayList
ops += filterListSize;
continue;
}
ops += filterListSize * 2;
}
return ops;
}
static long fastEnvFilter(int envVarCount, int filterListSize) {
long ops = 0;
Set<String> excludes = new HashSet<>();
Set<String> includes = new HashSet<>();
for (int i = 0; i < filterListSize; i++) {
excludes.add("EXCLUDE_" + i);
includes.add("INCLUDE_" + i);
}
Map<String, String> env = new HashMap<>();
for (int i = 0; i < envVarCount; i++) {
env.put("ENV_VAR_" + i, "value");
}
for (String envVar : env.keySet()) {
if (excludes.contains(envVar)) { // O(1)
ops += 1;
continue;
}
if (!includes.contains(envVar)) { // O(1)
ops += 1;
continue;
}
ops += 2;
}
return ops;
}
public static void main(String[] args) {
int pass = 0;
int total = 0;
// --- micronaut-0001 tests ---
{
total++;
long slow = slowResolveHierarchy(20, 5);
long fast = fastResolveHierarchy(20, 5);
boolean ok = slow > fast * 5;
System.out.println("[micronaut-0001] C=20 I=5: slow_ops=" + slow + " fast_ops=" + fast +
" ratio=" + (slow / Math.max(fast, 1)) + "x " + (ok ? "PASS" : "FAIL"));
if (ok) pass++;
}
{
total++;
// Correctness: same unique elements discovered
List<Integer> slowHierarchy = new ArrayList<>();
Set<Integer> fastHierarchy = new LinkedHashSet<>();
for (int i = 0; i < 30; i++) {
int val = i % 15;
if (!slowHierarchy.contains(val)) slowHierarchy.add(val);
fastHierarchy.add(val);
}
boolean ok = slowHierarchy.size() == fastHierarchy.size();
System.out.println("[micronaut-0001] correctness: slow=" + slowHierarchy.size() +
" fast=" + fastHierarchy.size() + " " + (ok ? "PASS" : "FAIL"));
if (ok) pass++;
}
// --- micronaut-0002 tests ---
{
total++;
long slow = slowAddRepeatableStereotype(30, 10);
long fast = fastAddRepeatableStereotype(30, 10);
boolean ok = slow > fast * 3;
System.out.println("[micronaut-0002] P=30 existing=10: slow_ops=" + slow + " fast_ops=" + fast +
" ratio=" + (slow / Math.max(fast, 1)) + "x " + (ok ? "PASS" : "FAIL"));
if (ok) pass++;
}
{
total++;
long slow = slowAddRepeatableStereotype(100, 50);
long fast = fastAddRepeatableStereotype(100, 50);
boolean ok = slow > fast * 10;
System.out.println("[micronaut-0002] P=100 existing=50: slow_ops=" + slow + " fast_ops=" + fast +
" ratio=" + (slow / Math.max(fast, 1)) + "x " + (ok ? "PASS" : "FAIL"));
if (ok) pass++;
}
{
total++;
// Correctness: same dedup result
List<String> slowResult = new ArrayList<>();
Set<String> fastResult = new LinkedHashSet<>();
String[] parents = {"a", "b", "a", "c", "b", "d"};
for (String p : parents) {
if (!slowResult.contains(p)) slowResult.add(p);
fastResult.add(p);
}
boolean ok = slowResult.size() == fastResult.size() &&
new ArrayList<>(fastResult).equals(slowResult);
System.out.println("[micronaut-0002] dedup correctness: slow=" + slowResult.size() +
" fast=" + fastResult.size() + " " + (ok ? "PASS" : "FAIL"));
if (ok) pass++;
}
// --- micronaut-0003 tests ---
{
total++;
long slow = slowEnvFilter(500, 50);
long fast = fastEnvFilter(500, 50);
boolean ok = slow > fast * 10;
System.out.println("[micronaut-0003] E=500 N=50: slow_ops=" + slow + " fast_ops=" + fast +
" ratio=" + (slow / Math.max(fast, 1)) + "x " + (ok ? "PASS" : "FAIL"));
if (ok) pass++;
}
{
total++;
// Correctness: same env vars pass through filter
List<String> slowPassed = new ArrayList<>();
List<String> fastPassed = new ArrayList<>();
List<String> excludeList = new ArrayList<>();
Set<String> excludeSet = new HashSet<>();
List<String> includeList = new ArrayList<>();
Set<String> includeSet = new HashSet<>();
for (int i = 0; i < 5; i++) {
excludeList.add("EX_" + i); excludeSet.add("EX_" + i);
includeList.add("ENV_VAR_" + i); includeSet.add("ENV_VAR_" + i);
}
for (int i = 0; i < 10; i++) {
String v = "ENV_VAR_" + i;
if (!excludeList.contains(v) && includeList.contains(v)) slowPassed.add(v);
if (!excludeSet.contains(v) && includeSet.contains(v)) fastPassed.add(v);
}
boolean ok = slowPassed.size() == fastPassed.size();
System.out.println("[micronaut-0003] filter correctness: slow=" + slowPassed.size() +
" fast=" + fastPassed.size() + " " + (ok ? "PASS" : "FAIL"));
if (ok) pass++;
}
System.out.println("\n" + pass + "/" + total + " PASS");
if (pass != total) {
System.exit(1);
}
}
}