def test_use_subclasses_of_arguments(self): # Even though the argument below is typed as the base class, the fact # that a faulty implementation exists is enough to produce a # counterexample: def f(foo: Cat) -> int: """ post: _ == 1 """ return foo.size() # Type repo doesn't load crosshair classes by default; load manually: type_repo._add_class(Cat) type_repo._add_class(BiggerCat) self.assertEqual(*check_fail(f))
def test_range_fail(self) -> None: def f(l: List[int]) -> List[int]: ''' pre: len(l) == 3 post: len(_) > len(l) ''' n: List[int] = [] for i in range(len(l)): n.append(l[i] + 1) return n self.assertEqual(*check_fail(f))
def test_dicts_inside_lists(self) -> None: def f(dicts: List[Dict[int, int]]) -> Dict[int, int]: ''' pre: len(dicts) <= 1 # to narrow search space (would love to make this larger) post: len(_) <= len(dicts) ''' ret = {} for d in dicts: ret.update(d) return ret self.assertEqual(*check_fail(f))
def test_nonlinear(self) -> None: def make_bigger(x: int, e: int) -> float: """ pre: e > 1 post: __return__ != 592704 """ # Expenentation is not SMT-solvable. (z3 gives unsat for this) # But CrossHair gracefully falls back to realized values, yielding # the counterexample of: 84 ** 3 return x**e self.assertEqual(*check_fail(make_bigger))
def TODO_test_dict_deep_equality(self) -> None: # This is too challenging right now. # TODO: 'set' type has no __args__ def f(a: Dict[bool, Set], b: Dict[str, List[Set[float]]]) -> object: ''' pre: a == {True: set()} pre: b == {'': [set(), {1.0}]} post: _ ''' if a == {True: set()}: if b == {'': [set(), {1.0}]}: return False return True self.assertEqual(*check_fail(f))
def test_equality(self) -> None: def f(l: List[int]) -> List[int]: """ pre: len(l) > 0 post: _ != l """ # extra check for positive equality: assert l == [x for x in l], "list does not equal itself" nl = l[:] nl[0] = 42 return nl self.assertEqual(*check_fail(f))
def test_symbolic_supports(self) -> None: def f( a: SupportsAbs, f: SupportsFloat, i: SupportsInt, r: SupportsRound, c: SupportsComplex, b: SupportsBytes, ) -> float: """ post: _.real <= 0 """ return abs(a) + float(f) + int(i) + round(r) + complex(c) + len( bytes(b)) self.assertEqual(*check_fail(f))
def TODO_test_dict_deep_equality( self, ) -> None: # This is too challenging right now. def f(a: Dict[bool, set], b: Dict[str, List[Set[float]]]) -> object: """ pre: a == {True: set()} pre: b == {'': [set(), {1.0}]} post: _ """ if a == {True: set()}: if b == {"": [set(), {1.0}]}: return False return True self.assertEqual(*check_fail(f))
def test_number_parse(self) -> None: number_re = re.compile(r"(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?") def f(s: str): """ pre: len(s) == 4 post: not _ """ return bool(number_re.fullmatch(s)) self.assertEqual(*check_fail( f, AnalysisOptionSet(max_iterations=20, per_path_timeout=5, per_condition_timeout=20), ))
def test_dicts_inside_lists_with_identity(self) -> None: # NOTE: the message is a little confusing because repr() # hides the fact that the identity of the lists is the same. def f(dicts: List[Dict[int, int]]): ''' Removes duplicate keys. pre: len(dicts) == 2 pre: len(dicts[0]) == 1 post: len(dicts[0]) == 1 ''' seen: Set[int] = set() for d in dicts: for k in d.keys(): if k in seen: del d[k] else: seen.add(k) self.assertEqual(*check_fail(f))
def test_runtime_type(self) -> None: def f(t: dict) -> dict: ''' post: t != {1: 2} ''' return t self.assertEqual(*check_fail(f))
def test_simple_bool_with_fail(self) -> None: def f(a: bool, b: bool) -> bool: ''' post: _ == a ''' return True if a else b self.assertEqual(*check_fail(f))
def test_match_basic_fail2(self) -> None: def f(s: str) -> bool: """ post: implies(_, len(s) <= 3) """ return bool(re.compile("ab?c").match(s)) self.assertEqual(*check_fail(f))
def test_int_str_comparison_fail(self) -> None: def f(a: int, b: str) -> Tuple[bool, bool]: ''' post: (not _[0]) or (not _[1]) ''' return (a != b, b != a) self.assertEqual(*check_fail(f))
def test_runtime_type(self) -> None: def f(t: Tuple) -> Tuple: ''' post: t != (1, 2) ''' return t self.assertEqual(*check_fail(f))
def test_symbolic_type_can_be_subclass(self) -> None: def f(typ: Type[Cat]): ''' post: _ == "<class '__main__.Cat'>" ''' return str(typ) # False when the type is instantiated as "BiggerCat": self.assertEqual(*check_fail(f))
def test_str_comparison_fail(self) -> None: def f(s1: str, s2: str) -> bool: ''' post: _ ''' return s1 >= s2 self.assertEqual(*check_fail(f))
def test_cast_to_bool_fail(self) -> None: def f(a: str) -> str: ''' post: a ''' return a self.assertEqual(*check_fail(f))
def test_prefixing_fail(self) -> None: def f(a: str, indent: bool) -> str: ''' post: len(_) == len(a) + indent ''' return (' ' if indent else '') + a self.assertEqual(*check_fail(f))
def test_specific_length(self) -> None: def f(b: bytes) -> int: """ post: _ != 5 """ return len(b) self.assertEqual(*check_fail(f))
def test_int_div_fail(self) -> None: def f(a: int, b: int) -> int: ''' post: a <= _ <= b ''' return (a + b) // 2 self.assertEqual(*check_fail(f))
def test_subtype_union(self) -> None: def f(s: Set[Union[int, str]]) -> None: ''' post: not (42 in s and '42' in s) ''' return s self.assertEqual(*check_fail(f))
def test_type_comparison(self) -> None: def f(t: Type) -> bool: ''' post: _ ''' return t == int self.assertEqual(*check_fail(f))
def test_symbolic_types_fail(self) -> None: def f(typ: Type): ''' post: _ ''' return issubclass(typ, str) self.assertEqual(*check_fail(f))
def test_bool_ors_fail(self) -> None: def f(a: bool, b: bool, c: bool, d: bool) -> bool: ''' post: _ == (a ^ b) or (c ^ d) ''' return a or b or c or d self.assertEqual(*check_fail(f))
def test_negative_index_slicing(self) -> None: def f(s: str) -> Tuple[str, str]: ''' post: sum(map(len, _)) == len(s) - 1 ''' idx = s.find(':') return (s[:idx], s[idx + 1:]) self.assertEqual(*check_fail(f)) # (fails when idx == -1)
def test_generic_object_equality(self) -> None: def f(thing: object, i: int): ''' post: not _ ''' return thing == i self.assertEqual(*check_fail(f))
def test_enum_in_container(self) -> None: def f(colors: List[Color]) -> bool: ''' post: not _ ''' return Color.RED in colors and Color.BLUE in colors self.assertEqual(*check_fail(f))
def test_hashable_values_fail(self) -> None: def f(b: bool, i: int, t: Tuple[str, ...], s: FrozenSet[float]) -> int: ''' post: _ % 10 != 0 ''' return hash((i, t, s)) self.assertEqual(*check_fail(f))
def test_symbolic_two_arg_callable(self) -> None: def f(i: int, callable: Callable[[int, int], int]) -> int: ''' post: _ != i ''' return callable(i, i) self.assertEqual(*check_fail(f))