Browse Source

Basic functionality.

No path matching.
No body / headers / query / etc filtering.
Herby Vojčík 6 years ago
parent
commit
644f388c9a

+ 7 - 1
src/Znock-Mocketry/Znock.extension.st

@@ -2,6 +2,12 @@ Extension { #name : #Znock }
 
 { #category : #'*Znock-Mocketry' }
 Znock >> intercept [
-
+	self removeAll.
 	ZnClient stub new will: [ ZnockClient newWithInterceptor: self ]
 ]
+
+{ #category : #'*Znock-Mocketry' }
+Znock >> verify [
+	self pendingExpectations should be isEmpty.
+	self removeAll
+]

+ 6 - 0
src/Znock/Object.extension.st

@@ -0,0 +1,6 @@
+Extension { #name : #Object }
+
+{ #category : #'*Znock' }
+Object >> znock [
+	^ Znock default baseFor: self
+]

+ 9 - 0
src/Znock/String.extension.st

@@ -0,0 +1,9 @@
+Extension { #name : #String }
+
+{ #category : #'*Znock' }
+String >> asHostFirstUrl [
+	| result |
+	result := ZnUrl fromString: self defaultScheme: #''.
+	result scheme == #'' ifTrue: [ result scheme: nil ].
+	^ result
+]

+ 6 - 0
src/Znock/ZnUrl.extension.st

@@ -0,0 +1,6 @@
+Extension { #name : #ZnUrl }
+
+{ #category : #'*Znock' }
+ZnUrl >> asHostFirstUrl [
+	^ self
+]

+ 44 - 0
src/Znock/Znock.class.st

@@ -1,6 +1,10 @@
 Class {
 	#name : #Znock,
 	#superclass : #ZnClient,
+	#instVars : [
+		'bases',
+		'expectations'
+	],
 	#classInstVars : [
 		'default'
 	],
@@ -12,3 +16,43 @@ Znock class >> default [
 
 	^ default ifNil: [ default := self new ]
 ]
+
+{ #category : #accessing }
+Znock >> addExpectation: aZnClient [
+	^ self expectations add: aZnClient
+]
+
+{ #category : #accessing }
+Znock >> baseFor: descriptor [
+	^ (self bases at: descriptor ifAbsentPut: [ ZnockBase in: self url: descriptor asHostFirstUrl ])
+		resetState;
+		yourself
+]
+
+{ #category : #accessing }
+Znock >> bases [
+	^ bases ifNil: [ bases := Dictionary new ]
+]
+
+{ #category : #operations }
+Znock >> consumeExpectationFor: aZnockClient [ 
+	^ expectations
+		detect: [ :one | aZnockClient matches: one ]
+		ifFound: [ :one | expectations remove: one. one ]
+		ifNone: [ nil ]
+]
+
+{ #category : #accessing }
+Znock >> expectations [
+	^ expectations ifNil: [ expectations := OrderedCollection new ]
+]
+
+{ #category : #public }
+Znock >> pendingExpectations [
+	^ self expectations copy.
+]
+
+{ #category : #public }
+Znock >> removeAll [
+	self expectations removeAll
+]

+ 116 - 0
src/Znock/ZnockBase.class.st

@@ -0,0 +1,116 @@
+Class {
+	#name : #ZnockBase,
+	#superclass : #Object,
+	#instVars : [
+		'owner',
+		'state',
+		'builtClient',
+		'baseUrl'
+	],
+	#category : #Znock
+}
+
+{ #category : #'instance creation' }
+ZnockBase class >> in: aZnock url: aZnUrl [
+	^ super new
+		baseUrl: aZnUrl;
+		owner: aZnock;
+		yourself
+]
+
+{ #category : #accessing }
+ZnockBase >> baseUrl [
+	^ baseUrl
+]
+
+{ #category : #accessing }
+ZnockBase >> baseUrl: aZnUrl [
+	baseUrl := aZnUrl
+]
+
+{ #category : #building }
+ZnockBase >> clientSelectors [
+	^ #(addPath: addPathSegment: delete get head host: http https method: options patch path: port: post put username:password:)
+]
+
+{ #category : #building }
+ZnockBase >> closeState: aSymbol [
+	"self shouldBeImplemented."
+]
+
+{ #category : #building }
+ZnockBase >> doesNotUnderstand: aMessage [
+	(self clientSelectors includes: aMessage selector) ifTrue: [
+		self request.
+		^ aMessage sendTo: builtClient ].
+	(self responseCreationSelectors includes: aMessage selector) ifTrue: [
+		self response ifNotNil: [ self error: 'Response already created' ].
+		^ builtClient response: (aMessage sendTo: ZnResponse) ].
+	(self responseSelectors includes: aMessage selector) ifTrue: [
+		self response.
+		^ aMessage sendTo: builtClient response ].
+	^ super doesNotUnderstand: aMessage
+]
+
+{ #category : #building }
+ZnockBase >> openState: aSymbol [
+	aSymbol == #request ifTrue: [
+		builtClient := ZnockExpectation new.
+		builtClient url: baseUrl.
+		builtClient request url scheme: baseUrl scheme ].
+	aSymbol == #response ifTrue: [ self owner addExpectation: builtClient ]
+]
+
+{ #category : #accessing }
+ZnockBase >> owner [
+	^ owner
+]
+
+{ #category : #accessing }
+ZnockBase >> owner: anObject [
+	owner := anObject
+]
+
+{ #category : #building }
+ZnockBase >> request [
+	self state: #request.
+	^ builtClient
+]
+
+{ #category : #building }
+ZnockBase >> resetState [
+	self state: nil
+]
+
+{ #category : #building }
+ZnockBase >> response [
+	self state: #response.
+	^ builtClient response
+]
+
+{ #category : #building }
+ZnockBase >> responseCreationSelectors [
+	^ #(accepted noContent notModified ok: redirect: redirect:entity: serverError: serverErrorWithEntity: statusCode: statusLine: unauthorized unauthorized: unauthorized:entity:)
+]
+
+{ #category : #building }
+ZnockBase >> responseSelectors [
+	^ #(addCookie: entity: headers: resetEntity: setLocation: setWWWAuthenticate: statusLine:)
+]
+
+{ #category : #building }
+ZnockBase >> state: aSymbol [
+	state == aSymbol ifTrue: [ ^ self ].
+	self closeState: state.
+	state := aSymbol.
+	self openState: state
+]
+
+{ #category : #public }
+ZnockBase >> url: anObject [
+	| scheme |
+	self request.
+	scheme := builtClient request url scheme.
+	builtClient url: anObject.
+	builtClient request url scheme: scheme
+]

+ 33 - 3
src/Znock/ZnockClient.class.st

@@ -1,12 +1,42 @@
 Class {
 	#name : #ZnockClient,
 	#superclass : #ZnClient,
+	#instVars : [
+		'interceptor'
+	],
 	#category : #Znock
 }
 
+{ #category : #'instance creation' }
+ZnockClient class >> newWithInterceptor: aZnock [ 
+	^ self new
+		interceptor: aZnock;
+		yourself
+]
+
 { #category : #'private protocol' }
 ZnockClient >> executeRequestResponse [
-	^ false
-		ifTrue: [ response := ZnResponse badRequest: self request. response contents ]
-		ifFalse: [ super executeRequestResponse ]
+	^ (interceptor consumeExpectationFor: self)
+		ifNotNil: [ :expectation | response := expectation response. response contents ]
+		ifNil: [ super executeRequestResponse ]
+]
+
+{ #category : #accessing }
+ZnockClient >> interceptor: anObject [
+	interceptor := anObject
+]
+
+{ #category : #comparing }
+ZnockClient >> matches: aZnockExpectation [
+	| req exp |
+	req := self request.
+	exp := aZnockExpectation request.
+	exp url scheme ifNotNil:
+		[ :scheme | scheme = req url scheme ifFalse: [ ^ false ] ].
+	exp url authority ifNotNil:
+		[ :authority | authority = req url authority ifFalse: [ ^ false ] ].
+	exp method ifNotNil:
+		[ :method | method = req method ifFalse: [ ^ false ] ].
+
+	^ true
 ]

+ 15 - 0
src/Znock/ZnockExpectation.class.st

@@ -0,0 +1,15 @@
+Class {
+	#name : #ZnockExpectation,
+	#superclass : #ZnClient,
+	#category : #Znock
+}
+
+{ #category : #operations }
+ZnockExpectation >> execute [
+	"Do nothing"
+]
+
+{ #category : #accessing }
+ZnockExpectation >> response: aZnResponse [
+	response := aZnResponse
+]