diff options
Diffstat (limited to 'debuginfo-tests/dexter/dex/command/commands/DexExpectProgramState.py')
-rw-r--r-- | debuginfo-tests/dexter/dex/command/commands/DexExpectProgramState.py | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/debuginfo-tests/dexter/dex/command/commands/DexExpectProgramState.py b/debuginfo-tests/dexter/dex/command/commands/DexExpectProgramState.py new file mode 100644 index 00000000000..78335838a65 --- /dev/null +++ b/debuginfo-tests/dexter/dex/command/commands/DexExpectProgramState.py @@ -0,0 +1,83 @@ +# DExTer : Debugging Experience Tester +# ~~~~~~ ~ ~~ ~ ~~ +# +# 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 +"""Command for specifying a partial or complete state for the program to enter +during execution. +""" + +from itertools import chain + +from dex.command.CommandBase import CommandBase +from dex.dextIR import ProgramState, SourceLocation, StackFrame, DextIR + +def frame_from_dict(source: dict) -> StackFrame: + if 'location' in source: + assert isinstance(source['location'], dict) + source['location'] = SourceLocation(**source['location']) + return StackFrame(**source) + +def state_from_dict(source: dict) -> ProgramState: + if 'frames' in source: + assert isinstance(source['frames'], list) + source['frames'] = list(map(frame_from_dict, source['frames'])) + return ProgramState(**source) + +class DexExpectProgramState(CommandBase): + """Expect to see a given program `state` a certain numer of `times`. + + DexExpectProgramState(state [,**times]) + + See Commands.md for more info. + """ + + def __init__(self, *args, **kwargs): + if len(args) != 1: + raise TypeError('expected exactly one unnamed arg') + + self.program_state_text = str(args[0]) + + self.expected_program_state = state_from_dict(args[0]) + + self.times = kwargs.pop('times', -1) + if kwargs: + raise TypeError('unexpected named args: {}'.format( + ', '.join(kwargs))) + + # Step indices at which the expected program state was encountered. + self.encounters = [] + + super(DexExpectProgramState, self).__init__() + + @staticmethod + def get_name(): + return __class__.__name__ + + def get_watches(self): + frame_expects = chain.from_iterable(frame.watches + for frame in self.expected_program_state.frames) + return set(frame_expects) + + def eval(self, step_collection: DextIR) -> bool: + for step in step_collection.steps: + if self.expected_program_state.match(step.program_state): + self.encounters.append(step.step_index) + + return self.times < 0 < len(self.encounters) or len(self.encounters) == self.times + + def has_labels(self): + return len(self.get_label_args()) > 0 + + def get_label_args(self): + return [frame.location.lineno + for frame in self.expected_program_state.frames + if frame.location and + isinstance(frame.location.lineno, str)] + + def resolve_label(self, label_line__pair): + label, line = label_line__pair + for frame in self.expected_program_state.frames: + if frame.location and frame.location.lineno == label: + frame.location.lineno = line |