diff --git a/source/JSONSchema-Core-Tests/JSONSchemaTests.class.st b/source/JSONSchema-Core-Tests/JSONSchemaTests.class.st index c83e3d0..0cbe3cd 100644 --- a/source/JSONSchema-Core-Tests/JSONSchemaTests.class.st +++ b/source/JSONSchema-Core-Tests/JSONSchemaTests.class.st @@ -5,6 +5,20 @@ Class { #package : 'JSONSchema-Core-Tests' } +{ #category : 'tests' } +JSONSchemaTests >> testAdditionalPropertiesFalseEnforcedWithoutPatternProperties [ + "Regression: JSONSchemaPatternPropertiesConstraint (the constraint that enforces + additionalProperties) only activated when patternProperties was present - + validate:'s own logic already handled the no-patternProperties case correctly, it + just never got attached. A properties-only schema with additionalProperties:false + silently accepted extra properties. Found 2026-08-02 via the RecurringEvents schema + (schema/recurring-events.schema.json)." + | schema | + schema := JSONSchema fromString: '{"type":"object","properties":{"foo":{"type":"string"}},"required":["foo"],"additionalProperties":false}'. + self shouldnt: [ schema validate: {'foo'->'bar'} asDictionary ] raise: Error. + self should: [ schema validate: {'foo'->'bar'. 'extra'->1} asDictionary ] raise: JSONTypeError +] + { #category : 'tests' } JSONSchemaTests >> testAllOfCompositionMergesRequiredAcrossBranches [ | definition schema | @@ -281,3 +295,21 @@ JSONSchemaTests >> testSimpleObjectSchema [ self assert: object foo equals: '123'. self assert: object bar equals: 123 ] + +{ #category : 'tests' } +JSONSchemaTests >> testValidateAcceptsValidDateTimeStringOnExplicitlyTypedSchema [ + "Regression: JSONPrimitiveSchema>>validate: (a leftover from before the generic + JSONSchemaFormatConstraint - Tier G - existed) called the format class's own + validate: with the raw JSON string. JSONFormatDateTime/JSONFormatDate/JSONFormatURI's + class-side validate: expect an already-converted value (DateAndTime/Date/ZnUrl, as + produced by the read: pipeline), so this crashed with a bogus JSONTypeError for + *every* valid date-time/date/uri string whenever type was explicit alongside + format - JSONSchemaFormatConstraint's own validateString: (which does the real, + correct check against the raw string) already covers this generically, making the + call redundant as well as wrong. Found 2026-08-02 via the RecurringEvents schema, + where e.g. dateAndTime declares type:string/format:date-time for its at property." + | schema | + schema := JSONSchema fromString: '{"type":"string","format":"date-time"}'. + self shouldnt: [ schema validate: '2026-01-01T00:00:00Z' ] raise: Error. + self should: [ schema validate: 'not-a-date' ] raise: JSONConstraintError +] diff --git a/source/JSONSchema-Core/JSONPrimitiveSchema.class.st b/source/JSONSchema-Core/JSONPrimitiveSchema.class.st index 72b7407..87190d0 100644 --- a/source/JSONSchema-Core/JSONPrimitiveSchema.class.st +++ b/source/JSONSchema-Core/JSONPrimitiveSchema.class.st @@ -141,10 +141,7 @@ JSONPrimitiveSchema >> schema: aSchema [ { #category : 'validation' } JSONPrimitiveSchema >> validate: anObject [ - super validate: anObject. - format ifNotNil: [ - format validate: anObject ] - + super validate: anObject ] { #category : 'writing' } diff --git a/source/JSONSchema-Core/JSONSchemaPatternPropertiesConstraint.class.st b/source/JSONSchema-Core/JSONSchemaPatternPropertiesConstraint.class.st index 341565e..fb44046 100644 --- a/source/JSONSchema-Core/JSONSchemaPatternPropertiesConstraint.class.st +++ b/source/JSONSchema-Core/JSONSchemaPatternPropertiesConstraint.class.st @@ -24,7 +24,11 @@ JSONSchemaPatternPropertiesConstraint >> initializeFromDefinition: aDefinition [ { #category : 'validation' } JSONSchemaPatternPropertiesConstraint >> validate [ - ^ patternProperties notNil + "Active whenever there is something to enforce beyond the schema's own declared + properties: either patternProperties itself, or a restricting additionalProperties + (false, or a schema) - the properties-only case (no patternProperties) still needs + this constraint to enforce additionalProperties." + ^ patternProperties notNil or: [ additionalProperties notNil and: [ additionalProperties ~= true ] ] ] { #category : 'validation' } @@ -33,10 +37,13 @@ JSONSchemaPatternPropertiesConstraint >> validate: aDictionary [ whose regex matches the name (unanchored search). A name is 'covered' if it is in properties or matched at least one pattern; names covered by neither are validated against additionalProperties when that is an actual schema (the default - is Boolean true = accept all)." + is Boolean true = accept all). patternProperties may be nil - a schema can declare + only properties/additionalProperties with no patternProperties at all." | resolvedPatterns | - resolvedPatterns := patternProperties associations collect: [ :assoc | - { assoc key asECMARegex. self resolveVisitor visitSchemaSpec: assoc value } ]. + resolvedPatterns := patternProperties + ifNil: [ #() ] + ifNotNil: [ patternProperties associations collect: [ :assoc | + { assoc key asECMARegex. self resolveVisitor visitSchemaSpec: assoc value } ] ]. aDictionary keysAndValuesDo: [ :key :value | | matchedPattern | matchedPattern := false. diff --git a/source/JSONSchema-Testsuite-Tests/JSONSchemaAdditionalPropertiesAllowsASchemaWhichShouldValidateTests.class.st b/source/JSONSchema-Testsuite-Tests/JSONSchemaAdditionalPropertiesAllowsASchemaWhichShouldValidateTests.class.st index 0232c98..8175793 100644 --- a/source/JSONSchema-Testsuite-Tests/JSONSchemaAdditionalPropertiesAllowsASchemaWhichShouldValidateTests.class.st +++ b/source/JSONSchema-Testsuite-Tests/JSONSchemaAdditionalPropertiesAllowsASchemaWhichShouldValidateTests.class.st @@ -6,11 +6,6 @@ Class { #tag : 'AdditionalProperties' } -{ #category : 'testing' } -JSONSchemaAdditionalPropertiesAllowsASchemaWhichShouldValidateTests >> expectedFailures [ - ^ #(#testAnAdditionalInvalidPropertyIsInvalid) -] - { #category : 'accessing' } JSONSchemaAdditionalPropertiesAllowsASchemaWhichShouldValidateTests >> schemaString [ ^ '{"properties":{"foo":{},"bar":{}},"additionalProperties":{"type":"boolean"}}' diff --git a/source/JSONSchema-Testsuite-Tests/JSONSchemaAdditionalPropertiesCanExistByItselfTests.class.st b/source/JSONSchema-Testsuite-Tests/JSONSchemaAdditionalPropertiesCanExistByItselfTests.class.st index 418c28c..7e9ebc6 100644 --- a/source/JSONSchema-Testsuite-Tests/JSONSchemaAdditionalPropertiesCanExistByItselfTests.class.st +++ b/source/JSONSchema-Testsuite-Tests/JSONSchemaAdditionalPropertiesCanExistByItselfTests.class.st @@ -6,11 +6,6 @@ Class { #tag : 'AdditionalProperties' } -{ #category : 'testing' } -JSONSchemaAdditionalPropertiesCanExistByItselfTests >> expectedFailures [ - ^ #(#testAnAdditionalInvalidPropertyIsInvalid) -] - { #category : 'accessing' } JSONSchemaAdditionalPropertiesCanExistByItselfTests >> schemaString [ ^ '{"additionalProperties":{"type":"boolean"}}' diff --git a/source/JSONSchema-Testsuite-Tests/JSONSchemaAdditionalPropertiesShouldNotLookInApplicatorsTests.class.st b/source/JSONSchema-Testsuite-Tests/JSONSchemaAdditionalPropertiesShouldNotLookInApplicatorsTests.class.st index df26ca1..b7f5097 100644 --- a/source/JSONSchema-Testsuite-Tests/JSONSchemaAdditionalPropertiesShouldNotLookInApplicatorsTests.class.st +++ b/source/JSONSchema-Testsuite-Tests/JSONSchemaAdditionalPropertiesShouldNotLookInApplicatorsTests.class.st @@ -6,11 +6,6 @@ Class { #tag : 'AdditionalProperties' } -{ #category : 'testing' } -JSONSchemaAdditionalPropertiesShouldNotLookInApplicatorsTests >> expectedFailures [ - ^ #(#testPropertiesDefinedInAllOfAreNotExamined) -] - { #category : 'accessing' } JSONSchemaAdditionalPropertiesShouldNotLookInApplicatorsTests >> schemaString [ ^ '{"allOf":[{"properties":{"foo":{}}}],"additionalProperties":{"type":"boolean"}}'