Exemple #1
0
 def test_diff_staticmethod(self):
     diffs = diff_behavior(
         walk_qualname(Base, "staticfoo"),
         foo2,
         DEFAULT_OPTIONS.overlay(max_iterations=10),
     )
     self.assertEqual(diffs, [])
Exemple #2
0
    def test_example_coverage(self) -> None:
        # Try to get examples that highlist the differences in the code.
        # Here, we add more conditions for the `return True` path and
        # another case where we used to just `return False`.
        def isack1(s: str) -> bool:
            if s in ("y", "yes"):
                return True
            return False

        def isack2(s: str) -> Optional[bool]:
            if s in ("y", "yes", "Y", "YES"):
                return True
            if s in ("n", "no", "N", "NO"):
                return False
            return None

        diffs = diff_behavior(
            FunctionInfo.from_fn(isack1),
            FunctionInfo.from_fn(isack2),
            DEFAULT_OPTIONS.overlay(max_iterations=20,
                                    per_condition_timeout=5),
        )
        debug("diffs=", diffs)
        assert not isinstance(diffs, str)
        return_vals = set(
            (d.result1.return_repr, d.result2.return_repr) for d in diffs)
        self.assertEqual(return_vals, {("False", "None"), ("False", "True")})
Exemple #3
0
 def test_diff_behavior_different(self) -> None:
     diffs = diff_behavior(foo1, foo3,
                           DEFAULT_OPTIONS.overlay(max_iterations=10))
     self.assertEqual(len(diffs), 1)
     diff = diffs[0]
     assert isinstance(diff, BehaviorDiff)
     self.assertGreater(int(diff.args["x"]), 1000)
     self.assertEqual(diff.result1.return_repr, "100")
     self.assertEqual(diff.result2.return_repr, "1000")
Exemple #4
0
 def test_diff_method(self):
     diffs = diff_behavior(
         walk_qualname(Base, "foo"),
         walk_qualname(Derived, "foo"),
         DEFAULT_OPTIONS.overlay(max_iterations=10),
     )
     assert isinstance(diffs, list)
     self.assertEqual(
         [(d.result1.return_repr, d.result2.return_repr) for d in diffs],
         [("10", "11")],
     )
Exemple #5
0
def diffbehavior(args: argparse.Namespace, options: AnalysisOptions,
                 stdout: TextIO, stderr: TextIO) -> int:
    def checked_load(qualname: str) -> Optional[FunctionInfo]:
        try:
            objs = list(load_files_or_qualnames([qualname]))
        except Exception as exc:
            print(f'Unable to load "{qualname}": {exc}', file=stderr)
            return None
        obj = objs[0]
        if not isinstance(obj, FunctionInfo):
            print(f'"{qualname}" does not target a function.', file=stderr)
            return None
        return obj

    (fn_name1, fn_name2) = (args.fn1, args.fn2)
    fn1 = checked_load(fn_name1)
    fn2 = checked_load(fn_name2)
    if fn1 is None or fn2 is None:
        return 2
    options.stats = collections.Counter()
    diffs = diff_behavior(fn1, fn2, options)
    debug("stats", options.stats)
    if isinstance(diffs, str):
        print(diffs, file=stderr)
        return 2
    elif len(diffs) == 0:
        num_paths = options.stats["num_paths"]
        exhausted = options.stats["exhaustion"] > 0
        stdout.write(
            f"No differences found. (attempted {num_paths} iterations)\n")
        if exhausted:
            stdout.write(
                "All paths exhausted, functions are likely the same!\n")
        else:
            stdout.write(
                "Consider trying longer with: --per_condition_timeout=<seconds>\n"
            )
        return 0
    else:
        width = max(len(fn_name1), len(fn_name2)) + 2
        for diff in diffs:
            inputs = ", ".join(f"{k}={v}" for k, v in diff.args.items())
            stdout.write(f"Given: ({inputs}),\n")
            result1, result2 = diff.result1, diff.result2
            differing_args = result1.get_differing_arg_mutations(result2)
            stdout.write(
                f"{fn_name1.rjust(width)} : {result1.describe(differing_args)}\n"
            )
            stdout.write(
                f"{fn_name2.rjust(width)} : {result2.describe(differing_args)}\n"
            )
        return 1
Exemple #6
0
    def test_diff_behavior_mutation(self) -> None:
        def cut_out_item1(a: List[int], i: int):
            a[i:i + 1] = []

        def cut_out_item2(a: List[int], i: int):
            a[:] = a[:i] + a[i + 1:]

        # TODO: this takes longer than I'd like (few iterations though):
        opts = DEFAULT_OPTIONS.overlay(max_iterations=20,
                                       per_path_timeout=10,
                                       per_condition_timeout=10)
        diffs = diff_behavior(
            FunctionInfo.from_fn(cut_out_item1),
            FunctionInfo.from_fn(cut_out_item2),
            opts,
        )
        assert not isinstance(diffs, str)
        self.assertEqual(len(diffs), 1)
        diff = diffs[0]
        self.assertGreater(len(diff.args["a"]), 1)
        self.assertEqual(diff.args["i"], "-1")
Exemple #7
0
def diffbehavior(args: argparse.Namespace, options: AnalysisOptions,
                 stdout: TextIO, stderr: TextIO) -> int:
    (fn_name1, fn_name2) = (args.fn1, args.fn2)
    fn1 = checked_load(fn_name1, stderr)
    fn2 = checked_load(fn_name2, stderr)
    if fn1 is None or fn2 is None:
        return 2
    options.stats = collections.Counter()
    diffs = diff_behavior(fn1, fn2, options)
    debug("stats", options.stats)
    if isinstance(diffs, str):
        print(diffs, file=stderr)
        return 2
    elif len(diffs) == 0:
        num_paths = options.stats["num_paths"]
        exhausted = options.stats["exhaustion"] > 0
        stdout.write(
            f"No differences found. (attempted {num_paths} iterations)\n")
        if exhausted:
            stdout.write(
                "All paths exhausted, functions are likely the same!\n")
        else:
            stdout.write(
                "Consider trying longer with: --per_condition_timeout=<seconds>\n"
            )
        return 0
    else:
        width = max(len(fn_name1), len(fn_name2)) + 2
        for diff in diffs:
            inputs = ", ".join(f"{k}={v}" for k, v in diff.args.items())
            stdout.write(f"Given: ({inputs}),\n")
            result1, result2 = diff.result1, diff.result2
            differing_args = result1.get_differing_arg_mutations(result2)
            stdout.write(
                f"{fn_name1.rjust(width)} : {result1.describe(differing_args)}\n"
            )
            stdout.write(
                f"{fn_name2.rjust(width)} : {result2.describe(differing_args)}\n"
            )
        return 1
Exemple #8
0
 def test_diff_behavior_same(self) -> None:
     diffs = diff_behavior(foo1, foo2,
                           DEFAULT_OPTIONS.overlay(max_iterations=10))
     self.assertEqual(diffs, [])