class DemoStateMachine(stateful.RuleBasedStateMachine): Things = stateful.Bundle("things") Stuff = stateful.Bundle("stuff") StuffAndThings = Things | Stuff @stateful.rule(target=Things, name=st.text()) def create_thing(self, name): return name @stateful.rule(target=Stuff, name=st.text()) def create_stuff(self, name): return name @stateful.rule(item=StuffAndThings) def do(self, item): return
class DemoStateMachine(stateful.RuleBasedStateMachine): Stuff = stateful.Bundle("stuff") @stateful.rule(target=Stuff, name=st.text()) def create_stuff(self, name): return name @stateful.rule(item=Stuff) def do(self, item): return
class PtrMixSM(stateful.RuleBasedStateMachine): def __init__(self): super().__init__() self._var = None self._contents = {} mixed_pointers = stateful.Bundle("mixed pointers") @stateful.initialize(target=mixed_pointers, a=pointers(), b=pointers()) def mixptr(self, a, b): self._var = lib.mixptr(a, b) self._contents = {a: b, b: a} return stateful.multiple(a, b) @stateful.invariant() def equation(self): # nothing to check if called before initialization. if self._contents: # make it work if a == b and thus _contents has 1 entry contents = list(self._contents) a, b = contents[0], contents[-1] assert self._var.content == lib.mixptr(a, b).content @stateful.invariant() def unmixptr(self): for ptr in self._contents: assert lib.unmixptr(self._var, ptr) == self._contents[ptr] @stateful.rule(target=mixed_pointers, a=stateful.consumes(mixed_pointers), b=pointers()) def remixptr(self, a, b): lib.remixptr(ffi.addressof(self._var), a, b) a = self._contents[a] self._contents = {a: b, b: a} return b
class ChatRules(sta.RuleBasedStateMachine): chat: Chat panels: OrderedDict[str, PanelSetting] custom_channels: OrderedDict[str, CustomChannelsSetting] colors: List[Color] def __init__(self) -> None: super(ChatRules, self).__init__() self.chat = Chat() self.panels = OrderedDict() self.custom_channels = OrderedDict() self.colors = parse_colors(default_colors) panel_refs = sta.Bundle("panels") custom_channel_refs = sta.Bundle("custom_channels") # Will be initialized once and stay fixed. standard_channel_refs = sta.Bundle("standard_channels") @sta.initialize(target=standard_channel_refs) def init_standard_channels(self) -> Any: return sta.multiple(*self.chat.standard_channels) # Panels @sta.invariant() def expected_number_of_panels(self) -> None: assert len(self.chat.panels) == len(self.panels) @sta.rule(target=panel_refs, name=valid_panel_name) def new_panel(self, name: str) -> Panel: name_lower = swtor_lower(name) assume(name_lower not in self.panels.keys()) num = len(self.panels) + 1 self.panels[name_lower] = PanelSetting(num, name, set()) return self.chat.panel(name) @sta.rule(panel_c=panel_refs) def existing_panel(self, panel_c: Panel) -> None: with pytest.raises(ValueError): self.chat.panel(panel_c.name) with pytest.raises(ValueError): self.chat.panel(swtor_lower(panel_c.name)) with pytest.raises(ValueError): self.chat.panel(swtor_upper(panel_c.name)) # Custom channels @sta.invariant() def expected_number_of_custom_channels(self) -> None: assert len(self.chat.custom_channels) == len(self.custom_channels) assert len(self.chat.custom_channels) <= num_custom_channels @sta.precondition(lambda self: len(self.custom_channels) < num_custom_channels) @sta.rule( target=custom_channel_refs, name=valid_custom_channel_name, password=valid_custom_channel_password, id=valid_custom_channel_id, ) def new_custom_channel( self, name: str, password: Optional[str], id: Optional[str] ) -> CustomChannel: name_lower = swtor_lower(name) assume(name_lower not in self.custom_channels) num = len(self.custom_channels) + 1 self.custom_channels[name_lower] = CustomChannelsSetting( name, password if password is not None else "", num, id if id is not None else f"usr.{name_lower}", ) return self.chat.custom_channel(name, password=password, id=id) @sta.precondition(lambda self: len(self.custom_channels) == num_custom_channels) @sta.rule( name=valid_custom_channel_name, password=valid_custom_channel_password, id=valid_custom_channel_id, ) def new_custom_channel_too_many( self, name: str, password: Optional[str], id: Optional[str] ) -> None: name_lower = swtor_lower(name) assume(name_lower not in self.custom_channels) with pytest.raises(RuntimeError): self.chat.custom_channel(name, password=password, id=id) @sta.rule(custom_channel_c=custom_channel_refs) def existing_custom_channel(self, custom_channel_c: CustomChannel) -> None: with pytest.raises(ValueError): self.chat.custom_channel(custom_channel_c.name) with pytest.raises(ValueError): self.chat.custom_channel(swtor_lower(custom_channel_c.name)) with pytest.raises(ValueError): self.chat.custom_channel(swtor_upper(custom_channel_c.name)) # Displaying channels @sta.rule( panel_c=panel_refs, channels_c=st.lists(st.one_of(standard_channel_refs, custom_channel_refs)), ) def panel_display_channel( self, panel_c: Panel, channels_c: Iterable[Channel] ) -> None: for channel_c in channels_c: self.panels[swtor_lower(panel_c.name)].channel_ixs.add(channel_c.ix) panel_c.display(*channels_c) # Setting colors @sta.rule( channel_c=st.one_of(standard_channel_refs, custom_channel_refs), color=valid_color, ) def replace_channel_color(self, channel_c: Channel, color: Color) -> None: self.colors[channel_c.ix] = color channel_c.color = color @sta.rule( channel_c=st.one_of(standard_channel_refs, custom_channel_refs), color=valid_color, ) def mutate_channel_color(self, channel_c: Channel, color: Color) -> None: self.colors[channel_c.ix].r = color.r self.colors[channel_c.ix].g = color.g self.colors[channel_c.ix].b = color.b channel_c.color.r = color.r channel_c.color.g = color.g channel_c.color.b = color.b @sta.rule( source_channel_c=st.one_of(standard_channel_refs, custom_channel_refs), target_channel_c=st.one_of(standard_channel_refs, custom_channel_refs), ) def link_channel_color( self, source_channel_c: Channel, target_channel_c: Channel ) -> None: self.colors[target_channel_c.ix] = self.colors[source_channel_c.ix] target_channel_c.color = source_channel_c.color # Applying the settings @sta.invariant() def apply_applies_settings(self) -> None: settings = {"foo": "bar"} self.chat.apply(settings) assert set(settings.keys()) == { "foo", "ChatChannels", "Chat_Custom_Channels", "ChatColors", } parse_panels(settings["ChatChannels"]) parse_custom_channels(settings["Chat_Custom_Channels"]) parse_colors(settings["ChatColors"]) # The panels setting (ChatChannels) @sta.precondition(lambda self: not self.panels) @sta.invariant() def channels_setting_has_a_default_panel(self) -> None: setting = self.chat.panels_setting() # note(f"panels_setting: {setting!r}") panels_s = parse_panels(setting) assert panels_s == [PanelSetting(1, "General", all_channel_ixs)] @sta.precondition(lambda self: self.panels) @sta.invariant() def channels_setting_is_correct(self) -> None: setting = self.chat.panels_setting() # note(f"channels_setting: {setting!r}") panels_s = parse_panels(setting) assert len(panels_s) == len(self.panels) displayed_ixs = set() for panel_s in panels_s: displayed_ixs |= panel_s.channel_ixs missing_ixs = all_channel_ixs - displayed_ixs extra_ixs = displayed_ixs - all_channel_ixs assert not missing_ixs, "A channel is not displayed in any panel" assert not extra_ixs, "An impossible channel is displayed in a panel" for (panel_s, panel) in zip(panels_s, self.panels.values()): assert panel_s.number == panel.number assert panel_s.name == panel.name missing_ixs = panel.channel_ixs - panel_s.channel_ixs extra_ixs = panel_s.channel_ixs - panel.channel_ixs assert not missing_ixs, "Fewer channels are displayed than expected" # The first panel should have the explicitly displayed channel # and possibly more. The other panels should only have the # explicitly displayed channels. if panel.number != 1: assert not extra_ixs, "More channels are displayed than expected" # The Chat_Custom_Channels setting @sta.invariant() def custom_channels_setting_is_correct(self) -> None: setting = self.chat.custom_channels_setting() # note(f"custom_channels_setting: {setting!r}") custom_channels_s = parse_custom_channels(setting) assert len(custom_channels_s) == len(self.custom_channels) for cc_s, cc in zip(custom_channels_s, self.custom_channels.values()): assert cc_s == cc # The ChatColors setting @sta.invariant() def colors_setting_is_correct(self) -> None: setting = self.chat.colors_setting() # note(f"colors_setting: {setting!r}") colors_s = parse_colors(setting) assert colors_s == self.colors
class VerificationStateMachine(stateful.RuleBasedStateMachine): """ Verify the implementation of a timing wheel against the :py:class:`TimerHeap`. """ scripts = stateful.Bundle("scripts") def make_epicycle(self): """ Make a timing wheel instance to test. """ raise NotImplementedError def assert_whens(self, wheel, heap): empty_raised = 'empty raised' try: wheel_when = wheel.when() except Empty: wheel_when = empty_raised try: heap_when = heap.when() except Empty: heap_when = empty_raised assert wheel_when == heap_when def play_script(self, script): wheel = self.make_epicycle() heap = TimerHeap() state = TimerState() for step in script: step(wheel, heap, state) no_empty_script = True @stateful.precondition(lambda self: self.no_empty_script) @stateful.rule(target=scripts) def inital_script(self): self.no_empty_script = False return pvector() @stateful.rule(interval=st.integers(min_value=0, max_value=16), script=scripts, target=scripts) def add(self, interval, script): def perform_add(wheel, heap, state): action = state.make_action() self.assert_whens(wheel, heap) wheel_request_id = wheel.add(interval, action.call_from_wheel) heap_request_id = heap.add(interval, action.call_from_heap) self.assert_whens(wheel, heap) assert wheel_request_id == heap_request_id state.record_action(wheel_request_id, action) script_with_add = script.append(perform_add) self.play_script(script_with_add) return script_with_add @stateful.rule(data=st.data(), script=scripts, target=scripts) def remove(self, data, script): def perform_remove(wheel, heap, state): if state.request_ids: request_id = data.draw(st.sampled_from(list( state.request_ids))) state.request_ids.pop(request_id) self.assert_whens(wheel, heap) wheel.remove(request_id) heap.remove(request_id) self.assert_whens(wheel, heap) script_with_remove = script.append(perform_remove) self.play_script(script_with_remove) return script_with_remove @stateful.rule(ticks=st.integers(min_value=1, max_value=127), script=scripts, target=scripts) def tick(self, ticks, script): def perform_tick(wheel, heap, state): for _ in range(ticks): wheel.tick() heap.tick() for action in state.request_ids.values(): action.equivalent() script_with_tick = script.append(perform_tick) self.play_script(script_with_tick) return script_with_tick