tests/GDBDebuggerTestsR.st
author Jan Vrany <jan.vrany@fit.cvut.cz>
Thu, 05 Jul 2018 13:30:40 +0100
changeset 127 1254cc005f57
parent 126 fb73b0af430b
child 129 661e16236c67
permissions -rw-r--r--
Added support for 'synthetic' frame variables ...i.e., frame variables for which there's no symbol and thus for which no variable object can be created (yet). Therefore we should fetch value and type. To make it simpler, also make `GDBVariable` somewhat polymorph with `GDBVariableObject` so we can use it in frame view (in VDB).

"
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 (using real test programs)         

    [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 := GDBDebugger new.
    self assert: debugger isConnected.

    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: / 12-02-2018 / 22:50:52 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 19-01-2018 / 09:23:24 / jv"
!

test_03
    | inferior1 thread1 |

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

    debugger := GDBDebugger new.
    self assert: debugger isConnected.

    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: / 01-06-2017 / 22:30:03 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 12-01-2018 / 14:53:19 / jv"
!

test_basic_01
    | timeToExit eventPumpProcess eventDispatchProcess|

    debugger := GDBDebugger new.
    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: / 31-05-2017 / 22:42:45 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 12-01-2018 / 15:29:08 / jv"
!

test_breakpoints_01a
    |  |

    debugger := GDBDebugger new.
    self assert: debugger isConnected.

    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: '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>"
!

test_breakpoints_01b
    |  |

    debugger := GDBDebugger new.
    self assert: debugger isConnected.

    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>"
!

test_breakpoints_01c
    |  |

    debugger := GDBDebugger new.
    self assert: debugger isConnected.

    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>"
!

test_breakpoints_03a

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

    debugger := GDBDebugger new.
    self assert: debugger isConnected.

    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: / 11-07-2017 / 11:06:20 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 12-01-2018 / 14:57:37 / jv"
!

test_breakpoints_04a
    debugger := GDBDebugger new.
    self assert: debugger isConnected.

    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 (format): / 11-07-2017 / 23:31:56 / 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 := GDBDebugger new.

    self assert: debugger isConnected.

    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 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: / 23-05-2018 / 10:49:08 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_directories
    | directories current |

    debugger := GDBDebugger new.
    self assert: debugger isConnected.

    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"
!

test_disassembly_01
    | asm |

    debugger := GDBDebugger new.
    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>"
!

test_features

    debugger := GDBDebugger new.
    self assert: debugger isConnected.
    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>"
!

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

    | stack1 stack2 |

    debugger := GDBDebugger new.
    self assert: debugger isConnected.
    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: / 30-01-2018 / 15:54:46 / Jan Vrany <jan.vrany@fit.cvut.cz>"
    "Modified: / 01-02-2018 / 21:04:23 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_stack_02
    | stack1 stack2 |

    debugger := GDBDebugger new.
    self assert: debugger isConnected.
    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: / 15-02-2018 / 09:16:05 / Jan Vrany <jan.vrany@fit.cvut.cz>"
!

test_variables_01
    | thread frame variables d |

    debugger := GDBDebugger new.
    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: / 13-02-2018 / 22:02:20 / 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 := GDBDebugger new.
    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>"
!

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

    debugger := GDBDebugger new.
    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: / 12-02-2018 / 22:36:53 / 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 |

    debugger := GDBDebugger new.
    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: / 13-02-2018 / 10:15: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 := GDBDebugger new.
    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>"
!

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

    debugger := GDBDebugger new.
    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>"
!

test_variables_07
    | stack v1 v2 v3 |

    debugger := GDBDebugger new.
    self assert: debugger isConnected.

    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>"
!

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



    debugger := GDBDebugger new.
    self assert: debugger isConnected.

    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 (comment): / 04-06-2018 / 11:02:19 / 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 := GDBDebugger new.
    self assert: debugger isConnected.

    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>"
!

test_variables_10a
    "
    Test 'synthatic' variables
    "
    | stack |

    debugger := GDBDebugger new.
    self assert: debugger isConnected.

    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>"
! !

!GDBDebuggerTestsR class methodsFor:'documentation'!

version_HG

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