package h02; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import org.tudalgo.algoutils.tutor.general.SpoonUtils; import spoon.reflect.declaration.CtElement; import spoon.reflect.declaration.CtMethod; import spoon.reflect.declaration.CtParameter; import java.io.IOException; import java.nio.file.Paths; import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.function.Consumer; import static h02.TestConstants.RANDOM_SEED; public abstract class TestUtils { /** * A generator for JSON test data. */ public interface JsonGenerator { /** * Generates a JSON object node. * * @param mapper The object mapper to use. * @param index The index of the object node. * @param rnd The random number generator to use. * @return The generated JSON object node. */ ObjectNode generateJson(ObjectMapper mapper, int index, Random rnd); } /** * Generates and saves JSON test data. * * @param generator The generator to use. * @param amount The amount of test data to generate. * @param fileName The file name to save the test data to. * @throws IOException If an I/O error occurs. */ public static void generateJsonTestData(final JsonGenerator generator, final int amount, final String fileName) throws IOException { final var seed = RANDOM_SEED; final var random = new java.util.Random(seed); final ObjectMapper mapper = new ObjectMapper(); final ArrayNode arrayNode = mapper.createArrayNode(); System.out.println("Generating test data with seed: " + seed); for (int i = 0; i < amount; i++) { arrayNode.add(generator.generateJson(mapper, i, random)); } // convert `ObjectNode` to pretty-print JSON // System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(arrayNode)); final var path = Paths.get( "src", "graderPrivate", "resources", "h02", fileName ).toAbsolutePath(); System.out.printf("Saving to file: %s%n", path); final var file = path.toFile(); file.createNewFile(); mapper.writerWithDefaultPrettyPrinter().writeValue(file, arrayNode); } /** * Returns the Spoon representation of the given method. * * @param clazz the method's owner * @param methodName the method name * @param paramTypes the method's formal parameter types, if any * @return the Spoon representation of the given method */ public static CtMethod getCtMethod(Class clazz, String methodName, Class... paramTypes) { return SpoonUtils.getType(clazz.getName()) .getMethodsByName(methodName) .stream() .filter(ctMethod -> { List> parameters = ctMethod.getParameters(); boolean result = parameters.size() == paramTypes.length; for (int i = 0; result && i < parameters.size(); i++) { result = parameters.get(i).getType().getQualifiedName().equals(paramTypes[i].getTypeName()); } return result; }) .findAny() .orElseThrow(); } /** * Applies the given consumer to the body and its descendants of the given method. * See also: {@link #getCtMethod(Class, String, Class[])}. * * @param clazz the method's owner * @param methodName the method name * @param paramTypes the method's formal parameter types, if any * @param consumer the consumer to apply */ public static void iterateMethodStatements(Class clazz, String methodName, Class[] paramTypes, Consumer> consumer) { Iterator iterator = getCtMethod(clazz, methodName, paramTypes) .getBody() .descendantIterator(); consumer.accept(iterator); } }