Christoph Thiede uploaded a new version of KernelTests to project The Trunk: http://source.squeak.org/trunk/KernelTests-ct.453.mcz
==================== Summary ====================
Name: KernelTests-ct.453 Author: ct Time: 25 February 2024, 8:46:33.380593 pm UUID: 081d7c84-95a3-3848-b6e6-a4a7c5007915 Ancestors: KernelTests-ct.452, KernelTests-ct.409, KernelTests-ct.417, KernelTests-ct.421, KernelTests-ct.448
Merges and revises several simulation tests from the inbox. As always, please refer to the original versions to read their full messages.
KernelTests-ct.376: Tests #contextEnsure: and #contextOn:do:. Includes regression tests for Kernel-ct.1296. Revision: Reduced overdetailed commentary and overcautious exception handlers, now that simulation works more robust.
KernelTests-ct.409: Adds new simulation tests for the reflection primitives 117 (primitiveExternalCall), 118 (primitiveDoPrimitiveWithArgs), and 218 (primitiveDoNamedPrimitiveWithArgs) and revises existing tests for the primitives 83 (primitivePerform), 84 (primitivePerformWithArgs), and 100 (primitivePerformInSuperclass) which do not need to be dispatched via primitive 118. Revision: Completely rework previously useless testPrimitive117. Revise examples in testPrimitive118: and testPrimitive218. Extend testPrimitive83 and testPrimitive84 with examples for invalid selectors and Objects as Methods and make the assertion more debug-friendly. Improve commentary. Document known failures due to erroneous VM behavior. Recategorize.
KernelTests-ct.417: Acceptance tests for #runUntilErrorOrReturnFrom:. Revision: Test resumed simulation of context after error.
KernelTests-ct.420: Tests simulation of primitive 188 (primitiveExecuteMethodArgsArray) and primitive 189 (primitiveExecuteMethod). Revision: Add example for invalid method to testPrimitive188:. Make assertions more debug-friendly. Improve commentary.
KernelTests-ct.421: Tests handling of objects as methods (OaM) during simulation of Object>>#withArgs:executeMethod: and Object>>#with:...executeMethod:.
KernelTests-ct.448: Complements Kernel-ct.1546 (fixes stepping through #mustBeBoolean errors and restarting from primitive methods that no longer fail).
=============== Diff against KernelTests-ct.452 ===============
Item was added: + ----- Method: ContextTest>>simulate: (in category 'private') ----- + simulate: aBlock + + | result | + [result := aBlock value] newProcess runUntil: [:ctxt | false]. + ^ result!
Item was changed: + ----- Method: ContextTest>>testBlockCannotReturn (in category 'tests - simulation') ----- - ----- Method: ContextTest>>testBlockCannotReturn (in category 'tests') ----- testBlockCannotReturn "Test if #return:from: correctly handles returns to dead or nil contexts."
| p | p := [ thisContext pc: nil ] newProcess. p runUntil: [:ctx | ctx method selector = #pc: and: [ctx sender isDead]]. "assert p stoped at the last instruction, i.e. a return, of #pc: and is about to return to a dead context" self assert: p suspendedContext method selector equals: #pc:. self assert: p suspendedContext sender isDead. self assert: p suspendedContext willReturn. self assert: p suspendedContext atEnd. p step. "step into a return to a dead sender"
self assert: p suspendedContext method selector = #cannotReturn:!
Item was changed: + ----- Method: ContextTest>>testBlockCannotReturnToNil (in category 'tests - simulation') ----- - ----- Method: ContextTest>>testBlockCannotReturnToNil (in category 'tests') ----- testBlockCannotReturnToNil "Test if #return:from: correctly handles returns to dead or nil contexts."
| context nextContext | context := [] asContext. "assert p is at the last instruction, i.e. a return, and is about to return to a nil context" self assert: context method selector = thisContext method selector. self assert: context sender isNil. self assert: context willReturn. self assert: context atEnd. nextContext := context step. "step into a return to a nil sender"
self assert: nextContext method selector = #cannotReturn:!
Item was added: + ----- Method: ContextTest>>testContextEnsure (in category 'tests') ----- + testContextEnsure + + | sideEffect block result | + block := + [sideEffect := nil. + thisContext insertSender: + (Context contextEnsure: + [sideEffect := sideEffect + 1]). + sideEffect := 0]. + + result := block value. + + self assert: 0 equals: result. + self assert: 1 equals: sideEffect.!
Item was added: + ----- Method: ContextTest>>testContextEnsureSimulation (in category 'tests') ----- + testContextEnsureSimulation + "Regression test for http://forum.world.st/BUG-s-in-Context-control-jump-runUntilErrorOrReturnFro..." + + | sideEffect block result | + block := + [sideEffect := nil. + thisContext insertSender: + (Context contextEnsure: + [sideEffect := sideEffect + 1]). + sideEffect := 0]. + + result := self simulate: block. + + self assert: 0 equals: result. + self assert: 1 equals: sideEffect.!
Item was added: + ----- Method: ContextTest>>testContextEnsureSimulationWithError (in category 'tests') ----- + testContextEnsureSimulationWithError + "Regression test for http://forum.world.st/BUG-s-in-Context-control-jump-runUntilErrorOrReturnFro..." + + | sideEffect block result | + block := + [sideEffect := nil. + thisContext insertSender: + (Context contextEnsure: + [sideEffect := sideEffect + 1]). + sideEffect := 0. + self error]. + + result := self simulate: [[block value] on: Error do: [42]]. + + self assert: 42 equals: result. + self assert: 1 equals: sideEffect.!
Item was added: + ----- Method: ContextTest>>testContextEnsureWithError (in category 'tests') ----- + testContextEnsureWithError + + | sideEffect block result | + block := + [sideEffect := nil. + thisContext insertSender: + (Context contextEnsure: + [sideEffect := sideEffect + 1]). + sideEffect := 0. + self error]. + + result := [block value] on: Error do: [42]. + + self assert: 42 equals: result. + self assert: 1 equals: sideEffect.!
Item was added: + ----- Method: ContextTest>>testContextOnDo (in category 'tests') ----- + testContextOnDo + + | sideEffect block result | + block := + [sideEffect := nil. + thisContext insertSender: + (Context contextOn: Error do: + [sideEffect := sideEffect + 1]). + sideEffect := 0]. + + result := block value. + + self assert: 0 equals: result. + self assert: 0 equals: sideEffect.!
Item was added: + ----- Method: ContextTest>>testContextOnDoSimulation (in category 'tests') ----- + testContextOnDoSimulation + "Regression test for http://forum.world.st/BUG-s-in-Context-control-jump-runUntilErrorOrReturnFro..." + + | sideEffect block result | + block := + [sideEffect := nil. + thisContext insertSender: + (Context contextOn: Error do: + [sideEffect := sideEffect + 1]). + sideEffect := 0]. + + result := self simulate: block. + + self assert: 0 equals: result. + self assert: 0 equals: sideEffect.!
Item was added: + ----- Method: ContextTest>>testContextOnDoSimulationWithError (in category 'tests') ----- + testContextOnDoSimulationWithError + "Regression test for http://forum.world.st/BUG-s-in-Context-control-jump-runUntilErrorOrReturnFro..." + + | sideEffect block result | + block := + [sideEffect := nil. + thisContext insertSender: + (Context contextOn: Error do: + [sideEffect := sideEffect + 1. + 42]). + sideEffect := 0. + self error]. + + result := self simulate: block. + + self assert: 42 equals: result. + self assert: 1 equals: sideEffect.!
Item was added: + ----- Method: ContextTest>>testContextOnDoWithError (in category 'tests') ----- + testContextOnDoWithError + + | sideEffect block result | + block := + [sideEffect := nil. + thisContext insertSender: + (Context contextOn: Error do: + [sideEffect := sideEffect + 1. + 42]). + sideEffect := 0. + self error]. + + result := block value. + + self assert: 42 equals: result. + self assert: 1 equals: sideEffect.!
Item was changed: + ----- Method: ContextTest>>testCopyStack (in category 'tests - query') ----- - ----- Method: ContextTest>>testCopyStack (in category 'tests') ----- testCopyStack self assert: aContext copyStack printString = aContext printString.!
Item was changed: + ----- Method: ContextTest>>testCopyTo (in category 'tests - query') ----- - ----- Method: ContextTest>>testCopyTo (in category 'tests') ----- testCopyTo
| context depth targetSender | context := thisContext. depth := 1. targetSender := context. [ (targetSender := targetSender sender) isNil ] whileFalse: [ | original copy | original := context. copy := context copyTo: targetSender. 1 to: depth do: [ :index | index = 1 ifFalse: [ "Since we're copying thisContext, the pc and stackPtr may be different for the current frame." self assert: original pc equals: copy pc; assert: original stackPtr equals: copy stackPtr ]. self deny: original == copy; assert: original method equals: copy method; assert: original closure equals: copy closure; assert: original receiver equals: copy receiver. original := original sender. copy := copy sender ]. self assert: copy isNil; assert: original == targetSender. depth := depth + 1 ]!
Item was changed: + ----- Method: ContextTest>>testFindContextSuchThat (in category 'tests - query') ----- - ----- Method: ContextTest>>testFindContextSuchThat (in category 'tests') ----- testFindContextSuchThat self assert: (aContext findContextSuchThat: [:each| true]) printString = aContext printString. self assert: (aContext hasContext: aContext). !
Item was changed: + ----- Method: ContextTest>>testMessageNotUnderstood (in category 'tests - simulation') ----- - ----- Method: ContextTest>>testMessageNotUnderstood (in category 'tests') ----- testMessageNotUnderstood
"A simulation error (recursive message not understood) occurs that cannot be handled by the simulated code" self should: [Context runSimulated: [[TestEmptyClass new foo] on: Error do: [:ex | ex]]] raise: Error. "The simulator sends #doesNotUnderstand: to the receiver even if the lookup class has no superclass." self assert: [Context runSimulated: [self executeShould: [ProtoObject new foo] inScopeOf: MessageNotUnderstood]]. self assert: [Context runSimulated: [self executeShould: [Compiler evaluate: 'super foo' for: Object new] inScopeOf: MessageNotUnderstood]].!
Item was changed: + ----- Method: ContextTest>>testObjectsAsMethod (in category 'tests - simulation') ----- - ----- Method: ContextTest>>testObjectsAsMethod (in category 'tests') ----- testObjectsAsMethod
| result error | + [SystemChangeNotifier uniqueInstance doSilently: [ - SystemChangeNotifier uniqueInstance doSilently: [ self class addSelector: #foo withMethod: (TestObjectForMethod new xxxMethod: thisContext homeMethod)]. result := Context runSimulated: [[self foo] on: Error do: [:ex | error := ex]]. + error ifNotNil: [self fail: error]] - error ifNotNil: [self fail: error]. + ensure: + [SystemChangeNotifier uniqueInstance doSilently: [ + [self assert: self foo equals: result] + ensure: [self class removeSelector: #foo]]].! - SystemChangeNotifier uniqueInstance doSilently: [ - [self assert: self foo equals: result] - ensure: [self class removeSelector: #foo]].!
Item was changed: + ----- Method: ContextTest>>testPrimitive100 (in category 'tests - simulation') ----- - ----- Method: ContextTest>>testPrimitive100 (in category 'tests') ----- testPrimitive100 + "Test simulation of primitive 100."
{ {#isNil. {}. Object}. "valid 0-arg message" {#=. {true}. UndefinedObject}. "valid unary message" {#ifNil:ifNotNil:. {[2]. [:x | x]}. Object}. "valid binary message" {{}. #=. {true}. SequenceableCollection}. "mirror primitive" + {'not a selector'. {}. Object}. "invalid selector" + {#isNil. 'not an array'. Object}. "invalid arguments" - {#isNil}. "missing arguments" - {#isNil. 'not an array'}. "invalid arguments" - {#isNil. {}}. "missing lookupClass" {#isNil. {'excess arg'}. Object}. "too many arguments" {#=. {}. UndefinedObject}. "missing argument" + {#isNil. {}. 'not a class'}. "invalid lookupClass" {#isNil. {}. Boolean}. "lookupClass not in inheritance chain" + } do: [:args | | block | + block := [[nil + perform: args first + withArguments: args second + inSuperclass: args third] + on: Error do: [:ex | ex description]]. - } do: [:args | self + assert: block value + equals: (Context runSimulated: block). + + block := [[thisContext + object: nil + perform: args first + withArguments: args second + inClass: args third] + on: Error do: [:ex | ex description]]. + self + assert: block value + equals: (Context runSimulated: block)].! - assert: (nil tryPrimitive: 100 withArgs: args) - equals: (Context runSimulated: [nil tryPrimitive: 100 withArgs: args])].!
Item was added: + ----- Method: ContextTest>>testPrimitive117 (in category 'tests - simulation') ----- + testPrimitive117 + "Test simulation of primitive 117 (aka named primitives)." + + "valid 0-arg primitive" + self + assert: (Float32Array withAll: {2.0. 3.0}) sum "<-- primitive 117 (aka named primitive)" + equals: (Context runSimulated: [(Float32Array withAll: {2.0. 3.0}) sum]). "<-- simulator sends tryNamedPrimitiveIn:for:withArgs: (primitive 218)" + + "valid unary primitive" + self + assert: ('wiffy' hashWithInitialHash: 42) + equals: (Context runSimulated: ['wiffy' hashWithInitialHash: 42]). + + "superfluous arguments" + self "cascade!!" + assert: ('wiffy' hashWithInitialHash: 42) + equals: (Context runSimulated: ['wiffy' hashWithInitialHash: 42]); + assert: true.!
Item was added: + ----- Method: ContextTest>>testPrimitive118 (in category 'tests - simulation') ----- + testPrimitive118 + "Test simulation of primitive 118." + + self testPrimitive118: [:receiver :primitiveIndex :arguments | + receiver tryPrimitive: primitiveIndex withArgs: arguments]. + + self flag: #bug. "Known bug: Mirror version of primitive 118 currently misbehaves in the OSVM." + self testPrimitive118: [:receiver :primitiveIndex :arguments | + thisContext receiver: receiver tryPrimitive: primitiveIndex withArgs: arguments].!
Item was added: + ----- Method: ContextTest>>testPrimitive118: (in category 'tests - simulation') ----- + testPrimitive118: primitiveBlock + + | input1 input2 | + { + {#isNil. 62. {}}. "valid 0-arg primitive" + {6. 9. {7}}. "valid unary primitive" + {6. 62. {7}}. "failing primitive" + {6. 'not a primitive'. {7}}. "invalid primitive" + {6. 9. 'not an array'}. "invalid arguments" + {#isNil. 62. {1}}. "too many arguments" + {6. 9. {}}. "missing argument" + + {6. 83. {#=. 6.0}}. "primitivePerform" + {6. 83. {#isNil. 'excess arg'}}. "primitivePerform - too many arguments" + {6. 84. {#=. {6.0}}}. "primitivePerformWithArgs" + {6. 84. {#isNil. 'excess arg'}}. "primitivePerformWithArgs - invalid arguments" + {6. 100. {#=. 6.0. Object}}. "primitivePerformInSuperclass" + {6. 100. {#isNil. {'excess arg'}. Object}}. "primitivePerformInSuperclass - too many arguments" + + {6. 118. {9. {7}}}. "primitiveDoPrimitiveWithArgs" + {6. 118. {9. {7. 13}}}. "primitiveDoPrimitiveWithArgs - superfluous arguments" + {6. 118. {118. {9. {7}}}}. "primitiveDoPrimitiveWithArgs - nested invocation" + {thisContext. 218. {Float32Array >> #sum. Float32Array withAll: {2.0. 3.0}. {}}}. "primitiveDoNamedPrimitiveWithArgs" + {thisContext. 218. {Float32Array >> #sum. Float32Array withAll: {2.0. 3.0}. {4.0}}}. "primitiveDoNamedPrimitiveWithArgs - superfluous arguments" + } do: [:args | | block | + block := [primitiveBlock valueWithArguments: args]. + self + assert: block value + equals: (Context runSimulated: block)]. + + self + assert: (primitiveBlock value: (input1 := {1. 2. 3}) value: 61 value: {2. 4}) + equals: (Context runSimulated: [primitiveBlock value: (input2 := {1. 2. 3}) value: 61 value: {2. 4}]); + assert: input1 + equals: input2.!
Item was added: + ----- Method: ContextTest>>testPrimitive188 (in category 'tests - simulation') ----- + testPrimitive188 + "Test simulation of primitive 188." + + self testPrimitive188: [:receiver :args :compiledMethod | + receiver withArgs: args executeMethod: compiledMethod]. + + self testPrimitive188: [:receiver :args :compiledMethod | + CompiledMethod receiver: receiver withArguments: args executeMethod: compiledMethod].!
Item was added: + ----- Method: ContextTest>>testPrimitive188: (in category 'tests - simulation') ----- + testPrimitive188: primitiveBlock + + | block | + { + {2. {}. SmallInteger >> #even}. "valid 0-arg message" + {2. {1}. Integer >> #<<}. "valid unary message" + {2. {3. 4}. Integer >> #raisedTo:modulo:}. "valid binary message" + {2. 'not an array'. Integer >> #<<}. "invalid arguments" + {2. {'excess arg'}. SmallInteger >> #even}. "too many arguments" + {2. {}. Integer >> #<<}. "missing argument" + {2. {1}. 'not a method'}. "invalid method" + {block := [(primitiveBlock valueWithArguments: {2. {3. 4}. TestObjectForMethod new xxxMethod: thisContext homeMethod}) + allButFirst "OaM selector is undefined behavior"]. {}. block class lookupSelector: #value} "object as method" + } do: [:args | + self + assert: ([primitiveBlock valueWithArguments: args] on: Error do: [:ex | ex description]) + equals: (Context runSimulated: [[primitiveBlock valueWithArguments: args] on: Error do: [:ex | ex description]])].!
Item was added: + ----- Method: ContextTest>>testPrimitive189 (in category 'tests - simulation') ----- + testPrimitive189 + "Test simulation of primitive 118." + + { + [2 executeMethod: SmallInteger >> #even]. "valid 0-arg message" + [2 with: 1 executeMethod: Integer >> #<<]. "valid unary message" + [2 with: 3 with: 4 executeMethod: Integer >> #raisedTo:modulo:]. "valid binary message" + [2 with: 1 executeMethod: Integer >> #even]. "too many arguments" + [2 executeMethod: Integer >> #<<]. "missing argument" + [2 with: 1 executeMethod: 'not a method']. "invalid method" + [(2 with: 3 with: 4 executeMethod: (TestObjectForMethod new xxxMethod: thisContext homeMethod)) + allButFirst "OaM selector is undefined behavior"] "object as method" + } do: [:block | + self + assert: (block on: Error do: [:ex | ex description]) + equals: (Context runSimulated: [block on: Error do: [:ex | ex description]])].!
Item was added: + ----- Method: ContextTest>>testPrimitive218 (in category 'tests') ----- + testPrimitive218 + "Test usage of primitive 218 through simulation." + + self testPrimitive117. + + "Test simulation of primitive 218." + self simulate: [self testPrimitive117].!
Item was changed: + ----- Method: ContextTest>>testPrimitive83 (in category 'tests - simulation') ----- - ----- Method: ContextTest>>testPrimitive83 (in category 'tests') ----- testPrimitive83 + "Test simulation of primitive 83."
+ self flag: #bug. "Known bug: Primitive 83 SPORADICALLY does NOT fail in the OSVM for missing argument!!" + { + [nil perform: #isNil]. "valid 0-arg message" + [nil perform: #= with: true]. "valid unary message" + [nil perform: #ifNil:ifNotNil: with: [2] with: [:x | x]]. "valid binary message" + [nil perform: #isNil with: 'excess arg']. "too many arguments" + [nil perform: #=]. "missing argument" + [nil perform: Object]. "invalid selector" + [[(self class + addSelector: #plonk:with: withMethod: (TestObjectForMethod new xxxMethod: thisContext homeMethod); + perform: #plonk:with: with: 2 with: 3) allButFirst "OaM selector is undefined behavior"] + ensure: [self class removeSelector: #plonk]]. + } do: [:block | - {#isNil}. "valid 0-arg message" - {#=. true}. "valid unary message" - {#ifNil:ifNotNil:. [2]. [:x | x]}. "valid binary message" - {#isNil. 'excess arg'}. "too many arguments" - {#=}. "missing argument" - } do: [:args | self + assert: (block on: Error do: [:ex | ex description]) + equals: (Context runSimulated: [block on: Error do: [:ex | ex description]])].! - assert: (nil tryPrimitive: 83 withArgs: args) - equals: (Context runSimulated: [nil tryPrimitive: 83 withArgs: args])].!
Item was changed: + ----- Method: ContextTest>>testPrimitive84 (in category 'tests - simulation') ----- - ----- Method: ContextTest>>testPrimitive84 (in category 'tests') ----- testPrimitive84 + "Test simulation of primitive 84."
{ {#isNil. {}}. "valid 0-arg message" {#=. {true}}. "valid unary message" {#ifNil:ifNotNil:. {[2]. [:x | x]}}. "valid binary message" - {#isNil}. "missing arguments" {#isNil. 'not an array'}. "invalid arguments" {#isNil. {'excess arg'}}. "too many arguments" {#=. {}}. "missing argument" + {Object. {}}. "invalid selector" + {#in:. + {[:it | + [(self class + addSelector: #plonk:with: withMethod: (TestObjectForMethod new xxxMethod: thisContext homeMethod); + perform: #plonk:with: withArguments: #(2 3)) allButFirst "OaM selector is undefined behavior"] + ensure: [self class removeSelector: #plonk]]}}. } do: [:args | self + assert: ([nil perform: args first withArguments: args second] on: Error do: [:ex | ex description]) + equals: (Context runSimulated: [[nil perform: args first withArguments: args second] on: Error do: [:ex | ex description]])].! - assert: (nil tryPrimitive: 84 withArgs: args) - equals: (Context runSimulated: [nil tryPrimitive: 84 withArgs: args])].!
Item was added: + ----- Method: ContextTest>>testRestartCallPrimitive (in category 'tests') ----- + testRestartCallPrimitive + + | array context start | + array := Array new. + context := [[array at: 1] value] asContext. + [context selector = #at:] whileFalse: [context := context step]. + start := context sender. + + array become: (Array with: 42). + context privRefresh. + context := context stepToSendOrReturn. + + self assert: start equals: context. + self assert: context willReturn. + self assert: 42 equals: context top.!
Item was added: + ----- Method: ContextTest>>testRunUntilErrorOrReturnFromError (in category 'tests') ----- + testRunUntilErrorOrReturnFromError + + | context process result sender error | + process := [result := 1 / 0] newProcess. + process runUntil: [:ctxt | ctxt receiver == self]. + context := process suspendedContext. + sender := context sender. + + result := context runUntilErrorOrReturnFrom: context. + context := result first. + error := result second. + + self assert: (context hasSender: sender). + self assert: (ZeroDivide handles: error). + + process suspendedContext: context. + process runUntil: [:ctxt | ctxt sender isNil]. + self assert: error identical: result.!
Item was added: + ----- Method: ContextTest>>testRunUntilErrorOrReturnFromNoError (in category 'tests') ----- + testRunUntilErrorOrReturnFromNoError + + | context process result sender error | + process := [6 * 7] newProcess. + process runUntil: [:ctxt | ctxt receiver == self]. + context := process suspendedContext. + sender := context sender. + + result := context runUntilErrorOrReturnFrom: context. + context := result first. + error := result second. + + self assert: sender equals: context. + self assert: nil equals: error. + self assert: 42 equals: context top.!
squeak-dev@lists.squeakfoundation.org