Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 34 additions & 9 deletions tools/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,9 @@
<lib.commons.io.version>2.17.0</lib.commons.io.version>
<lib.commons.lang3.version>3.17.0</lib.commons.lang3.version>
<lib.commons.text.version>1.12.0</lib.commons.text.version>
<lib.json.schema.validator>1.5.5</lib.json.schema.validator>
<lib.unirest.version>1.4.9</lib.unirest.version>
<lib.cyclonedx.core.java.version>10.0.0</lib.cyclonedx.core.java.version>
<lib.slf4j.api>2.0.16</lib.slf4j.api>
</properties>

<scm>
Expand Down Expand Up @@ -98,6 +99,24 @@
</repository>
</repositories>

<dependencyManagement>
<dependencies>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${lib.slf4j.api}</version>
</dependency>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${lib.slf4j.api}</version>
</dependency>

</dependencies>
</dependencyManagement>

<dependencies>
<!-- Apache Commons -->
<dependency>
Expand All @@ -123,16 +142,22 @@
<scope>compile</scope>
</dependency>
<!-- Unit tests -->
<dependency>
<groupId>com.networknt</groupId>
<artifactId>json-schema-validator</artifactId>
<version>${lib.json.schema.validator}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.0</version>
<artifactId>junit-jupiter-api</artifactId>
<version>5.11.4</version>
<scope>test</scope>
</dependency>
<!-- Runtime-only test dependency -->
<dependency>
<groupId>org.cyclonedx</groupId>
<artifactId>cyclonedx-core-java</artifactId>
<version>${lib.cyclonedx.core.java.version}</version>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
Expand All @@ -142,15 +167,15 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.5.1</version>
<version>3.5.2</version>
</plugin>
</plugins>
<testResources>
<testResource>
<directory>${basedir}/../schema</directory>
<directory>${project.basedir}/../schema</directory>
</testResource>
<testResource>
<directory>src/test/resources/</directory>
<directory>src/test/resources</directory>
</testResource>
</testResources>
</build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,14 @@ List<String> getAllResources() throws Exception {
return files;
}

List<String> getResources(final String resourceDirectory) throws Exception {
final List<String> files = new ArrayList<>();
String dir = resourceDirectory;
if (!resourceDirectory.endsWith("/")) {
dir += "/";
}
try (InputStream in = this.getClass().getClassLoader().getResourceAsStream(dir)) {
private List<String> getResources(final String resourceDirectory) throws Exception {
final List<String> resources = new ArrayList<>();
try (InputStream in = this.getClass().getClassLoader().getResourceAsStream(resourceDirectory)) {
if (in != null) {
files.addAll(IOUtils.readLines(in, StandardCharsets.UTF_8));
IOUtils.readLines(in, StandardCharsets.UTF_8)
.forEach(resource -> resources.add(resourceDirectory + resource));
}
}
return files;
return resources;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,68 +13,127 @@
*/
package org.cyclonedx.schema;

import java.io.File;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.networknt.schema.DefaultJsonMetaSchemaFactory;
import com.networknt.schema.DisallowUnknownKeywordFactory;
import com.networknt.schema.JsonMetaSchema;
import com.networknt.schema.JsonMetaSchemaFactory;
import com.networknt.schema.JsonSchema;
import com.networknt.schema.JsonSchemaFactory;
import com.networknt.schema.NonValidationKeyword;
import com.networknt.schema.SchemaId;
import com.networknt.schema.SchemaLocation;
import com.networknt.schema.SchemaValidatorsConfig;
import com.networknt.schema.resource.ClasspathSchemaLoader;
import com.networknt.schema.resource.DisallowSchemaLoader;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.cyclonedx.parsers.JsonParser;
import org.cyclonedx.Version;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;

import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
class JsonSchemaVerificationTest extends BaseSchemaVerificationTest {

private static final ObjectMapper MAPPER = new JsonMapper();

private static final String JSF_NAMESPACE = "http://cyclonedx.org/schema/jsf-0.82.schema.json";
private static final String SPDX_NAMESPACE = "http://cyclonedx.org/schema/spdx.schema.json";

private static final JsonSchema VERSION_12;
private static final JsonSchema VERSION_13;
private static final JsonSchema VERSION_14;
private static final JsonSchema VERSION_15;
private static final JsonSchema VERSION_16;

static {
JsonMetaSchemaFactory metaSchemaFactory = new DefaultJsonMetaSchemaFactory() {
@Override
public JsonMetaSchema getMetaSchema(
String iri, JsonSchemaFactory schemaFactory, SchemaValidatorsConfig config) {
return addCustomKeywords(super.getMetaSchema(iri, schemaFactory, config));
}
};
JsonSchemaFactory factory = JsonSchemaFactory.builder()
.defaultMetaSchemaIri(SchemaId.V7)
.metaSchema(addCustomKeywords(JsonMetaSchema.getV7()))
.metaSchemaFactory(metaSchemaFactory)
.schemaLoaders(b -> b.add(new ClasspathSchemaLoader()).add(DisallowSchemaLoader.getInstance()))
.schemaMappers(b -> b.mapPrefix(SPDX_NAMESPACE, "classpath:spdx.schema.json")
.mapPrefix(JSF_NAMESPACE, "classpath:jsf-0.82.schema.json"))
.build();
VERSION_12 = factory.getSchema(SchemaLocation.of("classpath:bom-1.2-strict.schema.json"));
VERSION_13 = factory.getSchema(SchemaLocation.of("classpath:bom-1.3-strict.schema.json"));
VERSION_14 = factory.getSchema(SchemaLocation.of("classpath:bom-1.4.schema.json"));
VERSION_15 = factory.getSchema(SchemaLocation.of("classpath:bom-1.5.schema.json"));
VERSION_16 = factory.getSchema(SchemaLocation.of("classpath:bom-1.6.schema.json"));
}

public class JsonSchemaVerificationTest extends BaseSchemaVerificationTest {
private static JsonMetaSchema addCustomKeywords(JsonMetaSchema metaSchema) {
return JsonMetaSchema.builder(metaSchema)
// Non-standard keywords in the CycloneDX schema files.
.keyword(new NonValidationKeyword("deprecated"))
.keyword(new NonValidationKeyword("meta:enum"))
.unknownKeywordFactory(new DisallowUnknownKeywordFactory())
.build();
}

@TestFactory
Collection<DynamicTest> dynamicTestsWithCollection() throws Exception {
final List<String> files = getAllResources();
final List<String> resources = getAllResources();
final List<DynamicTest> dynamicTests = new ArrayList<>();
for (final String file: files) {
if (file.endsWith(".json")) {
final Version schemaVersion;
if (file.endsWith("-1.2.json")) {
schemaVersion = Version.VERSION_12;
} else if (file.endsWith("-1.3.json")) {
schemaVersion = Version.VERSION_13;
} else if (file.endsWith("-1.4.json")) {
schemaVersion = Version.VERSION_14;
} else if (file.endsWith("-1.5.json")) {
schemaVersion = Version.VERSION_15;
} else if (file.endsWith("-1.6.json")) {
schemaVersion = Version.VERSION_16;
} else {
schemaVersion = null;
}
if (file.startsWith("valid") && schemaVersion != null) {
dynamicTests.add(DynamicTest.dynamicTest(file, () -> assertTrue(
isValidJson(schemaVersion, "/" + schemaVersion.getVersionString() + "/" + file), file)));
} else if (file.startsWith("invalid") && schemaVersion != null) {
dynamicTests.add(DynamicTest.dynamicTest(file, () -> assertFalse(
isValidJson(schemaVersion, "/" + schemaVersion.getVersionString() + "/" + file), file)));
for (final String resource : resources) {
String resourceName = StringUtils.substringAfterLast(resource, "/");
if (resourceName.endsWith(".json")) {
JsonSchema schema = getSchema(resourceName);
if (schema != null) {
if (resourceName.startsWith("valid")) {
dynamicTests.add(DynamicTest.dynamicTest(
resource, () -> assertTrue(isValid(schema, resource), resource)));
} else if (resourceName.startsWith("invalid")) {
dynamicTests.add(DynamicTest.dynamicTest(
resource, () -> assertFalse(isValid(schema, resource), resource)));
}
}
}
}
return dynamicTests;
}

private boolean isValidJson(Version version, String resource) throws Exception {
final File file = new File(this.getClass().getResource(resource).getFile());
final JsonParser parser = new JsonParser();
return parser.isValid(file, version);

// Uncomment to provide more detailed validation errors
/*
try {
final String jsonString = FileUtils.readFileToString(file, StandardCharsets.UTF_8);
parser.getJsonSchema(version, true).validate(new JSONObject(jsonString));
return true;
} catch (ValidationException e) {
e.printStackTrace();
private boolean isValid(JsonSchema schema, String resource) {
try (InputStream input = getClass().getClassLoader().getResourceAsStream(resource);
JsonParser parser = MAPPER.createParser(input)) {
JsonNode node = parser.readValueAsTree();
return schema.validate(node).isEmpty();
} catch (IOException e) {
return false;
}
*/
}

private JsonSchema getSchema(String resourceName) {
if (resourceName.endsWith("-1.2.json")) {
return VERSION_12;
}
if (resourceName.endsWith("-1.3.json")) {
return VERSION_13;
}
if (resourceName.endsWith("-1.4.json")) {
return VERSION_14;
}
if (resourceName.endsWith("-1.5.json")) {
return VERSION_15;
}
if (resourceName.endsWith("-1.6.json")) {
return VERSION_16;
}
return null;
}
}
Loading