tests/GDBDebuggerTestsR.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Thu, 13 Jun 2019 08:05:30 +0100
changeset 192 4f453d7413d4
parent 184 d70c70c3e495
child 208 b0d2028189fa
permissions -rw-r--r--
Fix quoting bug in `#test_directories`

"
jv:libgdbs - GNU Debugger Interface Library
Copyright (C) 2015-now Jan Vrany

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License. 

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
"
"{ Package: 'jv:libgdbs/tests' }"

"{ NameSpace: Smalltalk }"

GDBDebuggerTestCase subclass:#GDBDebuggerTestsR
	instanceVariableNames:''
	classVariableNames:''
	poolDictionaries:''
	category:'GDB-Core-Tests'
!

!GDBDebuggerTestsR class methodsFor:'documentation'!

copyright
"
jv:libgdbs - GNU Debugger Interface Library
Copyright (C) 2015-now Jan Vrany

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License. 

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
"
!

documentation
"
    Tests for GDBDebugger API. 

    # Custom Debugger Setup

    By default, this tests spawns a default, locally run
    debugger for each test (see GDBDebugger >> new). To customize
    the debugger setup, set GDBDebuggerTestsR >> debuggerSetupBlock
    returning a GDBDebugger instance with all the necessary setup 
    done. For example, to use externally run GDB over TCP socket:

     * First, run 'GDB/MI server' (don't confuse with `gdbservver`!!)
       run (in terminal):

           socat TCP4-LISTEN:1234,FORK EXEC:'gdb -i mi2'

     *





    




    [author:]
        Jan Vrany <jan.vrany@fit.cvut.cz>

    [instance variables:]

    [class variables:]

    [see also:]

"
! !

!GDBDebuggerTestsR class methodsFor:'accessing'!

resources
    ^ Array with: GDBDebuggeesResource

    "Created: / 28-02-2015 / 00:45:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!GDBDebuggerTestsR methodsFor:'tests - basic'!

test_02
    | inferior1 thread1 frame1 frame2  seqNo1 seqNo2 |

    debugger executable: GDBDebuggeesResource current binaryFactorial1.
    debugger send: 'b factorial'.

    debugger send: 'r' andWaitFor: GDBStoppedEvent.

    self assert: debugger inferiors size == 1.
    inferior1 := debugger inferiors anElement.
    "/ Windows (starting with Windows 10) introduced a new
    "/ multi-threaded program loader so it can load .dll
    "/ faster, supposedly. Therefore there may be couple other
    "/ threads. Hence in windows, only assert that there is
    "/ at least on thread.
    OperatingSystem isMSWINDOWSlike ifTrue:[
        self assert: inferior1 threads notEmpty.
    ] ifFalse:[ 
        self assert: inferior1 threads size == 1
    ].
    thread1 := inferior1 threads anElement.
    self assert: thread1 stack size == 2.
    self assert: thread1 status isStopped.
    frame1 := thread1 stack first.
    frame2 := thread1 stack second.
    self assert: frame1 variables size == 1.
    self assert: frame1 variables first name = 'i'.
    self assert: frame1 variables first value = '5'.


    self assert: frame2 variables size == 4.
    self assert: frame2 variables first name = 'argc'.
    self assert: frame2 variables second name = 'argv'.
    self assert: frame2 variables third name = 'i'.
    self assert: frame2 variables fourth name = 'f'.

    seqNo1 := debugger currentInferiorStateSequnceNumber.

    debugger send: 'd'.
    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.

    self assert: thread1 isDead.
    seqNo2 := debugger currentInferiorStateSequnceNumber.
    self assert: seqNo1 ~~ seqNo2.

    debugger send: 'quit' andWait: false.

    "Created: / 28-02-2015 / 00:55:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 19-01-2018 / 09:23:24 / jv"
    "Modified: / 18-10-2018 / 10:54:24 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_03
    | inferior1 thread1 |

    self skipIf: OperatingSystem isMSWINDOWSlike  description: 'Skipped since we cannot interact with inferor on Windows (no TTY support)'.

    debugger executable: GDBDebuggeesResource current binaryPressAnyKey.

    debugger send: (GDBMI_exec_run new).

    self assert: debugger inferiors size == 1.
    inferior1 := debugger inferiors anElement.
    self assert: inferior1 threads size == 1.
    thread1 := inferior1 threads anElement.
    self assert: thread1 isRunning.

    debugger send: (GDBMI_exec_interrupt new arguments: #('--all')) andWaitFor: GDBStoppedEvent.

    self assert: thread1 isRunning not.

    debugger inferiorStdin nextPutLine:'X'.  

    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.

    debugger send: 'quit' andWait: false

    "Created: / 08-03-2015 / 07:42:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 12-01-2018 / 14:53:19 / jv"
    "Modified: / 18-10-2018 / 10:55:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_basic_01
    | timeToExit eventPumpProcess eventDispatchProcess|

    timeToExit := 0.
    eventPumpProcess := (debugger instVarNamed: #connection) instVarNamed: #eventPumpProcess.
    eventDispatchProcess := (debugger instVarNamed: #connection) instVarNamed: #eventDispatchProcess.
    self assert: debugger isConnected.
    self assert: eventPumpProcess isDead not.
    self assert: eventDispatchProcess isDead not.
    debugger send: (GDBMI_gdb_exit new) andWait: false.      
    [ debugger isConnected and:[timeToExit < 2000] ] whileTrue:[
        Logger trace:'Still connected...'.
        Delay waitForMilliseconds: 200.  
        timeToExit := timeToExit + 200.
    ].
    self assert: timeToExit < 2000.
    self assert: debugger isConnected not.
    self assert: eventPumpProcess isDead.
    self assert: eventDispatchProcess isDead.

    "Created: / 24-06-2014 / 09:06:32 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 12-01-2018 / 15:29:08 / jv"
    "Modified: / 18-10-2018 / 10:55:06 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_breakpoints_01a
    debugger executable: GDBDebuggeesResource current binaryFactorial1.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'b factorial'.
    self assert: debugger breakpoints size == 1.

    debugger send: 'r' andWaitFor: GDBStoppedEvent.
    self assert: debugger breakpoints size == 1.
    self assert: debugger breakpoints first hasMultipleLocations not.
    self assert: debugger breakpoints first func = 'factorial'.


    debugger send: 'del'.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'quit' andWait: false.

    "Created: / 07-07-2017 / 12:25:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 26-03-2019 / 11:09:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_breakpoints_01b
    debugger executable: GDBDebuggeesResource current binaryFactorial1.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'b factorial'.
    self assert: debugger breakpoints size == 1.

    debugger send: 'r' andWaitFor: GDBStoppedEvent.
    self assert: debugger breakpoints size == 1.
    self assert: debugger breakpoints first func = 'factorial'.


    debugger send: 'dis ', debugger breakpoints anElement number printString.
    self assert: debugger breakpoints size == 1.
    self assert: debugger breakpoints anElement enabled == false.

    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.

    debugger send: 'quit' andWait: false.

    "Created: / 07-07-2017 / 12:27:12 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified (format): / 18-10-2018 / 10:55:23 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_breakpoints_01c
    debugger executable: GDBDebuggeesResource current binaryFactorial1.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'b factorial'.
    self assert: debugger breakpoints size == 1.

    debugger send: 'r' andWaitFor: GDBStoppedEvent.
    self assert: debugger breakpoints size == 1.
    self assert: debugger breakpoints first func = 'factorial'.


    debugger breakpoints anElement enabled: false.
    self assert: debugger breakpoints size == 1.
    self assert: debugger breakpoints anElement enabled == false.

    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.

    debugger send: 'quit' andWait: false.

    "Created: / 07-07-2017 / 12:34:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:55:30 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_breakpoints_02
    debugger executable: GDBDebuggeesResource current binaryFactorial1.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'b main'.
    self assert: debugger breakpoints size == 1.

    debugger send: 'r' andWaitFor: GDBStoppedEvent.
    self assert: debugger breakpoints size == 1.

    debugger send: 'del'.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'quit' andWait: false.

    "Created: / 07-07-2017 / 11:53:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 12-01-2018 / 22:04:46 / jv"
    "Modified: / 18-10-2018 / 10:55:36 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_breakpoints_03a

    self skipIf: OperatingSystem isMSWINDOWSlike  description: 'Skipped since we don;t have separate console TTY (no TTY support)'.

    debugger executable: GDBDebuggeesResource current binaryFactorial1.
    self assert: debugger breakpoints isEmpty.

    debugger consoleInput nextPutLine: 'b factorial'.
    Delay waitForSeconds: 1.  
    self assert: debugger breakpoints size == 1.

    debugger send: 'r' andWaitFor: GDBStoppedEvent.
    self assert: debugger breakpoints size == 1.
    self assert: debugger breakpoints first func = 'factorial'.


    debugger consoleInput nextPutLine: 'del 1'.
    Delay waitForSeconds: 1.  
    self assert: debugger breakpoints isEmpty.

    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'quit' andWait: false.

    "Created: / 10-07-2017 / 22:05:07 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 12-01-2018 / 14:57:37 / jv"
    "Modified: / 18-10-2018 / 10:55:43 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_breakpoints_04a
    debugger executable: GDBDebuggeesResource current binaryFactorial1.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'b factorial'.
    self assert: debugger breakpoints size == 1.

    debugger breakpoints first script: 'printf "factorial\n"
disable ', debugger breakpoints first number asString.

    debugger send: 'r' andWaitFor: GDBStoppedEvent.
    self assert: debugger breakpoints size == 1.
    "/ We need to wait a until breakpoint-modifed
    "/ event is received.
    Delay waitForMilliseconds: 200.  
    self assert: debugger breakpoints first enabled == false.

    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.

    debugger send: 'quit' andWait: false.

    "Created: / 11-07-2017 / 20:35:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:55:51 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_breakpoints_05a
    "
    This tests breakpoints with multiple locations. Due to a bug in
    GDB (up to 8.1), this test fails with stock GDB.

    Patches has been sent to GDB, see:

        * https://sourceware.org/ml/gdb/2018-05/msg00024.html
        * https://sourceware.org/ml/gdb-patches/2018-05/msg00836.html

    Meanwhile, this test is skipped.
    "    

    self skipIf: true description: 'Known to fail due to a bug in GDB'.

    debugger executable: GDBDebuggeesResource current binaryBreakpoints1.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'b add'.
    self assert: debugger breakpoints size == 1.
    self assert: debugger breakpoints first hasMultipleLocations.
    self assert: debugger breakpoints first locations size > 1.
    self assert: debugger breakpoints first enabled.
    self assert: debugger breakpoints first locations first enabled.

    debugger send: 'dis 1'.
    debugger send: 'dis 1.1'.
    self assert: debugger breakpoints first enabled not.
    self assert: debugger breakpoints first locations first enabled not.

    debugger send: 'en 1'.
    debugger send: 'en 1.1'.
    self assert: debugger breakpoints first enabled.
    self assert: debugger breakpoints first locations first enabled.

    debugger breakpoints first enabled: false.
    debugger breakpoints first locations first enabled: false.    
    self assert: debugger breakpoints first enabled not.
    self assert: debugger breakpoints first locations first enabled not.    

    debugger breakpoints first enabled: true.
    debugger breakpoints first locations first enabled: true.    
    self assert: debugger breakpoints first enabled.
    self assert: debugger breakpoints first locations first enabled.    

    debugger send: 'del 1'.
    self assert: debugger breakpoints size == 0.

    debugger send: 'quit' andWait: false.

    "Created: / 18-05-2018 / 10:52:10 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 26-03-2019 / 11:09:21 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_commands

    self assert: (debugger hasCommand: GDBMI_info_gdb_mi_command ).
    self assert: (debugger hasCommand: GDBMI_info_gdb_mi_command new operation).
    self deny: (debugger hasCommand: '-bogus').

    "Created: / 29-12-2018 / 23:13:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_directories
    | directories current |

    directories := debugger directories.
    self assert: directories isArray.
    self assert: directories notEmpty.

    "/ GDB uses cygwin paths, so convert Windows path to Cygwin paths
    "/ on Windows.
    OperatingSystem isMSWINDOWSlike ifTrue:[ 
        current := Filename currentDirectory cygName
    ] ifFalse:[ 
        current := Filename currentDirectory pathName
    ].

    debugger send: ('set directories %1' bindWith: current).
    directories := debugger directories.
    self assert: directories isArray.
    self assert:(directories includes: Filename currentDirectory pathName).

    "Created: / 09-03-2018 / 12:28:53 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 03-04-2018 / 21:08:26 / jv"
    "Modified: / 13-06-2019 / 07:45:22 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_disassembly_01
    | asm |

    debugger executable: GDBDebuggeesResource current binaryFactorial1.
    debugger send: 'r' andWaitFor: GDBThreadGroupExitedEvent.

    asm := debugger disassembleFile: 'factorial1.c' line: 3 count: nil.

    self assert: asm isSequenceable.
    self assert:(asm first isKindOf: GDBInstructionsAndSourceLine).

    debugger send: 'quit' andWait: false.

    "Created: / 22-06-2018 / 11:52:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:56:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_features

    self assert: debugger features isArray.
    self assert: debugger features notEmpty.
    self assert: (debugger hasFeature: debugger features anyOne).
    self assert: (debugger hasFeature: 'bla bla') not.
    self shouldnt:[ debugger ensureFeature: debugger features anyOne ] raise: Error.
    self should:  [ debugger ensureFeature: 'bla bla' ] raise: GDBUnsupportedFeatureError.
    debugger send: 'quit' andWait: false.

    "Created: / 07-02-2018 / 10:56:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:56:28 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_parameters_01
    | event |

    debugger announcer when: GDBCmdParamChangedEvent do:[:ev | event := ev ].

    debugger send: 'set prompt > '.
    self assert: (debugger getParameter: 'prompt') = '> '.
    self assert: event notNil.
    self assert: event name = 'prompt'.
    self assert: event value = '> '.

    event := nil.
    debugger setParameter: 'prompt' to: '$'.
    self assert: (debugger getParameter: 'prompt') = '$'.
    self assert: event notNil.
    self assert: event name = 'prompt'.
    self assert: event value = '$'.

    event := nil.
    debugger send: '-gdb-set prompt X'.
    self assert: (debugger getParameter: 'prompt') = 'X'.
    self assert: event notNil.
    self assert: event name = 'prompt'.
    self assert: event value = 'X'.
    

    debugger send: 'quit' andWait: false.

    "Created: / 19-01-2019 / 22:51:54 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_registers_01a
    | stack rax rip rsp raxValue1 ripValue1 rspValue1 raxValue2 ripValue2 rspValue2 |

    debugger executable: GDBDebuggeesResource current binaryFactorial1.
    debugger send: 'b factorial'.
    debugger send: 'r' andWaitFor: GDBStoppedEvent.
    debugger send: 'c' andWaitFor: GDBStoppedEvent.

    stack := debugger selectedInferior threads first stack.
    self assert: stack size == 3.

    self skipIf: (stack first arch name ~= 'x86_64') description: 'not supported on this architecture'.

    rax := stack first registers detect:[:reg | reg name = 'rax' ].
    rip := stack first registers detect:[:reg | reg name = 'rip' ].
    rsp := stack first registers detect:[:reg | reg name = 'rsp' ].

    self assert: rax hasChanged not.
    self assert: rip hasChanged not.
    self assert: rsp hasChanged not.

    raxValue1 := rax value.
    ripValue1 := rip value.
    rspValue1 := rsp value.

    debugger send: 'stepi' andWaitFor: GDBStoppedEvent.    
    debugger send: 'stepi' andWaitFor: GDBStoppedEvent.    
    debugger send: 'stepi' andWaitFor: GDBStoppedEvent.    
    debugger send: 'stepi' andWaitFor: GDBStoppedEvent.    

    raxValue2 := rax value.
    ripValue2 := rip value.
    rspValue2 := rsp value.

    self assert: raxValue1 ~= raxValue2.
    self assert: ripValue1 ~= ripValue2.
    self assert: rspValue1 = rspValue2.

    self assert: rax hasChanged.
    self assert: rip hasChanged.
    self assert: rsp hasChanged not.


    debugger send: 'd'.
    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
    debugger send: 'quit' andWait: false.

    "Created: / 27-09-2018 / 10:45:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:56:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_stack_01a
    "Tests that stack frames object are preserved amonh run/stop cycles
     if they 're still valid"

    | stack1 stack2 |

    debugger executable: GDBDebuggeesResource current binaryFactorial1.
    debugger send: 'b factorial'.
    debugger send: 'r' andWaitFor: GDBStoppedEvent.

    stack1 := debugger selectedInferior threads first stack.
    debugger send: 'c' andWaitFor: GDBStoppedEvent.
    stack2 := debugger selectedInferior threads first stack.
    self assert: stack1 size == 2.
    self assert: stack2 size == 3.
    self assert: stack1 first  == stack2 second.
    self assert: stack1 second == stack2 third.
    self assert: stack2 first line == 4.
    self assert: stack2 second line == 7.

    stack1 := debugger selectedInferior threads first stack.
    debugger send: 'c' andWaitFor: GDBStoppedEvent.
    stack2 := debugger selectedInferior threads first stack.
    self assert: stack1 size == 3.
    self assert: stack2 size == 4.
    self assert: stack1 first  == stack2 second.
    self assert: stack1 second == stack2 third.
    self assert: stack1 third == stack2 fourth.
    self assert: stack2 first line == 4.
    self assert: stack2 second line == 7.
    self assert: stack2 third line == 7.


    debugger send: 'd'.
    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
    debugger send: 'quit' andWait: false.

    "Created: / 06-08-2018 / 15:06:34 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:56:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_stack_01b
    "Tests that stack frames object are preserved amonh run/stop cycles
     if they 're still valid"

    | stack1 pc1 stack2 pc2 |

    debugger executable: GDBDebuggeesResource current binaryFactorial1.
    debugger send: 'b factorial'.
    debugger send: 'r' andWaitFor: GDBStoppedEvent.

    stack1 := debugger selectedInferior threads first stack.
    pc1 := stack1 first address.
    debugger send: 'stepi' andWaitFor: GDBStoppedEvent.
    stack2 := debugger selectedInferior threads first stack.
    pc2 := stack2 first address.
    self assert: stack1 size == 2.
    self assert: stack2 size == 2.
    self assert: pc1 ~= pc2.
    self assert: stack1 first  == stack1 first.
    self assert: stack1 second == stack2 second.

    debugger send: 'd'.
    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
    debugger send: 'quit' andWait: false.

    "Created: / 06-08-2018 / 15:07:39 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:57:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_stack_02
    | stack1 stack2 |

    debugger executable: GDBDebuggeesResource current binaryVariables1.
    debugger send: 'b set_data_i'.
    debugger send: 'r' andWaitFor: GDBStoppedEvent.

    stack1 := debugger selectedInferior threads first stack.
    debugger send: 'c' andWaitFor: GDBStoppedEvent.
    stack2 := debugger selectedInferior threads first stack.
    self assert: stack1 size == 2.
    self assert: stack2 size == 2.
    self assert: stack1 first ~~ stack2 first.

    debugger send: 'd'.
    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
    debugger send: 'quit' andWait: false.

    "Created: / 12-02-2018 / 21:46:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:57:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_stack_03
    "Tests that CLI commands 'up', 'down' and 'frame' emit GDBThreadSelected event
     and its thread and frame is properly set."

    | stack2 selection |

    debugger executable: GDBDebuggeesResource current binaryFactorial1.
    debugger send: 'b factorial'.
    debugger send: 'r' andWaitFor: GDBStoppedEvent.
    debugger send: 'c' andWaitFor: GDBStoppedEvent.

    stack2 := debugger selectedInferior threads first stack.
    debugger announcer when: GDBThreadSelectedEvent do: [:e | selection := e ].
    selection := nil.
    debugger send: 'up'.
    self assert: selection notNil.
    self assert: selection thread == debugger selectedInferior threads first.
    self assert: selection frame == stack2 second.

    debugger send: 'down'.
    self assert: selection notNil.
    self assert: selection thread == debugger selectedInferior threads first.
    self assert: selection frame == stack2 first.

    debugger send: 'frame 2'.
    self assert: selection notNil.
    self assert: selection thread == debugger selectedInferior threads first.
    self assert: selection frame == stack2 third.

    "Created: / 30-07-2018 / 07:07:48 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:57:50 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_variables_01
    | thread frame variables d |

    debugger executable: GDBDebuggeesResource current binaryVariables1.

    debugger send: 'b main'.
    debugger send: 'r' andWaitFor: GDBStoppedEvent.
    debugger send: 's' andWaitFor: GDBStoppedEvent.

    thread := debugger selectedInferior threads first.
    frame := thread stack first.
    variables :=  frame variables.

    self assert: variables size = 3. "/ argc, argv, d.
    self assert: variables first name = 'argc'.
    self assert: variables first varobj expression = 'argc'.
    self assert: variables first varobj thread == thread.
    self assert: variables first varobj frame == frame.

    self assert: variables second name = 'argv'.
    self assert: variables second varobj expression = 'argv'.

    self assert: variables third name = 'd'.
    self assert: variables third varobj expression = 'd'.

    d := variables third varobj.
    self assert: d hasChildren.
    self assert: d children size = 3.

    self assert: d children first parent == d.
    self assert: d children first hasChildren not.
    self assert: d children first children = #().
    self assert: d children first expression = 'i'.
    self assert: d children first value = '1'.
    self assert: d children first thread == thread.
    self assert: d children first frame == frame.
    

    self assert: d children third hasChildren.
    self assert: d children third children size = 2.
    self assert: d children third children first expression = 'as_i'.
    self assert: d children third children second expression = 'as_f'.

    self assert: d children third children first hasChildren.
    self assert: d children third children first children size = 2.
    self assert: d children third children first children first expression = 'a'.
    self assert: d children third children first children first value = '10'.
    self assert: d children third children first children second expression = 'b'.
    self assert: d children third children first children second value = '20'.
    
    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
    debugger send: 'quit' andWait: false.

    "Created: / 30-01-2018 / 10:27:40 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:57:56 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_variables_02
    "
    This test ensures that GDBVariable objects are preserved
    across multiple run-stop cycles
    "    
    | variables1 variables2 |

    debugger executable: GDBDebuggeesResource current binaryVariables1.

    debugger send: 'b main'.
    debugger send: 'r' andWaitFor: GDBStoppedEvent.
    debugger send: 's' andWaitFor: GDBStoppedEvent.

    variables1 := debugger selectedInferior threads first stack first variables.
    debugger send: 'next' andWaitFor: GDBStoppedEvent.
    variables2 := debugger selectedInferior threads first stack first variables.

    self assert: variables1 size = 3.
    self assert: variables2 size = 3.
    variables1 with: variables2 do:[:var1 :var2 | 
        self assert: var1 == var2    
    ].

    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
    debugger send: 'quit' andWait: false.

    "Created: / 01-02-2018 / 21:45:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:58:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_variables_03
    "
    This test tests GDBVariableObject >> hasChanged
    " 
    | variables d d_i |

    debugger executable: GDBDebuggeesResource current binaryVariables1.

    debugger send: 'b set_data_i'.
    debugger send: 'r' andWaitFor: GDBStoppedEvent.
    debugger send: 'del'.

    self assert: debugger selectedInferior threads first stack second func = 'main'.
    variables := debugger selectedInferior threads first stack second variables.
    self assert: variables third name = 'd'.
    self assert: variables third varobj expression = 'd'.   
    d := variables third varobj.
    self assert: d hasChildren.
    self assert: d expression = 'd'.
    self assert: d children size = 3.   
    d_i := d children first.
    self assert: d_i expression = 'i'.
    self assert: d_i value = '1'.
    self assert: d_i hasChanged not.
    self assert: d_i hasChildren not .   

    debugger selectFrame: debugger selectedInferior threads first stack first.
    debugger send: 'finish' andWaitFor: GDBStoppedEvent.
    self assert: debugger selectedInferior threads first stack first func = 'main'.
    self assert: d_i value = '12'.
    self assert: d_i hasChanged.
    self assert: d_i hasChanged.
    self assert: d_i hasChanged.

    debugger send: 's' andWaitFor: GDBStoppedEvent.
    self assert: d_i value = '12'.
    self assert: d_i hasChanged not.

    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
    debugger send: 'quit' andWait: false.

    "Created: / 01-02-2018 / 21:57:01 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:58:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_variables_04
    "
    Tests that the variable object get's invalid after
    inferior terminated.
    " 
    | variables d d_as_i_a events seqNo1 seqNo2 |

    events := OrderedCollection new.
    debugger announcer when: GDBEvent send: #add: to: events.

    debugger executable: GDBDebuggeesResource current binaryVariables1.


    debugger send: 'b set_data_i'.
    debugger send: 'r' andWaitFor: GDBStoppedEvent.
    seqNo1 := debugger currentInferiorStateSequnceNumber.

    self assert: debugger selectedInferior threads first stack second func = 'main'.
    variables := debugger selectedInferior threads first stack second variables.
    d := variables third varobj.
    self assert: d expression = 'd'.
    self assert: d isValid.
    d_as_i_a := d children third children first children first.
    self assert: d_as_i_a expression = 'a'.
    self assert: d_as_i_a isValid.

    debugger send: 'dis 1'. 
    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
    seqNo2 := debugger currentInferiorStateSequnceNumber.

    self assert: seqNo1 ~~ seqNo2.
    self assert: d isValid not.
    self assert: d value = '<invalid>'.
    self assert: d children isEmpty.
    self assert: d_as_i_a isValid not.    
    self assert: d_as_i_a value = '<invalid>'.
    self assert: debugger isConnected.

    debugger send: 'quit' andWait: false.

    "Created: / 04-02-2018 / 22:04:59 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:58:18 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_variables_05
    "
    Tests that the variable object get's invalid after
    frame returned
    " 
    | variables d |

    debugger executable: GDBDebuggeesResource current binaryVariables1.

    debugger send: 'b set_data_i'.
    debugger send: 'r' andWaitFor: GDBStoppedEvent.

    self assert: debugger selectedInferior threads first stack first func = 'set_data_i'.
    variables := debugger selectedInferior threads first stack first variables.
    d := variables second varobj.
    self assert: d expression = 'i'.
    self assert: d isValid.
    self assert: d inScope.

    debugger send: 'finish' andWaitFor: GDBStoppedEvent.

    self assert: d isValid.
    self assert: d inScope not.
    self assert: d hasChanged.
    self assert: d value = '<out-of-scope>'.

    debugger send: 'continue' andWaitFor: GDBStoppedEvent.  

    self assert: d isValid.
    self assert: d inScope.
    self assert: d hasChanged.
    self assert: d value = '24'.
    self assert: debugger isConnected.

    debugger send: 'quit' andWait: false.

    "Created: / 12-02-2018 / 21:34:04 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:58:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_variables_06
    "
    This test tests GDBVariableObject >> duplicate
    " 
    | variables d1 d_i1 d_i2 |

    debugger executable: GDBDebuggeesResource current binaryVariables1.

    debugger send: 'b set_data_i'.
    debugger send: 'r' andWaitFor: GDBStoppedEvent.
    debugger send: 'del'.

    self assert: debugger selectedInferior threads first stack second func = 'main'.
    variables := debugger selectedInferior threads first stack second variables.
    self assert: variables third name = 'd'.
    self assert: variables third varobj expression = 'd'.   
    d1 := variables third varobj.
    self assert: d1 hasChildren.
    self assert: d1 expression = 'd'.
    self assert: d1 children size = 3.   
    d_i1 := d1 children first.
    self assert: d_i1 expression = 'i'.
    self assert: d_i1 value = '1'.
    self assert: d_i1 hasChanged not.
    self assert: d_i1 hasChildren not .

    d_i2 := d_i1 duplicate.
    self assert: d_i2 expression = '(d).i'.
    self assert: d_i2 path = '(d).i'.
    self assert: d_i2 value = '1'.
    self assert: d_i2 hasChanged not.
    self assert: d_i2 hasChildren not .
    

    debugger selectFrame: debugger selectedInferior threads first stack first.
    debugger send: 'finish' andWaitFor: GDBStoppedEvent.
    self assert: debugger selectedInferior threads first stack first func = 'main'.
    self assert: d_i2 value = '12'.
    self assert: d_i2 hasChanged.
    self assert: d_i2 hasChanged.
    self assert: d_i2 hasChanged.

    debugger send: 's' andWaitFor: GDBStoppedEvent.
    self assert: d_i2 value = '12'.
    self assert: d_i2 hasChanged not.

    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
    debugger send: 'quit' andWait: false.

    "Created: / 13-02-2018 / 22:27:13 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:58:33 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_variables_07
    | stack v1 v2 v3 |

    debugger executable: GDBDebuggeesResource current binaryFactorial1.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'b factorial'.
    self assert: debugger breakpoints size == 1.

    debugger send: 'r' andWaitFor: GDBStoppedEvent.
    debugger send: 'c' andWaitFor: GDBStoppedEvent.

    stack := debugger selectedInferior threads first stack.   

    debugger selectFrame: stack third.
    v1 := debugger evaluate: 'i'  in: stack first.
    v2 := debugger evaluate: 'i'  in: stack second.
    self assert: v1 value = '4'.
    self assert: v2 value = '5'.

    debugger selectFrame: stack first.
    v3 := debugger evaluate: 'i'.
    self assert: v3 value = '4'.  

    debugger send: 'del'.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'c' andWaitFor: GDBThreadGroupExitedEvent.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'quit' andWait: false.

    "Created: / 20-03-2018 / 22:32:00 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:58:42 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_variables_08
    "
    This tests -var-info-path-expression on dynamic varobjs.
    "
    | c1 c1_cdr c1_cdr_cdr |

    debugger executable: GDBDebuggeesResource current binaryPyVarobj.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'source ', ((Smalltalk getPackageDirectoryForPackage:self class package)
            / 'c' / 'py-varobj.py') pathName.
    debugger enablePrettyPrinting.
    debugger send: 'b py-varobj.c:22'.
    debugger send: 'r'.

    c1 := debugger evaluate: '&c1'.
    self assert: c1 isDynamic.
    self assert: c1 path = '&c1'.

    c1_cdr := c1 children second.
    self assert: c1_cdr expression = 'cdr'.
    self assert: c1_cdr isDynamic.
    self assert: c1_cdr parent == c1.
    self should: [ c1_cdr path ] raise: GDBError.

    c1_cdr_cdr := c1_cdr children second.
    self assert: c1_cdr_cdr expression = 'cdr'.
    self assert: c1_cdr_cdr isDynamic.
    self assert: c1_cdr_cdr parent == c1_cdr.
    self should: [ c1_cdr_cdr path ] raise: GDBError.      

    debugger send: 'quit' andWait: false.

    "Created: / 01-06-2018 / 16:27:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:58:50 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_variables_09
    "
    Test #duplicate on children of a dynamic varobj
    "
    | c1 c1_cdr c1_cdr_d  c1_cdr_d_cdr c1_cdr_d_cdr_d |

    debugger executable: GDBDebuggeesResource current binaryPyVarobj.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'source ', ((Smalltalk getPackageDirectoryForPackage:self class package)
            / 'c' / 'py-varobj.py') pathName.
    debugger enablePrettyPrinting.
    debugger send: 'b py-varobj.c:22'.
    debugger send: 'r'.

    c1 := debugger evaluate: '&c1'.
    self assert: c1 isDynamic.
    self assert: c1 path = '&c1'.

    c1_cdr := c1 children second.
    self assert: c1_cdr expression = 'cdr'.
    self assert: c1_cdr isDynamic.
    self assert: c1_cdr parent == c1.

    c1_cdr_d := c1_cdr duplicate.
    self assert: c1_cdr_d ~= c1_cdr.
    self assert: c1_cdr_d parent ~= c1_cdr parent.

    c1_cdr_d_cdr := c1_cdr_d children second.
    self assert: c1_cdr_d_cdr expression = 'cdr'.
    self assert: c1_cdr_d_cdr isDynamic.
    self assert: c1_cdr_d_cdr parent == c1_cdr_d
.
    c1_cdr_d_cdr_d := c1_cdr_d_cdr duplicate.
    self assert: c1_cdr_d_cdr_d ~= c1_cdr_d_cdr.
    self assert: c1_cdr_d_cdr_d parent ~= c1_cdr_d_cdr parent.

    debugger send: 'quit' andWait: false.

    "Created: / 04-06-2018 / 15:08:29 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:58:55 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_variables_10a
    "
    Test 'synthatic' variables
    "
    | stack |

    debugger executable: GDBDebuggeesResource current binaryFactorial1.
    self assert: debugger breakpoints isEmpty.

    debugger send: 'source ', ((Smalltalk getPackageDirectoryForPackage:self class package)
            / 'c' / 'py-framedecorator.py') pathName.
    debugger enableFrameFilters.
    debugger send: 'b factorial'.
    debugger send: 'r' andWaitFor: GDBStoppedEvent.

    stack := debugger selectedInferior threads first stack.
    self assert: stack first variables size == 7.
    self assert: stack first variables first name = 'syntheticArg0'.
    self assert: stack first variables first varobj isNil.
    self assert: stack first variables fourth name = 'i'.
    self assert: stack first variables fourth varobj notNil.
    "
    VDBFrameApplication new
        debugger: debugger;
        frame: stack first;
        open.
    "
    debugger send: 'quit' andWait: false.

    "Created: / 05-07-2018 / 11:48:58 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 18-10-2018 / 10:59:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
! !

!GDBDebuggerTestsR class methodsFor:'documentation'!

version_HG

    ^ '$Changeset: <not expanded> $'
! !