github.com/kaptinlin/jsonschema@v0.4.6/tests/format_test.go (about) 1 package tests 2 3 import ( 4 "testing" 5 6 "github.com/kaptinlin/jsonschema" 7 "github.com/stretchr/testify/assert" 8 "github.com/stretchr/testify/require" 9 ) 10 11 // TestFormatForTestSuite executes the format validation tests for Schema Test Suite. 12 func TestFormatForTestSuite(t *testing.T) { 13 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/format.json", 14 "idn-email format", 15 "idn-hostname format") 16 } 17 18 func TestFormatDateTimeForTestSuite(t *testing.T) { 19 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/date-time.json") 20 } 21 22 func TestFormatDateForTestSuite(t *testing.T) { 23 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/date.json") 24 } 25 26 func TestFormatDurationForTestSuite(t *testing.T) { 27 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/duration.json") 28 } 29 30 func TestFormatEmailForTestSuite(t *testing.T) { 31 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/email.json") 32 } 33 34 func TestFormatHostnameForTestSuite(t *testing.T) { 35 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/hostname.json") 36 } 37 38 func TestFormatIpv4ForTestSuite(t *testing.T) { 39 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/ipv4.json") 40 } 41 42 func TestFormatIpv6ForTestSuite(t *testing.T) { 43 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/ipv6.json") 44 } 45 46 func TestFormatIriReferenceForTestSuite(t *testing.T) { 47 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/iri-reference.json") 48 } 49 50 func TestFormatIriForTestSuite(t *testing.T) { 51 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/iri.json") 52 } 53 54 func TestFormatJsonPointerForTestSuite(t *testing.T) { 55 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/json-pointer.json") 56 } 57 58 func TestFormatRegexForTestSuite(t *testing.T) { 59 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/regex.json") 60 } 61 62 func TestFormatRelativeJsonPointerForTestSuite(t *testing.T) { 63 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/relative-json-pointer.json") 64 } 65 66 func TestFormatTimeForTestSuite(t *testing.T) { 67 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/time.json") 68 } 69 70 func TestFormatUnknowForTestSuite(t *testing.T) { 71 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/unknown.json") 72 } 73 74 func TestFormatUriReferenceForTestSuite(t *testing.T) { 75 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/uri-reference.json") 76 } 77 78 func TestFormatUriTemplateForTestSuite(t *testing.T) { 79 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/uri-template.json") 80 } 81 82 func TestFormatUriForTestSuite(t *testing.T) { 83 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/uri.json") 84 } 85 86 func TestFormatUuidForTestSuite(t *testing.T) { 87 testJSONSchemaTestSuiteWithFilePath(t, "../testdata/JSON-Schema-Test-Suite/tests/draft2020-12/optional/format/uuid.json") 88 } 89 90 // TestCompileBatchFormatValidation tests that format validation works correctly 91 // when using CompileBatch method 92 func TestCompileBatchFormatValidation(t *testing.T) { 93 compiler := jsonschema.NewCompiler() 94 compiler.SetAssertFormat(true) // Enable format validation 95 compiler.RegisterFormat("ipv4", jsonschema.IsIPV4, "string") 96 97 schemas := map[string][]byte{ 98 "schema1": []byte(`{ 99 "$schema": "https://json-schema.org/draft/2020-12/schema", 100 "type": "object", 101 "properties": { 102 "ip_addr": { 103 "type": "string", 104 "format": "ipv4" 105 } 106 } 107 }`), 108 } 109 110 compiledSchemas, err := compiler.CompileBatch(schemas) 111 require.NoError(t, err, "CompileBatch should not fail") 112 require.Len(t, compiledSchemas, 1, "Should compile one schema") 113 114 schema1 := compiledSchemas["schema1"] 115 require.NotNil(t, schema1, "Schema should not be nil") 116 117 // Test valid IPv4 address 118 validData := map[string]interface{}{ 119 "ip_addr": "192.168.1.1", 120 } 121 result := schema1.Validate(validData) 122 assert.True(t, result.IsValid(), "Valid IPv4 address should pass validation") 123 124 // Test invalid IPv4 address - this should fail when AssertFormat is true 125 invalidData := map[string]interface{}{ 126 "ip_addr": "256.256.256.256", 127 } 128 result = schema1.Validate(invalidData) 129 assert.False(t, result.IsValid(), "Invalid IPv4 address should fail validation when AssertFormat is enabled") 130 131 // Verify the error contains format information (check both top level and details) 132 hasFormatError := false 133 134 // Check top level errors 135 for _, err := range result.Errors { 136 if err.Keyword == "format" { 137 hasFormatError = true 138 break 139 } 140 } 141 142 // Check detailed errors recursively 143 if !hasFormatError { 144 var checkDetails func([]*jsonschema.EvaluationResult) bool 145 checkDetails = func(details []*jsonschema.EvaluationResult) bool { 146 for _, detail := range details { 147 for _, err := range detail.Errors { 148 if err.Keyword == "format" { 149 return true 150 } 151 } 152 if checkDetails(detail.Details) { 153 return true 154 } 155 } 156 return false 157 } 158 hasFormatError = checkDetails(result.Details) 159 } 160 161 assert.True(t, hasFormatError, "Should have format validation error") 162 } 163 164 // TestCompileBatchVsRegularCompileFormatValidation compares format validation 165 // between CompileBatch and regular Compile methods 166 func TestCompileBatchVsRegularCompileFormatValidation(t *testing.T) { 167 compiler1 := jsonschema.NewCompiler() 168 compiler1.SetAssertFormat(true) 169 compiler1.RegisterFormat("email", jsonschema.IsEmail, "string") 170 compiler1.RegisterFormat("ipv4", jsonschema.IsIPV4, "string") 171 172 compiler2 := jsonschema.NewCompiler() 173 compiler2.SetAssertFormat(true) 174 compiler2.RegisterFormat("email", jsonschema.IsEmail, "string") 175 compiler2.RegisterFormat("ipv4", jsonschema.IsIPV4, "string") 176 177 schemaBytes := []byte(`{ 178 "$schema": "https://json-schema.org/draft/2020-12/schema", 179 "type": "object", 180 "properties": { 181 "email": { 182 "type": "string", 183 "format": "email" 184 }, 185 "ip_addr": { 186 "type": "string", 187 "format": "ipv4" 188 } 189 } 190 }`) 191 192 // Compile using regular Compile method 193 regularSchema, err := compiler1.Compile(schemaBytes) 194 require.NoError(t, err, "Regular compilation should not fail") 195 196 // Compile using CompileBatch method 197 batchSchemas, err := compiler2.CompileBatch(map[string][]byte{ 198 "test": schemaBytes, 199 }) 200 require.NoError(t, err, "Batch compilation should not fail") 201 batchSchema := batchSchemas["test"] 202 203 // Test data with invalid formats 204 testData := map[string]interface{}{ 205 "email": "invalid-email", 206 "ip_addr": "256.256.256.256", 207 } 208 209 // Both should behave the same way 210 regularResult := regularSchema.Validate(testData) 211 batchResult := batchSchema.Validate(testData) 212 213 assert.Equal(t, regularResult.IsValid(), batchResult.IsValid(), 214 "Regular and batch compiled schemas should have same validation result") 215 216 // Both should fail validation due to invalid formats 217 assert.False(t, regularResult.IsValid(), "Regular compiled schema should reject invalid formats") 218 assert.False(t, batchResult.IsValid(), "Batch compiled schema should reject invalid formats") 219 220 // Count format errors in both results (including detailed errors) 221 regularFormatErrors := 0 222 batchFormatErrors := 0 223 224 // Helper function to count format errors recursively 225 var countFormatErrors func([]*jsonschema.EvaluationResult) int 226 countFormatErrors = func(details []*jsonschema.EvaluationResult) int { 227 count := 0 228 for _, detail := range details { 229 for _, err := range detail.Errors { 230 if err.Keyword == "format" { 231 count++ 232 } 233 } 234 count += countFormatErrors(detail.Details) 235 } 236 return count 237 } 238 239 // Count regular result errors 240 for _, err := range regularResult.Errors { 241 if err.Keyword == "format" { 242 regularFormatErrors++ 243 } 244 } 245 regularFormatErrors += countFormatErrors(regularResult.Details) 246 247 // Count batch result errors 248 for _, err := range batchResult.Errors { 249 if err.Keyword == "format" { 250 batchFormatErrors++ 251 } 252 } 253 batchFormatErrors += countFormatErrors(batchResult.Details) 254 255 assert.Equal(t, regularFormatErrors, batchFormatErrors, 256 "Both methods should produce the same number of format errors") 257 assert.Greater(t, regularFormatErrors, 0, "Should have format errors") 258 }