diff options
Diffstat (limited to 'lldb')
45 files changed, 853 insertions, 214 deletions
diff --git a/lldb/docs/resources/test.rst b/lldb/docs/resources/test.rst index 5275786..2b0e901 100644 --- a/lldb/docs/resources/test.rst +++ b/lldb/docs/resources/test.rst @@ -17,8 +17,8 @@ The LLDB test suite consists of three different kinds of test: the output. * **API tests**: Integration tests that interact with the debugger through the SB API. These are written in Python and use LLDB's ``dotest.py`` testing - framework on top of Python's `unittest2 - <https://docs.python.org/2/library/unittest.html>`_. + framework on top of Python's `unittest + <https://docs.python.org/3/library/unittest.html>`_. All three test suites use ``lit`` (`LLVM Integrated Tester <https://llvm.org/docs/CommandGuide/lit.html>`_ ) as the test driver. The test @@ -94,7 +94,7 @@ programs from source, run them, and debug the processes. As mentioned before, ``dotest.py`` is LLDB's testing framework. The implementation is located under ``lldb/packages/Python/lldbsuite``. We have several extensions and custom test primitives on top of what's offered by -`unittest2 <https://docs.python.org/2/library/unittest.html>`_. Those can be +`unittest <https://docs.python.org/3/library/unittest.html>`_. Those can be found in `lldbtest.py <https://github.com/llvm/llvm-project/blob/main/lldb/packages/Python/lldbsuite/test/lldbtest.py>`_. @@ -146,7 +146,7 @@ the test should be run or not. :: - @expectedFailure(checking_function_name) + @skipTestIfFn(checking_function_name) In addition to providing a lot more flexibility when it comes to writing the test, the API test also allow for much more complex scenarios when it comes to diff --git a/lldb/docs/testsuite/a-detailed-walkthrough.txt b/lldb/docs/testsuite/a-detailed-walkthrough.txt index 57c9dbc..8a70437 100644 --- a/lldb/docs/testsuite/a-detailed-walkthrough.txt +++ b/lldb/docs/testsuite/a-detailed-walkthrough.txt @@ -58,16 +58,15 @@ display their output. For brevity, the '-t' output is not included here. Notice the 'expected failures=1' message at the end of the run. This is because of a bug currently in lldb such that setting target.process.output-path to 'stdout.txt' does not have any effect on the redirection of the standard output -of the subsequent launched process. We are using unittest2 (a backport of new -unittest features for Python 2.4-2.6) to decorate (mark) the particular test -method as such: +of the subsequent launched process. We are using unittest to decorate (mark) +the particular test method as such: - @unittest2.expectedFailure + @unittest.expectedFailure # rdar://problem/8435794 # settings set target.process.output-path does not seem to work def test_set_output_path(self): -See http://pypi.python.org/pypi/unittest2 for more details. +See http://docs.python.org/library/unittest.html for more details. Now let's look inside the test method: diff --git a/lldb/include/lldb/Interpreter/OptionValueSInt64.h b/lldb/include/lldb/Interpreter/OptionValueSInt64.h index 5efae62..3cf41d3 100644 --- a/lldb/include/lldb/Interpreter/OptionValueSInt64.h +++ b/lldb/include/lldb/Interpreter/OptionValueSInt64.h @@ -86,8 +86,8 @@ public: protected: int64_t m_current_value = 0; int64_t m_default_value = 0; - int64_t m_min_value = INT64_MIN; - int64_t m_max_value = INT64_MAX; + int64_t m_min_value = std::numeric_limits<int64_t>::min(); + int64_t m_max_value = std::numeric_limits<int64_t>::max(); }; } // namespace lldb_private diff --git a/lldb/include/lldb/Interpreter/OptionValueUInt64.h b/lldb/include/lldb/Interpreter/OptionValueUInt64.h index 30c27bf..0707607 100644 --- a/lldb/include/lldb/Interpreter/OptionValueUInt64.h +++ b/lldb/include/lldb/Interpreter/OptionValueUInt64.h @@ -64,13 +64,35 @@ public: uint64_t GetDefaultValue() const { return m_default_value; } - void SetCurrentValue(uint64_t value) { m_current_value = value; } + bool SetCurrentValue(uint64_t value) { + if (value >= m_min_value && value <= m_max_value) { + m_current_value = value; + return true; + } + return false; + } + + bool SetDefaultValue(uint64_t value) { + if (value >= m_min_value && value <= m_max_value) { + m_default_value = value; + return true; + } + return false; + } + + void SetMinimumValue(int64_t v) { m_min_value = v; } + + uint64_t GetMinimumValue() const { return m_min_value; } + + void SetMaximumValue(int64_t v) { m_max_value = v; } - void SetDefaultValue(uint64_t value) { m_default_value = value; } + uint64_t GetMaximumValue() const { return m_max_value; } protected: uint64_t m_current_value = 0; uint64_t m_default_value = 0; + uint64_t m_min_value = std::numeric_limits<uint64_t>::min(); + uint64_t m_max_value = std::numeric_limits<uint64_t>::max(); }; } // namespace lldb_private diff --git a/lldb/include/lldb/Interpreter/Options.h b/lldb/include/lldb/Interpreter/Options.h index bf74927..18a87e4 100644 --- a/lldb/include/lldb/Interpreter/Options.h +++ b/lldb/include/lldb/Interpreter/Options.h @@ -336,6 +336,39 @@ public: bool m_did_finalize = false; }; +/// Creates an error that represents the failure to parse an command line option +/// argument. This creates an error containing all information needed to show +/// the developer what went wrong when parsing their command. It is recommended +/// to use this instead of writing an error by hand. +/// +/// \param[in] option_arg +/// The argument that was attempted to be parsed. +/// +/// \param[in] short_option +/// The short form of the option. For example, if the flag is -f, the short +/// option is "f". +/// +/// \param[in] long_option +/// The long form of the option. This field is optional. If the flag is +/// --force, then the long option is "force". +/// +/// \param[in] additional_context +/// This is extra context that will get included in the error. This field is +/// optional. +/// +/// \return +/// An llvm::Error that contains a standardized format for what went wrong +/// when parsing and why. +llvm::Error CreateOptionParsingError(llvm::StringRef option_arg, + const char short_option, + llvm::StringRef long_option = {}, + llvm::StringRef additional_context = {}); + +static constexpr llvm::StringLiteral g_bool_parsing_error_message = + "Failed to parse as boolean"; +static constexpr llvm::StringLiteral g_int_parsing_error_message = + "Failed to parse as integer"; + } // namespace lldb_private #endif // LLDB_INTERPRETER_OPTIONS_H diff --git a/lldb/packages/Python/lldbsuite/test/README-TestSuite b/lldb/packages/Python/lldbsuite/test/README-TestSuite index f76e836..388f94d 100644 --- a/lldb/packages/Python/lldbsuite/test/README-TestSuite +++ b/lldb/packages/Python/lldbsuite/test/README-TestSuite @@ -91,20 +91,6 @@ to the Python test suite under the current 'test' directory. Contains platform specific plugin to build binaries with dsym/dwarf debugging info. Other platform specific functionalities may be added in the future. -- unittest2 directory - - Many new features were added to unittest in Python 2.7, including test - discovery. unittest2 allows you to use these features with earlier versions of - Python. - - It currently has unittest2 0.5.1 from http://pypi.python.org/pypi/unittest2. - Version 0.5.1 of unittest2 has feature parity with unittest in Python 2.7 - final. If you want to ensure that your tests run identically under unittest2 - and unittest in Python 2.7 you should use unittest2 0.5.1. - - Later versions of unittest2 include changes in unittest made in Python 3.2 and - onwards after the release of Python 2.7. - - Profiling dotest.py runs I used the following command line thingy to do the profiling on a SnowLeopard diff --git a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py index bb863bb..27a76a6 100644 --- a/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py +++ b/lldb/packages/Python/lldbsuite/test/tools/lldb-dap/dap_server.py @@ -501,6 +501,18 @@ class DebugCommunication(object): return variable["value"] return None + def get_local_variable_child(self, name, child_name, frameIndex=0, threadId=None): + local = self.get_local_variable(name, frameIndex, threadId) + if local["variablesReference"] == 0: + return None + children = self.request_variables(local["variablesReference"])["body"][ + "variables" + ] + for child in children: + if child["name"] == child_name: + return child + return None + def replay_packets(self, replay_file_path): f = open(replay_file_path, "r") mode = "invalid" @@ -895,6 +907,41 @@ class DebugCommunication(object): } return self.send_recv(command_dict) + def request_dataBreakpointInfo( + self, variablesReference, name, frameIndex=0, threadId=None + ): + stackFrame = self.get_stackFrame(frameIndex=frameIndex, threadId=threadId) + if stackFrame is None: + return [] + args_dict = { + "variablesReference": variablesReference, + "name": name, + "frameId": stackFrame["id"], + } + command_dict = { + "command": "dataBreakpointInfo", + "type": "request", + "arguments": args_dict, + } + return self.send_recv(command_dict) + + def request_setDataBreakpoint(self, dataBreakpoints): + """dataBreakpoints is a list of dictionary with following fields: + { + dataId: (address in hex)/(size in bytes) + accessType: read/write/readWrite + [condition]: string + [hitCondition]: string + } + """ + args_dict = {"breakpoints": dataBreakpoints} + command_dict = { + "command": "setDataBreakpoints", + "type": "request", + "arguments": args_dict, + } + return self.send_recv(command_dict) + def request_compileUnits(self, moduleId): args_dict = {"moduleId": moduleId} command_dict = { diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp index 3fdf5cd..fc22176 100644 --- a/lldb/source/Commands/CommandObjectBreakpoint.cpp +++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp @@ -64,6 +64,8 @@ public: Status error; const int short_option = g_breakpoint_modify_options[option_idx].short_option; + const char *long_option = + g_breakpoint_modify_options[option_idx].long_option; switch (short_option) { case 'c': @@ -84,18 +86,17 @@ public: case 'G': { bool value, success; value = OptionArgParser::ToBoolean(option_arg, false, &success); - if (success) { + if (success) m_bp_opts.SetAutoContinue(value); - } else - error.SetErrorStringWithFormat( - "invalid boolean value '%s' passed for -G option", - option_arg.str().c_str()); + else + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_bool_parsing_error_message); } break; case 'i': { uint32_t ignore_count; if (option_arg.getAsInteger(0, ignore_count)) - error.SetErrorStringWithFormat("invalid ignore count '%s'", - option_arg.str().c_str()); + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_int_parsing_error_message); else m_bp_opts.SetIgnoreCount(ignore_count); } break; @@ -105,27 +106,29 @@ public: if (success) { m_bp_opts.SetOneShot(value); } else - error.SetErrorStringWithFormat( - "invalid boolean value '%s' passed for -o option", - option_arg.str().c_str()); + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_bool_parsing_error_message); } break; case 't': { lldb::tid_t thread_id = LLDB_INVALID_THREAD_ID; if (option_arg == "current") { if (!execution_context) { - error.SetErrorStringWithFormat("No context to determine current " - "thread"); + error = CreateOptionParsingError( + option_arg, short_option, long_option, + "No context to determine current thread"); } else { ThreadSP ctx_thread_sp = execution_context->GetThreadSP(); if (!ctx_thread_sp || !ctx_thread_sp->IsValid()) { - error.SetErrorStringWithFormat("No currently selected thread"); + error = + CreateOptionParsingError(option_arg, short_option, long_option, + "No currently selected thread"); } else { thread_id = ctx_thread_sp->GetID(); } } } else if (option_arg.getAsInteger(0, thread_id)) { - error.SetErrorStringWithFormat("invalid thread id string '%s'", - option_arg.str().c_str()); + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_int_parsing_error_message); } if (thread_id != LLDB_INVALID_THREAD_ID) m_bp_opts.SetThreadID(thread_id); @@ -139,8 +142,8 @@ public: case 'x': { uint32_t thread_index = UINT32_MAX; if (option_arg.getAsInteger(0, thread_index)) { - error.SetErrorStringWithFormat("invalid thread index string '%s'", - option_arg.str().c_str()); + error = CreateOptionParsingError(option_arg, short_option, long_option, + g_int_parsing_error_message); } else { m_bp_opts.GetThreadSpec()->SetIndex(thread_index); } diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td index 4cfff80..a6cb951 100644 --- a/lldb/source/Core/CoreProperties.td +++ b/lldb/source/Core/CoreProperties.td @@ -132,7 +132,7 @@ let Definition = "debugger" in { Global, DefaultStringValue<"${ansi.normal}">, Desc<"When displaying the line marker in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the line to be marked.">; - def TerminalWidth: Property<"term-width", "SInt64">, + def TerminalWidth: Property<"term-width", "UInt64">, Global, DefaultUnsignedValue<80>, Desc<"The maximum number of columns to use for displaying text.">; diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 97311b4..c3e603d 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -365,7 +365,7 @@ bool Debugger::SetREPLLanguage(lldb::LanguageType repl_lang) { uint64_t Debugger::GetTerminalWidth() const { const uint32_t idx = ePropertyTerminalWidth; - return GetPropertyAtIndexAs<int64_t>( + return GetPropertyAtIndexAs<uint64_t>( idx, g_debugger_properties[idx].default_uint_value); } @@ -886,8 +886,8 @@ Debugger::Debugger(lldb::LogOutputCallback log_callback, void *baton) } assert(m_dummy_target_sp.get() && "Couldn't construct dummy target?"); - OptionValueSInt64 *term_width = - m_collection_sp->GetPropertyAtIndexAsOptionValueSInt64( + OptionValueUInt64 *term_width = + m_collection_sp->GetPropertyAtIndexAsOptionValueUInt64( ePropertyTerminalWidth); term_width->SetMinimumValue(10); term_width->SetMaximumValue(1024); diff --git a/lldb/source/Interpreter/OptionValueUInt64.cpp b/lldb/source/Interpreter/OptionValueUInt64.cpp index 1999c63..2e69c16 100644 --- a/lldb/source/Interpreter/OptionValueUInt64.cpp +++ b/lldb/source/Interpreter/OptionValueUInt64.cpp @@ -47,9 +47,16 @@ Status OptionValueUInt64::SetValueFromString(llvm::StringRef value_ref, llvm::StringRef value_trimmed = value_ref.trim(); uint64_t value; if (llvm::to_integer(value_trimmed, value)) { - m_value_was_set = true; - m_current_value = value; - NotifyValueChanged(); + if (value >= m_min_value && value <= m_max_value) { + m_value_was_set = true; + m_current_value = value; + NotifyValueChanged(); + } else { + error.SetErrorStringWithFormat( + "%" PRIu64 " is out of range, valid values must be between %" PRIu64 + " and %" PRIu64 ".", + value, m_min_value, m_max_value); + } } else { error.SetErrorStringWithFormat("invalid uint64_t string value: '%s'", value_ref.str().c_str()); diff --git a/lldb/source/Interpreter/Options.cpp b/lldb/source/Interpreter/Options.cpp index 89fe690..51b7e6b 100644 --- a/lldb/source/Interpreter/Options.cpp +++ b/lldb/source/Interpreter/Options.cpp @@ -1365,3 +1365,16 @@ llvm::Expected<Args> Options::Parse(const Args &args, argv.erase(argv.begin(), argv.begin() + OptionParser::GetOptionIndex()); return ReconstituteArgsAfterParsing(argv, args); } + +llvm::Error lldb_private::CreateOptionParsingError( + llvm::StringRef option_arg, const char short_option, + llvm::StringRef long_option, llvm::StringRef additional_context) { + std::string buffer; + llvm::raw_string_ostream stream(buffer); + stream << "Invalid value ('" << option_arg << "') for -" << short_option; + if (!long_option.empty()) + stream << " (" << long_option << ")"; + if (!additional_context.empty()) + stream << ": " << additional_context; + return llvm::createStringError(llvm::inconvertibleErrorCode(), buffer); +} diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 23a8a66..137795c 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -2937,14 +2937,11 @@ void Process::CompleteAttach() { DidAttach(process_arch); if (process_arch.IsValid()) { + LLDB_LOG(log, + "Process::{0} replacing process architecture with DidAttach() " + "architecture: \"{1}\"", + __FUNCTION__, process_arch.GetTriple().getTriple()); GetTarget().SetArchitecture(process_arch); - if (log) { - const char *triple_str = process_arch.GetTriple().getTriple().c_str(); - LLDB_LOGF(log, - "Process::%s replacing process architecture with DidAttach() " - "architecture: %s", - __FUNCTION__, triple_str ? triple_str : "<null>"); - } } // We just attached. If we have a platform, ask it for the process diff --git a/lldb/test/API/commands/expression/call-throws/TestCallThatThrows.py b/lldb/test/API/commands/expression/call-throws/TestCallThatThrows.py index 2868ec5..b8cc87c 100644 --- a/lldb/test/API/commands/expression/call-throws/TestCallThatThrows.py +++ b/lldb/test/API/commands/expression/call-throws/TestCallThatThrows.py @@ -46,7 +46,7 @@ class ExprCommandWithThrowTestCase(TestBase): value = frame.EvaluateExpression("[my_class callMeIThrow]", options) self.assertTrue(value.IsValid()) - self.assertEqual(value.GetError().Success(), False) + self.assertFalse(value.GetError().Success()) self.check_after_call() diff --git a/lldb/test/API/commands/expression/dont_allow_jit/TestAllowJIT.py b/lldb/test/API/commands/expression/dont_allow_jit/TestAllowJIT.py index 307d452..eb812f1 100644 --- a/lldb/test/API/commands/expression/dont_allow_jit/TestAllowJIT.py +++ b/lldb/test/API/commands/expression/dont_allow_jit/TestAllowJIT.py @@ -54,7 +54,7 @@ class TestAllowJIT(TestBase): # First make sure we can call the function with the default option set. options = lldb.SBExpressionOptions() # Check that the default is to allow JIT: - self.assertEqual(options.GetAllowJIT(), True, "Default is true") + self.assertTrue(options.GetAllowJIT(), "Default is true") # Now use the options: result = frame.EvaluateExpression("call_me(10)", options) @@ -64,9 +64,7 @@ class TestAllowJIT(TestBase): # Now disallow JIT and make sure it fails: options.SetAllowJIT(False) # Check that we got the right value: - self.assertEqual( - options.GetAllowJIT(), False, "Got False after setting to False" - ) + self.assertFalse(options.GetAllowJIT(), "Got False after setting to False") # Again use it and ensure we fail: result = frame.EvaluateExpression("call_me(10)", options) @@ -79,7 +77,7 @@ class TestAllowJIT(TestBase): # Finally set the allow JIT value back to true and make sure that works: options.SetAllowJIT(True) - self.assertEqual(options.GetAllowJIT(), True, "Set back to True correctly") + self.assertTrue(options.GetAllowJIT(), "Set back to True correctly") # And again, make sure this works: result = frame.EvaluateExpression("call_me(10)", options) diff --git a/lldb/test/API/commands/settings/TestSettings.py b/lldb/test/API/commands/settings/TestSettings.py index a2d8454..104a9f0 100644 --- a/lldb/test/API/commands/settings/TestSettings.py +++ b/lldb/test/API/commands/settings/TestSettings.py @@ -2,7 +2,6 @@ Test lldb settings command. """ - import json import os import re @@ -151,14 +150,22 @@ class SettingsCommandTestCase(TestBase): self.expect( "settings show term-width", SETTING_MSG("term-width"), - startstr="term-width (int) = 70", + startstr="term-width (unsigned) = 70", ) # The overall display should also reflect the new setting. self.expect( "settings show", SETTING_MSG("term-width"), - substrs=["term-width (int) = 70"], + substrs=["term-width (unsigned) = 70"], + ) + + self.dbg.SetTerminalWidth(60) + + self.expect( + "settings show", + SETTING_MSG("term-width"), + substrs=["term-width (unsigned) = 60"], ) # rdar://problem/10712130 @@ -593,7 +600,7 @@ class SettingsCommandTestCase(TestBase): self.expect( "settings show term-width", SETTING_MSG("term-width"), - startstr="term-width (int) = 60", + startstr="term-width (unsigned) = 60", ) self.runCmd("settings clear term-width", check=False) # string diff --git a/lldb/test/API/commands/statistics/basic/TestStats.py b/lldb/test/API/commands/statistics/basic/TestStats.py index 6f08322..fb6fc07 100644 --- a/lldb/test/API/commands/statistics/basic/TestStats.py +++ b/lldb/test/API/commands/statistics/basic/TestStats.py @@ -35,17 +35,13 @@ class TestCase(TestBase): ) def verify_key_in_dict(self, key, d, description): - self.assertEqual( - key in d, - True, - 'make sure key "%s" is in dictionary %s' % (key, description), + self.assertIn( + key, d, 'make sure key "%s" is in dictionary %s' % (key, description) ) def verify_key_not_in_dict(self, key, d, description): - self.assertEqual( - key in d, - False, - 'make sure key "%s" is in dictionary %s' % (key, description), + self.assertNotIn( + key, d, 'make sure key "%s" is in dictionary %s' % (key, description) ) def verify_keys(self, dict, description, keys_exist, keys_missing=None): @@ -120,9 +116,7 @@ class TestCase(TestBase): self.verify_success_fail_count(stats, "frameVariable", 1, 0) # Test that "stopCount" is available when the process has run - self.assertEqual( - "stopCount" in stats, True, 'ensure "stopCount" is in target JSON' - ) + self.assertIn("stopCount", stats, 'ensure "stopCount" is in target JSON') self.assertGreater( stats["stopCount"], 0, 'make sure "stopCount" is greater than zero' ) @@ -484,9 +478,9 @@ class TestCase(TestBase): exe = self.getBuildArtifact(exe_name) dsym = self.getBuildArtifact(exe_name + ".dSYM") # Make sure the executable file exists after building. - self.assertEqual(os.path.exists(exe), True) + self.assertTrue(os.path.exists(exe)) # Make sure the dSYM file exists after building. - self.assertEqual(os.path.isdir(dsym), True) + self.assertTrue(os.path.isdir(dsym)) # Create the target target = self.createTestTarget(file_path=exe) @@ -532,9 +526,9 @@ class TestCase(TestBase): exe = self.getBuildArtifact(exe_name) dsym = self.getBuildArtifact(exe_name + ".dSYM") # Make sure the executable file exists after building. - self.assertEqual(os.path.exists(exe), True) + self.assertTrue(os.path.exists(exe)) # Make sure the dSYM file doesn't exist after building. - self.assertEqual(os.path.isdir(dsym), False) + self.assertFalse(os.path.isdir(dsym)) # Create the target target = self.createTestTarget(file_path=exe) @@ -585,11 +579,11 @@ class TestCase(TestBase): dsym = self.getBuildArtifact(exe_name + ".dSYM") main_obj = self.getBuildArtifact("main.o") # Make sure the executable file exists after building. - self.assertEqual(os.path.exists(exe), True) + self.assertTrue(os.path.exists(exe)) # Make sure the dSYM file doesn't exist after building. - self.assertEqual(os.path.isdir(dsym), False) + self.assertFalse(os.path.isdir(dsym)) # Make sure the main.o object file exists after building. - self.assertEqual(os.path.exists(main_obj), True) + self.assertTrue(os.path.exists(main_obj)) # Delete the main.o file that contains the debug info so we force an # error when we run to main and try to get variables @@ -604,7 +598,7 @@ class TestCase(TestBase): # Make sure we have "debugInfoHadVariableErrors" variable that is set to # false before failing to get local variables due to missing .o file. - self.assertEqual(exe_stats["debugInfoHadVariableErrors"], False) + self.assertFalse(exe_stats["debugInfoHadVariableErrors"]) # Verify that the top level statistic that aggregates the number of # modules with debugInfoHadVariableErrors is zero @@ -624,7 +618,7 @@ class TestCase(TestBase): # Make sure we have "hadFrameVariableErrors" variable that is set to # true after failing to get local variables due to missing .o file. - self.assertEqual(exe_stats["debugInfoHadVariableErrors"], True) + self.assertTrue(exe_stats["debugInfoHadVariableErrors"]) # Verify that the top level statistic that aggregates the number of # modules with debugInfoHadVariableErrors is greater than zero diff --git a/lldb/test/API/commands/trace/TestTraceSave.py b/lldb/test/API/commands/trace/TestTraceSave.py index ef1ab2f..af38669 100644 --- a/lldb/test/API/commands/trace/TestTraceSave.py +++ b/lldb/test/API/commands/trace/TestTraceSave.py @@ -179,11 +179,11 @@ class TestTraceSave(TraceIntelPTTestCaseBase): res = lldb.SBCommandReturnObject() ci.HandleCommand("thread trace dump instructions -c 10 --forwards", res) - self.assertEqual(res.Succeeded(), True) + self.assertTrue(res.Succeeded()) first_ten_instructions = res.GetOutput() ci.HandleCommand("thread trace dump instructions -c 10", res) - self.assertEqual(res.Succeeded(), True) + self.assertTrue(res.Succeeded()) last_ten_instructions = res.GetOutput() # Now, save the trace to <trace_copy_dir> @@ -203,11 +203,11 @@ class TestTraceSave(TraceIntelPTTestCaseBase): # Compare with instructions saved at the first time ci.HandleCommand("thread trace dump instructions -c 10 --forwards", res) - self.assertEqual(res.Succeeded(), True) + self.assertTrue(res.Succeeded()) self.assertEqual(res.GetOutput(), first_ten_instructions) ci.HandleCommand("thread trace dump instructions -c 10", res) - self.assertEqual(res.Succeeded(), True) + self.assertTrue(res.Succeeded()) self.assertEqual(res.GetOutput(), last_ten_instructions) def testSaveKernelTrace(self): diff --git a/lldb/test/API/functionalities/breakpoint/address_breakpoints/TestBadAddressBreakpoints.py b/lldb/test/API/functionalities/breakpoint/address_breakpoints/TestBadAddressBreakpoints.py index 0ab11a4..d120692 100644 --- a/lldb/test/API/functionalities/breakpoint/address_breakpoints/TestBadAddressBreakpoints.py +++ b/lldb/test/API/functionalities/breakpoint/address_breakpoints/TestBadAddressBreakpoints.py @@ -40,7 +40,7 @@ class BadAddressBreakpointTestCase(TestBase): bkpt = target.BreakpointCreateByAddress(illegal_address) # Verify that breakpoint is not resolved. for bp_loc in bkpt: - self.assertEqual(bp_loc.IsResolved(), False) + self.assertFalse(bp_loc.IsResolved()) else: self.fail( "Could not find an illegal address at which to set a bad breakpoint." diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py b/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py index 620f648..ea24295 100644 --- a/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py +++ b/lldb/test/API/functionalities/breakpoint/breakpoint_command/TestBreakpointCommand.py @@ -572,9 +572,9 @@ class BreakpointCommandTestCase(TestBase): res = target.GetStatistics().GetAsJSON(stream) self.assertTrue(res.Success()) debug_stats = json.loads(stream.GetData()) - self.assertEqual( - "targets" in debug_stats, - True, + self.assertIn( + "targets", + debug_stats, 'Make sure the "targets" key in in target.GetStatistics()', ) target_stats = debug_stats["targets"][0] @@ -659,9 +659,9 @@ class BreakpointCommandTestCase(TestBase): res = target.GetStatistics().GetAsJSON(stream) self.assertTrue(res.Success()) debug_stats = json.loads(stream.GetData()) - self.assertEqual( - "targets" in debug_stats, - True, + self.assertIn( + "targets", + debug_stats, 'Make sure the "targets" key in in target.GetStatistics()', ) target_stats = debug_stats["targets"][0] diff --git a/lldb/test/API/functionalities/breakpoint/breakpoint_names/TestBreakpointNames.py b/lldb/test/API/functionalities/breakpoint/breakpoint_names/TestBreakpointNames.py index 330f916..0f9510c 100644 --- a/lldb/test/API/functionalities/breakpoint/breakpoint_names/TestBreakpointNames.py +++ b/lldb/test/API/functionalities/breakpoint/breakpoint_names/TestBreakpointNames.py @@ -389,7 +389,7 @@ class BreakpointNames(TestBase): ) def check_permission_results(self, bp_name): - self.assertEqual(bp_name.GetAllowDelete(), False, "Didn't set allow delete.") + self.assertFalse(bp_name.GetAllowDelete(), "Didn't set allow delete.") protected_bkpt = self.target.BreakpointCreateByLocation(self.main_file_spec, 10) protected_id = protected_bkpt.GetID() @@ -402,14 +402,11 @@ class BreakpointNames(TestBase): self.assertSuccess(success, "Couldn't add this name to the breakpoint") self.target.DisableAllBreakpoints() - self.assertEqual( - protected_bkpt.IsEnabled(), - True, - "Didnt' keep breakpoint from being disabled", + self.assertTrue( + protected_bkpt.IsEnabled(), "Didnt' keep breakpoint from being disabled" ) - self.assertEqual( + self.assertFalse( unprotected_bkpt.IsEnabled(), - False, "Protected too many breakpoints from disabling.", ) @@ -418,14 +415,11 @@ class BreakpointNames(TestBase): result = lldb.SBCommandReturnObject() self.dbg.GetCommandInterpreter().HandleCommand("break disable", result) self.assertTrue(result.Succeeded()) - self.assertEqual( - protected_bkpt.IsEnabled(), - True, - "Didnt' keep breakpoint from being disabled", + self.assertTrue( + protected_bkpt.IsEnabled(), "Didnt' keep breakpoint from being disabled" ) - self.assertEqual( + self.assertFalse( unprotected_bkpt.IsEnabled(), - False, "Protected too many breakpoints from disabling.", ) diff --git a/lldb/test/API/functionalities/gdb_remote_client/TestJLink6Armv7RegisterDefinition.py b/lldb/test/API/functionalities/gdb_remote_client/TestJLink6Armv7RegisterDefinition.py index eb7c036..3a42662 100644 --- a/lldb/test/API/functionalities/gdb_remote_client/TestJLink6Armv7RegisterDefinition.py +++ b/lldb/test/API/functionalities/gdb_remote_client/TestJLink6Armv7RegisterDefinition.py @@ -198,7 +198,7 @@ class TestJLink6Armv7RegisterDefinition(GDBRemoteTestBase): error = lldb.SBError() data = lldb.SBData() data.SetData(error, val, lldb.eByteOrderBig, 4) - self.assertEqual(r1_valobj.SetData(data, error), True) + self.assertTrue(r1_valobj.SetData(data, error)) self.assertSuccess(error) r1_valobj = process.GetThreadAtIndex(0).GetFrameAtIndex(0).FindRegister("r1") diff --git a/lldb/test/API/functionalities/module_cache/simple_exe/TestModuleCacheSimple.py b/lldb/test/API/functionalities/module_cache/simple_exe/TestModuleCacheSimple.py index 4214bd1..abf4cf3 100644 --- a/lldb/test/API/functionalities/module_cache/simple_exe/TestModuleCacheSimple.py +++ b/lldb/test/API/functionalities/module_cache/simple_exe/TestModuleCacheSimple.py @@ -66,18 +66,16 @@ class ModuleCacheTestcaseSimple(TestBase): # get a different creation and modification time for the file since some # OSs store the modification time in seconds since Jan 1, 1970. os.remove(exe) - self.assertEqual( - os.path.exists(exe), - False, - "make sure we were able to remove the executable", + self.assertFalse( + os.path.exists(exe), "make sure we were able to remove the executable" ) time.sleep(2) # Now rebuild the binary so it has a different content which should # update the UUID to make the cache miss when it tries to load the # symbol table from the binary at the same path. self.build(dictionary={"CFLAGS_EXTRAS": "-DEXTRA_FUNCTION"}) - self.assertEqual( - os.path.exists(exe), True, "make sure executable exists after rebuild" + self.assertTrue( + os.path.exists(exe), "make sure executable exists after rebuild" ) # Make sure the modification time has changed or this test will fail. exe_mtime_2 = os.path.getmtime(exe) @@ -99,9 +97,8 @@ class ModuleCacheTestcaseSimple(TestBase): main_module = target.GetModuleAtIndex(0) self.assertTrue(main_module.IsValid()) main_module.GetNumSymbols() - self.assertEqual( + self.assertTrue( os.path.exists(symtab_cache_path), - True, 'make sure "symtab" cache files exists after cache is updated', ) symtab_mtime_2 = os.path.getmtime(symtab_cache_path) diff --git a/lldb/test/API/functionalities/progress_reporting/TestTrimmedProgressReporting.py b/lldb/test/API/functionalities/progress_reporting/TestTrimmedProgressReporting.py index 357999b..ee35dbd 100644 --- a/lldb/test/API/functionalities/progress_reporting/TestTrimmedProgressReporting.py +++ b/lldb/test/API/functionalities/progress_reporting/TestTrimmedProgressReporting.py @@ -24,7 +24,8 @@ class TestTrimmedProgressReporting(PExpectTest): ) self.expect("set set term-width " + str(term_width)) self.expect( - "set show term-width", substrs=["term-width (int) = " + str(term_width)] + "set show term-width", + substrs=["term-width (unsigned) = " + str(term_width)], ) self.child.send("file " + self.getBuildArtifact("a.out") + "\n") diff --git a/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py b/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py index eee91bf..851097b 100644 --- a/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py +++ b/lldb/test/API/functionalities/stats_api/TestStatisticsAPI.py @@ -33,47 +33,47 @@ class TestStatsAPI(TestBase): stream = lldb.SBStream() res = stats.GetAsJSON(stream) debug_stats = json.loads(stream.GetData()) - self.assertEqual( - "targets" in debug_stats, - True, + self.assertIn( + "targets", + debug_stats, 'Make sure the "targets" key in in target.GetStatistics()', ) - self.assertEqual( - "modules" in debug_stats, - True, + self.assertIn( + "modules", + debug_stats, 'Make sure the "modules" key in in target.GetStatistics()', ) stats_json = debug_stats["targets"][0] - self.assertEqual( - "expressionEvaluation" in stats_json, - True, + self.assertIn( + "expressionEvaluation", + stats_json, 'Make sure the "expressionEvaluation" key in in target.GetStatistics()["targets"][0]', ) - self.assertEqual( - "frameVariable" in stats_json, - True, + self.assertIn( + "frameVariable", + stats_json, 'Make sure the "frameVariable" key in in target.GetStatistics()["targets"][0]', ) expressionEvaluation = stats_json["expressionEvaluation"] - self.assertEqual( - "successes" in expressionEvaluation, - True, + self.assertIn( + "successes", + expressionEvaluation, 'Make sure the "successes" key in in "expressionEvaluation" dictionary"', ) - self.assertEqual( - "failures" in expressionEvaluation, - True, + self.assertIn( + "failures", + expressionEvaluation, 'Make sure the "failures" key in in "expressionEvaluation" dictionary"', ) frameVariable = stats_json["frameVariable"] - self.assertEqual( - "successes" in frameVariable, - True, + self.assertIn( + "successes", + frameVariable, 'Make sure the "successes" key in in "frameVariable" dictionary"', ) - self.assertEqual( - "failures" in frameVariable, - True, + self.assertIn( + "failures", + frameVariable, 'Make sure the "failures" key in in "frameVariable" dictionary"', ) diff --git a/lldb/test/API/functionalities/thread/backtrace_limit/TestBacktraceLimit.py b/lldb/test/API/functionalities/thread/backtrace_limit/TestBacktraceLimit.py index 98baea4..fded504 100644 --- a/lldb/test/API/functionalities/thread/backtrace_limit/TestBacktraceLimit.py +++ b/lldb/test/API/functionalities/thread/backtrace_limit/TestBacktraceLimit.py @@ -23,5 +23,5 @@ class BacktraceLimitSettingTest(TestBase): interp.HandleCommand( "settings set target.process.thread.max-backtrace-depth 30", result ) - self.assertEqual(True, result.Succeeded()) + self.assertTrue(result.Succeeded()) self.assertEqual(30, thread.GetNumFrames()) diff --git a/lldb/test/API/macosx/arm-corefile-regctx/TestArmMachoCorefileRegctx.py b/lldb/test/API/macosx/arm-corefile-regctx/TestArmMachoCorefileRegctx.py index 1ecb0f4..4190ea3 100644 --- a/lldb/test/API/macosx/arm-corefile-regctx/TestArmMachoCorefileRegctx.py +++ b/lldb/test/API/macosx/arm-corefile-regctx/TestArmMachoCorefileRegctx.py @@ -28,7 +28,7 @@ class TestArmMachoCorefileRegctx(TestBase): target = self.dbg.CreateTarget("") err = lldb.SBError() process = target.LoadCore(self.corefile) - self.assertEqual(process.IsValid(), True) + self.assertTrue(process.IsValid()) thread = process.GetSelectedThread() frame = thread.GetSelectedFrame() @@ -51,7 +51,7 @@ class TestArmMachoCorefileRegctx(TestBase): target = self.dbg.CreateTarget("") err = lldb.SBError() process = target.LoadCore(self.corefile) - self.assertEqual(process.IsValid(), True) + self.assertTrue(process.IsValid()) thread = process.GetSelectedThread() frame = thread.GetSelectedFrame() diff --git a/lldb/test/API/macosx/lc-note/addrable-bits/TestAddrableBitsCorefile.py b/lldb/test/API/macosx/lc-note/addrable-bits/TestAddrableBitsCorefile.py index 221fe62..e56ecfc 100644 --- a/lldb/test/API/macosx/lc-note/addrable-bits/TestAddrableBitsCorefile.py +++ b/lldb/test/API/macosx/lc-note/addrable-bits/TestAddrableBitsCorefile.py @@ -29,7 +29,7 @@ class TestAddrableBitsCorefile(TestBase): (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint( self, "break here", lldb.SBFileSpec("main.c") ) - self.assertEqual(process.IsValid(), True) + self.assertTrue(process.IsValid()) found_main = False for f in thread.frames: diff --git a/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py b/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py index b9d2055..db3074d 100644 --- a/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py +++ b/lldb/test/API/macosx/lc-note/firmware-corefile/TestFirmwareCorefiles.py @@ -73,7 +73,7 @@ class TestFirmwareCorefiles(TestBase): if self.TraceOn(): self.runCmd("script print('loading corefile %s')" % verstr_corefile) process = target.LoadCore(verstr_corefile) - self.assertEqual(process.IsValid(), True) + self.assertTrue(process.IsValid()) if self.TraceOn(): self.runCmd("image list") self.runCmd("target mod dump sections") @@ -91,7 +91,7 @@ class TestFirmwareCorefiles(TestBase): "script print('loading corefile %s')" % verstr_corefile_invalid_ident ) process = target.LoadCore(verstr_corefile_invalid_ident) - self.assertEqual(process.IsValid(), True) + self.assertTrue(process.IsValid()) # Third, try the "kern ver str" corefile where it loads at an address target = self.dbg.CreateTarget("") @@ -99,7 +99,7 @@ class TestFirmwareCorefiles(TestBase): if self.TraceOn(): self.runCmd("script print('loading corefile %s')" % verstr_corefile_addr) process = target.LoadCore(verstr_corefile_addr) - self.assertEqual(process.IsValid(), True) + self.assertTrue(process.IsValid()) if self.TraceOn(): self.runCmd("image list") self.runCmd("target mod dump sections") @@ -178,7 +178,7 @@ class TestFirmwareCorefiles(TestBase): if self.TraceOn(): self.runCmd("script print('loading corefile %s')" % binspec_corefile) process = target.LoadCore(binspec_corefile) - self.assertEqual(process.IsValid(), True) + self.assertTrue(process.IsValid()) if self.TraceOn(): self.runCmd("image list") self.runCmd("target mod dump sections") @@ -192,7 +192,7 @@ class TestFirmwareCorefiles(TestBase): if self.TraceOn(): self.runCmd("script print('loading corefile %s')" % binspec_corefile_addr) process = target.LoadCore(binspec_corefile_addr) - self.assertEqual(process.IsValid(), True) + self.assertTrue(process.IsValid()) if self.TraceOn(): self.runCmd("image list") self.runCmd("target mod dump sections") @@ -212,7 +212,7 @@ class TestFirmwareCorefiles(TestBase): "script print('loading corefile %s')" % binspec_corefile_slideonly ) process = target.LoadCore(binspec_corefile_slideonly) - self.assertEqual(process.IsValid(), True) + self.assertTrue(process.IsValid()) if self.TraceOn(): self.runCmd("image list") self.runCmd("target mod dump sections") @@ -352,7 +352,7 @@ class TestFirmwareCorefiles(TestBase): ) process = target.LoadCore(binspec_corefile_addr) - self.assertEqual(process.IsValid(), True) + self.assertTrue(process.IsValid()) if self.TraceOn(): self.runCmd("image list") self.runCmd("target mod dump sections") diff --git a/lldb/test/API/macosx/lc-note/kern-ver-str/TestKernVerStrLCNOTE.py b/lldb/test/API/macosx/lc-note/kern-ver-str/TestKernVerStrLCNOTE.py index 9713c4a..d436619 100644 --- a/lldb/test/API/macosx/lc-note/kern-ver-str/TestKernVerStrLCNOTE.py +++ b/lldb/test/API/macosx/lc-note/kern-ver-str/TestKernVerStrLCNOTE.py @@ -94,7 +94,7 @@ class TestKernVerStrLCNOTE(TestBase): self.target = self.dbg.CreateTarget("") err = lldb.SBError() self.process = self.target.LoadCore(self.corefile) - self.assertEqual(self.process.IsValid(), True) + self.assertTrue(self.process.IsValid()) if self.TraceOn(): self.runCmd("image list") self.assertEqual(self.target.GetNumModules(), 1) diff --git a/lldb/test/API/macosx/lc-note/multiple-binary-corefile/TestMultipleBinaryCorefile.py b/lldb/test/API/macosx/lc-note/multiple-binary-corefile/TestMultipleBinaryCorefile.py index 0a0bc68..897eab2 100644 --- a/lldb/test/API/macosx/lc-note/multiple-binary-corefile/TestMultipleBinaryCorefile.py +++ b/lldb/test/API/macosx/lc-note/multiple-binary-corefile/TestMultipleBinaryCorefile.py @@ -45,7 +45,7 @@ class TestMultipleBinaryCorefile(TestBase): if self.TraceOn(): print("loading corefile %s" % self.corefile) process = target.LoadCore(self.corefile) - self.assertEqual(process.IsValid(), True) + self.assertTrue(process.IsValid()) if self.TraceOn(): print("image list after loading corefile:") self.runCmd("image list") diff --git a/lldb/test/API/macosx/queues/TestQueues.py b/lldb/test/API/macosx/queues/TestQueues.py index f2d15bb..45b52af 100644 --- a/lldb/test/API/macosx/queues/TestQueues.py +++ b/lldb/test/API/macosx/queues/TestQueues.py @@ -457,9 +457,8 @@ class TestQueues(TestBase): "doing_the_work_2", "queue 2's pending item #0 should be doing_the_work_2", ) - self.assertEqual( + self.assertFalse( queue_performer_2.GetPendingItemAtIndex(9999).IsValid(), - False, "queue 2's pending item #9999 is invalid", ) diff --git a/lldb/test/API/macosx/safe-to-func-call/TestSafeFuncCalls.py b/lldb/test/API/macosx/safe-to-func-call/TestSafeFuncCalls.py index 6a37b25..551cab1 100644 --- a/lldb/test/API/macosx/safe-to-func-call/TestSafeFuncCalls.py +++ b/lldb/test/API/macosx/safe-to-func-call/TestSafeFuncCalls.py @@ -49,8 +49,7 @@ class TestSafeFuncCalls(TestBase): main_thread.SafeToCallFunctions(), "It is safe to call functions on the main thread", ) - self.assertEqual( + self.assertFalse( select_thread.SafeToCallFunctions(), - False, "It is not safe to call functions on the select thread", ) diff --git a/lldb/test/API/python_api/interpreter/TestRunCommandInterpreterAPI.py b/lldb/test/API/python_api/interpreter/TestRunCommandInterpreterAPI.py index 64e0770..af97493 100644 --- a/lldb/test/API/python_api/interpreter/TestRunCommandInterpreterAPI.py +++ b/lldb/test/API/python_api/interpreter/TestRunCommandInterpreterAPI.py @@ -79,13 +79,13 @@ class SBCommandInterpreterRunOptionsCase(TestBase): opts = lldb.SBCommandInterpreterRunOptions() # Check getters with default values - self.assertEqual(opts.GetStopOnContinue(), False) - self.assertEqual(opts.GetStopOnError(), False) - self.assertEqual(opts.GetStopOnCrash(), False) - self.assertEqual(opts.GetEchoCommands(), True) - self.assertEqual(opts.GetPrintResults(), True) - self.assertEqual(opts.GetPrintErrors(), True) - self.assertEqual(opts.GetAddToHistory(), True) + self.assertFalse(opts.GetStopOnContinue()) + self.assertFalse(opts.GetStopOnError()) + self.assertFalse(opts.GetStopOnCrash()) + self.assertTrue(opts.GetEchoCommands()) + self.assertTrue(opts.GetPrintResults()) + self.assertTrue(opts.GetPrintErrors()) + self.assertTrue(opts.GetAddToHistory()) # Invert values opts.SetStopOnContinue(not opts.GetStopOnContinue()) @@ -97,10 +97,10 @@ class SBCommandInterpreterRunOptionsCase(TestBase): opts.SetAddToHistory(not opts.GetAddToHistory()) # Check the value changed - self.assertEqual(opts.GetStopOnContinue(), True) - self.assertEqual(opts.GetStopOnError(), True) - self.assertEqual(opts.GetStopOnCrash(), True) - self.assertEqual(opts.GetEchoCommands(), False) - self.assertEqual(opts.GetPrintResults(), False) - self.assertEqual(opts.GetPrintErrors(), False) - self.assertEqual(opts.GetAddToHistory(), False) + self.assertTrue(opts.GetStopOnContinue()) + self.assertTrue(opts.GetStopOnError()) + self.assertTrue(opts.GetStopOnCrash()) + self.assertFalse(opts.GetEchoCommands()) + self.assertFalse(opts.GetPrintResults()) + self.assertFalse(opts.GetPrintErrors()) + self.assertFalse(opts.GetAddToHistory()) diff --git a/lldb/test/API/tools/lldb-dap/databreakpoint/Makefile b/lldb/test/API/tools/lldb-dap/databreakpoint/Makefile new file mode 100644 index 0000000..99998b2 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/databreakpoint/Makefile @@ -0,0 +1,3 @@ +CXX_SOURCES := main.cpp + +include Makefile.rules diff --git a/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py b/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py new file mode 100644 index 0000000..17cdad8 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/databreakpoint/TestDAP_setDataBreakpoints.py @@ -0,0 +1,131 @@ +""" +Test lldb-dap dataBreakpointInfo and setDataBreakpoints requests +""" + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +import lldbdap_testcase + + +class TestDAP_setDataBreakpoints(lldbdap_testcase.DAPTestCaseBase): + def setUp(self): + lldbdap_testcase.DAPTestCaseBase.setUp(self) + self.accessTypes = ["read", "write", "readWrite"] + + @skipIfWindows + @skipIfRemote + def test_expression(self): + """Tests setting data breakpoints on expression.""" + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + source = "main.cpp" + first_loop_break_line = line_number(source, "// first loop breakpoint") + self.set_source_breakpoints(source, [first_loop_break_line]) + self.continue_to_next_stop() + self.dap_server.get_stackFrame() + # Test setting write watchpoint using expressions: &x, arr+2 + response_x = self.dap_server.request_dataBreakpointInfo(0, "&x") + response_arr_2 = self.dap_server.request_dataBreakpointInfo(0, "arr+2") + # Test response from dataBreakpointInfo request. + self.assertEquals(response_x["body"]["dataId"].split("/")[1], "4") + self.assertEquals(response_x["body"]["accessTypes"], self.accessTypes) + self.assertEquals(response_arr_2["body"]["dataId"].split("/")[1], "4") + self.assertEquals(response_arr_2["body"]["accessTypes"], self.accessTypes) + dataBreakpoints = [ + {"dataId": response_x["body"]["dataId"], "accessType": "write"}, + {"dataId": response_arr_2["body"]["dataId"], "accessType": "write"}, + ] + set_response = self.dap_server.request_setDataBreakpoint(dataBreakpoints) + self.assertEquals( + set_response["body"]["breakpoints"], + [{"verified": True}, {"verified": True}], + ) + + self.continue_to_next_stop() + x_val = self.dap_server.get_local_variable_value("x") + i_val = self.dap_server.get_local_variable_value("i") + self.assertEquals(x_val, "2") + self.assertEquals(i_val, "1") + + self.continue_to_next_stop() + arr_2 = self.dap_server.get_local_variable_child("arr", "[2]") + i_val = self.dap_server.get_local_variable_value("i") + self.assertEquals(arr_2["value"], "42") + self.assertEquals(i_val, "2") + + @skipIfWindows + @skipIfRemote + def test_functionality(self): + """Tests setting data breakpoints on variable.""" + program = self.getBuildArtifact("a.out") + self.build_and_launch(program) + source = "main.cpp" + first_loop_break_line = line_number(source, "// first loop breakpoint") + self.set_source_breakpoints(source, [first_loop_break_line]) + self.continue_to_next_stop() + self.dap_server.get_local_variables() + # Test write watchpoints on x, arr[2] + response_x = self.dap_server.request_dataBreakpointInfo(1, "x") + arr = self.dap_server.get_local_variable("arr") + response_arr_2 = self.dap_server.request_dataBreakpointInfo( + arr["variablesReference"], "[2]" + ) + + # Test response from dataBreakpointInfo request. + self.assertEquals(response_x["body"]["dataId"].split("/")[1], "4") + self.assertEquals(response_x["body"]["accessTypes"], self.accessTypes) + self.assertEquals(response_arr_2["body"]["dataId"].split("/")[1], "4") + self.assertEquals(response_arr_2["body"]["accessTypes"], self.accessTypes) + dataBreakpoints = [ + {"dataId": response_x["body"]["dataId"], "accessType": "write"}, + {"dataId": response_arr_2["body"]["dataId"], "accessType": "write"}, + ] + set_response = self.dap_server.request_setDataBreakpoint(dataBreakpoints) + self.assertEquals( + set_response["body"]["breakpoints"], + [{"verified": True}, {"verified": True}], + ) + + self.continue_to_next_stop() + x_val = self.dap_server.get_local_variable_value("x") + i_val = self.dap_server.get_local_variable_value("i") + self.assertEquals(x_val, "2") + self.assertEquals(i_val, "1") + + self.continue_to_next_stop() + arr_2 = self.dap_server.get_local_variable_child("arr", "[2]") + i_val = self.dap_server.get_local_variable_value("i") + self.assertEquals(arr_2["value"], "42") + self.assertEquals(i_val, "2") + self.dap_server.request_setDataBreakpoint([]) + + # Test hit condition + second_loop_break_line = line_number(source, "// second loop breakpoint") + breakpoint_ids = self.set_source_breakpoints(source, [second_loop_break_line]) + self.continue_to_breakpoints(breakpoint_ids) + dataBreakpoints = [ + { + "dataId": response_x["body"]["dataId"], + "accessType": "write", + "hitCondition": "2", + } + ] + set_response = self.dap_server.request_setDataBreakpoint(dataBreakpoints) + self.assertEquals(set_response["body"]["breakpoints"], [{"verified": True}]) + self.continue_to_next_stop() + x_val = self.dap_server.get_local_variable_value("x") + self.assertEquals(x_val, "3") + + # Test condition + dataBreakpoints = [ + { + "dataId": response_x["body"]["dataId"], + "accessType": "write", + "condition": "x==10", + } + ] + set_response = self.dap_server.request_setDataBreakpoint(dataBreakpoints) + self.assertEquals(set_response["body"]["breakpoints"], [{"verified": True}]) + self.continue_to_next_stop() + x_val = self.dap_server.get_local_variable_value("x") + self.assertEquals(x_val, "10") diff --git a/lldb/test/API/tools/lldb-dap/databreakpoint/main.cpp b/lldb/test/API/tools/lldb-dap/databreakpoint/main.cpp new file mode 100644 index 0000000..bef09c2 --- /dev/null +++ b/lldb/test/API/tools/lldb-dap/databreakpoint/main.cpp @@ -0,0 +1,17 @@ +int main(int argc, char const *argv[]) { + // Test for data breakpoint + int x = 0; + int arr[4] = {1, 2, 3, 4}; + for (int i = 0; i < 5; ++i) { // first loop breakpoint + if (i == 1) { + x = i + 1; + } else if (i == 2) { + arr[i] = 42; + } + } + + x = 1; + for (int i = 0; i < 10; ++i) { // second loop breakpoint + ++x; + } +} diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt index f8c0e4e..f8f0d86 100644 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ b/lldb/tools/lldb-dap/CMakeLists.txt @@ -37,6 +37,7 @@ add_lldb_tool(lldb-dap RunInTerminal.cpp SourceBreakpoint.cpp DAP.cpp + Watchpoint.cpp LINK_LIBS liblldb diff --git a/lldb/tools/lldb-dap/DAPForward.h b/lldb/tools/lldb-dap/DAPForward.h index fffff1e..8c79488 100644 --- a/lldb/tools/lldb-dap/DAPForward.h +++ b/lldb/tools/lldb-dap/DAPForward.h @@ -14,6 +14,7 @@ struct BreakpointBase; struct ExceptionBreakpoint; struct FunctionBreakpoint; struct SourceBreakpoint; +struct Watchpoint; } // namespace lldb_dap namespace lldb { @@ -39,6 +40,7 @@ class SBStringList; class SBTarget; class SBThread; class SBValue; +class SBWatchpoint; } // namespace lldb #endif diff --git a/lldb/tools/lldb-dap/Watchpoint.cpp b/lldb/tools/lldb-dap/Watchpoint.cpp new file mode 100644 index 0000000..2f176e0 --- /dev/null +++ b/lldb/tools/lldb-dap/Watchpoint.cpp @@ -0,0 +1,48 @@ +//===-- Watchpoint.cpp ------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Watchpoint.h" +#include "DAP.h" +#include "JSONUtils.h" +#include "llvm/ADT/StringExtras.h" + +namespace lldb_dap { +Watchpoint::Watchpoint(const llvm::json::Object &obj) : BreakpointBase(obj) { + llvm::StringRef dataId = GetString(obj, "dataId"); + std::string accessType = GetString(obj, "accessType").str(); + auto [addr_str, size_str] = dataId.split('/'); + lldb::addr_t addr; + size_t size; + llvm::to_integer(addr_str, addr, 16); + llvm::to_integer(size_str, size); + lldb::SBWatchpointOptions options; + options.SetWatchpointTypeRead(accessType != "write"); + if (accessType != "read") + options.SetWatchpointTypeWrite(lldb::eWatchpointWriteTypeOnModify); + wp = g_dap.target.WatchpointCreateByAddress(addr, size, options, error); + SetCondition(); + SetHitCondition(); +} + +void Watchpoint::SetCondition() { wp.SetCondition(condition.c_str()); } + +void Watchpoint::SetHitCondition() { + uint64_t hitCount = 0; + if (llvm::to_integer(hitCondition, hitCount)) + wp.SetIgnoreCount(hitCount - 1); +} + +void Watchpoint::CreateJsonObject(llvm::json::Object &object) { + if (error.Success()) { + object.try_emplace("verified", true); + } else { + object.try_emplace("verified", false); + EmplaceSafeString(object, "message", error.GetCString()); + } +} +} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Watchpoint.h b/lldb/tools/lldb-dap/Watchpoint.h new file mode 100644 index 0000000..026b07d --- /dev/null +++ b/lldb/tools/lldb-dap/Watchpoint.h @@ -0,0 +1,34 @@ +//===-- Watchpoint.h --------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_TOOLS_LLDB_DAP_WATCHPOINT_H +#define LLDB_TOOLS_LLDB_DAP_WATCHPOINT_H + +#include "BreakpointBase.h" +#include "lldb/API/SBError.h" +#include "lldb/API/SBWatchpoint.h" +#include "lldb/API/SBWatchpointOptions.h" + +namespace lldb_dap { + +struct Watchpoint : public BreakpointBase { + // The LLDB breakpoint associated wit this watchpoint. + lldb::SBWatchpoint wp; + lldb::SBError error; + + Watchpoint() = default; + Watchpoint(const llvm::json::Object &obj); + Watchpoint(lldb::SBWatchpoint wp) : wp(wp) {} + + void SetCondition() override; + void SetHitCondition() override; + void CreateJsonObject(llvm::json::Object &object) override; +}; +} // namespace lldb_dap + +#endif diff --git a/lldb/tools/lldb-dap/lldb-dap.cpp b/lldb/tools/lldb-dap/lldb-dap.cpp index 78b0b40..c6a275b 100644 --- a/lldb/tools/lldb-dap/lldb-dap.cpp +++ b/lldb/tools/lldb-dap/lldb-dap.cpp @@ -7,6 +7,8 @@ //===----------------------------------------------------------------------===// #include "DAP.h" +#include "Watchpoint.h" +#include "lldb/API/SBMemoryRegionInfo.h" #include <cassert> #include <climits> @@ -560,6 +562,46 @@ void EventThreadFunction() { } } +lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name) { + lldb::SBValue variable; + if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) { + bool is_duplicated_variable_name = name.contains(" @"); + // variablesReference is one of our scopes, not an actual variable it is + // asking for a variable in locals or globals or registers + int64_t end_idx = top_scope->GetSize(); + // Searching backward so that we choose the variable in closest scope + // among variables of the same name. + for (int64_t i = end_idx - 1; i >= 0; --i) { + lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i); + std::string variable_name = CreateUniqueVariableNameForDisplay( + curr_variable, is_duplicated_variable_name); + if (variable_name == name) { + variable = curr_variable; + break; + } + } + } else { + // This is not under the globals or locals scope, so there are no duplicated + // names. + + // We have a named item within an actual variable so we need to find it + // withing the container variable by name. + lldb::SBValue container = g_dap.variables.GetVariable(variablesReference); + variable = container.GetChildMemberWithName(name.data()); + if (!variable.IsValid()) { + if (name.starts_with("[")) { + llvm::StringRef index_str(name.drop_front(1)); + uint64_t index = 0; + if (!index_str.consumeInteger(0, index)) { + if (index_str == "]") + variable = container.GetChildAtIndex(index); + } + } + } + } + return variable; +} + // Both attach and launch take a either a sourcePath or sourceMap // argument (or neither), from which we need to set the target.source-map. void SetSourceMapFromArguments(const llvm::json::Object &arguments) { @@ -1647,6 +1689,8 @@ void request_initialize(const llvm::json::Object &request) { body.try_emplace("supportsProgressReporting", true); // The debug adapter supports 'logMessage' in breakpoint. body.try_emplace("supportsLogPoints", true); + // The debug adapter supports data watchpoints. + body.try_emplace("supportsDataBreakpoints", true); response.try_emplace("body", std::move(body)); g_dap.SendJSON(llvm::json::Value(std::move(response))); @@ -2593,6 +2637,264 @@ void request_setFunctionBreakpoints(const llvm::json::Object &request) { g_dap.SendJSON(llvm::json::Value(std::move(response))); } +// "DataBreakpointInfoRequest": { +// "allOf": [ { "$ref": "#/definitions/Request" }, { +// "type": "object", +// "description": "Obtains information on a possible data breakpoint that +// could be set on an expression or variable.\nClients should only call this +// request if the corresponding capability `supportsDataBreakpoints` is +// true.", "properties": { +// "command": { +// "type": "string", +// "enum": [ "dataBreakpointInfo" ] +// }, +// "arguments": { +// "$ref": "#/definitions/DataBreakpointInfoArguments" +// } +// }, +// "required": [ "command", "arguments" ] +// }] +// }, +// "DataBreakpointInfoArguments": { +// "type": "object", +// "description": "Arguments for `dataBreakpointInfo` request.", +// "properties": { +// "variablesReference": { +// "type": "integer", +// "description": "Reference to the variable container if the data +// breakpoint is requested for a child of the container. The +// `variablesReference` must have been obtained in the current suspended +// state. See 'Lifetime of Object References' in the Overview section for +// details." +// }, +// "name": { +// "type": "string", +// "description": "The name of the variable's child to obtain data +// breakpoint information for.\nIf `variablesReference` isn't specified, +// this can be an expression." +// }, +// "frameId": { +// "type": "integer", +// "description": "When `name` is an expression, evaluate it in the scope +// of this stack frame. If not specified, the expression is evaluated in +// the global scope. When `variablesReference` is specified, this property +// has no effect." +// } +// }, +// "required": [ "name" ] +// }, +// "DataBreakpointInfoResponse": { +// "allOf": [ { "$ref": "#/definitions/Response" }, { +// "type": "object", +// "description": "Response to `dataBreakpointInfo` request.", +// "properties": { +// "body": { +// "type": "object", +// "properties": { +// "dataId": { +// "type": [ "string", "null" ], +// "description": "An identifier for the data on which a data +// breakpoint can be registered with the `setDataBreakpoints` +// request or null if no data breakpoint is available. If a +// `variablesReference` or `frameId` is passed, the `dataId` is +// valid in the current suspended state, otherwise it's valid +// indefinitely. See 'Lifetime of Object References' in the Overview +// section for details. Breakpoints set using the `dataId` in the +// `setDataBreakpoints` request may outlive the lifetime of the +// associated `dataId`." +// }, +// "description": { +// "type": "string", +// "description": "UI string that describes on what data the +// breakpoint is set on or why a data breakpoint is not available." +// }, +// "accessTypes": { +// "type": "array", +// "items": { +// "$ref": "#/definitions/DataBreakpointAccessType" +// }, +// "description": "Attribute lists the available access types for a +// potential data breakpoint. A UI client could surface this +// information." +// }, +// "canPersist": { +// "type": "boolean", +// "description": "Attribute indicates that a potential data +// breakpoint could be persisted across sessions." +// } +// }, +// "required": [ "dataId", "description" ] +// } +// }, +// "required": [ "body" ] +// }] +// } +void request_dataBreakpointInfo(const llvm::json::Object &request) { + llvm::json::Object response; + FillResponse(request, response); + llvm::json::Object body; + lldb::SBError error; + llvm::json::Array accessTypes{"read", "write", "readWrite"}; + const auto *arguments = request.getObject("arguments"); + const auto variablesReference = + GetUnsigned(arguments, "variablesReference", 0); + llvm::StringRef name = GetString(arguments, "name"); + lldb::SBFrame frame = g_dap.GetLLDBFrame(*arguments); + lldb::SBValue variable = FindVariable(variablesReference, name); + std::string addr, size; + + if (variable.IsValid()) { + lldb::addr_t load_addr = variable.GetLoadAddress(); + size_t byte_size = variable.GetByteSize(); + if (load_addr == LLDB_INVALID_ADDRESS) { + body.try_emplace("dataId", nullptr); + body.try_emplace("description", + "does not exist in memory, its location is " + + std::string(variable.GetLocation())); + } else if (byte_size == 0) { + body.try_emplace("dataId", nullptr); + body.try_emplace("description", "variable size is 0"); + } else { + addr = llvm::utohexstr(load_addr); + size = llvm::utostr(byte_size); + } + } else if (variablesReference == 0 && frame.IsValid()) { + lldb::SBValue value = frame.EvaluateExpression(name.data()); + if (value.GetError().Fail()) { + lldb::SBError error = value.GetError(); + const char *error_cstr = error.GetCString(); + body.try_emplace("dataId", nullptr); + body.try_emplace("description", error_cstr && error_cstr[0] + ? std::string(error_cstr) + : "evaluation failed"); + } else { + uint64_t load_addr = value.GetValueAsUnsigned(); + addr = llvm::utohexstr(load_addr); + lldb::SBMemoryRegionInfo region; + lldb::SBError err = + g_dap.target.GetProcess().GetMemoryRegionInfo(load_addr, region); + if (err.Success()) { + if (!(region.IsReadable() || region.IsWritable())) { + body.try_emplace("dataId", nullptr); + body.try_emplace("description", + "memory region for address " + addr + + " has no read or write permissions"); + } else { + lldb::SBData data = value.GetPointeeData(); + if (data.IsValid()) + size = llvm::utostr(data.GetByteSize()); + else { + body.try_emplace("dataId", nullptr); + body.try_emplace("description", + "unable to get byte size for expression: " + + name.str()); + } + } + } else { + body.try_emplace("dataId", nullptr); + body.try_emplace("description", + "unable to get memory region info for address " + + addr); + } + } + } else { + body.try_emplace("dataId", nullptr); + body.try_emplace("description", "variable not found: " + name.str()); + } + + if (!body.getObject("dataId")) { + body.try_emplace("dataId", addr + "/" + size); + body.try_emplace("accessTypes", std::move(accessTypes)); + body.try_emplace("description", + size + " bytes at " + addr + " " + name.str()); + } + response.try_emplace("body", std::move(body)); + g_dap.SendJSON(llvm::json::Value(std::move(response))); +} + +// "SetDataBreakpointsRequest": { +// "allOf": [ { "$ref": "#/definitions/Request" }, { +// "type": "object", +// "description": "Replaces all existing data breakpoints with new data +// breakpoints.\nTo clear all data breakpoints, specify an empty +// array.\nWhen a data breakpoint is hit, a `stopped` event (with reason +// `data breakpoint`) is generated.\nClients should only call this request +// if the corresponding capability `supportsDataBreakpoints` is true.", +// "properties": { +// "command": { +// "type": "string", +// "enum": [ "setDataBreakpoints" ] +// }, +// "arguments": { +// "$ref": "#/definitions/SetDataBreakpointsArguments" +// } +// }, +// "required": [ "command", "arguments" ] +// }] +// }, +// "SetDataBreakpointsArguments": { +// "type": "object", +// "description": "Arguments for `setDataBreakpoints` request.", +// "properties": { +// "breakpoints": { +// "type": "array", +// "items": { +// "$ref": "#/definitions/DataBreakpoint" +// }, +// "description": "The contents of this array replaces all existing data +// breakpoints. An empty array clears all data breakpoints." +// } +// }, +// "required": [ "breakpoints" ] +// }, +// "SetDataBreakpointsResponse": { +// "allOf": [ { "$ref": "#/definitions/Response" }, { +// "type": "object", +// "description": "Response to `setDataBreakpoints` request.\nReturned is +// information about each breakpoint created by this request.", +// "properties": { +// "body": { +// "type": "object", +// "properties": { +// "breakpoints": { +// "type": "array", +// "items": { +// "$ref": "#/definitions/Breakpoint" +// }, +// "description": "Information about the data breakpoints. The array +// elements correspond to the elements of the input argument +// `breakpoints` array." +// } +// }, +// "required": [ "breakpoints" ] +// } +// }, +// "required": [ "body" ] +// }] +// } +void request_setDataBreakpoints(const llvm::json::Object &request) { + llvm::json::Object response; + lldb::SBError error; + FillResponse(request, response); + const auto *arguments = request.getObject("arguments"); + const auto *breakpoints = arguments->getArray("breakpoints"); + llvm::json::Array response_breakpoints; + g_dap.target.DeleteAllWatchpoints(); + if (breakpoints) { + for (const auto &bp : *breakpoints) { + const auto *bp_obj = bp.getAsObject(); + if (bp_obj) { + Watchpoint wp(*bp_obj); + AppendBreakpoint(&wp, response_breakpoints); + } + } + } + llvm::json::Object body; + body.try_emplace("breakpoints", std::move(response_breakpoints)); + response.try_emplace("body", std::move(body)); + g_dap.SendJSON(llvm::json::Value(std::move(response))); +} + // "SourceRequest": { // "allOf": [ { "$ref": "#/definitions/Request" }, { // "type": "object", @@ -3076,7 +3378,6 @@ void request_setVariable(const llvm::json::Object &request) { const auto variablesReference = GetUnsigned(arguments, "variablesReference", 0); llvm::StringRef name = GetString(arguments, "name"); - bool is_duplicated_variable_name = name.contains(" @"); const auto value = GetString(arguments, "value"); // Set success to false just in case we don't find the variable by name @@ -3097,40 +3398,8 @@ void request_setVariable(const llvm::json::Object &request) { const auto id_value = GetUnsigned(arguments, "id", UINT64_MAX); if (id_value != UINT64_MAX) { variable = g_dap.variables.GetVariable(id_value); - } else if (lldb::SBValueList *top_scope = - GetTopLevelScope(variablesReference)) { - // variablesReference is one of our scopes, not an actual variable it is - // asking for a variable in locals or globals or registers - int64_t end_idx = top_scope->GetSize(); - // Searching backward so that we choose the variable in closest scope - // among variables of the same name. - for (int64_t i = end_idx - 1; i >= 0; --i) { - lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i); - std::string variable_name = CreateUniqueVariableNameForDisplay( - curr_variable, is_duplicated_variable_name); - if (variable_name == name) { - variable = curr_variable; - break; - } - } } else { - // This is not under the globals or locals scope, so there are no duplicated - // names. - - // We have a named item within an actual variable so we need to find it - // withing the container variable by name. - lldb::SBValue container = g_dap.variables.GetVariable(variablesReference); - variable = container.GetChildMemberWithName(name.data()); - if (!variable.IsValid()) { - if (name.starts_with("[")) { - llvm::StringRef index_str(name.drop_front(1)); - uint64_t index = 0; - if (!index_str.consumeInteger(0, index)) { - if (index_str == "]") - variable = container.GetChildAtIndex(index); - } - } - } + variable = FindVariable(variablesReference, name); } if (variable.IsValid()) { @@ -3613,6 +3882,10 @@ void RegisterRequestCallbacks() { request_setExceptionBreakpoints); g_dap.RegisterRequestCallback("setFunctionBreakpoints", request_setFunctionBreakpoints); + g_dap.RegisterRequestCallback("dataBreakpointInfo", + request_dataBreakpointInfo); + g_dap.RegisterRequestCallback("setDataBreakpoints", + request_setDataBreakpoints); g_dap.RegisterRequestCallback("setVariable", request_setVariable); g_dap.RegisterRequestCallback("source", request_source); g_dap.RegisterRequestCallback("stackTrace", request_stackTrace); diff --git a/lldb/unittests/Interpreter/CMakeLists.txt b/lldb/unittests/Interpreter/CMakeLists.txt index 5b5268f..54cea99 100644 --- a/lldb/unittests/Interpreter/CMakeLists.txt +++ b/lldb/unittests/Interpreter/CMakeLists.txt @@ -2,6 +2,7 @@ add_lldb_unittest(InterpreterTests TestCommandPaths.cpp TestCompletion.cpp TestOptionArgParser.cpp + TestOptions.cpp TestOptionValue.cpp TestOptionValueFileColonLine.cpp TestRegexCommand.cpp diff --git a/lldb/unittests/Interpreter/TestOptions.cpp b/lldb/unittests/Interpreter/TestOptions.cpp new file mode 100644 index 0000000..93474e3 --- /dev/null +++ b/lldb/unittests/Interpreter/TestOptions.cpp @@ -0,0 +1,29 @@ +//===-- TestOptions.cpp ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "lldb/Interpreter/Options.h" +#include "gtest/gtest.h" + +#include "llvm/Testing/Support/Error.h" + +using namespace lldb_private; + +TEST(OptionsTest, CreateOptionParsingError) { + ASSERT_THAT_ERROR( + CreateOptionParsingError("yippee", 'f', "fun", + "unable to convert 'yippee' to boolean"), + llvm::FailedWithMessage("Invalid value ('yippee') for -f (fun): unable " + "to convert 'yippee' to boolean")); + + ASSERT_THAT_ERROR( + CreateOptionParsingError("52", 'b', "bean-count"), + llvm::FailedWithMessage("Invalid value ('52') for -b (bean-count)")); + + ASSERT_THAT_ERROR(CreateOptionParsingError("c", 'm'), + llvm::FailedWithMessage("Invalid value ('c') for -m")); +} diff --git a/lldb/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp b/lldb/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp index a4db4627f..b90fbb7 100644 --- a/lldb/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp +++ b/lldb/unittests/ScriptInterpreter/Python/PythonDataObjectsTests.cpp @@ -11,6 +11,7 @@ #include "Plugins/ScriptInterpreter/Python/PythonDataObjects.h" #include "Plugins/ScriptInterpreter/Python/ScriptInterpreterPython.h" +#include "TestingSupport/SubsystemRAII.h" #include "lldb/Host/File.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostInfo.h" @@ -26,6 +27,8 @@ using namespace lldb_private::python; using llvm::Expected; class PythonDataObjectsTest : public PythonTestSuite { + SubsystemRAII<FileSystem> subsystems; + public: void SetUp() override { PythonTestSuite::SetUp(); @@ -209,8 +212,8 @@ TEST_F(PythonDataObjectsTest, TestPythonBoolean) { }; // Test PythonBoolean constructed from long integer values. - test_from_long(0); // Test 'false' value. - test_from_long(1); // Test 'true' value. + test_from_long(0); // Test 'false' value. + test_from_long(1); // Test 'true' value. test_from_long(~0); // Any value != 0 is 'true'. } @@ -811,7 +814,8 @@ main = foo testing::ContainsRegex("line 7, in baz"), testing::ContainsRegex("ZeroDivisionError"))))); -#if !((defined(_WIN32) || defined(_WIN64)) && (defined(__aarch64__) || defined(_M_ARM64))) +#if !((defined(_WIN32) || defined(_WIN64)) && \ + (defined(__aarch64__) || defined(_M_ARM64))) static const char script2[] = R"( class MyError(Exception): |