1
2
3
4
5
6 package gov.nist.secauto.metaschema.databind.codegen;
7
8 import static org.junit.jupiter.api.Assertions.assertAll;
9
10 import gov.nist.secauto.metaschema.core.model.IBoundObject;
11 import gov.nist.secauto.metaschema.core.model.IModule;
12 import gov.nist.secauto.metaschema.core.model.MetaschemaException;
13 import gov.nist.secauto.metaschema.core.model.constraint.IConstraintSet;
14 import gov.nist.secauto.metaschema.core.util.CollectionUtil;
15 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
16 import gov.nist.secauto.metaschema.databind.IBindingContext;
17 import gov.nist.secauto.metaschema.databind.codegen.config.DefaultBindingConfiguration;
18 import gov.nist.secauto.metaschema.databind.io.Format;
19 import gov.nist.secauto.metaschema.databind.io.IDeserializer;
20
21 import org.apache.logging.log4j.LogManager;
22 import org.apache.logging.log4j.Logger;
23
24 import java.io.IOException;
25 import java.io.Writer;
26 import java.nio.file.Files;
27 import java.nio.file.Path;
28 import java.nio.file.Paths;
29 import java.nio.file.StandardOpenOption;
30 import java.util.Collection;
31
32 import edu.umd.cs.findbugs.annotations.NonNull;
33 import edu.umd.cs.findbugs.annotations.Nullable;
34
35 @SuppressWarnings("PMD.AbstractClassWithoutAbstractMethod")
36 public abstract class AbstractMetaschemaTest {
37
38 private static final Logger LOGGER = LogManager.getLogger(AbstractMetaschemaTest.class);
39
40
41 @NonNull
42 protected Path generationDir = ObjectUtils.notNull(Paths.get("target/generated-test-sources/metaschema"));
43
44 @NonNull
45 protected static IBindingContext newBindingContext() throws IOException {
46 return newBindingContext(CollectionUtil.emptyList());
47 }
48
49 @NonNull
50 protected static IBindingContext newBindingContext(@NonNull Collection<IConstraintSet> constraints)
51 throws IOException {
52 Path generationDir = Paths.get("target/generated-modules");
53 Files.createDirectories(generationDir);
54
55 return IBindingContext.builder()
56 .compilePath(ObjectUtils.notNull(Files.createTempDirectory(generationDir, "modules-")))
57 .constraintSet(constraints)
58 .build();
59 }
60
61 @NonNull
62 public Class<? extends IBoundObject> compileModule(
63 @NonNull Path moduleFile,
64 @Nullable Path bindingFile,
65 @NonNull String rootClassName,
66 @NonNull Path classDir)
67 throws IOException, ClassNotFoundException, MetaschemaException {
68 IModule module = newBindingContext().loadMetaschema(moduleFile);
69
70 DefaultBindingConfiguration bindingConfiguration = new DefaultBindingConfiguration();
71 if (bindingFile != null && Files.exists(bindingFile) && Files.isRegularFile(bindingFile)) {
72 bindingConfiguration.load(bindingFile);
73 }
74
75 ModuleCompilerHelper.compileModule(module, classDir, bindingConfiguration);
76
77
78 return ObjectUtils.asType(ObjectUtils.notNull(ModuleCompilerHelper.newClassLoader(
79 classDir,
80 ObjectUtils.notNull(Thread.currentThread().getContextClassLoader()))
81 .loadClass(rootClassName)));
82 }
83
84 @NonNull
85 private static <T extends IBoundObject> T read(
86 @NonNull Format format,
87 @NonNull Path file,
88 @NonNull Class<T> rootClass,
89 @NonNull IBindingContext context)
90 throws IOException {
91 IDeserializer<T> deserializer = context.newDeserializer(format, rootClass);
92 LOGGER.info("Reading content: {}", file);
93 return deserializer.deserialize(file);
94 }
95
96 private static <T extends IBoundObject> void write(
97 @NonNull Format format,
98 @NonNull Path file,
99 @NonNull T rootObject,
100 @NonNull IBindingContext context) throws IOException {
101 @SuppressWarnings("unchecked")
102 Class<T> clazz = (Class<T>) rootObject.getClass();
103
104 try (Writer writer = Files.newBufferedWriter(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE,
105 StandardOpenOption.TRUNCATE_EXISTING)) {
106 assert writer != null;
107 context.newSerializer(format, clazz).serialize(rootObject, writer);
108 }
109 }
110
111 public void runTests(@NonNull String testPath, @NonNull String rootClassName, @NonNull Path classDir)
112 throws ClassNotFoundException, IOException, MetaschemaException {
113 runTests(testPath, rootClassName, classDir, null);
114 }
115
116 public void runTests(
117 @NonNull String testPath,
118 @NonNull String rootClassName,
119 @NonNull Path classDir,
120 java.util.function.Consumer<Object> assertions)
121 throws ClassNotFoundException, IOException, MetaschemaException {
122 runTests(
123 ObjectUtils.notNull(Paths.get(String.format("src/test/resources/metaschema/%s/metaschema.xml", testPath))),
124 ObjectUtils.notNull(Paths.get(String.format("src/test/resources/metaschema/%s/binding.xml", testPath))),
125 ObjectUtils.notNull(Paths.get(String.format("src/test/resources/metaschema/%s/example.xml", testPath))),
126 rootClassName,
127 classDir,
128 assertions);
129 }
130
131 public void runTests(
132 @NonNull Path metaschemaPath,
133 @NonNull Path bindingPath,
134 @Nullable Path examplePath,
135 @NonNull String rootClassName,
136 @NonNull Path classDir,
137 java.util.function.Consumer<Object> assertions)
138 throws ClassNotFoundException, IOException, MetaschemaException {
139
140 Class<? extends IBoundObject> rootClass = compileModule(
141 metaschemaPath,
142 bindingPath,
143 rootClassName,
144 classDir);
145 runTests(examplePath, rootClass, assertions);
146 }
147
148 public <T extends IBoundObject> void runTests(
149 @Nullable Path examplePath,
150 @NonNull Class<? extends T> rootClass,
151 java.util.function.Consumer<Object> assertions) throws IOException {
152
153 if (examplePath != null && Files.exists(examplePath)) {
154 IBindingContext context = newBindingContext();
155 if (LOGGER.isInfoEnabled()) {
156 LOGGER.info("Testing XML file: {}", examplePath.toString());
157 }
158
159 {
160
161 T root = read(Format.XML, examplePath, rootClass, context);
162 if (LOGGER.isDebugEnabled()) {
163 LOGGER.atDebug().log("Read XML: Object: {}", root.toString());
164 }
165 if (assertions != null) {
166 assertAll("Deserialize XML", () -> {
167 assertions.accept(root);
168 });
169 }
170
171 if (LOGGER.isDebugEnabled()) {
172 LOGGER.atDebug().log("Write XML:");
173 }
174 write(Format.XML, ObjectUtils.notNull(Paths.get("target/out.xml")), root, context);
175
176 if (LOGGER.isDebugEnabled()) {
177 LOGGER.atDebug().log("Write JSON:");
178 }
179 write(Format.XML, ObjectUtils.notNull(Paths.get("target/out.json")), root, context);
180 }
181
182 Object root = read(Format.XML, ObjectUtils.notNull(Paths.get("target/out.xml")), rootClass, context);
183 if (assertions != null) {
184 assertAll("Deserialize XML (roundtrip)", () -> assertions.accept(root));
185 }
186 }
187 }
188
189 }