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