I want to inject faults into Pharo methods. Something like
ifTrue:ifFalse:
to ifFalse:ifTrue:
,+
to -
,and:
to or:
,etc.
How could I do this? Are there new/other possibilities in Pharo 3?
Pharo 4 will have a solution for that, but for now you have to do it by hand...
For normal messages like #+, #-, etc... you can modify the literal array of the method, but it won't work for message like #ifTrue:ifFalse: and #ifFalse:ifTrue: because the compiler inlines the code for better performances. One solution is to copy the AST of the method, modify it, compile it and install it in the class. Something like that should work:
FaultInjector>>#replace: aSelector with: anotherSelector in: aCompiledMethod
| newAST |
"Save the original method to restore it later"
replacedMethods add: aCompiledMethod.
"Copy the AST"
newAST := aCompiledMethod ast copy.
"Rewriting the AST"
newAST nodesDo: [ :each |
(each isMessage and: [ each selector = aSelector ])
ifTrue: [ each selector: anotherSelector ] ].
"Compile the AST and install the new method"
aCompiledMethod methodClass
addSelectorSilently: aCompiledMethod selector
withMethod: (newAST generate: aCompiledMethod trailer).
Then you should have a method to restore the methods you replaced:
FaultInjector>>#restore
replacedMethods do: [ :each |
each methodClass
addSelectorSilently: each selector
withMethod: each ].
replacedMethods removeAll