def test_syntax_error(self) -> None: def f(x: int) -> int: """ pre: x && x """ self.assertEqual( *check_messages(analyze_function(f), state=MessageType.SYNTAX_ERR) )
def test_methods_directly(self) -> None: # Running analysis on individual methods directly works a little # differently, especially for staticmethod/classmethod. Confirm these # don't explode: messages = analyze_any(Person.a_regular_method, AnalysisOptions()) self.assertEqual( *check_messages(messages, state=MessageType.CONFIRMED))
def test_super(self): class FooDetector(SmokeDetector): def signaling_alarm(self, air_samples: List[str]): return super().signaling_alarm(air_samples) self.assertEqual(*check_messages(analyze_class(FooDetector), state=MessageType.CONFIRMED))
def test_static_method(self) -> None: messages = analyze_any( walk_qualname(Person, "a_static_method"), AnalysisOptionSet(per_condition_timeout=5), ) self.assertEqual( *check_messages(messages, state=MessageType.CONFIRMED))
def test_invalid_raises(self) -> None: def f(x: int) -> int: """ raises: NotExistingError """ return x self.assertEqual( *check_messages(analyze_function(f), state=MessageType.SYNTAX_ERR))
def test_expr_name_resolution(self): ''' dataclass() generates several methods. It can be tricky to ensure that invariants for these methods can resolve names in the correct namespace. ''' self.assertEqual(*check_messages(analyze_class(ReferenceHoldingClass), state=MessageType.CONFIRMED))
def test_icontract_snapshots(self): messages = analyze_function( icontract_appender, DEFAULT_OPTIONS.overlay( analysis_kind=[AnalysisKind.icontract]), ) self.assertEqual(*check_messages( messages, state=MessageType.POST_FAIL, line=95, column=0))
def test_old_works_in_invariants(self) -> None: class FrozenApples: ''' inv: self.count == __old__.self.count ''' count: int def add_one(self): self.count += 1 messages = analyze_class(FrozenApples) self.assertEqual(*check_messages(messages, state=MessageType.POST_FAIL))
def test_readonly_property_contract(self) -> None: class Clock: @property def time(self) -> int: """ post: _ == self.time """ return 120 messages = analyze_class(Clock) self.assertEqual(*check_messages(messages, state=MessageType.CONFIRMED))
def test_methods_directly(self) -> None: # Running analysis on individual methods directly works a little # differently, especially for staticmethod/classmethod. Confirm these # don't explode: messages = analyze_any( walk_qualname(Person, "a_regular_method"), AnalysisOptionSet(per_condition_timeout=5), ) self.assertEqual(*check_messages(messages, state=MessageType.CONFIRMED))
def test_use_inherited_postconditions(self): class CarbonMonoxideDetector(SmokeDetector): def signaling_alarm(self, air_samples: List[str]) -> bool: ''' post: implies('carbon_monoxide' in air_samples, _ == True) ''' return 'carbon_monoxide' in air_samples # fails: does not detect smoke self.assertEqual(*check_messages(analyze_class(CarbonMonoxideDetector), state=MessageType.POST_FAIL))
def test_error_message_in_unrelated_method(self) -> None: messages = analyze_class(OverloadedContainer) self.assertEqual(*check_messages( messages, state=MessageType.POST_FAIL, message= "false when calling total_weight(self = OverloadedContainer) (which returns 13)", line=132, ))
def test_bad_invariant(self): class Foo: """ inv: self.item == 7 """ def do_a_thing(self) -> None: pass self.assertEqual( *check_messages(analyze_class(Foo), state=MessageType.PRE_UNSAT))
def test_inherited_preconditions_overridable(self): class SmokeDetectorWithBattery(SmokeDetector): _battery_power: int def signaling_alarm(self, air_samples: List[str]) -> bool: ''' pre: self._battery_power > 0 or self._is_plugged_in ''' return 'smoke' in air_samples self.assertEqual(*check_messages(analyze_class(SmokeDetectorWithBattery), state=MessageType.CONFIRMED))
def test_error_message_in_unrelated_method(self) -> None: messages = analyze_class(OverloadedContainer) line = ShippingContainer.total_weight.__code__.co_firstlineno + 1 self.assertEqual( *check_messages( messages, state=MessageType.POST_FAIL, message="false when calling total_weight(self = OverloadedContainer) (which returns 13)", line=line, ) )
def test_asserts(self): messages = analyze_function( remove_smallest_with_asserts, DEFAULT_OPTIONS.overlay( analysis_kind=[AnalysisKind.asserts], max_iterations=10, per_condition_timeout=5, ), ) self.assertEqual(*check_messages( messages, state=MessageType.EXEC_ERR, line=85, column=0))
def test_icontract_snapshots(self): messages = analyze_function( icontract_appender, DEFAULT_OPTIONS.overlay(analysis_kind=[AnalysisKind.icontract]), ) line = icontract_appender.__wrapped__.__code__.co_firstlineno + 1 self.assertEqual( *check_messages( messages, state=MessageType.POST_FAIL, line=line, column=0 ) )
def TODO_test_cannot_strengthen_inherited_preconditions(self): class PowerHungrySmokeDetector(SmokeDetector): _battery_power: int def signaling_alarm(self, air_samples: List[str]) -> bool: ''' pre: self._is_plugged_in pre: self._battery_power > 0 ''' return 'smoke' in air_samples self.assertEqual(*check_messages(analyze_class(PowerHungrySmokeDetector), state=MessageType.PRE_INVALID))
def test_error_message_has_unmodified_args(self) -> None: def f(foo: List[Pokeable]) -> None: ''' pre: len(foo) == 1 pre: foo[0].x == 10 post[foo]: foo[0].x == 12 ''' foo[0].poke() self.assertEqual(*check_messages( analyze_function(f), state=MessageType.POST_FAIL, message='false when calling f(foo = [Pokeable(10)])'))
def test_hypothesis_counterexample_text(): messages = analyze_function( foo, DEFAULT_OPTIONS.overlay( analysis_kind=[AnalysisKind.hypothesis], max_iterations=10, per_condition_timeout=20, per_path_timeout=5, ), ) actual, expected = check_messages( messages, state=MessageType.EXEC_ERR, message="AssertionError: assert False when calling foo(x = False)", ) assert actual == expected
def test_check_parent_conditions(self): # Ensure that conditions of parent classes are checked in children # even when not overridden. class Parent: def size(self) -> int: return 1 def amount_smaller(self, other_size: int) -> int: ''' pre: other_size >= 1 post: _ >= 0 ''' return other_size - self.size() class Child(Parent): def size(self) -> int: return 2 messages = analyze_class(Child) self.assertEqual(*check_messages(messages, state=MessageType.POST_FAIL))
def test_typevar(self) -> None: T = TypeVar('T') class MaybePair(Generic[T]): ''' inv: (self.left is None) == (self.right is None) ''' left: Optional[T] right: Optional[T] def setpair(self, left: Optional[T], right: Optional[T]): '''post[self]: True''' if (left is None) ^ (right is None): raise ValueError('Populate both values or neither value in the pair') self.left, self.right = left, right messages = analyze_class(MaybePair) self.assertEqual(*check_messages(messages, state=MessageType.EXEC_ERR))
def test_old_works_in_invariants(self) -> None: @dataclasses.dataclass class FrozenApples: """ inv: self.count == __old__.self.count """ count: int def add_one(self): self.count += 1 messages = analyze_class(FrozenApples) self.assertEqual(*check_messages(messages, state=MessageType.POST_FAIL)) # Also confirm we can create one as an argument: def f(a: FrozenApples) -> int: """post: True""" return 0 self.assertEqual(*check_ok(f))
def test_recursive_postcondition_enforcement_suspension(self) -> None: messages = analyze_class(Measurer) self.assertEqual( *check_messages(messages, state=MessageType.POST_FAIL))
def test_inheritance_base_class_ok(self): self.assertEqual(*check_messages(analyze_class(SmokeDetector), state=MessageType.CONFIRMED))
def test_person_class(self) -> None: messages = analyze_class(Person) self.assertEqual( *check_messages(messages, state=MessageType.CONFIRMED))
def test_pokeable_class(self) -> None: messages = analyze_class(Pokeable) self.assertEqual(*check_messages( messages, state=MessageType.POST_FAIL, line=58, column=0))
def test_pokeable_class(self) -> None: messages = analyze_class(Pokeable) line = Pokeable.wild_pokeby.__code__.co_firstlineno self.assertEqual( *check_messages(messages, state=MessageType.POST_FAIL, line=line, column=0) )
def test_static_method(self) -> None: messages = analyze_any(Person.a_static_method, AnalysisOptions()) self.assertEqual(*check_messages(messages, state=MessageType.CONFIRMED))