Delta define: #AbstractExceptionHandlingTest as: ( (Class subclassOf: 'TestCase' instanceVariables: '')) ! (Delta mirrorFor: #AbstractExceptionHandlingTest) revision: '$Revision:$'! (Delta mirrorFor: #AbstractExceptionHandlingTest) group: 'Unclassified'! (Delta mirrorFor: #AbstractExceptionHandlingTest) comment: ''! Delta define: #BlockExceptionDescriptor as: ( (Class subclassOf: 'Object' instanceVariables: 'defaultBlock handlerBlock resumeBlock')) ! (Delta mirrorFor: #BlockExceptionDescriptor) revision: '$Revision$'! (Delta mirrorFor: #BlockExceptionDescriptor) group: 'exceptions'! (Delta mirrorFor: #BlockExceptionDescriptor) comment: 'Implements the protocol from the ANSI standard using configurable actionsdefined as blocks. Intended to be used primarily as a testing aid.'! Delta define: #BlockExceptionDescriptorTest as: ( (Class subclassOf: 'AbstractExceptionHandlingTest' instanceVariables: 'exception')) ! (Delta mirrorFor: #BlockExceptionDescriptorTest) revision: '$Revision:$'! (Delta mirrorFor: #BlockExceptionDescriptorTest) group: 'Unclassified'! (Delta mirrorFor: #BlockExceptionDescriptorTest) comment: ''! Delta define: #BlockExceptionHandlerTest as: ( (Class subclassOf: 'AbstractExceptionHandlingTest' instanceVariables: '')) ! (Delta mirrorFor: #BlockExceptionHandlerTest) revision: '$Revision:$'! (Delta mirrorFor: #BlockExceptionHandlerTest) group: 'Unclassified'! (Delta mirrorFor: #BlockExceptionHandlerTest) comment: ''! Delta define: #BlockExceptionSelector as: ( (Class subclassOf: 'Object' instanceVariables: 'handlesBlock')) ! (Delta mirrorFor: #BlockExceptionSelector) revision: '$Revision$'! (Delta mirrorFor: #BlockExceptionSelector) group: 'exceptions'! (Delta mirrorFor: #BlockExceptionSelector) comment: 'Determines whether an exception can be handled by evaluating the handlesBlock.'! Delta define: #BlockExceptionSelectorTest as: ( (Class subclassOf: 'AbstractExceptionHandlingTest' instanceVariables: '')) ! (Delta mirrorFor: #BlockExceptionSelectorTest) revision: '$Revision:$'! (Delta mirrorFor: #BlockExceptionSelectorTest) group: 'Unclassified'! (Delta mirrorFor: #BlockExceptionSelectorTest) comment: ''! Delta define: #BlockWithoutArgumentsExceptionHandlingTest as: ( (Class subclassOf: 'AbstractExceptionHandlingTest' instanceVariables: '')) ! (Delta mirrorFor: #BlockWithoutArgumentsExceptionHandlingTest) revision: '$Revision:$'! (Delta mirrorFor: #BlockWithoutArgumentsExceptionHandlingTest) group: 'Unclassified'! (Delta mirrorFor: #BlockWithoutArgumentsExceptionHandlingTest) comment: ''! Delta define: #ErrorTest as: ( (Class subclassOf: 'AbstractExceptionHandlingTest' instanceVariables: 'handlers')) ! (Delta mirrorFor: #ErrorTest) revision: '$Revision:$'! (Delta mirrorFor: #ErrorTest) group: 'Unclassified'! (Delta mirrorFor: #ErrorTest) comment: ''! Delta define: #ExceptionTest as: ( (Class subclassOf: 'AbstractExceptionHandlingTest' instanceVariables: '')) ! (Delta mirrorFor: #ExceptionTest) revision: '$Revision:$'! (Delta mirrorFor: #ExceptionTest) group: 'Unclassified'! (Delta mirrorFor: #ExceptionTest) comment: ''! Delta define: #HaltTest as: ( (Class subclassOf: 'AbstractExceptionHandlingTest' instanceVariables: '')) ! (Delta mirrorFor: #HaltTest) revision: '$Revision:$'! (Delta mirrorFor: #HaltTest) group: 'Unclassified'! (Delta mirrorFor: #HaltTest) comment: ''! Delta define: #LinkedExceptionHandlerTest as: ( (Class subclassOf: 'AbstractExceptionHandlingTest' instanceVariables: '')) ! (Delta mirrorFor: #LinkedExceptionHandlerTest) revision: '$Revision:$'! (Delta mirrorFor: #LinkedExceptionHandlerTest) group: 'Unclassified'! (Delta mirrorFor: #LinkedExceptionHandlerTest) comment: ''! Delta define: #MessageNotUnderstoodTest as: ( (Class subclassOf: 'AbstractExceptionHandlingTest' instanceVariables: '')) ! (Delta mirrorFor: #MessageNotUnderstoodTest) revision: '$Revision:$'! (Delta mirrorFor: #MessageNotUnderstoodTest) group: 'Unclassified'! (Delta mirrorFor: #MessageNotUnderstoodTest) comment: ''! Delta define: #NotificationTest as: ( (Class subclassOf: 'AbstractExceptionHandlingTest' instanceVariables: '')) ! (Delta mirrorFor: #NotificationTest) revision: '$Revision:$'! (Delta mirrorFor: #NotificationTest) group: 'Unclassified'! (Delta mirrorFor: #NotificationTest) comment: ''! Delta define: #ProcessExceptionHandlingTest as: ( (Class subclassOf: 'AbstractExceptionHandlingTest' instanceVariables: '')) ! (Delta mirrorFor: #ProcessExceptionHandlingTest) revision: '$Revision:$'! (Delta mirrorFor: #ProcessExceptionHandlingTest) group: 'Unclassified'! (Delta mirrorFor: #ProcessExceptionHandlingTest) comment: ''! Delta define: #TestException as: ( (Class subclassOf: 'Exception' instanceVariables: 'defaultActionBlock resumable')) ! (Delta mirrorFor: #TestException) revision: '$Revision$'! (Delta mirrorFor: #TestException) group: 'exceptions'! (Delta mirrorFor: #TestException) comment: 'Concrete exception class that can be used for testing'! Delta define: #WarningTest as: ( (Class subclassOf: 'AbstractExceptionHandlingTest' instanceVariables: '')) ! (Delta mirrorFor: #WarningTest) revision: '$Revision:$'! (Delta mirrorFor: #WarningTest) group: 'Unclassified'! (Delta mirrorFor: #WarningTest) comment: ''! Delta define: #ZeroDivideTest as: ( (Class subclassOf: 'AbstractExceptionHandlingTest' instanceVariables: '')) ! (Delta mirrorFor: #ZeroDivideTest) revision: '$Revision:$'! (Delta mirrorFor: #ZeroDivideTest) group: 'Unclassified'! (Delta mirrorFor: #ZeroDivideTest) comment: ''! ! (Delta mirrorFor: #AbstractExceptionHandlingTest) classSide methodsFor: 'Testing' ! isAbstract ^name = #AbstractExceptionHandlingTest! ! ! (Delta mirrorFor: #AbstractExceptionHandlingTest) methodsFor: 'Running' ! tearDown " some of these tests do nasty things to the exception environment so best clean up after them by resetting it" Processor activeProcess resetExceptionEnvironment! ! ! (Delta mirrorFor: #AbstractExceptionHandlingTest) methodsFor: 'test support' ! withStopHandler: stopHandler do: aBlock | oldHandler | oldHandler := Processor stopHandler. Processor stopHandler: stopHandler. aBlock ensure: [Processor stopHandler: oldHandler]! ! ! (Delta mirrorFor: #BlockExceptionDescriptor) classSide methodsFor: 'instantiation' ! falseSelector ^BlockExceptionSelector handlesBlock: [:ex| false]! new ^super new initialize; yourself! trueSelector ^BlockExceptionSelector handlesBlock: [:ex| true]! ! ! (Delta mirrorFor: #BlockExceptionDescriptor) methodsFor: 'configuring' ! defaultActionBlock: block defaultBlock := block! handler: handler handlerBlock value: handler ! handlerBlock: block handlerBlock := block ! resumeBlock: aBlock resumeBlock := aBlock! ! ! (Delta mirrorFor: #BlockExceptionDescriptor) methodsFor: 'exception descriptor' ! defaultAction ^defaultBlock value! isResumable ^true! resume: aValue resumeBlock value: aValue! ! ! (Delta mirrorFor: #BlockExceptionDescriptor) methodsFor: 'initialization' ! initialize defaultBlock := [nil]. handlerBlock := [:ignore|]. resumeBlock := [:ignore|]! ! ! (Delta mirrorFor: #BlockExceptionDescriptor) methodsFor: 'restricted - exception handling' ! inContextDo: aBlock ^aBlock value! ! ! (Delta mirrorFor: #BlockExceptionDescriptorTest) methodsFor: 'Running' ! setUp super setUp. exception := BlockExceptionDescriptor new! ! ! (Delta mirrorFor: #BlockExceptionDescriptorTest) methodsFor: 'testing' ! testDefaultActionShouldInvokeDefaultActionBlock |wasInvoked| exception := BlockExceptionDescriptor new. wasInvoked := false. exception defaultActionBlock: [wasInvoked := true]. exception defaultAction. self assert: wasInvoked! testDefaultDefault self assert: exception defaultAction isNil! testHandlerShouldDelegateToHandlerBlock |actualHandler| exception handlerBlock: [:handler| actualHandler := handler]. exception handler: #handler. self assert: (actualHandler == #handler)! ! ! (Delta mirrorFor: #BlockExceptionHandlerTest) methodsFor: 'Testing' ! testDefaultHandlerShouldReportErrorAfterReturnFromNonResumableDefaultAction | handler exception wasHandled | handler := BlockExceptionHandler default. exception := TestException defaultActionBlock: []. exception resumable: false. [exception signal. self signalFailure: 'Handler should not return'] on: Error do: [:error| self assert: 'Return from non-resumable default action is not supported' = error messageText description: error messageText. wasHandled := true]. self assert: wasHandled description: 'Handler should report error'! testShouldInvokeHandlerBlockWithException |handled exception| handled := false. exception = Object new. (BlockExceptionHandler handleBlock: [:ex| self assert: (ex == exception). handled := true]) handle: exception. self assert: handled! ! ! (Delta mirrorFor: #BlockExceptionSelector) classSide methodsFor: 'instantiation' ! falseSelector ^BlockExceptionSelector handlesBlock: [:ex| false]! handlesBlock: block ^self new handlesBlock: block; yourself! trueSelector ^BlockExceptionSelector handlesBlock: [:ex| true]! ! ! (Delta mirrorFor: #BlockExceptionSelector) methodsFor: 'exception selector' ! handles: exceptionDescriptor ^handlesBlock value: exceptionDescriptor! ! ! (Delta mirrorFor: #BlockExceptionSelector) methodsFor: 'private - initialization' ! handlesBlock: block handlesBlock := block ! ! ! (Delta mirrorFor: #BlockExceptionSelectorTest) methodsFor: 'Testing' ! testShouldHandleWhenHandleBlockReturnsTrue |canHandle selector| selector := BlockExceptionSelector handlesBlock: [:ex| canHandle]. canHandle := true. self assert: (selector handles: nil). canHandle := false. self deny: (selector handles: nil)! testShouldPassExceptionToHandlesBlock |exception selector| exception := Object new. selector := BlockExceptionSelector handlesBlock: [:ex| self assert: (ex == exception). true]. self assert: (selector handles: exception)! ! ! (Delta mirrorFor: #BlockWithoutArgumentsExceptionHandlingTest) methodsFor: 'testing' ! testOnDoShouldInvokeDoWhenExceptionSignalled |wasHandled| wasHandled := false. [Exception signal] on: Exception do: [:ex| wasHandled := true]. self assert: wasHandled description: 'Signalled exception should be handled'! testOnDoShouldInvokeNestedHandler |innerInvoked outerInvoked| innerInvoked := false. outerInvoked := false. [[Exception signal] on: BlockExceptionSelector falseSelector do: [:ex| innerInvoked := true]] on: Exception do: [:ex| outerInvoked := true]. self deny: innerInvoked description: 'Inner handler should not be invoked'. self assert: outerInvoked description: 'Outer handler should be invoked'! testOnDoShouldPopHandler |handlerInvoked descriptor defaultInvoked| descriptor := BlockExceptionDescriptor new. descriptor defaultActionBlock: [defaultInvoked := true]; resumeBlock: [:value| ^self " force NLR"]. [Exception signal] on: BlockExceptionSelector trueSelector do: [:ex| handlerInvoked := true]. defaultInvoked := false. handlerInvoked := false. [Processor activeProcess handle: descriptor] ensure: [self deny: handlerInvoked description: 'Handler should have been popped'. self assert: defaultInvoked description: 'Default action should have been invoked']! testShouldUnwindExceptionHandlersWhenHandlingException | wasInvoked | wasInvoked := false. [[[Notification signal] on: Error do: [:ex| self signalFailure: 'Should be caught by outer handler']] on: Notification do: [:ex| self error: 'Provoke outer handler']] on: Error do: [:ex| wasInvoked:= true]. self assert: wasInvoked description: 'Outer handler should be invoked'! ! ! (Delta mirrorFor: #ErrorTest) methodsFor: 'testing' ! testDefaultActionShouldPassToStopHandler | wasHandled processError | wasHandled := false. self withStopHandler: [:p| wasHandled := true. processError := p processError] do: [[self error: 'this is an error'] fork. Processor yield]. self assert: wasHandled description: 'defaultAction should invoke the stopHandler'. self assert: (processError isKindOf: ProcessExplicitError) description: 'Process stopped with wrong kind of error', processError printString. self assert: 'this is an error' = processError msg description: 'Process stopped with wrong message: ', processError msg! testErrorShouldSignalError | wasSignalled | wasSignalled := true. [self error: 'error message'. self signalFailure: 'should not return'] on: Error do: [:ex| wasSignalled := true. self assert: 'error message' = ex messageText description: ex messageText printString]. self assert: wasSignalled description: 'Error should be signalled'! testShouldNotBeResumable self deny: Error new isResumable! ! ! (Delta mirrorFor: #ExceptionTest) methodsFor: 'Testing' ! testDefaultActionShouldExecuteInSignallingEnvironment | original wasHandled | original := TestException defaultActionBlock: [self error: '']. original resumable: true. wasHandled := false. [original signal] on: Error do: [:ex| wasHandled := true]. self assert: wasHandled! testDefaultActionShouldExecuteInSignallingEnvironmentAfterResumableOuter | original wasHandled | original := TestException defaultActionBlock: [self error: '']. original resumable: true. wasHandled := false. [[original signal] on: Error do: [:ex| wasHandled := true]] on: TestException do: [:ex| ex outer]. self assert: wasHandled! testIsNestedShouldBeFalseWhenOuterHandlerDoesntHandle |wasHandled| wasHandled := false. [[Exception signal] on: Exception do: [:ex| self deny: ex isNested. wasHandled := true]] on: TestException do: [:ex|]. self assert: wasHandled! testIsNestedShouldBeFalseWithNoHandler |exception| exception := Exception new. self deny: exception isNested! testIsNestedShouldBeTrueWhenOuterHandlerHandles |wasHandled| wasHandled := false. [[Exception signal] on: Exception do: [:ex| self assert: ex isNested. wasHandled:= true]] on: Exception do: [:ex| self shouldNotHappen]. self assert: wasHandled! testIsNestedShouldBeTrueWhenOuterOuterHandlerHandles |wasHandled| wasHandled := false. [[[Exception signal] on: Exception do: [:ex| self assert: ex isNested. wasHandled := true]] on: TestException do: [:ex|]] on: Exception do: [:ex|]. self assert: wasHandled! testOuterShouldInvokeAndReturnDefaultActionWhenResumable |outer result| [(TestException defaultActionBlock: [#result]) resumable: true; signal] on: TestException do: [:ex| self assert: ex outer == #result description: 'outer returned wrong result'. result := #returned]. self assert: result == #returned description: 'outer did not return'! testOuterShouldReturnResumptionValueWhenResumed |wasResumed| wasResumed := false. [[TestException new resumable: true; signal] on: TestException do: [:ex| |result| result := ex outer. self assert: 'result' = result description: result printString. wasResumed := true]] on: TestException do: [:ex| ex resume: 'result'. self signalFailure: 'Resume should not return']. self assert: wasResumed description: 'not resumed'! testOuterTwiceShouldInvokeSurroundingHandlerTwice |count| count := 0. [[TestException new resumable: true; signal] on: TestException do: [:ex| ex outer. ex outer]] on: TestException do: [:ex| count := count + 1. ex resume]. self assert: count == 2 description: 'Count was ', count printString! testPassShouldDeferToOuterHandler |wasPassed| wasPassed := false. [[TestException signal] on: TestException do: [:ex| ex pass. self signalFailure: 'pass should not return']] on: TestException do: [:ex| wasPassed := true]. self assert: wasPassed! testPassShouldInvokeDefaultActionWithoutReturning | signalReturned | signalReturned := false. [|result| result := (TestException defaultActionBlock: ['result']) resumable: true; signal. self assert: result = 'result' description: result printString. signalReturned := true] on: TestException do: [:ex| ex pass. self signalFailure: 'Pass should not return']. self assert: signalReturned description: 'Signal did not return'! testPassShouldInvokeSurroundingHandler | wasPassed | wasPassed := false. [[TestException new signal] on: TestException do: [:ex| ex pass. self signalFailure: 'Pass should not return']] on: TestException do: [:ex| wasPassed := true]. self assert: wasPassed description: 'Outer handler not invoked'! testResignalAsShouldRestoreSignalEnvironment |log| log := String new writeStream. [[Exception signal] on: TestException do: [:ex| log nextPutAll: 'resignal']] on: Exception do: [:ex| [log nextPutAll: 'signal '. ex resignalAs: TestException new] ifCurtailed: [log nextPutAll: 'curtail ']]. self assert: log contents = 'signal curtail resignal' description: log contents! testResumeAfterPassShouldReturnFromSignal | wasReturned | wasReturned := false. [[|result| result := TestException new resumable: true; signal. wasReturned := true] on: TestException do: [:ex| ex pass. self signalFailure: 'Pass should not return']] on: TestException do: [:ex| ex resume]. self assert: wasReturned description: 'Resume did not return from signal'! testResumeAfterPassShouldReturnResultFromSignal | wasReturned | wasReturned := false. [[|result| result := TestException new resumable: true; signal. self assert: 'result' = result description: result printString. wasReturned := true] on: TestException do: [:ex| ex pass. self signalFailure: 'Pass should not return']] on: TestException do: [:ex| ex resume: 'result']. self assert: wasReturned description: 'Resume did not return from signal'! testResumeShouldReturnAsValueOfOuter |result| [[Exception signal] on: Exception do: [:ex| result := ex outer]] on: Exception do: [:ex| ex resume: #result]. self assert: result == #result description: result printString! testResumeShouldReturnValueAsResultOfSignal |wasResumed| wasResumed := false. [|result| result := TestException new resumable: true; signal. self assert: #resume == result description: result printString. wasResumed := true] on: TestException do: [:ex| ex resume: #resume]. self assert: wasResumed description: 'Should have resumed after signal'! testRetryShouldReevaluateProtectee |count| count := 0. [count := count + 1. count == 1 ifTrue:[Exception signal]] on: Exception do: [:ex| ex retry]. self assert: count == 2 description: 'Count was ' , count printString! testRetryUsingShouldReplaceProtectee |log count| log := String new writeStream. count := 0. [[Exception signal] ensure: [log nextPutAll: 'unwind ']] on: Exception do: [:ex| log nextPutAll: 'handle '. count := count + 1. count = 1 ifTrue: [ex retryUsing: [log nextPutAll: 'using '. Exception signal]]]. self assert: log contents = 'handle unwind using handle ' description: log contents! testReturnShouldDelegateToHandler |exception handler result| exception := Exception new. handler := BlockExceptionHandler new. result := #invalid. handler returnBlock: [:value| result := value]. exception handler: handler. exception return. self assert: result isNil description: 'Return should pass back nil'! testSignalShouldInvokeProcessHandler |wasInvoked| wasInvoked := false. Processor activeProcess pushHandler: (LinkedExceptionHandler on: Exception do: [:ex| wasInvoked := true]). Exception signal. [self assert: wasInvoked description: 'Should invoke exception handler'] ensure: [Processor activeProcess popHandler]! ! ! (Delta mirrorFor: #HaltTest) methodsFor: 'Testing' ! testDefaultActionShouldStopWithProcessHaltError | wasHandled processError | wasHandled := false. self withStopHandler: [:p| wasHandled := true. processError := p processError] do: [[self halt] fork. Processor yield]. self assert: wasHandled description: 'Halt should have been handled'. self assert: (processError isKindOf: ProcessHaltError) description: 'Wrong kind of error reported'! testHaltShouldSignalHalt | wasSignalled | wasSignalled := false. [self halt] on: Halt do: [:ex| wasSignalled := true]. self assert: wasSignalled! testShouldBeResumable self assert: Halt new isResumable! ! ! (Delta mirrorFor: #LinkedExceptionHandlerTest) methodsFor: 'testing' ! testHandlerShouldSetHandlerOnException |handler exception assignedHandler| exception := BlockExceptionDescriptor new. exception handlerBlock: [:handler| assignedHandler := handler]. handler := LinkedExceptionHandler on: BlockExceptionSelector trueSelector do: [:ex| ]. self assert: assignedHandler ~~ handler description: 'Handler should not have been assigned yet'. handler handle: exception. self assert: assignedHandler == handler description: 'Handler should have been assigned'! testPassShouldDeferToNextHandler |handler trueSelector exception wasPassed nextHandler| exception := BlockExceptionDescriptor new. handler := LinkedExceptionHandler on: BlockExceptionSelector trueSelector do: [:ex| ]. nextHandler := BlockExceptionHandler handleBlock: [:ex| wasPassed := true]. handler nextHandler: nextHandler. wasPassed := false. handler pass: exception. self assert: wasPassed description: 'Handler should defer pass to nextHandler'! testReturnShouldEvaluateReturnBlock |handler result | handler := LinkedExceptionHandler on: nil do: [:ex| ] return: [:returnValue| result := returnValue]. handler return: #value. self assert: result == #value description: 'Should have invoked return'! testShouldDelegateToNextHandlerWhenNoMatch |handled exception nextHandler| handled := false. exception := BlockExceptionDescriptor new. nextHandler := BlockExceptionHandler handleBlock: [:ex| self assert: ex == exception description: 'Handler invoked with wrong exception'. handled := true]. (LinkedExceptionHandler on: BlockExceptionSelector falseSelector do: [:ex| self signalFailure: 'Should not invoke hander']) nextHandler: nextHandler; handle: exception. self assert: handled description: 'Next handler not invoked'! testShouldInvokeExceptionsDefaultActionWhenNoNextHandler |handled exception| handled := false. exception := BlockExceptionDescriptor new. exception defaultActionBlock: [handled := true]. (LinkedExceptionHandler on: BlockExceptionSelector falseSelector do: [:ex| self shouldNotHappen]) handle: exception. self assert: handled description: 'Default action not invoked'! testShouldInvokeHandleBlockWhenExceptionMatches |handled exception| handled := false. exception := BlockExceptionDescriptor new. (LinkedExceptionHandler on: BlockExceptionSelector trueSelector do: [:ex| self assert: ex == exception description: 'Handler invoked with wrong exception'. handled := true]) handle: exception. self assert: handled description: 'Exception not handled by handler'! ! ! (Delta mirrorFor: #MessageNotUnderstoodTest) methodsFor: 'testing' ! testMessageShouldReturnMessageThatWasNotUnderstood | message | message := Message receiver: 1 selector: #zork arguments: #(). [(MessageNotUnderstood message: message) signal.] on: MessageNotUnderstood do: [:ex| self assert: message = ex message description: 'Wrong message']! testReceiverShouldReturnReceiverOfMessage | message | message := Message receiver: 1 selector: #zork arguments: #(). [(MessageNotUnderstood message: message) signal.] on: MessageNotUnderstood do: [:ex| self assert: 1 = ex receiver description: 'Wrong receiver']! testResumeShouldReturnResultFromSignal " note that until doesNotUnderstand: is fixed in the VM we cannot use the more obvious test of sending a message to an object that cannot understand it" |result| [result := (MessageNotUnderstood message: (Message receiver: 1 selector: #zork arguments: #())) signal.] on: MessageNotUnderstood do: [:ex| ex resume: 5]. self assert: result = 5 description: 'Result not returned'! testShouldBeResumable self assert: MessageNotUnderstood new isResumable! ! ! (Delta mirrorFor: #NotificationTest) methodsFor: 'Testing' ! testDefaultActionReturnsNil self assert: Notification signal isNil! testIsResumable self assert: Notification new isResumable! ! ! (Delta mirrorFor: #ProcessExceptionHandlingTest) methodsFor: 'testing' ! testHandleShouldInvokeDefaultAction |exception wasInvoked| wasInvoked := false. exception := BlockExceptionDescriptor new. exception defaultActionBlock: [wasInvoked := true]; resumeBlock: [:value|^self "force NLR to prevent problems with test infrastructure"]. [Processor activeProcess handle: exception] ensure: [self assert: wasInvoked description: 'Default action not invoked']! testPushedHandlerShouldDeferToDefaultHandlerWhenExceptionDoesntMatch |process wasInvoked exception| exception := BlockExceptionDescriptor new. exception defaultActionBlock: [wasInvoked := true]. process := Processor activeProcess. process pushHandler: (LinkedExceptionHandler on: BlockExceptionSelector falseSelector do: [:ex| ]). wasInvoked := false. [[process handle: exception] ensure: [self assert: wasInvoked description: 'Default action not invoked']] ensure: [process popHandler]! testPushedHandlerShouldDeferToOuterHandlerWhenExceptionDoesntMatch |process wasInvoked exception outerHandler| wasInvoked := false. exception := BlockExceptionDescriptor new. exception defaultActionBlock: []; resumeBlock: [:value|^self "force NLR to prevent problems with test infrastructure"]. outerHandler := (LinkedExceptionHandler on: BlockExceptionSelector trueSelector do: [:ex| wasInvoked := true]). process := Processor activeProcess. process pushHandler: outerHandler. process pushHandler: (LinkedExceptionHandler on: BlockExceptionSelector falseSelector do: [:ex| ]). [[process handle: exception] ensure: [self assert: wasInvoked description: 'Outer handler should have been invoked']] ensure: [process popHandler. process popHandler]! testPushedHandlerShouldReplaceDefaultHandler |process wasInvoked exception| process := Processor activeProcess. exception := BlockExceptionDescriptor new. wasInvoked := false. process pushHandler: (LinkedExceptionHandler on: BlockExceptionSelector trueSelector do: [:ex| wasInvoked := true]). [wasInvoked := false. process handle: exception] ensure: [process popHandler]. self assert: wasInvoked description: 'Handler should be invoked'! ! ! (Delta mirrorFor: #TestException) classSide methodsFor: 'test support' ! defaultActionBlock: block ^self new defaultActionBlock: block; yourself! ! ! (Delta mirrorFor: #TestException) methodsFor: 'test support' ! defaultAction ^defaultActionBlock value! defaultActionBlock: block defaultActionBlock := block! isResumable ^resumable isNil ifTrue: [false] ifFalse: [resumable]! resumable: boolean ^resumable := boolean! ! ! (Delta mirrorFor: #WarningTest) methodsFor: 'Testing' ! testDefaultActionShouldProvokeHalt | wasHalted wasSignalled | wasHalted := wasSignalled := false. [[Warning signal] on: Halt do: [:ex| wasHalted := true]] on: Warning do: [:ex| wasSignalled := true. ex outer]. self assert: wasSignalled description: 'Should have signalled Warning'. self assert: wasHalted description: 'Default action should have halted'! testShouldBeResumable self assert: Warning new isResumable! ! ! (Delta mirrorFor: #ZeroDivideTest) methodsFor: 'Testing' ! testDivideByZeroShouldSignalZeroDivide | wasSignalled | wasSignalled := false. [1/0] on: ZeroDivide do: [:ex| wasSignalled := true. self assert: 1 = ex dividend description: 'Wrong dividend:', ex dividend printString. self assert: 'divide by zero' = ex messageText description: 'Wrong message: ', ex messageText printString]. self assert: wasSignalled description: 'Should have signalled'! testDividendShouldReturnDividendThatCreatedException [(ZeroDivide dividend: 1) signal] on: ZeroDivide do: [:ex| self assert: 1 = ex dividend]! testShouldBeResumable self assert: ZeroDivide new isResumable! !