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
105 changes: 105 additions & 0 deletions source/OpenAPI-Client-Tests/OARequestBuilderTest.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@ Class {
#tag : 'Tests'
}

{ #category : 'tests' }
OARequestBuilderTest >> testAddCookieParameterAccumulatesIntoCookieHeader [
| client builder |
client := ZnClient new.
builder := OARequestBuilder new client: client.
builder addCookieParameter: 'session' value: 'abc'.
builder addCookieParameter: 'theme' value: 'dark'.
self assert: (client request headers at: 'Cookie') equals: 'session=abc; theme=dark'
]

{ #category : 'tests' }
OARequestBuilderTest >> testAddFormBodyBuildsFormUrlEncodedEntity [
| client builder entity |
Expand All @@ -17,6 +27,88 @@ OARequestBuilderTest >> testAddFormBodyBuildsFormUrlEncodedEntity [
self assert: (entity contents at: 'email') equals: 'test@example.com'
]

{ #category : 'tests' }
OARequestBuilderTest >> testAddHeaderParameterSetsRequestHeader [
"OAHeaderParametersLocation and OACookieParameterLocation used to have no
#write:value:to: method at all - writing any header or cookie parameter into a
real request via OAParameter>>copyFrom:to: crashed with #doesNotUnderstand."
| client builder |
client := ZnClient new.
builder := OARequestBuilder new client: client.
builder addHeaderParameter: 'X-Api-Key' value: 'secret123'.
self assert: (client request headers at: 'X-Api-Key') equals: 'secret123'
]

{ #category : 'tests' }
OARequestBuilderTest >> testWriteBodyWithAllOfComposedSchemaDoesNotCrash [
"allOf-composed schemas (no direct type/properties keyword, like petstoreExpanded's
Pet = allOf[NewPet, {id}]) resolve to JSONSchemaAnyObject via #asJSONSchema since
nothing sets schemaClass for a bare allOf. Writing a body against such a schema
must degrade to a plain passthrough rather than crash."
| definition schema mediaType client builder body |
definition := JSONSchemaDefinition new
allOf: { JSONSchemaDefinition new
properties: { 'name' -> (JSONSchemaDefinition new typeString: 'string'; yourself) } asDictionary;
yourself };
yourself.
schema := definition asJSONSchema.
self assert: schema class equals: JSONSchemaAnyObject.
mediaType := OAMediaTypeObject new schema: schema.
client := ZnClient new.
builder := OARequestBuilder new client: client.
body := Dictionary new at: 'name' put: 'Rex'; yourself.
mediaType writeBody: body builder: builder.
self assert: client request entity contents equals: '{"name":"Rex"}'
]

{ #category : 'tests' }
OARequestBuilderTest >> testWriteBodyWithNonObjectSchemaDoesNotCrash [
"Regression test: OAMediaTypeObject>>writeBody:builder: used to send #isAnyObject
unconditionally to the body schema. #isAnyObject is only implemented on
JSONSchemaObject, so any non-object body schema (bare string, array, or an
allOf-composed schema which resolves to JSONSchemaAnyObject) crashed with
#doesNotUnderstand: #isAnyObject when building a real request."
| mediaType client builder |
mediaType := OAMediaTypeObject new schema: JSONSchema string.
client := ZnClient new.
builder := OARequestBuilder new client: client.
mediaType writeBody: 'hello world' builder: builder.
self assert: client request entity contents equals: '"hello world"'
]

{ #category : 'tests' }
OARequestBuilderTest >> testWriteFormBodyWithAllOfComposedSchemaDoesNotCrash [
"Same passthrough bug as #writeBody:builder: (both send #isAnyObject
unconditionally), but for the x-www-form-urlencoded path. An allOf-composed
body schema resolves to JSONSchemaAnyObject and must still form-encode."
| definition schema mediaType client builder body |
definition := JSONSchemaDefinition new
allOf: { JSONSchemaDefinition new
properties: { 'name' -> (JSONSchemaDefinition new typeString: 'string'; yourself) } asDictionary;
yourself };
yourself.
schema := definition asJSONSchema.
self assert: schema class equals: JSONSchemaAnyObject.
mediaType := OAMediaTypeObject new schema: schema.
client := ZnClient new.
builder := OARequestBuilder new client: client.
body := Dictionary new at: 'name' put: 'Rex'; yourself.
mediaType writeFormBody: body builder: builder.
self assert: client request entity contentType sub equals: 'x-www-form-urlencoded'.
self assert: (client request entity contents at: 'name') equals: 'Rex'
]

{ #category : 'tests' }
OARequestBuilderTest >> testCookieParameterWrittenViaParameterCopyFromTo [
| param builder client dict |
client := ZnClient new.
param := OAParameter new name: 'session'; in: #cookie; required: true; schema: JSONSchema string; yourself.
builder := OARequestBuilder new client: client.
dict := Dictionary new at: 'session' put: 'abc'; yourself.
param copyFrom: dict to: builder.
self assert: (client request headers at: 'Cookie') equals: 'session=abc'
]

{ #category : 'tests' }
OARequestBuilderTest >> testFlattenArrayOfObjects [
| builder result items |
Expand Down Expand Up @@ -76,3 +168,16 @@ OARequestBuilderTest >> testFlattenScalarValues [
self assert: (result at: 'customer') equals: 'cus_123'.
self assert: (result at: 'trial_end') equals: 'now'
]

{ #category : 'tests' }
OARequestBuilderTest >> testHeaderParameterWrittenViaParameterCopyFromTo [
"End-to-end: a header OAParameter must be writable via the same
#copyFrom:to: path OAOperation>>applyParameters:builder: actually uses."
| param builder client dict |
client := ZnClient new.
param := OAParameter new name: 'X-Api-Key'; in: #header; required: true; schema: JSONSchema string; yourself.
builder := OARequestBuilder new client: client.
dict := Dictionary new at: 'X-Api-Key' put: 'secret123'; yourself.
param copyFrom: dict to: builder.
self assert: (client request headers at: 'X-Api-Key') equals: 'secret123'
]
19 changes: 18 additions & 1 deletion source/OpenAPI-Client/OARequestBuilder.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,25 @@ OARequestBuilder >> addJSONBody: aDictionary [
type: ZnMimeType applicationJson setCharSetUTF8)
]

{ #category : 'building' }
OARequestBuilder >> addCookieParameter: key value: value [
"Multiple cookie parameters must accumulate into a single 'Cookie' header
(name=value pairs joined by '; '), rather than each overwriting the last."
| pair existing |
pair := key asString , '=' , value asString.
existing := client request headers at: 'Cookie' ifAbsent: [ nil ].
client headerAt: 'Cookie' put: (existing
ifNil: [ pair ]
ifNotNil: [ existing , '; ' , pair ])
]

{ #category : 'building' }
OARequestBuilder >> addHeaderParameter: key value: value [
client headerAt: key put: value asString
]

{ #category : 'as yet unclassified' }
OARequestBuilder >> addPathParameter: key value: value [
OARequestBuilder >> addPathParameter: key value: value [
pathParameters at: key put: value
]

Expand Down
61 changes: 61 additions & 0 deletions source/OpenAPI-Core-Tests/OAExampleDocumentsTests.class.st
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
Class {
#name : 'OAExampleDocumentsTests',
#superclass : 'TestCase',
#category : 'OpenAPI-Core-Tests',
#package : 'OpenAPI-Core-Tests'
}

{ #category : 'tests' }
OAExampleDocumentsTests >> testAllBundledExamplesRoundTripExceptUspto [
"Broader than validity: confirms OpenAPI fromString:/specString handle every bundled
official example without raising, except uspto (see #testUsptoRoundTripFailsOnSchemaTypeSerialization
for the known, not-yet-fixed gap)."
#(petstore petstoreExpanded apiWithExamples callbackExample linkExample) do: [ :selector |
| api |
self shouldnt: [ api := OpenAPI fromString: (OAExampleDocuments perform: selector) ] raise: Error.
self shouldnt: [ api specString ] raise: Error ]
]

{ #category : 'tests' }
OAExampleDocumentsTests >> testApiWithExamplesIsValid [
self assert: (OADocumentValidator isValidDocument: OAExampleDocuments apiWithExamples)
]

{ #category : 'tests' }
OAExampleDocumentsTests >> testCallbackExampleIsValid [
self assert: (OADocumentValidator isValidDocument: OAExampleDocuments callbackExample)
]

{ #category : 'tests' }
OAExampleDocumentsTests >> testLinkExampleIsValid [
self assert: (OADocumentValidator isValidDocument: OAExampleDocuments linkExample)
]

{ #category : 'tests' }
OAExampleDocumentsTests >> testPetstoreExpandedIsValid [
self assert: (OADocumentValidator isValidDocument: OAExampleDocuments petstoreExpanded)
]

{ #category : 'tests' }
OAExampleDocumentsTests >> testPetstoreIsValid [
self assert: (OADocumentValidator isValidDocument: OAExampleDocuments petstore)
]

{ #category : 'tests' }
OAExampleDocumentsTests >> testUsptoIsValid [
self assert: (OADocumentValidator isValidDocument: OAExampleDocuments uspto)
]

{ #category : 'tests' }
OAExampleDocumentsTests >> testUsptoRoundTripFailsOnSchemaTypeSerialization [
"Known gap, not fixed here: JSONSchemaDefinition has typeString: (reader) but no
typeString (writer) accessor, so specString cannot re-serialize a schema's type keyword.
Deliberately not fixed in this pass - schemaClass defaults to JSONSchemaAnyObject even
when no type: was ever specified, so a naive typeString getter would wrongly inject
type:any into schemas that never had a type keyword. A correct fix needs to track
whether type was explicitly specified (the same pattern already used for #const /
#constSpecified) before it can round-trip safely."
| api |
api := OpenAPI fromString: OAExampleDocuments uspto.
self should: [ api specString ] raise: MessageNotUnderstood
]
7 changes: 7 additions & 0 deletions source/OpenAPI-Core/OACookieParameterLocation.class.st
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,10 @@ Class {
#package : 'OpenAPI-Core',
#tag : 'Model'
}

{ #category : 'writing' }
OACookieParameterLocation >> write: key value: value to: builder [
"Previously missing entirely - see OAHeaderParametersLocation>>write:value:to:
for the same gap affecting 'in: #cookie' parameters."
builder addCookieParameter: key value: value
]
Loading
Loading