• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.networknt.schema;
18 
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertNotNull;
21 import static org.junit.jupiter.api.Assertions.assertThrows;
22 
23 import java.util.Collections;
24 import java.util.Set;
25 
26 import org.junit.jupiter.api.Test;
27 
28 import com.networknt.schema.SpecVersion.VersionFlag;
29 import com.networknt.schema.output.OutputUnit;
30 
31 /**
32  * Tests for vocabulary support in meta schemas.
33  */
34 public class VocabularyTest {
35     @Test
noValidation()36     void noValidation() {
37         String metaSchemaData = "{\r\n"
38                 + "  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\r\n"
39                 + "  \"$id\": \"https://www.example.com/no-validation-no-format/schema\",\r\n"
40                 + "  \"$vocabulary\": {\r\n"
41                 + "    \"https://www.example.com/vocab/validation\": false,\r\n"
42                 + "    \"https://json-schema.org/draft/2020-12/vocab/applicator\": true,\r\n"
43                 + "    \"https://json-schema.org/draft/2020-12/vocab/core\": true\r\n"
44                 + "  },\r\n"
45                 + "  \"allOf\": [\r\n"
46                 + "    { \"$ref\": \"https://json-schema.org/draft/2020-12/meta/applicator\" },\r\n"
47                 + "    { \"$ref\": \"https://json-schema.org/draft/2020-12/meta/core\" }\r\n"
48                 + "  ]\r\n"
49                 + "}";
50         String schemaData = "{\r\n"
51                 + "  \"$id\": \"https://schema/using/no/validation\",\r\n"
52                 + "  \"$schema\": \"https://www.example.com/no-validation-no-format/schema\",\r\n"
53                 + "  \"properties\": {\r\n"
54                 + "    \"badProperty\": false,\r\n"
55                 + "    \"numberProperty\": {\r\n"
56                 + "      \"minimum\": 10\r\n"
57                 + "    }\r\n"
58                 + "  }\r\n"
59                 + "}";
60         JsonSchema schema = JsonSchemaFactory
61                 .getInstance(VersionFlag.V202012,
62                         builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(Collections
63                                 .singletonMap("https://www.example.com/no-validation-no-format/schema",
64                                         metaSchemaData))))
65                 .getSchema(schemaData);
66 
67         String inputDataNoValidation = "{\r\n"
68                 + "  \"numberProperty\": 1\r\n"
69                 + "}";
70 
71         Set<ValidationMessage> messages = schema.validate(inputDataNoValidation, InputFormat.JSON);
72         assertEquals(0, messages.size());
73 
74         // Set validation vocab
75         schema = JsonSchemaFactory
76                 .getInstance(VersionFlag.V202012,
77                         builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(Collections
78                                 .singletonMap("https://www.example.com/no-validation-no-format/schema",
79                                         metaSchemaData.replace("https://www.example.com/vocab/validation",
80                                                 Vocabulary.V202012_VALIDATION.getIri())))))
81                 .getSchema(schemaData);
82         messages = schema.validate(inputDataNoValidation, InputFormat.JSON);
83         assertEquals(1, messages.size());
84         assertEquals("minimum", messages.iterator().next().getType());
85     }
86 
87     @Test
noFormatValidation()88     void noFormatValidation() {
89         String metaSchemaData = "{\r\n"
90                 + "  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\r\n"
91                 + "  \"$id\": \"https://www.example.com/no-validation-no-format/schema\",\r\n"
92                 + "  \"$vocabulary\": {\r\n"
93                 + "    \"https://www.example.com/vocab/format\": false,\r\n"
94                 + "    \"https://json-schema.org/draft/2020-12/vocab/applicator\": true,\r\n"
95                 + "    \"https://json-schema.org/draft/2020-12/vocab/core\": true\r\n"
96                 + "  },\r\n"
97                 + "  \"allOf\": [\r\n"
98                 + "    { \"$ref\": \"https://json-schema.org/draft/2020-12/meta/applicator\" },\r\n"
99                 + "    { \"$ref\": \"https://json-schema.org/draft/2020-12/meta/core\" }\r\n"
100                 + "  ]\r\n"
101                 + "}";
102         String schemaData = "{\r\n"
103                 + "  \"$id\": \"https://schema/using/no/format\",\r\n"
104                 + "  \"$schema\": \"https://www.example.com/no-validation-no-format/schema\",\r\n"
105                 + "  \"properties\": {\r\n"
106                 + "    \"dateProperty\": {\r\n"
107                 + "      \"format\": \"date\"\r\n"
108                 + "    }\r\n"
109                 + "  }\r\n"
110                 + "}";
111         JsonSchema schema = JsonSchemaFactory
112                 .getInstance(VersionFlag.V202012,
113                         builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(Collections
114                                 .singletonMap("https://www.example.com/no-validation-no-format/schema",
115                                         metaSchemaData))))
116                 .getSchema(schemaData);
117 
118         String inputDataNoValidation = "{\r\n"
119                 + "  \"dateProperty\": \"hello\"\r\n"
120                 + "}";
121 
122         Set<ValidationMessage> messages = schema.validate(inputDataNoValidation, InputFormat.JSON,
123                 executionContext -> executionContext.getExecutionConfig().setFormatAssertionsEnabled(true));
124         assertEquals(0, messages.size());
125 
126         // Set format assertion vocab
127         schema = JsonSchemaFactory
128                 .getInstance(VersionFlag.V202012,
129                         builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(Collections
130                                 .singletonMap("https://www.example.com/no-validation-no-format/schema",
131                                         metaSchemaData.replace("https://www.example.com/vocab/format",
132                                                 Vocabulary.V202012_FORMAT_ASSERTION.getIri())))))
133                 .getSchema(schemaData);
134         messages = schema.validate(inputDataNoValidation, InputFormat.JSON);
135         assertEquals(1, messages.size());
136         assertEquals("format", messages.iterator().next().getType());
137     }
138 
139     @Test
requiredUnknownVocabulary()140     void requiredUnknownVocabulary() {
141         String metaSchemaData = "{\r\n"
142                 + "  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\r\n"
143                 + "  \"$id\": \"https://www.example.com/no-validation-no-format/schema\",\r\n"
144                 + "  \"$vocabulary\": {\r\n"
145                 + "    \"https://www.example.com/vocab/format\": true,\r\n"
146                 + "    \"https://json-schema.org/draft/2020-12/vocab/applicator\": true,\r\n"
147                 + "    \"https://json-schema.org/draft/2020-12/vocab/core\": true\r\n"
148                 + "  },\r\n"
149                 + "  \"allOf\": [\r\n"
150                 + "    { \"$ref\": \"https://json-schema.org/draft/2020-12/meta/applicator\" },\r\n"
151                 + "    { \"$ref\": \"https://json-schema.org/draft/2020-12/meta/core\" }\r\n"
152                 + "  ]\r\n"
153                 + "}";
154         String schemaData = "{\r\n"
155                 + "  \"$id\": \"https://schema/using/no/format\",\r\n"
156                 + "  \"$schema\": \"https://www.example.com/no-validation-no-format/schema\",\r\n"
157                 + "  \"properties\": {\r\n"
158                 + "    \"dateProperty\": {\r\n"
159                 + "      \"format\": \"date\"\r\n"
160                 + "    }\r\n"
161                 + "  }\r\n"
162                 + "}";
163         JsonSchemaFactory factory = JsonSchemaFactory
164                 .getInstance(VersionFlag.V202012,
165                         builder -> builder.schemaLoaders(schemaLoaders -> schemaLoaders.schemas(Collections
166                                 .singletonMap("https://www.example.com/no-validation-no-format/schema",
167                                         metaSchemaData))));
168         assertThrows(InvalidSchemaException.class, () -> factory.getSchema(schemaData));
169     }
170 
171     @Test
customVocabulary()172     void customVocabulary() {
173         String metaSchemaData = "{\r\n"
174                 + "  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\r\n"
175                 + "  \"$id\": \"https://www.example.com/no-validation-no-format/schema\",\r\n"
176                 + "  \"$vocabulary\": {\r\n"
177                 + "    \"https://www.example.com/vocab/format\": true,\r\n"
178                 + "    \"https://json-schema.org/draft/2020-12/vocab/applicator\": true,\r\n"
179                 + "    \"https://json-schema.org/draft/2020-12/vocab/core\": true\r\n"
180                 + "  },\r\n"
181                 + "  \"allOf\": [\r\n"
182                 + "    { \"$ref\": \"https://json-schema.org/draft/2020-12/meta/applicator\" },\r\n"
183                 + "    { \"$ref\": \"https://json-schema.org/draft/2020-12/meta/core\" }\r\n"
184                 + "  ]\r\n"
185                 + "}";
186         String schemaData = "{\r\n"
187                 + "  \"$id\": \"https://schema/using/no/format\",\r\n"
188                 + "  \"$schema\": \"https://www.example.com/no-validation-no-format/schema\",\r\n"
189                 + "  \"hello\": {\r\n"
190                 + "    \"dateProperty\": {\r\n"
191                 + "      \"format\": \"date\"\r\n"
192                 + "    }\r\n"
193                 + "  }\r\n"
194                 + "}";
195         VocabularyFactory vocabularyFactory = uri -> {
196             if ("https://www.example.com/vocab/format".equals(uri)) {
197                 return new Vocabulary("https://www.example.com/vocab/format", new AnnotationKeyword("hello"));
198             }
199             return null;
200         };
201 
202         JsonMetaSchema metaSchema = JsonMetaSchema
203                 .builder(JsonMetaSchema.getV202012().getIri(), JsonMetaSchema.getV202012())
204                 .vocabularyFactory(vocabularyFactory)
205                 .build();
206         JsonSchemaFactory factory = JsonSchemaFactory
207                 .getInstance(VersionFlag.V202012,
208                         builder -> builder.metaSchema(metaSchema).schemaLoaders(schemaLoaders -> schemaLoaders.schemas(Collections
209                                 .singletonMap("https://www.example.com/no-validation-no-format/schema",
210                                         metaSchemaData))));
211         JsonSchema schema = factory.getSchema(schemaData);
212         OutputUnit outputUnit = schema.validate("{}", InputFormat.JSON, OutputFormat.HIERARCHICAL, executionContext -> {
213             executionContext.getExecutionConfig().setAnnotationCollectionEnabled(true);
214             executionContext.getExecutionConfig().setAnnotationCollectionFilter(keyword -> true);
215         });
216         assertNotNull(outputUnit.getAnnotations().get("hello"));
217     }
218 }
219