# 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, StepExpectInfo 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 = set() for idx, frame in enumerate(self.expected_program_state.frames): path = ( frame.location.path if frame.location and frame.location.path else self.path ) line_range = ( range(frame.location.lineno, frame.location.lineno + 1) if frame.location and frame.location.lineno else None ) for watch in frame.watches: frame_expects.add( StepExpectInfo( expression=watch, path=path, frame_idx=idx, line_range=line_range, ) ) return 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 )