Search code examples
testingsmalltalkpharofault

How to programmatically inject faults into Pharo methods?


I want to inject faults into Pharo methods. Something like

  • change ifTrue:ifFalse: to ifFalse:ifTrue:,
  • change + to -,
  • change and: to or:,

etc.

How could I do this? Are there new/other possibilities in Pharo 3?


Solution

  • 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