From aa1c8e9c4ff2560d89dc5c9295fc3ebd6ec307b1 Mon Sep 17 00:00:00 2001 From: kdmukai Date: Mon, 15 Jul 2024 16:54:56 -0500 Subject: [PATCH] Further clarifications, one more FlowTest exception added --- tests/base.py | 9 +++++++++ tests/test_flows.py | 27 ++++++++++++++++++++++----- tests/test_flows_seed.py | 6 ++---- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/tests/base.py b/tests/base.py index d4c89c63..100ac741 100644 --- a/tests/base.py +++ b/tests/base.py @@ -157,6 +157,10 @@ class FlowTestUnexpectedRedirectException(FlowBasedTestException): pass +class FlowTestMissingRedirectException(FlowBasedTestException): + """ The Controller's current View did NOT trigger a redirect when one was expected by the current FlowStep in the sequence """ + pass + class FlowTest(BaseTest): """ Base class for any tests that do flow-based testing """ @@ -225,6 +229,11 @@ class FlowTest(BaseTest): # but we weren't expecting it. raise FlowTestUnexpectedRedirectException(f"Unexpected redirect to {destination.View_cls}") + elif mock_run_screen.call_count > prev_mock_run_screen_call_count and cur_flow_step.is_redirect: + # The View ran its Screen, but the current FlowStep was expecting it + # to redirect (is_redirect=True) *instead of* running its Screen. + raise FlowTestMissingRedirectException(f"FlowStep expected redirect but {cur_flow_step.expected_view} did not redirect") + finally: # Regardless of the outcome, we always move our FlowTest # sequence forward. diff --git a/tests/test_flows.py b/tests/test_flows.py index 1d482c17..acb8e8a3 100644 --- a/tests/test_flows.py +++ b/tests/test_flows.py @@ -1,11 +1,12 @@ import pytest # Must import test base before the Controller -from base import FlowTest, FlowStep, FlowTestUnexpectedRedirectException, FlowTestUnexpectedViewException, FlowTestInvalidButtonDataSelectionException +from base import FlowTest, FlowStep, FlowTestMissingRedirectException, FlowTestUnexpectedRedirectException, FlowTestUnexpectedViewException, FlowTestInvalidButtonDataSelectionException from seedsigner.controller import Controller from seedsigner.gui.screens.screen import RET_CODE__BACK_BUTTON, RET_CODE__POWER_BUTTON from seedsigner.models.seed import Seed +from seedsigner.views import scan_views from seedsigner.views.psbt_views import PSBTSelectSeedView from seedsigner.views.seed_views import SeedBackupView, SeedMnemonicEntryView, SeedOptionsView, SeedsMenuView from seedsigner.views.view import MainMenuView, PowerOptionsView, UnhandledExceptionView @@ -42,15 +43,21 @@ class TestFlowTest(FlowTest): def test_UnhandledExceptionView(self): """ - Ensure that the FlowTest will raise a FlowTestUnexpectedViewException if an - UnhandledExceptionView is encountered. + This is a regression test to ensure that the FlowTest is aware of exceptions that + redirect to the UnhandledExceptionView. If that isn't the expected View, the + FlowTest should raise a FlowTestUnexpectedViewException. """ + # This sequence simulates a FlowTest that is unaware of an exception that will + # derail the sequence (i.e. somebody wrote a bad FlowTest or something unexpected + # is breaking). The sequence should fail with FlowTestUnexpectedViewException. with pytest.raises(FlowTestUnexpectedViewException): self.run_sequence([ - FlowStep(SeedOptionsView), # <-- There is no seed loaded nor a seed_num specified. Should raise an UnhandledException. + FlowStep(PSBTSelectSeedView), # <-- There is no PSBT loaded. Should raise an exception that routes us to the UnhandledExceptionView. + FlowStep(scan_views.ScanSeedQRView), # <-- This is not the View we'll end up at; FlowTest should raise the FlowTestUnexpectedViewException ]) - # If we don't trap the exception, we should end up at the UnhandledExceptionView. + # This sequence *expects* an exception to route us to the UnhandledExceptionView + # and therefore can complete successfully. self.run_sequence([ FlowStep(PSBTSelectSeedView), # <-- There's no PSBT loaded. FlowStep(UnhandledExceptionView), @@ -83,6 +90,16 @@ class TestFlowTest(FlowTest): ]) + def test_FlowTestMissingRedirectException(self): + """ + If the FlowStep specifies is_redirect but the View does NOT redirect, raise FlowTestMissingRedirectException + """ + with pytest.raises(FlowTestMissingRedirectException): + self.run_sequence([ + FlowStep(MainMenuView, button_data_selection=MainMenuView.TOOLS, is_redirect=True), + ]) + + def test_before_run_executes(self): """ Ensure that the FlowTest can execute a function before running a View. diff --git a/tests/test_flows_seed.py b/tests/test_flows_seed.py index e654c1b5..c46e0173 100644 --- a/tests/test_flows_seed.py +++ b/tests/test_flows_seed.py @@ -561,8 +561,6 @@ class TestMessageSigningFlows(FlowTest): expect_network_mismatch_error(self.load_short_message_into_decoder) - - def test_sign_message_option_disabled(self): """ Should redirect to OptionDisabledView if a `signmessage` QR is scanned with @@ -583,7 +581,7 @@ class TestMessageSigningFlows(FlowTest): # First test routing to update the setting self.run_sequence( sequence + [ - FlowStep(OptionDisabledView, button_data_selection=OptionDisabledView.UPDATE_SETTING, is_redirect=True), + FlowStep(OptionDisabledView, button_data_selection=OptionDisabledView.UPDATE_SETTING), FlowStep(settings_views.SettingsEntryUpdateSelectionView), ] ) @@ -591,7 +589,7 @@ class TestMessageSigningFlows(FlowTest): # Now test exiting to Main Menu self.run_sequence( sequence + [ - FlowStep(OptionDisabledView, button_data_selection=OptionDisabledView.DONE, is_redirect=True), + FlowStep(OptionDisabledView, button_data_selection=OptionDisabledView.DONE), FlowStep(MainMenuView), ] )