1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package gov.nist.secauto.metaschema.databind.codegen;
28
29 import static org.junit.jupiter.api.Assertions.assertAll;
30 import static org.junit.jupiter.api.Assertions.assertEquals;
31
32 import gov.nist.secauto.metaschema.core.model.IModule;
33 import gov.nist.secauto.metaschema.core.model.MetaschemaException;
34 import gov.nist.secauto.metaschema.core.model.xml.ModuleLoader;
35 import gov.nist.secauto.metaschema.core.util.ObjectUtils;
36 import gov.nist.secauto.metaschema.databind.IBindingContext;
37 import gov.nist.secauto.metaschema.databind.codegen.config.DefaultBindingConfiguration;
38 import gov.nist.secauto.metaschema.databind.io.BindingException;
39 import gov.nist.secauto.metaschema.databind.io.Format;
40 import gov.nist.secauto.metaschema.databind.io.IDeserializer;
41
42 import org.apache.logging.log4j.LogManager;
43 import org.apache.logging.log4j.Logger;
44 import org.junit.jupiter.api.Assertions;
45 import org.junit.jupiter.api.Test;
46 import org.junit.jupiter.api.io.TempDir;
47 import org.junit.platform.commons.util.ReflectionUtils;
48
49 import java.io.IOException;
50 import java.io.Writer;
51 import java.nio.file.Files;
52 import java.nio.file.Path;
53 import java.nio.file.Paths;
54 import java.nio.file.StandardOpenOption;
55 import java.util.Iterator;
56 import java.util.List;
57 import java.util.Map;
58 import java.util.Set;
59
60 import edu.umd.cs.findbugs.annotations.NonNull;
61 import edu.umd.cs.findbugs.annotations.Nullable;
62
63 class BasicMetaschemaTest {
64 private static final ModuleLoader LOADER = new ModuleLoader();
65 private static final Logger LOGGER = LogManager.getLogger(BasicMetaschemaTest.class);
66 @TempDir
67 Path generationDir;
68
69
70
71
72 @NonNull
73 private static IModule loadModule(@NonNull Path moduleFile) throws MetaschemaException, IOException {
74 return LOADER.load(moduleFile);
75 }
76
77 public static Class<?> compileModule(@NonNull Path moduleFile, @Nullable Path bindingFile,
78 @NonNull String rootClassName, @NonNull Path classDir)
79 throws IOException, ClassNotFoundException, MetaschemaException {
80 IModule module = loadModule(moduleFile);
81
82 DefaultBindingConfiguration bindingConfiguration = new DefaultBindingConfiguration();
83 if (bindingFile != null && Files.exists(bindingFile) && Files.isRegularFile(bindingFile)) {
84 bindingConfiguration.load(bindingFile);
85 }
86
87 ModuleCompilerHelper.compileModule(module, classDir, bindingConfiguration);
88
89
90 return ModuleCompilerHelper.newClassLoader(
91 classDir,
92 ObjectUtils.notNull(Thread.currentThread().getContextClassLoader()))
93 .loadClass(rootClassName);
94 }
95
96 private static Object read(@NonNull Format format, @NonNull Path file, @NonNull Class<?> rootClass)
97 throws IOException {
98 IBindingContext context = IBindingContext.instance();
99
100 IDeserializer<?> deserializer = context.newDeserializer(format, rootClass);
101 LOGGER.info("Reading content: {}", file);
102 Object value = deserializer.deserialize(file);
103 return value;
104 }
105
106 private static <CLASS> void write(@NonNull Format format, @NonNull Path file, CLASS rootObject) throws IOException {
107 IBindingContext context = IBindingContext.instance();
108 @SuppressWarnings("unchecked") Class<CLASS> clazz = (Class<CLASS>) rootObject.getClass();
109
110 try (Writer writer = Files.newBufferedWriter(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE,
111 StandardOpenOption.TRUNCATE_EXISTING)) {
112 assert writer != null;
113 context.newSerializer(format, clazz).serialize(rootObject, writer);
114 }
115 }
116
117 private static void runTests(@NonNull String testPath, @NonNull String rootClassName, @NonNull Path classDir)
118 throws ClassNotFoundException, IOException, MetaschemaException, BindingException {
119 runTests(testPath, rootClassName, classDir, null);
120 }
121
122 @SuppressWarnings("unused")
123 private static void runTests(
124 @NonNull String testPath,
125 @NonNull String rootClassName,
126 @NonNull Path classDir,
127 java.util.function.Consumer<Object> assertions)
128 throws ClassNotFoundException, IOException, MetaschemaException, BindingException {
129
130 Class<?> rootClass = compileModule(
131 ObjectUtils.notNull(Paths.get(String.format("src/test/resources/metaschema/%s/metaschema.xml", testPath))),
132 Paths.get(String.format("src/test/resources/metaschema/%s/binding.xml", testPath)),
133 rootClassName,
134 classDir);
135
136 assert rootClass != null;
137
138 Path xmlExample = Paths.get(String.format("src/test/resources/metaschema/%s/example.xml",
139 testPath));
140 LOGGER.info("Testing XML file: {}", xmlExample.toString());
141 if (Files.exists(xmlExample)) {
142 String xml;
143 {
144 Object root = read(Format.XML, xmlExample, rootClass);
145 LOGGER.atDebug().log("Read XML: Object: {}", root.toString());
146 if (assertions != null) {
147 assertAll("Deserialize XML", () -> {
148 assertions.accept(root);
149 });
150 }
151
152 LOGGER.atDebug().log("Write XML:");
153 write(Format.XML, ObjectUtils.notNull(Paths.get("target/out.xml")), root);
154
155 LOGGER.atDebug().log("Write JSON:");
156 write(Format.XML, ObjectUtils.notNull(Paths.get("target/out.json")), root);
157 }
158
159 Object root = read(Format.XML, ObjectUtils.notNull(Paths.get("target/out.xml")), rootClass);
160 if (assertions != null) {
161 assertAll("Deserialize XML (roundtrip)", () -> assertions.accept(root));
162 }
163 }
164 }
165
166 @Test
167 void testSimpleMetaschema() throws MetaschemaException, IOException, ClassNotFoundException, BindingException {
168 runTests("simple", "gov.nist.csrc.ns.metaschema.testing.simple.TopLevel", ObjectUtils.notNull(generationDir));
169
170
171
172
173
174
175
176
177
178 }
179
180 @Test
181 void testSimpleUuidMetaschema()
182 throws MetaschemaException, IOException, ClassNotFoundException, BindingException {
183 runTests(
184 "simple_with_uuid",
185 "gov.nist.csrc.ns.metaschema.testing.simple.with.uuid.TopLevel",
186 ObjectUtils.notNull(generationDir),
187 (obj) -> {
188 try {
189 Assertions.assertEquals("5de455cf-2f8d-4da2-9182-323d433e1065", reflectMethod(obj, "getUuid").toString());
190 } catch (NoSuchMethodException | SecurityException e) {
191 Assertions.fail(e);
192 }
193 });
194 }
195
196 @Test
197 void testSimpleWithFieldMetaschema()
198 throws MetaschemaException, IOException, ClassNotFoundException, BindingException {
199 runTests(
200 "simple_with_field",
201 "gov.nist.csrc.ns.metaschema.testing.simple.with.field.TopLevel",
202 ObjectUtils.notNull(generationDir));
203 }
204
205 private static Object reflectMethod(Object obj, String name) throws NoSuchMethodException {
206 return ReflectionUtils.invokeMethod(obj.getClass().getMethod(name), obj);
207 }
208
209 @Test
210 void testFieldsWithFlagMetaschema()
211 throws MetaschemaException, IOException, ClassNotFoundException, BindingException {
212 runTests(
213 "fields_with_flags",
214 "gov.nist.csrc.ns.metaschema.testing.fields.with.flags.TopLevel",
215 ObjectUtils.notNull(generationDir),
216 (obj) -> {
217 try {
218 Assertions.assertEquals("test", reflectMethod(obj, "getId"));
219 Object field1 = ReflectionUtils.invokeMethod(obj.getClass().getMethod("getComplexField1"), obj);
220 Assertions.assertNotNull(field1);
221 Assertions.assertEquals("complex-field1", reflectMethod(field1, "getId"));
222 Assertions.assertEquals("test-string", reflectMethod(field1, "getValue"));
223
224 @SuppressWarnings("unchecked") List<Object> field2s
225 = (List<Object>) ReflectionUtils.invokeMethod(obj.getClass().getMethod("getComplexFields2"),
226 obj);
227 Assertions.assertNotNull(field2s);
228 Assertions.assertEquals(1, field2s.size());
229 Object field2 = field2s.get(0);
230 Assertions.assertEquals("complex-field2-1", reflectMethod(field2, "getId"));
231 Assertions.assertEquals("test-string2", reflectMethod(field2, "getValue"));
232
233 @SuppressWarnings("unchecked") List<Object> field3s
234 = (List<Object>) ReflectionUtils.invokeMethod(obj.getClass().getMethod("getComplexFields3"),
235 obj);
236 Assertions.assertEquals(2, field3s.size());
237 Assertions.assertAll("ComplexFields4 item", () -> {
238 Object item = field3s.get(0);
239 assertEquals("complex-field3-1", reflectMethod(item, "getId2"));
240 assertEquals("test-string3", reflectMethod(item, "getValue"));
241 });
242 Assertions.assertAll("ComplexFields4 item", () -> {
243 Object item = field3s.get(1);
244 assertEquals("complex-field3-2", reflectMethod(item, "getId2"));
245 assertEquals("test-string4", reflectMethod(item, "getValue"));
246 });
247
248 Assertions.assertAll("ComplexFields4", () -> {
249 @SuppressWarnings("unchecked") Map<String, Object> collection
250 = (Map<String, Object>) ReflectionUtils.invokeMethod(obj.getClass().getMethod("getComplexFields4"),
251 obj);
252 Assertions.assertNotNull(collection);
253 Assertions.assertEquals(2, collection.size());
254 Set<Map.Entry<String, Object>> entries = collection.entrySet();
255 Iterator<Map.Entry<String, Object>> iter = entries.iterator();
256
257 Assertions.assertAll("ComplexFields4 item", () -> {
258 Map.Entry<String, Object> entry = iter.next();
259 assertEquals("complex-field4-1", entry.getKey());
260 assertEquals("complex-field4-1", reflectMethod(entry.getValue(), "getId2"));
261 assertEquals("test-string5", reflectMethod(entry.getValue(), "getValue"));
262 });
263
264 Assertions.assertAll("ComplexFields4 item", () -> {
265 Map.Entry<String, Object> entry = iter.next();
266 assertEquals("complex-field4-2", entry.getKey());
267 assertEquals("complex-field4-2", reflectMethod(entry.getValue(), "getId2"));
268 assertEquals("test-string6", reflectMethod(entry.getValue(), "getValue"));
269 });
270 });
271 } catch (NoSuchMethodException | SecurityException e) {
272 Assertions.fail(e);
273 }
274 });
275 }
276
277 @Test
278 void testAssemblyMetaschema()
279 throws MetaschemaException, IOException, ClassNotFoundException, BindingException {
280 runTests(
281 "assembly",
282 "gov.nist.itl.metaschema.codegen.xml.example.assembly.TopLevel",
283 ObjectUtils.notNull(generationDir),
284 (obj) -> {
285 try {
286 Assertions.assertEquals("test", reflectMethod(obj, "getId"));
287 } catch (NoSuchMethodException | SecurityException e) {
288 Assertions.fail(e);
289 }
290 });
291 }
292
293 @Test
294 void testLocalDefinitionsMetaschema()
295 throws MetaschemaException, IOException, ClassNotFoundException, BindingException {
296 runTests(
297 "local-definitions",
298 "gov.nist.csrc.ns.metaschema.testing.local.definitions.TopLevel",
299 ObjectUtils.notNull(generationDir));
300 }
301 }