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
32 changes: 32 additions & 0 deletions source/JSONSchema-Core-Tests/JSONSchemaTests.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
Expand Down Expand Up @@ -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
]
5 changes: 1 addition & 4 deletions source/JSONSchema-Core/JSONPrimitiveSchema.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -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' }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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' }
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@ Class {
#tag : 'AdditionalProperties'
}

{ #category : 'testing' }
JSONSchemaAdditionalPropertiesAllowsASchemaWhichShouldValidateTests >> expectedFailures [
^ #(#testAnAdditionalInvalidPropertyIsInvalid)
]

{ #category : 'accessing' }
JSONSchemaAdditionalPropertiesAllowsASchemaWhichShouldValidateTests >> schemaString [
^ '{"properties":{"foo":{},"bar":{}},"additionalProperties":{"type":"boolean"}}'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@ Class {
#tag : 'AdditionalProperties'
}

{ #category : 'testing' }
JSONSchemaAdditionalPropertiesCanExistByItselfTests >> expectedFailures [
^ #(#testAnAdditionalInvalidPropertyIsInvalid)
]

{ #category : 'accessing' }
JSONSchemaAdditionalPropertiesCanExistByItselfTests >> schemaString [
^ '{"additionalProperties":{"type":"boolean"}}'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,6 @@ Class {
#tag : 'AdditionalProperties'
}

{ #category : 'testing' }
JSONSchemaAdditionalPropertiesShouldNotLookInApplicatorsTests >> expectedFailures [
^ #(#testPropertiesDefinedInAllOfAreNotExamined)
]

{ #category : 'accessing' }
JSONSchemaAdditionalPropertiesShouldNotLookInApplicatorsTests >> schemaString [
^ '{"allOf":[{"properties":{"foo":{}}}],"additionalProperties":{"type":"boolean"}}'
Expand Down
Loading