Der benutzerdefinierte JQF-Generator kann die Filialabdeckung nicht erhöhen
Posted: 27 Dec 2024, 10:19
Ich verwende JQF+Zest zum Fuzzing.
Da ich viele verschiedene Klassen testen muss, möchte ich nicht für jede einzelne manuell einen Generator schreiben, also habe ich den folgenden einfachen generischen Generator geschrieben:
Ich verwende einen einfachen Fall, um diesen Generator zu testen
Nachdem ich jedoch ../bin/jqf-zest -c "$DEPENDENCY": ausgeführt habe. Testen Sie fuzzLocalDateTime. Ich beobachte, dass die Codeabdeckung hängen bleibt und sich nicht wie folgt erhöht
Da ich viele verschiedene Klassen testen muss, möchte ich nicht für jede einzelne manuell einen Generator schreiben, also habe ich den folgenden einfachen generischen Generator geschrieben:
Code: Select all
package caohch1;
import com.pholser.junit.quickcheck.generator.Generator;
import com.pholser.junit.quickcheck.random.SourceOfRandomness;
import com.pholser.junit.quickcheck.generator.GenerationStatus;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
public class GenericGenerator extends Generator {
private final Class type;
public GenericGenerator(Class type) {
super(type);
this.type = type;
}
@Override
public T generate(SourceOfRandomness random, GenerationStatus status) {
random.nextBytes(4); // Consume some random bytes for JQF
try {
T instance = createInstance(random);
if (instance != null) {
populateFields(instance, random);
}
return instance;
} catch (Exception e) {
return null;
}
}
private T createInstance(SourceOfRandomness random) {
Constructor[] constructors = type.getDeclaredConstructors();
Arrays.sort(constructors, (c1, c2) ->
Integer.compare(c1.getParameterCount(), c2.getParameterCount()));
for (Constructor constructor : constructors) {
constructor.setAccessible(true);
try {
Class[] paramTypes = constructor.getParameterTypes();
Object[] params = new Object[paramTypes.length];
for (int i = 0; i < paramTypes.length; i++) {
params[i] = generateRandomValue(paramTypes[i], random);
}
@SuppressWarnings("unchecked")
T instance = (T) constructor.newInstance(params);
return instance;
} catch (Exception e) {
continue;
}
}
return null;
}
private void populateFields(T instance, SourceOfRandomness random) {
try {
for (Field field : instance.getClass().getFields()) {
if (!Modifier.isStatic(field.getModifiers()) &&
!Modifier.isFinal(field.getModifiers())) {
Object value = generateRandomValue(field.getType(), random);
if (value != null) {
field.set(instance, value);
}
}
}
} catch (Exception e) {
// Ignore field population errors
}
}
private Object generateRandomValue(Class type, SourceOfRandomness random) {
random.nextBytes(1);
if (type == int.class || type == Integer.class) {
return random.nextInt();
}
if (type == long.class || type == Long.class) {
return random.nextLong();
}
if (type == boolean.class || type == Boolean.class) {
return random.nextBoolean();
}
if (type == byte.class || type == Byte.class) {
return random.nextByte(Byte.MIN_VALUE, Byte.MAX_VALUE);
}
if (type == char.class || type == Character.class) {
return (char) random.nextChar(Character.MIN_VALUE, Character.MAX_VALUE);
}
if (type == double.class || type == Double.class) {
return random.nextDouble();
}
if (type == float.class || type == Float.class) {
return random.nextFloat();
}
if (type == String.class) {
int length = random.nextInt(); // Example length, adjust as needed
StringBuilder sb = new StringBuilder(length);
for (int i = 0; i < length; i++) {
sb.append(random.nextChar(Character.MIN_VALUE, Character.MAX_VALUE));
}
return sb.toString();
}
if (type.isEnum()) {
Object[] constants = type.getEnumConstants();
return constants[random.nextInt(constants.length)];
}
if (List.class.isAssignableFrom(type)) {
return new ArrayList();
}
if (Set.class.isAssignableFrom(type)) {
return new HashSet();
}
if (Map.class.isAssignableFrom(type)) {
return new HashMap();
}
try {
return new GenericGenerator(type).generate(random, null);
} catch (Exception e) {
return null;
}
}
}
Code: Select all
public class Test {
@Fuzz
public void fuzzLocalDateTime(@From(GenericGenerator.class) String var1, @From(GenericGenerator.class) String var2) throws IllegalArgumentException, DateTimeParseException {
LocalDateTime.parse(var1, DateTimeFormatter.ofPattern(var2));
}
}
Code: Select all
Semantic Fuzzing with Zest
--------------------------
Test name: Test#fuzzLocalDateTime
Instrumentation: Janala
Results directory: ...../fuzz-results
Elapsed time: 9s (no time limit)
Number of executions: 11,578 (no trial limit)
Valid inputs: 11,578 (100.00%)
Cycles completed: 10
Unique failures: 0
Queue size: 3 (1 favored last cycle)
Current parent input: 0 (favored) {627/1000 mutations}
Execution speed: 2,116/sec now | 1,178/sec overall
Total coverage: 147 branches (0.22% of map)
Valid coverage: 147 branches (0.22% of map)