brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.2 KiB · 01ed11a Raw
295 lines · python
1"""tESt the SBCommandInterpreter APIs."""2 3import json4import lldb5from lldbsuite.test.decorators import *6from lldbsuite.test.lldbtest import *7from lldbsuite.test import lldbutil8 9 10class CommandInterpreterAPICase(TestBase):11    NO_DEBUG_INFO_TESTCASE = True12 13    def setUp(self):14        # Call super's setUp().15        TestBase.setUp(self)16        # Find the line number to break on inside main.cpp.17        self.line = line_number("main.c", "Hello world.")18 19    def buildAndCreateTarget(self):20        self.build()21        exe = self.getBuildArtifact("a.out")22 23        # Create a target by the debugger.24        target = self.dbg.CreateTarget(exe)25        self.assertTrue(target, VALID_TARGET)26 27        # Retrieve the associated command interpreter from our debugger.28        ci = self.dbg.GetCommandInterpreter()29        self.assertTrue(ci, VALID_COMMAND_INTERPRETER)30        return ci31 32    def test_with_process_launch_api(self):33        """Test the SBCommandInterpreter APIs."""34        ci = self.buildAndCreateTarget()35 36        # Exercise some APIs....37 38        self.assertTrue(ci.HasCommands())39        self.assertTrue(ci.HasAliases())40        self.assertTrue(ci.HasAliasOptions())41        self.assertTrue(ci.CommandExists("breakpoint"))42        self.assertTrue(ci.CommandExists("target"))43        self.assertTrue(ci.CommandExists("platform"))44        self.assertTrue(ci.AliasExists("file"))45        self.assertTrue(ci.AliasExists("run"))46        self.assertTrue(ci.AliasExists("bt"))47 48        res = lldb.SBCommandReturnObject()49        ci.HandleCommand("breakpoint set -f main.c -l %d" % self.line, res)50        self.assertTrue(res.Succeeded())51        ci.HandleCommand("process launch", res)52        self.assertTrue(res.Succeeded())53 54        # Boundary conditions should not crash lldb!55        self.assertFalse(ci.CommandExists(None))56        self.assertFalse(ci.AliasExists(None))57        ci.HandleCommand(None, res)58        self.assertFalse(res.Succeeded())59        res.AppendMessage("Just appended a message.")60        res.AppendMessage(None)61        if self.TraceOn():62            print(res)63 64        process = ci.GetProcess()65        self.assertTrue(process)66 67        import lldbsuite.test.lldbutil as lldbutil68 69        if process.GetState() != lldb.eStateStopped:70            self.fail(71                "Process should be in the 'stopped' state, "72                "instead the actual state is: '%s'"73                % lldbutil.state_type_to_str(process.GetState())74            )75 76        if self.TraceOn():77            lldbutil.print_stacktraces(process)78 79    def test_command_output(self):80        """Test command output handling."""81        ci = self.dbg.GetCommandInterpreter()82        self.assertTrue(ci, VALID_COMMAND_INTERPRETER)83 84        # Test that a command which produces no output returns "" instead of85        # None.86        res = lldb.SBCommandReturnObject()87        ci.HandleCommand("settings set use-color false", res)88        self.assertTrue(res.Succeeded())89        self.assertIsNotNone(res.GetOutput())90        self.assertEqual(res.GetOutput(), "")91        self.assertIsNotNone(res.GetError())92        self.assertEqual(res.GetError(), "")93 94    def getTranscriptAsPythonObject(self, ci):95        """Retrieve the transcript and convert it into a Python object"""96        structured_data = ci.GetTranscript()97        self.assertTrue(structured_data.IsValid())98 99        stream = lldb.SBStream()100        self.assertTrue(stream)101 102        error = structured_data.GetAsJSON(stream)103        self.assertSuccess(error)104 105        return json.loads(stream.GetData())106 107    def test_get_transcript(self):108        """Test structured transcript generation and retrieval."""109        ci = self.buildAndCreateTarget()110        self.assertTrue(ci, VALID_COMMAND_INTERPRETER)111 112        # Make sure the "save-transcript" setting is on113        self.runCmd("settings set interpreter.save-transcript true")114 115        # Send a few commands through the command interpreter.116        #117        # Using `ci.HandleCommand` because some commands will fail so that we118        # can test the "error" field in the saved transcript.119        res = lldb.SBCommandReturnObject()120        ci.HandleCommand("version", res)121        ci.HandleCommand("an-unknown-command", res)122        ci.HandleCommand("br s -f main.c -l %d" % self.line, res)123        ci.HandleCommand("p a", res)124        ci.HandleCommand("statistics dump", res)125        total_number_of_commands = 6126 127        # Get transcript as python object128        transcript = self.getTranscriptAsPythonObject(ci)129 130        # All commands should have expected fields.131        for command in transcript:132            self.assertIn("command", command)133            # Unresolved commands don't have "commandName"/"commandArguments".134            # We will validate these fields below, instead of here.135            self.assertIn("output", command)136            self.assertIn("error", command)137            self.assertIn("durationInSeconds", command)138            self.assertIn("timestampInEpochSeconds", command)139 140        # The following validates individual commands in the transcript.141        #142        # Notes:143        # 1. Some of the asserts rely on the exact output format of the144        #    commands. Hopefully we are not changing them any time soon.145        # 2. We are removing the time-related fields from each command, so146        #    that some of the validations below can be easier / more readable.147        for command in transcript:148            del command["durationInSeconds"]149            del command["timestampInEpochSeconds"]150 151        # (lldb) version152        self.assertEqual(transcript[0]["command"], "version")153        self.assertEqual(transcript[0]["commandName"], "version")154        self.assertEqual(transcript[0]["commandArguments"], "")155        self.assertIn("lldb version", transcript[0]["output"])156        self.assertEqual(transcript[0]["error"], "")157 158        # (lldb) an-unknown-command159        self.assertEqual(160            transcript[1],161            {162                "command": "an-unknown-command",163                # Unresolved commands don't have "commandName"/"commandArguments"164                "output": "",165                "error": "error: 'an-unknown-command' is not a valid command.\n",166            },167        )168 169        # (lldb) br s -f main.c -l <line>170        self.assertEqual(transcript[2]["command"], "br s -f main.c -l %d" % self.line)171        self.assertEqual(transcript[2]["commandName"], "breakpoint set")172        self.assertEqual(173            transcript[2]["commandArguments"], "-f main.c -l %d" % self.line174        )175        # Breakpoint 1: where = a.out`main + 29 at main.c:5:3, address = 0x0000000100000f7d176        self.assertIn("Breakpoint 1: where = a.out`main ", transcript[2]["output"])177        self.assertEqual(transcript[2]["error"], "")178 179        # (lldb) p a180        self.assertEqual(181            transcript[3],182            {183                "command": "p a",184                "commandName": "dwim-print",185                "commandArguments": "-- a",186                "output": "",187                "error": "note: Falling back to default language. Ran expression as 'Objective C++'.\n"188                "error: <user expression 0>:1:1: use of undeclared identifier 'a'\n    1 | a\n      | ^\n",189            },190        )191 192        # (lldb) statistics dump193        self.assertEqual(transcript[4]["command"], "statistics dump")194        self.assertEqual(transcript[4]["commandName"], "statistics dump")195        self.assertEqual(transcript[4]["commandArguments"], "")196        self.assertEqual(transcript[4]["error"], "")197        statistics_dump = json.loads(transcript[4]["output"])198        # Dump result should be valid JSON199        self.assertTrue(statistics_dump is not json.JSONDecodeError)200        # Dump result should contain expected fields201        self.assertIn("commands", statistics_dump)202        self.assertIn("memory", statistics_dump)203        self.assertIn("modules", statistics_dump)204        self.assertIn("targets", statistics_dump)205 206    def test_save_transcript_setting_default(self):207        ci = self.dbg.GetCommandInterpreter()208        self.assertTrue(ci, VALID_COMMAND_INTERPRETER)209 210        # The setting's default value should be "false"211        self.runCmd(212            "settings show interpreter.save-transcript",213            "interpreter.save-transcript (boolean) = false\n",214        )215 216    def test_save_transcript_setting_off(self):217        ci = self.dbg.GetCommandInterpreter()218        self.assertTrue(ci, VALID_COMMAND_INTERPRETER)219 220        # Make sure the setting is off221        self.runCmd("settings set interpreter.save-transcript false")222 223        # The transcript should be empty after running a command224        self.runCmd("version")225        transcript = self.getTranscriptAsPythonObject(ci)226        self.assertEqual(transcript, [])227 228    def test_save_transcript_setting_on(self):229        ci = self.dbg.GetCommandInterpreter()230        self.assertTrue(ci, VALID_COMMAND_INTERPRETER)231 232        # Make sure the setting is on233        self.runCmd("settings set interpreter.save-transcript true")234 235        # The transcript should contain one item after running a command236        self.runCmd("version")237        transcript = self.getTranscriptAsPythonObject(ci)238        self.assertEqual(len(transcript), 1)239        self.assertEqual(transcript[0]["command"], "version")240 241    def test_get_transcript_returns_copy(self):242        """243        Test that the returned structured data is *at least* a shallow copy.244 245        We believe that a deep copy *is* performed in `SBCommandInterpreter::GetTranscript`.246        However, the deep copy cannot be tested and doesn't need to be tested,247        because there is no logic in the command interpreter to modify a248        transcript item (representing a command) after it has been returned.249        """250        ci = self.dbg.GetCommandInterpreter()251        self.assertTrue(ci, VALID_COMMAND_INTERPRETER)252 253        # Make sure the setting is on254        self.runCmd("settings set interpreter.save-transcript true")255 256        # Run commands and get the transcript as structured data257        self.runCmd("version")258        structured_data_1 = ci.GetTranscript()259        self.assertTrue(structured_data_1.IsValid())260        self.assertEqual(structured_data_1.GetSize(), 1)261        self.assertEqual(262            structured_data_1.GetItemAtIndex(0)263            .GetValueForKey("command")264            .GetStringValue(100),265            "version",266        )267 268        # Run some more commands and get the transcript as structured data again269        self.runCmd("help")270        structured_data_2 = ci.GetTranscript()271        self.assertTrue(structured_data_2.IsValid())272        self.assertEqual(structured_data_2.GetSize(), 2)273        self.assertEqual(274            structured_data_2.GetItemAtIndex(0)275            .GetValueForKey("command")276            .GetStringValue(100),277            "version",278        )279        self.assertEqual(280            structured_data_2.GetItemAtIndex(1)281            .GetValueForKey("command")282            .GetStringValue(100),283            "help",284        )285 286        # Now, the first structured data should remain unchanged287        self.assertTrue(structured_data_1.IsValid())288        self.assertEqual(structured_data_1.GetSize(), 1)289        self.assertEqual(290            structured_data_1.GetItemAtIndex(0)291            .GetValueForKey("command")292            .GetStringValue(100),293            "version",294        )295