Repository navigation
Add gdb-repr directive for tests/debuginfo
#160377
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
bed1558
7e05251
ae019ac
f9df6ad
54e542a
a411a33
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import os | ||
|
|
||
| debugger = os.environ.get("DEBUGGER_TESTER_DEBUGGER") | ||
|
|
||
| if debugger == "lldb": | ||
| from .lldb.batchmode import main as main | ||
| elif debugger == "gdb": | ||
| from .gdb.gdb_commands import ReprCommand as ReprCommand |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -69,7 +69,7 @@ class Target(Enum): | |
|
|
||
| def get_target() -> Target: | ||
| # set by compiletest when launching LLDB | ||
| t: str = os.environ["LLDB_BATCHMODE_TARGET_TRIPLE"] | ||
| t: str = os.environ["DEBUGGER_TESTER_TARGET_TRIPLE"] | ||
|
|
||
| if t.endswith("windows-msvc"): | ||
| return Target.WindowsMsvc | ||
|
|
@@ -79,7 +79,7 @@ def get_target() -> Target: | |
| return Target.NonWindows | ||
|
|
||
|
|
||
| BLESS: Final[bool] = os.environ["LLDB_BATCHMODE_BLESS_TEST_DATA"] == "1" | ||
| BLESS: Final[bool] = os.environ["DEBUGGER_TESTER_BLESS_TEST_DATA"] == "1" | ||
| """Global constant set by `compiletest` that determines whether or not we are blessing the test | ||
| data.""" | ||
|
|
||
|
|
@@ -490,7 +490,7 @@ class TargetData: | |
| Additionally, since there are differences in the internals of some structs based on OS (e.g. | ||
| `PathBuf`/`OsString`), we need to be aware of whether we're on Windows or not. | ||
|
|
||
| A global var `TARGET` is set to the current variant upon `lldb_batchmode`'s instantiation using | ||
| A global var `TARGET` is set to the current variant upon `debugger_tester`'s instantiation using | ||
| an env var passed from `compiletest` and is not expected to change afterwards. | ||
| """ | ||
|
|
||
|
|
@@ -513,7 +513,7 @@ class TargetData: | |
| @staticmethod | ||
| def initialize() -> "TargetData": | ||
| result = TargetData() | ||
| path = os.environ["LLDB_BATCHMODE_INPUT_DATA_PATH"] | ||
| path = os.environ["DEBUGGER_TESTER_INPUT_DATA_PATH"] | ||
| if not os.path.isfile(path): | ||
| if BLESS: | ||
| return result | ||
|
|
@@ -535,12 +535,12 @@ def initialize() -> "TargetData": | |
| return result | ||
|
|
||
| def save_blessing(self, metadata: BlessMetadata): | ||
| """Writes the entirety of `self` to the env var `LLDB_BATCHMODE_INPUT_DATA_PATH`, which is | ||
| set by `compiletest` before running `lldb_batchmode. Used to finalize changes made by one or | ||
| more `from_lldb.bless_variable` calls. | ||
| """Writes the entirety of `self` to the env var `DEBUGGER_TESTER_INPUT_DATA_PATH`, which is | ||
| set by `compiletest` before running `debugger_tester`. Used to finalize changes made by one | ||
| or more `from_lldb.bless_variable` calls. | ||
|
|
||
| This function should be called exactly once, right before | ||
| `lldb_batchmode.runner.main` exits if the following conditions are met: | ||
| `debugger_tester.lldb.batchmode.main` exits if the following conditions are met: | ||
|
|
||
| 1. No other exceptions or error states occurred | ||
| 2. `BLESS == True` | ||
|
|
@@ -551,7 +551,7 @@ def save_blessing(self, metadata: BlessMetadata): | |
| """ | ||
|
|
||
| self.bless_metadata = metadata | ||
| path = os.environ["LLDB_BATCHMODE_INPUT_DATA_PATH"] | ||
| path = os.environ["DEBUGGER_TESTER_INPUT_DATA_PATH"] | ||
| # dumping directly to a file is somewhat unsafe. If the `Variable`/`Type` data ends up in a | ||
| # state that cannot be serialized correctly, the json ends up malformed, and we could end up | ||
| # overwriting valid test data with a complete mess. Since the in-memory data is typically | ||
|
|
@@ -599,3 +599,80 @@ def clean_nones(value): | |
|
|
||
|
|
||
| INPUT_DATA: TargetData = TargetData.initialize() | ||
|
|
||
|
|
||
| TYPES_TESTED: dict[str, Result] = {} | ||
| """Since types are unique and unchanging, we only need to test each type once. This also helps | ||
| ensure we have tested all types in `INPUT_DATA` | ||
| """ | ||
|
|
||
|
|
||
| VARS_TESTED: list[dict[str, Result]] = [] | ||
| """Used to help ensure all expected variables were tested. Each element of the list corresponds to a | ||
| breakpoint, and contains a set of all of the variable names tested for that breakpoint.""" | ||
|
|
||
|
|
||
| def tested_all_types() -> bool: | ||
| """Returns true if all types in INPUT_DATA were tested this run.""" | ||
|
|
||
| expected_types = set(INPUT_DATA.types) | ||
| untested_types = expected_types.difference(TYPES_TESTED.keys()) | ||
|
|
||
| if len(untested_types) != 0: | ||
| print( | ||
| f"{ANSI_RED}[repr error]{ANSI_END} The following types were expected, but were not \ | ||
| tested:\n {untested_types}" | ||
| ) | ||
|
|
||
| return len(untested_types) == 0 | ||
|
|
||
|
|
||
| def tested_all_variables() -> bool: | ||
| expected_vars = [set(vars) for vars in INPUT_DATA.breakpoints] | ||
|
|
||
| untested_vars = [ | ||
| expected.difference(tested.keys()) | ||
| for expected, tested in zip(expected_vars, VARS_TESTED) | ||
| ] | ||
|
|
||
| tested_not_expected = [ | ||
| set(tested.keys()).difference(expected) | ||
| for expected, tested in zip(expected_vars, VARS_TESTED) | ||
| ] | ||
|
|
||
| result = True | ||
|
|
||
| # `zip()` stops producing values once the shorter of the 2 iterators are exhausted, so we need | ||
| # to check if we found more breakpoints than expected. | ||
| # | ||
| # If `expected_vars` were shorter, it would have caused an indexing error during the `check` | ||
| # logic (which also outputs an error message and returns `Result.Mismatch`), so that case does | ||
| # not need to be checked here. | ||
| if len(VARS_TESTED) > len(expected_vars): | ||
| result = False | ||
| print( | ||
| f"{ANSI_RED}[repr error]{ANSI_END} Expected data for {len(expected_vars)} \ | ||
| breakpoints, got data for {len(VARS_TESTED)} breakpoints.w" | ||
| ) | ||
|
|
||
| for i, v in enumerate(untested_vars): | ||
| if len(v) == 0: | ||
| continue | ||
|
|
||
| result = False | ||
| print( | ||
| f"{ANSI_RED}[repr error]{ANSI_END} The following variables were expected at \ | ||
| breakpoint#{i}, but were not tested:\n {v}" | ||
| ) | ||
|
|
||
| for i, v in enumerate(tested_not_expected): | ||
| if len(v) == 0: | ||
| continue | ||
|
|
||
| result = False | ||
| print( | ||
| f"{ANSI_RED}[repr error]{ANSI_END} The following variables were tested, but do not \ | ||
| exist in the input data at breakpoint#{i}:\n {v}" | ||
| ) | ||
|
|
||
| return result | ||
|
Comment on lines
+604
to
+678
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These were just moved from I might be able to factor more of the checking logic out and share it between lldb and gdb. There are less differences for their API than I was expecting. It would probably require passing a few wrappers to the check function that abstract away the debugger-specific accesses, but we'll see. |
||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be good to also rename |
Uh oh!
There was an error while loading. Please reload this page.