From a1033c0e5f20c9eb9ca9d27dc5f510bede3c7157 Mon Sep 17 00:00:00 2001 From: matejcik Date: Thu, 14 Nov 2024 15:11:03 +0100 Subject: [PATCH] feat(tests): simplify asserts on translated strings --- tests/click_tests/common.py | 31 +-- tests/click_tests/recovery.py | 92 ++++---- tests/click_tests/reset.py | 23 +- tests/click_tests/test_autolock.py | 23 +- .../click_tests/test_backup_slip39_custom.py | 11 +- tests/click_tests/test_passphrase_tr.py | 20 +- tests/click_tests/test_pin.py | 22 +- tests/click_tests/test_reset_bip39.py | 6 +- tests/click_tests/test_tutorial_mercury.py | 84 ++++---- tests/click_tests/test_tutorial_tr.py | 2 +- tests/conftest.py | 3 +- .../test_reset_recovery_bip39.py | 3 + .../test_reset_recovery_slip39_advanced.py | 4 + .../test_reset_recovery_slip39_basic.py | 3 + tests/device_tests/test_repeated_backup.py | 8 +- tests/device_tests/test_sdcard.py | 16 +- .../test_session_id_and_passphrase.py | 16 +- tests/input_flows.py | 56 +++-- tests/input_flows_helpers.py | 204 ++++++++---------- tests/translations.py | 137 ++++-------- tests/ui_tests/fixtures.json | 6 +- 21 files changed, 337 insertions(+), 433 deletions(-) diff --git a/tests/click_tests/common.py b/tests/click_tests/common.py index cd1c1edf65..aaeeb97c66 100644 --- a/tests/click_tests/common.py +++ b/tests/click_tests/common.py @@ -1,16 +1,18 @@ from __future__ import annotations +import typing as t from enum import Enum -from typing import TYPE_CHECKING from trezorlib.debuglink import LayoutType from .. import buttons from .. import translations as TR -if TYPE_CHECKING: +if t.TYPE_CHECKING: from trezorlib.debuglink import DebugLink, LayoutContent + AllActionsType = t.List[t.Union[str, t.Tuple[str, ...]]] + # Passphrases and addresses for both models class CommonPass: @@ -82,7 +84,7 @@ def go_back(debug: "DebugLink", r_middle: bool = False) -> LayoutContent: def navigate_to_action_and_press( debug: "DebugLink", wanted_action: str, - all_actions: list[str], + all_actions: AllActionsType, is_carousel: bool = True, hold_ms: int = 0, ) -> None: @@ -129,16 +131,19 @@ def unlock_gesture(debug: "DebugLink") -> LayoutContent: raise RuntimeError("Unknown model") -def _get_action_index(wanted_action: str, all_actions: list[str]) -> int: +def _get_action_index(wanted_action: str, all_actions: AllActionsType) -> int: """Get index of the action in the list of all actions""" if wanted_action in all_actions: return all_actions.index(wanted_action) - else: - # It may happen that one action item can mean multiple actions - # (e.g. "CANCEL|DELETE" in the passphrase layout - both actions are on the same button) - for index, action in enumerate(all_actions): - subactions = action.split("|") - if wanted_action in subactions: + for index, action in enumerate(all_actions): + if not isinstance(action, tuple): + action = (action,) + for subaction in action: + try: + tr = TR.translate(subaction) + except KeyError: + continue + if tr == wanted_action: return index raise ValueError(f"Action {wanted_action} is not supported in {all_actions}") @@ -148,7 +153,7 @@ def _move_one_closer( debug: "DebugLink", wanted_action: str, current_action: str, - all_actions: list[str], + all_actions: AllActionsType, is_carousel: bool, ) -> LayoutContent: """Pressing either left or right regarding to the current situation""" @@ -169,7 +174,3 @@ def _move_one_closer( return debug.press_left() else: return debug.press_right() - - -def get_possible_btn_texts(path: str) -> str: - return "|".join(TR.translate(path)) diff --git a/tests/click_tests/recovery.py b/tests/click_tests/recovery.py index 89a6b6bc8b..c2e2aabc6c 100644 --- a/tests/click_tests/recovery.py +++ b/tests/click_tests/recovery.py @@ -4,15 +4,13 @@ from trezorlib.debuglink import LayoutType from .. import buttons from .. import translations as TR -from .common import get_possible_btn_texts, go_next +from .common import go_next if TYPE_CHECKING: from trezorlib.debuglink import DebugLink, LayoutContent -DELETE_BTN_TEXTS = get_possible_btn_texts("inputs__delete") + get_possible_btn_texts( - "inputs__previous" -) +DELETE_BTN_TEXTS = ("inputs__delete", "inputs__previous") def enter_word( @@ -50,7 +48,7 @@ def enter_word( def confirm_recovery(debug: "DebugLink", title: str = "recovery__title") -> None: layout = debug.read_layout() - TR.assert_equals(layout.title(), title) + assert TR.translate(title) == layout.title() if debug.layout_type is LayoutType.TT: debug.click(buttons.OK) elif debug.layout_type is LayoutType.Mercury: @@ -108,11 +106,11 @@ def select_number_of_words( return debug.click(coords) if debug.layout_type is LayoutType.TT: - TR.assert_equals(debug.read_layout().text_content(), "recovery__num_of_words") + assert debug.read_layout().text_content() == TR.recovery__num_of_words layout = select_tt() elif debug.layout_type is LayoutType.TR: layout = debug.press_right() - TR.assert_equals(layout.title(), "word_count__title") + assert layout.title() == TR.word_count__title layout = select_tr() elif debug.layout_type is LayoutType.Mercury: layout = select_mercury() @@ -121,30 +119,24 @@ def select_number_of_words( if unlock_repeated_backup: if debug.layout_type is LayoutType.TR: - TR.assert_in(layout.text_content(), "recovery__enter_backup") + assert TR.recovery__enter_backup in layout.text_content() else: - TR.assert_in_multiple( - layout.text_content(), - ["recovery__only_first_n_letters", "recovery__enter_each_word"], + assert ( + TR.recovery__only_first_n_letters in layout.text_content() + or TR.recovery__enter_each_word in layout.text_content() ) elif num_of_words in (20, 33): - TR.assert_in_multiple( - layout.text_content(), - [ - "recovery__enter_backup", - "recovery__enter_any_share", - "recovery__only_first_n_letters", - "recovery__enter_each_word", - ], + assert ( + TR.recovery__enter_backup in layout.text_content() + or TR.recovery__enter_any_share in layout.text_content() + or TR.recovery__only_first_n_letters in layout.text_content() + or TR.recovery__enter_each_word in layout.text_content() ) else: # BIP-39 - TR.assert_in_multiple( - layout.text_content(), - [ - "recovery__enter_backup", - "recovery__only_first_n_letters", - "recovery__enter_each_word", - ], + assert ( + TR.recovery__enter_backup in layout.text_content() + or TR.recovery__only_first_n_letters in layout.text_content() + or TR.recovery__enter_each_word in layout.text_content() ) @@ -155,14 +147,14 @@ def enter_share( before_title: str = "recovery__title_recover", ) -> "LayoutContent": if debug.layout_type is LayoutType.TR: - TR.assert_in(debug.read_layout().title(), before_title) + assert TR.translate(before_title) in debug.read_layout().title() layout = debug.read_layout() for _ in range(layout.page_count()): layout = debug.press_right() elif debug.layout_type is LayoutType.Mercury: layout = debug.swipe_up() else: - TR.assert_in(debug.read_layout().title(), before_title) + assert TR.translate(before_title) in debug.read_layout().title() layout = debug.click(buttons.OK) assert "MnemonicKeyboard" in layout.all_components() @@ -180,15 +172,12 @@ def enter_shares( text: str = "recovery__enter_any_share", after_layout_text: str = "recovery__wallet_recovered", ) -> None: - TR.assert_in_multiple( - debug.read_layout().text_content(), - [ - "recovery__enter_backup", - "recovery__enter_any_share", - "recovery__only_first_n_letters", - "recovery__enter_each_word", - text, - ], + assert ( + TR.recovery__enter_backup in debug.read_layout().text_content() + or TR.recovery__enter_any_share in debug.read_layout().text_content() + or TR.recovery__only_first_n_letters in debug.read_layout().text_content() + or TR.recovery__enter_each_word in debug.read_layout().text_content() + or TR.translate(text) in debug.read_layout().text_content() ) for index, share in enumerate(shares): enter_share( @@ -196,14 +185,14 @@ def enter_shares( ) if index < len(shares) - 1: # FIXME: when ui-t3t1 done for shamir, we want to check the template below - TR.assert_in(debug.read_layout().title(), enter_share_before_title) + assert TR.translate(enter_share_before_title) in debug.read_layout().title() # TR.assert_in( # debug.read_layout().text_content(), # "recovery__x_of_y_entered_template", # template=(index + 1, len(shares)), # ) - TR.assert_in(debug.read_layout().text_content(), after_layout_text) + assert TR.translate(after_layout_text) in debug.read_layout().text_content() def enter_seed( @@ -218,7 +207,7 @@ def enter_seed( for word in seed_words: enter_word(debug, word, is_slip39=is_slip39) - TR.assert_in(debug.read_layout().text_content(), after_layout_text) + assert TR.translate(after_layout_text) in debug.read_layout().text_content() def enter_seed_previous_correct( @@ -244,12 +233,18 @@ def enter_seed_previous_correct( elif debug.layout_type is LayoutType.TR: layout = debug.read_layout() - while layout.get_middle_choice() not in DELETE_BTN_TEXTS: + middle_choice = layout.get_middle_choice() + while not any( + TR.translate(btn) == middle_choice for btn in DELETE_BTN_TEXTS + ): layout = debug.press_right() layout = debug.press_middle() for _ in range(len(bad_word)): - while layout.get_middle_choice() not in DELETE_BTN_TEXTS: + middle_choice = layout.get_middle_choice() + while not any( + TR.translate(btn) == middle_choice for btn in DELETE_BTN_TEXTS + ): layout = debug.press_left() layout = debug.press_middle() elif debug.layout_type is LayoutType.Mercury: @@ -273,14 +268,11 @@ def enter_seed_previous_correct( def prepare_enter_seed( debug: "DebugLink", layout_text: str = "recovery__enter_backup" ) -> None: - TR.assert_in_multiple( - debug.read_layout().text_content(), - [ - "recovery__enter_backup", - "recovery__only_first_n_letters", - "recovery__enter_each_word", - layout_text, - ], + assert ( + TR.recovery__enter_backup in debug.read_layout().text_content() + or TR.recovery__only_first_n_letters in debug.read_layout().text_content() + or TR.recovery__enter_each_word in debug.read_layout().text_content() + or TR.translate(layout_text) in debug.read_layout().text_content() ) if debug.layout_type is LayoutType.TT: debug.click(buttons.OK) diff --git a/tests/click_tests/reset.py b/tests/click_tests/reset.py index b5c601ba34..4da0618375 100644 --- a/tests/click_tests/reset.py +++ b/tests/click_tests/reset.py @@ -13,7 +13,7 @@ if TYPE_CHECKING: def confirm_new_wallet(debug: "DebugLink") -> None: - TR.assert_equals(debug.read_layout().title(), "reset__title_create_wallet") + assert debug.read_layout().title() == TR.reset__title_create_wallet if debug.layout_type is LayoutType.TT: debug.click(buttons.OK) elif debug.layout_type is LayoutType.Mercury: @@ -22,9 +22,9 @@ def confirm_new_wallet(debug: "DebugLink") -> None: elif debug.layout_type is LayoutType.TR: debug.press_right() debug.press_right() - TR.assert_in_multiple( - debug.read_layout().text_content(), - ["backup__new_wallet_successfully_created", "backup__new_wallet_created"], + assert ( + TR.backup__new_wallet_successfully_created in debug.read_layout().text_content() + or TR.backup__new_wallet_created in debug.read_layout().text_content() ) if debug.layout_type is LayoutType.Mercury: debug.swipe_up() @@ -74,9 +74,10 @@ def set_selection(debug: "DebugLink", button: tuple[int, int], diff: int) -> Non debug.swipe_up() elif debug.layout_type is LayoutType.TR: layout = debug.read_layout() - if layout.title() in TR.translate( - "reset__title_number_of_shares" - ) + TR.translate("words__title_threshold"): + if ( + layout.title() + in TR.reset__title_number_of_shares + TR.words__title_threshold + ): # Special info screens layout = debug.press_right() assert "NumberInput" in layout.all_components() @@ -131,7 +132,9 @@ def confirm_words(debug: "DebugLink", words: list[str]) -> None: layout = debug.read_layout() if debug.layout_type is LayoutType.TT: - TR.assert_template(layout.text_content(), "reset__select_word_x_of_y_template") + assert TR.regexp("reset__select_word_x_of_y_template").match( + layout.text_content() + ) for _ in range(3): # "Select word 3 of 20" # ^ @@ -146,7 +149,7 @@ def confirm_words(debug: "DebugLink", words: list[str]) -> None: button_pos = btn_texts.index(wanted_word) layout = debug.click(buttons.RESET_WORD_CHECK[button_pos]) elif debug.layout_type is LayoutType.Mercury: - TR.assert_template(layout.subtitle(), "reset__select_word_x_of_y_template") + assert TR.regexp("reset__select_word_x_of_y_template").match(layout.subtitle()) for _ in range(3): # "Select word 3 of 20" # ^ @@ -161,7 +164,7 @@ def confirm_words(debug: "DebugLink", words: list[str]) -> None: button_pos = btn_texts.index(wanted_word) layout = debug.click(buttons.VERTICAL_MENU[button_pos]) elif debug.layout_type is LayoutType.TR: - TR.assert_in(layout.text_content(), "reset__select_correct_word") + assert TR.reset__select_correct_word in layout.text_content() layout = debug.press_right() for _ in range(3): # "SELECT 2ND WORD" diff --git a/tests/click_tests/test_autolock.py b/tests/click_tests/test_autolock.py index 18e8209e84..542d752754 100644 --- a/tests/click_tests/test_autolock.py +++ b/tests/click_tests/test_autolock.py @@ -65,9 +65,8 @@ def set_autolock_delay(device_handler: "BackgroundDeviceHandler", delay_ms: int) debug.input("1234") - TR.assert_template( - debug.read_layout().text_content(), - "auto_lock__change_template", + assert TR.regexp("auto_lock__change_template").match( + debug.read_layout().text_content() ) layout = go_next(debug) @@ -108,17 +107,17 @@ def test_autolock_interrupts_signing(device_handler: "BackgroundDeviceHandler"): if debug.layout_type is LayoutType.TT: debug.click(buttons.OK) layout = debug.click(buttons.OK) - TR.assert_in(layout.text_content(), "send__total_amount") + assert TR.send__total_amount in layout.text_content() assert "0.0039 BTC" in layout.text_content() elif debug.layout_type is LayoutType.Mercury: debug.swipe_up() layout = debug.swipe_up() - TR.assert_in(layout.text_content(), "send__total_amount") + assert TR.send__total_amount in layout.text_content() assert "0.0039 BTC" in layout.text_content() elif debug.layout_type is LayoutType.TR: debug.press_right() layout = debug.press_right() - TR.assert_in(layout.text_content(), "send__total_amount") + assert TR.send__total_amount in layout.text_content() assert "0.0039 BTC" in layout.text_content() # wait for autolock to kick in @@ -160,18 +159,18 @@ def test_autolock_does_not_interrupt_signing(device_handler: "BackgroundDeviceHa if debug.layout_type is LayoutType.TT: debug.click(buttons.OK) layout = debug.click(buttons.OK) - TR.assert_in(layout.text_content(), "send__total_amount") + assert TR.send__total_amount in layout.text_content() assert "0.0039 BTC" in layout.text_content() elif debug.layout_type is LayoutType.Mercury: debug.swipe_up() layout = debug.swipe_up() - TR.assert_in(layout.text_content(), "send__total_amount") + assert TR.send__total_amount in layout.text_content() assert "0.0039 BTC" in layout.text_content() debug.swipe_up() elif debug.layout_type is LayoutType.TR: debug.press_right() layout = debug.press_right() - TR.assert_in(layout.text_content(), "send__total_amount") + assert TR.send__total_amount in layout.text_content() assert "0.0039 BTC" in layout.text_content() def sleepy_filter(msg: MessageType) -> MessageType: @@ -274,7 +273,7 @@ def test_autolock_interrupts_passphrase(device_handler: "BackgroundDeviceHandler def unlock_dry_run(debug: "DebugLink") -> "LayoutContent": - TR.assert_in(debug.read_layout().text_content(), "recovery__check_dry_run") + assert TR.recovery__check_dry_run in debug.read_layout().text_content() layout = go_next(debug) assert "PinKeyboard" in layout.all_components() @@ -291,7 +290,7 @@ def test_dryrun_locks_at_number_of_words(device_handler: "BackgroundDeviceHandle device_handler.run(device.recover, dry_run=True) # type: ignore layout = unlock_dry_run(debug) - TR.assert_in(debug.read_layout().text_content(), "recovery__num_of_words") + assert TR.recovery__num_of_words in debug.read_layout().text_content() if debug.layout_type is LayoutType.TR: debug.press_right() @@ -312,7 +311,7 @@ def test_dryrun_locks_at_number_of_words(device_handler: "BackgroundDeviceHandle assert layout is not None # we are back at homescreen - TR.assert_in(debug.read_layout().text_content(), "recovery__num_of_words") + assert TR.recovery__num_of_words in debug.read_layout().text_content() @pytest.mark.setup_client(pin=PIN4) diff --git a/tests/click_tests/test_backup_slip39_custom.py b/tests/click_tests/test_backup_slip39_custom.py index b31cf32cfb..be01683d07 100644 --- a/tests/click_tests/test_backup_slip39_custom.py +++ b/tests/click_tests/test_backup_slip39_custom.py @@ -76,18 +76,17 @@ def test_backup_slip39_custom( # confirm backup configuration if share_count > 1: - TR.assert_template( - debug.read_layout().text_content(), - "reset__create_x_of_y_multi_share_backup_template", + assert TR.regexp("reset__create_x_of_y_multi_share_backup_template").match( + debug.read_layout().text_content() ) else: - TR.assert_template( - debug.read_layout().text_content(), "backup__info_single_share_backup" + assert TR.regexp("backup__info_single_share_backup").match( + debug.read_layout().text_content() ) reset.confirm_read(debug) # confirm backup intro - TR.assert_in(debug.read_layout().text_content(), "reset__never_make_digital_copy") + assert TR.reset__never_make_digital_copy in debug.read_layout().text_content() reset.confirm_read(debug, middle_r=True) all_words: list[str] = [] diff --git a/tests/click_tests/test_passphrase_tr.py b/tests/click_tests/test_passphrase_tr.py index d76bb063e5..57685451ba 100644 --- a/tests/click_tests/test_passphrase_tr.py +++ b/tests/click_tests/test_passphrase_tr.py @@ -21,7 +21,6 @@ import pytest from trezorlib import exceptions -from .. import translations as TR from ..common import get_test_address from .common import ( CommonPass, @@ -56,20 +55,11 @@ assert len(AAA_51) == 51 assert AAA_51_ADDRESS == AAA_50_ADDRESS -def _get_possible_btns(path: str) -> str: - return "|".join(TR.translate(path)) - - -def _get_cancel_or_delete() -> str: - paths = ["inputs__cancel", "inputs__delete"] - return "|".join(_get_possible_btns(path) for path in paths) - - -BACK = _get_possible_btns("inputs__back") -SHOW = _get_possible_btns("inputs__show") -ENTER = _get_possible_btns("inputs__enter") -SPACE = _get_possible_btns("inputs__space") -CANCEL_OR_DELETE = _get_cancel_or_delete() +BACK = "inputs__back" +SHOW = "inputs__show" +ENTER = "inputs__enter" +SPACE = "inputs__space" +CANCEL_OR_DELETE = ("inputs__cancel", "inputs__delete") # fmt: off MENU_ACTIONS = [SHOW, CANCEL_OR_DELETE, ENTER, "abc", "ABC", "123", "#$!", SPACE] DIGITS_ACTIONS = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", BACK] diff --git a/tests/click_tests/test_pin.py b/tests/click_tests/test_pin.py index 2819a4c40e..4566dd51b7 100644 --- a/tests/click_tests/test_pin.py +++ b/tests/click_tests/test_pin.py @@ -25,12 +25,7 @@ from trezorlib.debuglink import LayoutType from .. import buttons from .. import translations as TR -from .common import ( - get_possible_btn_texts, - go_back, - go_next, - navigate_to_action_and_press, -) +from .common import go_back, go_next, navigate_to_action_and_press if TYPE_CHECKING: from trezorlib.debuglink import DebugLink @@ -48,9 +43,9 @@ PIN24 = "875163065288639289952973" PIN50 = "31415926535897932384626433832795028841971693993751" PIN60 = PIN50 + "9" * 10 -DELETE = get_possible_btn_texts("inputs__delete") -SHOW = get_possible_btn_texts("inputs__show") -ENTER = get_possible_btn_texts("inputs__enter") +DELETE = "inputs__delete" +SHOW = "inputs__show" +ENTER = "inputs__enter" TR_PIN_ACTIONS = [ @@ -103,8 +98,9 @@ def prepare( elif situation == Situation.PIN_SETUP: # Set new PIN device_handler.run(device.change_pin) # type: ignore - TR.assert_in_multiple( - debug.read_layout().text_content(), ["pin__turn_on", "pin__info"] + assert ( + TR.pin__turn_on in debug.read_layout().text_content() + or TR.pin__info in debug.read_layout().text_content() ) if debug.layout_type in (LayoutType.TT, LayoutType.Mercury): go_next(debug) @@ -117,7 +113,7 @@ def prepare( # Change PIN device_handler.run(device.change_pin) # type: ignore _input_see_confirm(debug, old_pin) - TR.assert_in(debug.read_layout().text_content(), "pin__change") + assert TR.pin__change in debug.read_layout().text_content() go_next(debug) _input_see_confirm(debug, old_pin) elif situation == Situation.WIPE_CODE_SETUP: @@ -125,7 +121,7 @@ def prepare( device_handler.run(device.change_wipe_code) # type: ignore if old_pin: _input_see_confirm(debug, old_pin) - TR.assert_in(debug.read_layout().text_content(), "wipe_code__turn_on") + assert TR.wipe_code__turn_on in debug.read_layout().text_content() go_next(debug) if debug.layout_type is LayoutType.TR: go_next(debug) diff --git a/tests/click_tests/test_reset_bip39.py b/tests/click_tests/test_reset_bip39.py index 0fffd5042f..907246fb51 100644 --- a/tests/click_tests/test_reset_bip39.py +++ b/tests/click_tests/test_reset_bip39.py @@ -59,13 +59,13 @@ def test_reset_bip39(device_handler: "BackgroundDeviceHandler"): # confirm backup intro # parametrized string - TR.assert_template( - debug.read_layout().text_content(), "backup__info_single_share_backup" + assert TR.regexp("backup__info_single_share_backup").match( + debug.read_layout().text_content() ) reset.confirm_read(debug) # confirm backup warning - TR.assert_in(debug.read_layout().text_content(), "reset__never_make_digital_copy") + assert TR.reset__never_make_digital_copy in debug.read_layout().text_content() reset.confirm_read(debug, middle_r=True) # read words diff --git a/tests/click_tests/test_tutorial_mercury.py b/tests/click_tests/test_tutorial_mercury.py index b7a56a596b..36794d27dd 100644 --- a/tests/click_tests/test_tutorial_mercury.py +++ b/tests/click_tests/test_tutorial_mercury.py @@ -39,17 +39,17 @@ def test_tutorial_ignore_menu(device_handler: "BackgroundDeviceHandler"): device_handler.run(device.show_device_tutorial) layout = debug.read_layout() - TR.assert_equals(layout.title(), "tutorial__welcome_safe5") + assert layout.title() == TR.tutorial__welcome_safe5 layout = debug.click(buttons.TAP_TO_CONFIRM) - TR.assert_equals(layout.title(), "tutorial__title_lets_begin") + assert layout.title() == TR.tutorial__title_lets_begin layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_easy_navigation") + assert layout.title() == TR.tutorial__title_easy_navigation layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_handy_menu") + assert layout.title() == TR.tutorial__title_handy_menu layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_hold") + assert layout.title() == TR.tutorial__title_hold layout = debug.click(buttons.TAP_TO_CONFIRM, hold_ms=1000) - TR.assert_equals(layout.title(), "tutorial__title_well_done") + assert layout.title() == TR.tutorial__title_well_done debug.swipe_up() device_handler.result() @@ -60,23 +60,23 @@ def test_tutorial_menu_open_close(device_handler: "BackgroundDeviceHandler"): device_handler.run(device.show_device_tutorial) layout = debug.read_layout() - TR.assert_equals(layout.title(), "tutorial__welcome_safe5") + assert layout.title() == TR.tutorial__welcome_safe5 layout = debug.click(buttons.TAP_TO_CONFIRM) - TR.assert_equals(layout.title(), "tutorial__title_lets_begin") + assert layout.title() == TR.tutorial__title_lets_begin layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_easy_navigation") + assert layout.title() == TR.tutorial__title_easy_navigation layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_handy_menu") + assert layout.title() == TR.tutorial__title_handy_menu layout = debug.click(buttons.CORNER_BUTTON) - TR.assert_in(layout.text_content(), "tutorial__did_you_know") + assert TR.tutorial__did_you_know in layout.text_content() layout = debug.click(buttons.CORNER_BUTTON) - TR.assert_equals(layout.title(), "tutorial__title_handy_menu") + assert layout.title() == TR.tutorial__title_handy_menu layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_hold") + assert layout.title() == TR.tutorial__title_hold layout = debug.click(buttons.TAP_TO_CONFIRM, hold_ms=1000) - TR.assert_equals(layout.title(), "tutorial__title_well_done") + assert layout.title() == TR.tutorial__title_well_done debug.swipe_up() device_handler.result() @@ -87,20 +87,20 @@ def test_tutorial_menu_exit(device_handler: "BackgroundDeviceHandler"): device_handler.run(device.show_device_tutorial) layout = debug.read_layout() - TR.assert_equals(layout.title(), "tutorial__welcome_safe5") + assert layout.title() == TR.tutorial__welcome_safe5 layout = debug.click(buttons.TAP_TO_CONFIRM) - TR.assert_equals(layout.title(), "tutorial__title_lets_begin") + assert layout.title() == TR.tutorial__title_lets_begin layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_easy_navigation") + assert layout.title() == TR.tutorial__title_easy_navigation layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_handy_menu") + assert layout.title() == TR.tutorial__title_handy_menu layout = debug.click(buttons.CORNER_BUTTON) - TR.assert_in(layout.text_content(), "tutorial__did_you_know") + assert TR.tutorial__did_you_know in layout.text_content() layout = debug.click(buttons.VERTICAL_MENU[2]) - TR.assert_in(layout.footer(), "instructions__hold_to_exit_tutorial") + assert TR.instructions__hold_to_exit_tutorial in layout.footer() layout = debug.click(buttons.TAP_TO_CONFIRM, hold_ms=1000) - TR.assert_equals(layout.title(), "tutorial__title_well_done") + assert layout.title() == TR.tutorial__title_well_done debug.swipe_up() device_handler.result() @@ -111,27 +111,27 @@ def test_tutorial_menu_repeat(device_handler: "BackgroundDeviceHandler"): device_handler.run(device.show_device_tutorial) layout = debug.read_layout() - TR.assert_equals(layout.title(), "tutorial__welcome_safe5") + assert layout.title() == TR.tutorial__welcome_safe5 layout = debug.click(buttons.TAP_TO_CONFIRM) - TR.assert_equals(layout.title(), "tutorial__title_lets_begin") + assert layout.title() == TR.tutorial__title_lets_begin layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_easy_navigation") + assert layout.title() == TR.tutorial__title_easy_navigation layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_handy_menu") + assert layout.title() == TR.tutorial__title_handy_menu layout = debug.click(buttons.CORNER_BUTTON) - TR.assert_in(layout.text_content(), "tutorial__did_you_know") + assert TR.tutorial__did_you_know in layout.text_content() layout = debug.click(buttons.VERTICAL_MENU[1]) - TR.assert_equals(layout.title(), "tutorial__title_lets_begin") + assert layout.title() == TR.tutorial__title_lets_begin layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_easy_navigation") + assert layout.title() == TR.tutorial__title_easy_navigation layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_handy_menu") + assert layout.title() == TR.tutorial__title_handy_menu layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_hold") + assert layout.title() == TR.tutorial__title_hold layout = debug.click(buttons.TAP_TO_CONFIRM, hold_ms=1000) - TR.assert_equals(layout.title(), "tutorial__title_well_done") + assert layout.title() == TR.tutorial__title_well_done debug.swipe_up() device_handler.result() @@ -142,31 +142,29 @@ def test_tutorial_menu_funfact(device_handler: "BackgroundDeviceHandler"): device_handler.run(device.show_device_tutorial) layout = debug.read_layout() - TR.assert_equals(layout.title(), "tutorial__welcome_safe5") + assert layout.title() == TR.tutorial__welcome_safe5 layout = debug.click(buttons.TAP_TO_CONFIRM) - TR.assert_equals(layout.title(), "tutorial__title_lets_begin") + assert layout.title() == TR.tutorial__title_lets_begin layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_easy_navigation") + assert layout.title() == TR.tutorial__title_easy_navigation layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_handy_menu") + assert layout.title() == TR.tutorial__title_handy_menu layout = debug.click(buttons.CORNER_BUTTON) - TR.assert_in(layout.text_content(), "tutorial__did_you_know") + assert TR.tutorial__did_you_know in layout.text_content() layout = debug.click(buttons.VERTICAL_MENU[0]) - text_content = [ - s.replace("\n", " ") for s in TR.translate("tutorial__first_wallet") - ] + text_content = [s.replace("\n", " ") for s in TR.tutorial__first_wallet] assert layout.text_content() in text_content layout = debug.click(buttons.CORNER_BUTTON) - TR.assert_in(layout.text_content(), "tutorial__did_you_know") + assert TR.tutorial__did_you_know in layout.text_content() layout = debug.click(buttons.CORNER_BUTTON) - TR.assert_equals(layout.title(), "tutorial__title_handy_menu") + assert layout.title() == TR.tutorial__title_handy_menu layout = debug.swipe_up() - TR.assert_equals(layout.title(), "tutorial__title_hold") + assert layout.title() == TR.tutorial__title_hold layout = debug.click(buttons.TAP_TO_CONFIRM, hold_ms=1000) - TR.assert_equals(layout.title(), "tutorial__title_well_done") + assert layout.title() == TR.tutorial__title_well_done debug.swipe_up() device_handler.result() diff --git a/tests/click_tests/test_tutorial_tr.py b/tests/click_tests/test_tutorial_tr.py index 8cf3d4f39d..81d2645ace 100644 --- a/tests/click_tests/test_tutorial_tr.py +++ b/tests/click_tests/test_tutorial_tr.py @@ -57,7 +57,7 @@ def go_through_tutorial_tr(debug: "DebugLink") -> None: debug.press_right() debug.press_right() layout = debug.press_middle() - TR.assert_equals(layout.title(), "tutorial__title_tutorial_complete") + assert layout.title() == TR.tutorial__title_tutorial_complete def test_tutorial_finish(device_handler: "BackgroundDeviceHandler"): diff --git a/tests/conftest.py b/tests/conftest.py index 00dacb5292..c78c9a766f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -309,8 +309,7 @@ def client( if _raw_client.model is not models.T1B1: lang = request.session.config.getoption("lang") or "en" assert isinstance(lang, str) - if lang != "en": - translations.set_language(_raw_client, lang) + translations.set_language(_raw_client, lang) setup_params = dict( uninitialized=False, diff --git a/tests/device_tests/reset_recovery/test_reset_recovery_bip39.py b/tests/device_tests/reset_recovery/test_reset_recovery_bip39.py index ea69e07970..89c327fb8f 100644 --- a/tests/device_tests/reset_recovery/test_reset_recovery_bip39.py +++ b/tests/device_tests/reset_recovery/test_reset_recovery_bip39.py @@ -23,6 +23,7 @@ from trezorlib.tools import parse_path from ...common import WITH_MOCK_URANDOM from ...input_flows import InputFlowBip39Recovery, InputFlowBip39ResetBackup +from ...translations import set_language @pytest.mark.models("core") @@ -31,7 +32,9 @@ def test_reset_recovery(client: Client): mnemonic = reset(client) address_before = btc.get_address(client, "Bitcoin", parse_path("m/44h/0h/0h/0/0")) + lang = client.features.language or "en" device.wipe(client) + set_language(client, lang[:2]) recover(client, mnemonic) address_after = btc.get_address(client, "Bitcoin", parse_path("m/44h/0h/0h/0/0")) assert address_before == address_after diff --git a/tests/device_tests/reset_recovery/test_reset_recovery_slip39_advanced.py b/tests/device_tests/reset_recovery/test_reset_recovery_slip39_advanced.py index e37b4f5099..8b42940d75 100644 --- a/tests/device_tests/reset_recovery/test_reset_recovery_slip39_advanced.py +++ b/tests/device_tests/reset_recovery/test_reset_recovery_slip39_advanced.py @@ -26,6 +26,7 @@ from ...input_flows import ( InputFlowSlip39AdvancedRecovery, InputFlowSlip39AdvancedResetRecovery, ) +from ...translations import set_language @pytest.mark.models("core") @@ -49,7 +50,10 @@ def test_reset_recovery(client: Client): + mnemonics[22:25], ] for combination in test_combinations: + lang = client.features.language or "en" device.wipe(client) + set_language(client, lang[:2]) + recover(client, combination) address_after = btc.get_address( client, "Bitcoin", parse_path("m/44h/0h/0h/0/0") diff --git a/tests/device_tests/reset_recovery/test_reset_recovery_slip39_basic.py b/tests/device_tests/reset_recovery/test_reset_recovery_slip39_basic.py index 3980b1a149..6b72246a10 100644 --- a/tests/device_tests/reset_recovery/test_reset_recovery_slip39_basic.py +++ b/tests/device_tests/reset_recovery/test_reset_recovery_slip39_basic.py @@ -28,6 +28,7 @@ from ...input_flows import ( InputFlowSlip39BasicRecovery, InputFlowSlip39BasicResetRecovery, ) +from ...translations import set_language @pytest.mark.models("core") @@ -38,7 +39,9 @@ def test_reset_recovery(client: Client): address_before = btc.get_address(client, "Bitcoin", parse_path("m/44h/0h/0h/0/0")) for share_subset in itertools.combinations(mnemonics, 3): + lang = client.features.language or "en" device.wipe(client) + set_language(client, lang[:2]) selected_mnemonics = share_subset recover(client, selected_mnemonics) address_after = btc.get_address( diff --git a/tests/device_tests/test_repeated_backup.py b/tests/device_tests/test_repeated_backup.py index 36afeae905..3bf2d42510 100644 --- a/tests/device_tests/test_repeated_backup.py +++ b/tests/device_tests/test_repeated_backup.py @@ -162,7 +162,7 @@ def test_repeated_backup_cancel(client: Client): assert client.features.recovery_status == messages.RecoveryStatus.Backup layout = client.debug.read_layout() - TR.assert_in(layout.text_content(), "recovery__unlock_repeated_backup") + assert TR.recovery__unlock_repeated_backup in layout.text_content() # send a Cancel message @@ -218,7 +218,7 @@ def test_repeated_backup_send_disallowed_message(client: Client): assert client.features.recovery_status == messages.RecoveryStatus.Backup layout = client.debug.read_layout() - TR.assert_in(layout.text_content(), "recovery__unlock_repeated_backup") + assert TR.recovery__unlock_repeated_backup in layout.text_content() # send a GetAddress message @@ -237,6 +237,6 @@ def test_repeated_backup_send_disallowed_message(client: Client): assert client.features.recovery_status == messages.RecoveryStatus.Backup # we are still on the confirmation screen! - TR.assert_in( - client.debug.read_layout().text_content(), "recovery__unlock_repeated_backup" + assert ( + TR.recovery__unlock_repeated_backup in client.debug.read_layout().text_content() ) diff --git a/tests/device_tests/test_sdcard.py b/tests/device_tests/test_sdcard.py index e0c13af944..69098d81df 100644 --- a/tests/device_tests/test_sdcard.py +++ b/tests/device_tests/test_sdcard.py @@ -59,7 +59,7 @@ def test_sd_protect_unlock(client: Client): client.debug.input("1234") yield # do you really want to enable SD protection - TR.assert_in(layout().text_content(), "sd_card__enable") + assert TR.sd_card__enable in layout().text_content() client.debug.press_yes() yield # enter current PIN @@ -67,7 +67,7 @@ def test_sd_protect_unlock(client: Client): client.debug.input("1234") yield # you have successfully enabled SD protection - TR.assert_in(layout().text_content(), "sd_card__enabled") + assert TR.sd_card__enabled in layout().text_content() client.debug.press_yes() with client: @@ -77,7 +77,7 @@ def test_sd_protect_unlock(client: Client): def input_flow_change_pin(): yield # do you really want to change PIN? - TR.assert_equals(layout().title(), "pin__title_settings") + assert layout().title() == TR.pin__title_settings client.debug.press_yes() yield # enter current PIN @@ -93,7 +93,7 @@ def test_sd_protect_unlock(client: Client): client.debug.input("1234") yield # Pin change successful - TR.assert_in(layout().text_content(), "pin__changed") + assert TR.pin__changed in layout().text_content() client.debug.press_yes() with client: @@ -105,7 +105,7 @@ def test_sd_protect_unlock(client: Client): def input_flow_change_pin_format(): yield # do you really want to change PIN? - TR.assert_equals(layout().title(), "pin__title_settings") + assert layout().title() == TR.pin__title_settings client.debug.press_yes() yield # enter current PIN @@ -113,9 +113,9 @@ def test_sd_protect_unlock(client: Client): client.debug.input("1234") yield # SD card problem - TR.assert_in_multiple( - layout().text_content(), - ["sd_card__unplug_and_insert_correct", "sd_card__insert_correct_card"], + assert ( + TR.sd_card__unplug_and_insert_correct in layout().text_content() + or TR.sd_card__insert_correct_card in layout().text_content() ) client.debug.press_no() # close diff --git a/tests/device_tests/test_session_id_and_passphrase.py b/tests/device_tests/test_session_id_and_passphrase.py index 263fb9d76b..1bb9cbd70a 100644 --- a/tests/device_tests/test_session_id_and_passphrase.py +++ b/tests/device_tests/test_session_id_and_passphrase.py @@ -398,10 +398,7 @@ def test_hide_passphrase_from_host(client: Client): def input_flow(): yield content = client.debug.read_layout().text_content().lower() - assert any( - (s[:50].lower() in content) - for s in TR.translate("passphrase__from_host_not_shown") - ) + assert TR.passphrase__from_host_not_shown[:50].lower() in content if client.layout_type in (LayoutType.TT, LayoutType.Mercury): client.debug.press_yes() elif client.layout_type is LayoutType.TR: @@ -435,17 +432,14 @@ def test_hide_passphrase_from_host(client: Client): def input_flow(): yield - TR.assert_in( - client.debug.read_layout().text_content(), - "passphrase__next_screen_will_show_passphrase", + assert ( + TR.passphrase__next_screen_will_show_passphrase + in client.debug.read_layout().text_content() ) client.debug.press_yes() yield - TR.assert_equals( - client.debug.read_layout().title(), - "passphrase__title_confirm", - ) + assert client.debug.read_layout().title() == TR.passphrase__title_confirm assert passphrase in client.debug.read_layout().text_content() client.debug.press_yes() diff --git a/tests/input_flows.py b/tests/input_flows.py index 0b543751d3..74057b05a8 100644 --- a/tests/input_flows.py +++ b/tests/input_flows.py @@ -428,9 +428,9 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): expected_title = f"MULTISIG XPUB #{xpub_num + 1}" assert expected_title in title if self.index == xpub_num: - TR.assert_in(title, "address__title_yours") + assert TR.address__title_yours in title else: - TR.assert_in(title, "address__title_cosigner") + assert TR.address__title_cosigner in title def input_flow_tt(self) -> BRGeneratorType: yield # multisig address warning @@ -438,7 +438,7 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): yield # show address layout = self.debug.read_layout() - TR.assert_in(layout.title(), "address__title_receive_address") + assert TR.address__title_receive_address in layout.title() assert "(MULTISIG)" in layout.title() assert layout.text_content().replace(" ", "") == self.address @@ -448,7 +448,7 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): layout = self.debug.swipe_left() # address details assert "Multisig 2 of 3" in layout.screen_content() - TR.assert_in(layout.screen_content(), "address_details__derivation_path") + assert TR.address_details__derivation_path in layout.screen_content() # Three xpub pages with the same testing logic for xpub_num in range(3): @@ -471,7 +471,7 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): yield # show address layout = self.debug.read_layout() - TR.assert_in(layout.title(), "address__title_receive_address") + assert TR.address__title_receive_address in layout.title() assert "(MULTISIG)" in layout.title() assert layout.text_content().replace(" ", "") == self.address @@ -512,7 +512,7 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): yield # show address layout = self.debug.read_layout() - TR.assert_in(layout.title(), "address__title_receive_address") + assert TR.address__title_receive_address in layout.title() assert layout.text_content().replace(" ", "") == self.address self.debug.click(buttons.CORNER_BUTTON) @@ -529,7 +529,7 @@ class InputFlowShowMultisigXPUBs(InputFlowBase): layout = self.debug.synchronize_at("AddressDetails") # address details assert "Multisig 2 of 3" in layout.screen_content() - TR.assert_in(layout.screen_content(), "address_details__derivation_path") + assert TR.address_details__derivation_path in layout.screen_content() # three xpub pages with the same testing logic for _xpub_num in range(3): @@ -629,7 +629,7 @@ class InputFlowShowXpubQRCode(InputFlowBase): br = yield layout = self.debug.read_layout() - assert layout.title() in TR.translate("address__public_key") + ["XPUB"] + assert layout.title() in (TR.address__public_key, ["XPUB"]) self.debug.click(buttons.CORNER_BUTTON) assert "VerticalMenu" in self.all_components() @@ -644,7 +644,7 @@ class InputFlowShowXpubQRCode(InputFlowBase): self.debug.click(buttons.VERTICAL_MENU[1]) layout = self.debug.synchronize_at("AddressDetails") # address details - TR.assert_in(layout.screen_content(), "address_details__derivation_path") + assert TR.address_details__derivation_path in layout.screen_content() self.debug.click(buttons.CORNER_BUTTON) layout = self.debug.synchronize_at("VerticalMenu") @@ -859,9 +859,9 @@ class InputFlowSignTxInformation(InputFlowBase): super().__init__(client) def assert_content(self, content: str, title_path: str) -> None: - TR.assert_in(content, title_path) + assert TR.translate(title_path) in content assert "Legacy #6" in content - TR.assert_in(content, "confirm_total__fee_rate") + assert TR.confirm_total__fee_rate in content assert "71.56 sat" in content def input_flow_tt(self) -> BRGeneratorType: @@ -887,9 +887,9 @@ class InputFlowSignTxInformationMixed(InputFlowBase): super().__init__(client) def assert_content(self, content: str, title_path: str) -> None: - TR.assert_in(content, title_path) - TR.assert_in(content, "bitcoin__multiple_accounts") - TR.assert_in(content, "confirm_total__fee_rate") + assert TR.translate(title_path) in content + assert TR.bitcoin__multiple_accounts in content + assert TR.confirm_total__fee_rate in content assert "18.33 sat" in content def input_flow_tt(self) -> BRGeneratorType: @@ -1049,7 +1049,7 @@ class InputFlowLockTimeBlockHeight(InputFlowBase): def assert_func(self, debug: DebugLink, br: messages.ButtonRequest) -> None: layout_text = get_text_possible_pagination(debug, br) - TR.assert_in(layout_text, "bitcoin__locktime_set_to_blockheight") + assert TR.bitcoin__locktime_set_to_blockheight in layout_text assert self.block_height in layout_text def input_flow_tt(self) -> BRGeneratorType: @@ -1073,7 +1073,7 @@ class InputFlowLockTimeDatetime(InputFlowBase): def assert_func(self, debug: DebugLink, br: messages.ButtonRequest) -> None: layout_text = get_text_possible_pagination(debug, br) - TR.assert_in(layout_text, "bitcoin__locktime_set_to") + assert TR.bitcoin__locktime_set_to in layout_text assert self.lock_time_str.replace(" ", "") in layout_text.replace(" ", "") def input_flow_tt(self) -> BRGeneratorType: @@ -2207,26 +2207,26 @@ class InputFlowResetSkipBackup(InputFlowBase): def input_flow_tt(self) -> BRGeneratorType: yield from self.BAK.confirm_new_wallet() yield # Skip Backup - TR.assert_in(self.text_content(), "backup__new_wallet_successfully_created") + assert TR.backup__new_wallet_successfully_created in self.text_content() self.debug.press_no() yield # Confirm skip backup - TR.assert_in(self.text_content(), "backup__want_to_skip") + assert TR.backup__want_to_skip in self.text_content() self.debug.press_no() def input_flow_tr(self) -> BRGeneratorType: yield from self.BAK.confirm_new_wallet() yield # Skip Backup - TR.assert_in(self.text_content(), "backup__new_wallet_created") + assert TR.backup__new_wallet_created in self.text_content() self.debug.press_right() self.debug.press_no() yield # Confirm skip backup - TR.assert_in(self.text_content(), "backup__want_to_skip") + assert TR.backup__want_to_skip in self.text_content() self.debug.press_no() def input_flow_t3t1(self) -> BRGeneratorType: yield from self.BAK.confirm_new_wallet() yield # Skip Backup - TR.assert_in(self.text_content(), "backup__new_wallet_created") + assert TR.backup__new_wallet_created in self.text_content() self.debug.swipe_up() yield self.debug.click(buttons.CORNER_BUTTON) @@ -2266,14 +2266,12 @@ class InputFlowConfirmAllWarnings(InputFlowBase): text = layout.text_content().lower() # hi priority warning hi_prio = ( - TR.translate("ethereum__unknown_contract_address") - + TR.translate("addr_mismatch__wrong_derivation_path") - + TR.translate("send__receiving_to_multisig") - + [ - "witness path", - "certificate path", - "pool owner staking path", - ] + TR.ethereum__unknown_contract_address, + TR.addr_mismatch__wrong_derivation_path, + TR.send__receiving_to_multisig, + "witness path", + "certificate path", + "pool owner staking path", ) if any(needle.lower() in text for needle in hi_prio): self.debug.click(buttons.CORNER_BUTTON) diff --git a/tests/input_flows_helpers.py b/tests/input_flows_helpers.py index 1ec7b1f570..77abfb374c 100644 --- a/tests/input_flows_helpers.py +++ b/tests/input_flows_helpers.py @@ -28,8 +28,9 @@ class PinFlow: self.debug.input(pin) if self.client.layout_type is LayoutType.TR: assert (yield).name == f"reenter_{what}" # Reenter PIN - TR.assert_in( - self.debug.read_layout().text_content(), f"{what}__reenter_to_confirm" + assert ( + TR.translate(f"{what}__reenter_to_confirm") + in self.debug.read_layout().text_content() ) self.debug.press_yes() assert (yield).name == "pin_device" # Enter PIN again @@ -47,7 +48,7 @@ class BackupFlow: def confirm_new_wallet(self) -> BRGeneratorType: yield - TR.assert_in(self.debug.read_layout().text_content(), "reset__by_continuing") + assert TR.reset__by_continuing in self.debug.read_layout().text_content() if self.client.layout_type is LayoutType.TR: self.debug.press_right() self.debug.press_yes() @@ -64,14 +65,14 @@ class RecoveryFlow: def confirm_recovery(self) -> BRGeneratorType: assert (yield).name == "recover_device" - TR.assert_in(self._text_content(), "reset__by_continuing") + assert TR.reset__by_continuing in self._text_content() if self.client.layout_type is LayoutType.TR: self.debug.press_right() self.debug.press_yes() def confirm_dry_run(self) -> BRGeneratorType: assert (yield).name == "confirm_seedcheck" - TR.assert_in(self._text_content(), "recovery__check_dry_run") + assert TR.recovery__check_dry_run in self._text_content() self.debug.press_yes() def setup_slip39_recovery(self, num_words: int) -> BRGeneratorType: @@ -94,18 +95,18 @@ class RecoveryFlow: def tr_recovery_homescreen(self) -> BRGeneratorType: yield - TR.assert_in(self._text_content(), "recovery__num_of_words") + assert TR.recovery__num_of_words in self._text_content() self.debug.press_yes() def enter_your_backup(self) -> BRGeneratorType: assert (yield).name == "recovery" if self.debug.layout_type is LayoutType.Mercury: - TR.assert_in(self._text_content(), "recovery__enter_each_word") + assert TR.recovery__enter_each_word in self._text_content() else: - TR.assert_in(self._text_content(), "recovery__enter_backup") - is_dry_run = any( - title in self.debug.read_layout().title().lower() - for title in TR.translate("recovery__title_dry_run", lower=True) + assert TR.recovery__enter_backup in self._text_content() + is_dry_run = ( + TR.recovery__title_dry_run.lower() + in self.debug.read_layout().title().lower() ) if self.client.layout_type is LayoutType.TR and not is_dry_run: # Normal recovery has extra info (not dry run) @@ -115,13 +116,13 @@ class RecoveryFlow: def enter_any_share(self) -> BRGeneratorType: assert (yield).name == "recovery" - TR.assert_in_multiple( - self._text_content(), - ["recovery__enter_any_share", "recovery__enter_each_word"], + assert ( + TR.recovery__enter_any_share in self._text_content() + or TR.recovery__enter_each_word in self._text_content() ) - is_dry_run = any( - title in self.debug.read_layout().title().lower() - for title in TR.translate("recovery__title_dry_run", lower=True) + is_dry_run = ( + TR.recovery__title_dry_run.lower() + in self.debug.read_layout().title().lower() ) if self.client.layout_type is LayoutType.TR and not is_dry_run: # Normal recovery has extra info (not dry run) @@ -132,17 +133,17 @@ class RecoveryFlow: def abort_recovery(self, confirm: bool) -> BRGeneratorType: yield if self.client.layout_type is LayoutType.TR: - TR.assert_in(self._text_content(), "recovery__num_of_words") + assert TR.recovery__num_of_words in self._text_content() self.debug.press_no() yield - TR.assert_in(self._text_content(), "recovery__wanna_cancel_recovery") + assert TR.recovery__wanna_cancel_recovery in self._text_content() self.debug.press_right() if confirm: self.debug.press_yes() else: self.debug.press_no() elif self.client.layout_type is LayoutType.Mercury: - TR.assert_in(self._text_content(), "recovery__enter_each_word") + assert TR.recovery__enter_each_word in self._text_content() self.debug.click(buttons.CORNER_BUTTON) self.debug.synchronize_at("VerticalMenu") if confirm: @@ -150,10 +151,10 @@ class RecoveryFlow: else: self.debug.click(buttons.CORNER_BUTTON) else: - TR.assert_in(self._text_content(), "recovery__enter_any_share") + assert TR.recovery__enter_any_share in self._text_content() self.debug.press_no() yield - TR.assert_in(self._text_content(), "recovery__wanna_cancel_recovery") + assert TR.recovery__wanna_cancel_recovery in self._text_content() if confirm: self.debug.press_yes() else: @@ -162,32 +163,32 @@ class RecoveryFlow: def abort_recovery_between_shares(self) -> BRGeneratorType: yield if self.client.layout_type is LayoutType.TR: - TR.assert_template( - self._text_content(), "recovery__x_of_y_entered_template" + assert TR.regexp("recovery__x_of_y_entered_template").search( + self._text_content() ) self.debug.press_no() assert (yield).name == "abort_recovery" - TR.assert_in(self._text_content(), "recovery__wanna_cancel_recovery") + assert TR.recovery__wanna_cancel_recovery in self._text_content() self.debug.press_right() self.debug.press_yes() elif self.client.layout_type is LayoutType.Mercury: - TR.assert_template( - self._text_content(), "recovery__x_of_y_entered_template" + assert TR.regexp("recovery__x_of_y_entered_template").search( + self._text_content() ) self.debug.click(buttons.CORNER_BUTTON) self.debug.synchronize_at("VerticalMenu") self.debug.click(buttons.VERTICAL_MENU[0]) assert (yield).name == "abort_recovery" layout = self.debug.swipe_up() - TR.assert_equals(layout.title(), "recovery__title_cancel_recovery") + assert layout.title() == TR.recovery__title_cancel_recovery self.debug.click(buttons.TAP_TO_CONFIRM) else: - TR.assert_template( - self._text_content(), "recovery__x_of_y_entered_template" + assert TR.regexp("recovery__x_of_y_entered_template").search( + self._text_content() ) self.debug.press_no() assert (yield).name == "abort_recovery" - TR.assert_in(self._text_content(), "recovery__wanna_cancel_recovery") + assert TR.recovery__wanna_cancel_recovery in self._text_content() self.debug.press_yes() def input_number_of_words(self, num_words: int) -> BRGeneratorType: @@ -195,52 +196,52 @@ class RecoveryFlow: assert br.code == B.MnemonicWordCount assert br.name == "recovery_word_count" if self.client.layout_type is LayoutType.TR: - TR.assert_in(self.debug.read_layout().title(), "word_count__title") + assert TR.word_count__title in self.debug.read_layout().title() else: - TR.assert_in(self._text_content(), "recovery__num_of_words") + assert TR.recovery__num_of_words in self._text_content() self.debug.input(str(num_words)) def warning_invalid_recovery_seed(self) -> BRGeneratorType: br = yield assert br.code == B.Warning - TR.assert_in(self._text_content(), "recovery__invalid_wallet_backup_entered") + assert TR.recovery__invalid_wallet_backup_entered in self._text_content() self.debug.press_yes() def warning_invalid_recovery_share(self) -> BRGeneratorType: br = yield assert br.code == B.Warning - TR.assert_in(self._text_content(), "recovery__invalid_share_entered") + assert TR.recovery__invalid_share_entered in self._text_content() self.debug.press_yes() def warning_group_threshold_reached(self) -> BRGeneratorType: br = yield assert br.code == B.Warning - TR.assert_in(self._text_content(), "recovery__group_threshold_reached") + assert TR.recovery__group_threshold_reached in self._text_content() self.debug.press_yes() def warning_share_already_entered(self) -> BRGeneratorType: br = yield assert br.code == B.Warning - TR.assert_in(self._text_content(), "recovery__share_already_entered") + assert TR.recovery__share_already_entered in self._text_content() self.debug.press_yes() def warning_share_from_another_shamir(self) -> BRGeneratorType: br = yield assert br.code == B.Warning - TR.assert_in( - self._text_content(), "recovery__share_from_another_multi_share_backup" + assert ( + TR.recovery__share_from_another_multi_share_backup in self._text_content() ) self.debug.press_yes() def success_share_group_entered(self) -> BRGeneratorType: assert (yield).name == "share_success" - TR.assert_in(self._text_content(), "recovery__you_have_entered") + assert TR.recovery__you_have_entered in self._text_content() self.debug.press_yes() def success_wallet_recovered(self) -> BRGeneratorType: br = yield assert br.code == B.Success - TR.assert_in(self._text_content(), "recovery__wallet_recovered") + assert TR.recovery__wallet_recovered in self._text_content() self.debug.press_yes() def success_bip39_dry_run_valid(self) -> BRGeneratorType: @@ -249,7 +250,7 @@ class RecoveryFlow: text = get_text_possible_pagination(self.debug, br) # TODO: make sure the translations fit on one page if self.client.layout_type not in (LayoutType.TT, LayoutType.Mercury): - TR.assert_in(text, "recovery__dry_run_bip39_valid_match") + assert TR.recovery__dry_run_bip39_valid_match in text self.debug.press_yes() def success_slip39_dryrun_valid(self) -> BRGeneratorType: @@ -258,7 +259,7 @@ class RecoveryFlow: text = get_text_possible_pagination(self.debug, br) # TODO: make sure the translations fit on one page if self.client.layout_type not in (LayoutType.TT, LayoutType.Mercury): - TR.assert_in(text, "recovery__dry_run_slip39_valid_match") + assert TR.recovery__dry_run_slip39_valid_match in text self.debug.press_yes() def warning_slip39_dryrun_mismatch(self) -> BRGeneratorType: @@ -267,7 +268,7 @@ class RecoveryFlow: text = get_text_possible_pagination(self.debug, br) # TODO: make sure the translations fit on one page on TT if self.client.layout_type not in (LayoutType.TT, LayoutType.Mercury): - TR.assert_in(text, "recovery__dry_run_slip39_valid_mismatch") + assert TR.recovery__dry_run_slip39_valid_mismatch in text self.debug.press_yes() def warning_bip39_dryrun_mismatch(self) -> BRGeneratorType: @@ -276,7 +277,7 @@ class RecoveryFlow: text = get_text_possible_pagination(self.debug, br) # TODO: make sure the translations fit on one page if self.client.layout_type not in (LayoutType.TT, LayoutType.Mercury): - TR.assert_in(text, "recovery__dry_run_bip39_valid_mismatch") + assert TR.recovery__dry_run_bip39_valid_mismatch in text self.debug.press_yes() def success_more_shares_needed( @@ -352,7 +353,7 @@ class EthereumFlow: def confirm_data(self, info: bool = False, cancel: bool = False) -> BRGeneratorType: assert (yield).name == "confirm_data" - TR.assert_equals(self.debug.read_layout().title(), "ethereum__title_input_data") + assert self.debug.read_layout().title() == TR.ethereum__title_input_data if info: self.debug.press_info() elif cancel: @@ -364,7 +365,7 @@ class EthereumFlow: br = yield assert br.name == "confirm_data" assert br.pages is not None - TR.assert_equals(self.debug.read_layout().title(), "ethereum__title_input_data") + assert self.debug.read_layout().title() == TR.ethereum__title_input_data for _ in range(br.pages): self.debug.read_layout() go_next(self.debug) @@ -380,7 +381,7 @@ class EthereumFlow: assert br.name == "confirm_data" assert br.pages is not None assert br.pages > 2 - TR.assert_equals(self.debug.read_layout().title(), "ethereum__title_input_data") + assert self.debug.read_layout().title() == TR.ethereum__title_input_data if self.client.layout_type is LayoutType.TR: self.debug.press_right() self.debug.press_right() @@ -398,15 +399,15 @@ class EthereumFlow: self, cancel: bool, info: bool, go_back_from_summary: bool ) -> BRGeneratorType: assert (yield).name == "confirm_ethereum_tx" - TR.assert_equals(self.debug.read_layout().title(), "words__address") + assert self.debug.read_layout().title() == TR.words__address if cancel: self.debug.press_no() return self.debug.press_yes() assert (yield).name == "confirm_ethereum_tx" - TR.assert_equals(self.debug.read_layout().title(), "words__title_summary") - TR.assert_in(self.debug.read_layout().text_content(), "send__maximum_fee") + assert self.debug.read_layout().title() == TR.words__title_summary + assert TR.send__maximum_fee in self.debug.read_layout().text_content() if go_back_from_summary: self.debug.press_no() assert (yield).name == "confirm_ethereum_tx" @@ -414,8 +415,8 @@ class EthereumFlow: assert (yield).name == "confirm_ethereum_tx" if info: self.debug.press_info() - TR.assert_in(self.debug.read_layout().text_content(), "ethereum__gas_limit") - TR.assert_in(self.debug.read_layout().text_content(), "ethereum__gas_price") + assert TR.ethereum__gas_limit in self.debug.read_layout().text_content() + assert TR.ethereum__gas_price in self.debug.read_layout().text_content() self.debug.press_no() self.debug.press_yes() assert (yield).name == "confirm_ethereum_tx" @@ -424,16 +425,16 @@ class EthereumFlow: self, cancel: bool, info: bool, go_back_from_summary: bool ) -> BRGeneratorType: assert (yield).name == "confirm_ethereum_tx" - TR.assert_in_multiple( - self.debug.read_layout().title(), - ["ethereum__interaction_contract", "words__recipient"], + assert ( + TR.ethereum__interaction_contract in self.debug.read_layout().title() + or TR.words__recipient in self.debug.read_layout().title() ) if cancel: self.debug.press_left() return self.debug.press_right() assert (yield).name == "confirm_ethereum_tx" - TR.assert_in(self.debug.read_layout().text_content(), "send__maximum_fee") + assert TR.send__maximum_fee in self.debug.read_layout().text_content() if go_back_from_summary: self.debug.press_left() assert (yield).name == "confirm_ethereum_tx" @@ -441,9 +442,9 @@ class EthereumFlow: assert (yield).name == "confirm_ethereum_tx" if info: self.debug.press_right() - TR.assert_in(self.debug.read_layout().text_content(), "ethereum__gas_limit") + assert TR.ethereum__gas_limit in self.debug.read_layout().text_content() self.debug.press_right() - TR.assert_in(self.debug.read_layout().text_content(), "ethereum__gas_price") + assert TR.ethereum__gas_price in self.debug.read_layout().text_content() self.debug.press_left() self.debug.press_left() self.debug.press_middle() @@ -454,8 +455,8 @@ class EthereumFlow: ) -> BRGeneratorType: assert (yield).name == "confirm_output" title = self.debug.read_layout().title() - TR.assert_in(title, "words__address") - TR.assert_in(title, "words__recipient") + assert TR.words__address in title + assert TR.words__recipient in title if cancel: self.debug.press_no() @@ -464,8 +465,8 @@ class EthereumFlow: self.debug.swipe_up() assert (yield).name == "confirm_total" layout = self.debug.read_layout() - TR.assert_equals(layout.title(), "words__title_summary") - TR.assert_in(layout.text_content(), "send__maximum_fee") + assert layout.title() == TR.words__title_summary + assert TR.send__maximum_fee in layout.text_content() if go_back_from_summary: self.debug.press_no() assert (yield).name == "confirm_ethereum_tx" @@ -476,8 +477,8 @@ class EthereumFlow: self.debug.synchronize_at("VerticalMenu") self.debug.click(buttons.VERTICAL_MENU[0]) text = self.debug.read_layout().text_content() - TR.assert_in(text, "ethereum__gas_limit") - TR.assert_in(text, "ethereum__gas_price") + assert TR.ethereum__gas_limit in text + assert TR.ethereum__gas_price in text self.debug.click(buttons.CORNER_BUTTON) self.debug.click(buttons.CORNER_BUTTON) self.debug.swipe_up() @@ -507,21 +508,15 @@ class EthereumFlow: br = yield assert br.code == B.SignTx assert br.name == "confirm_ethereum_staking_tx" - TR.assert_equals_multiple( - self.debug.read_layout().title(), - [ - "ethereum__staking_stake", - "ethereum__staking_unstake", - "ethereum__staking_claim", - ], + assert self.debug.read_layout().title() in ( + TR.ethereum__staking_stake, + TR.ethereum__staking_unstake, + TR.ethereum__staking_claim, ) - TR.assert_equals_multiple( - self.debug.read_layout().text_content(), - [ - "ethereum__staking_stake_intro", - "ethereum__staking_unstake_intro", - "ethereum__staking_claim_intro", - ], + assert self.debug.read_layout().text_content() in ( + TR.ethereum__staking_stake_intro, + TR.ethereum__staking_unstake_intro, + TR.ethereum__staking_claim_intro, ) if self.client.layout_type is LayoutType.TT: # confirm intro @@ -529,12 +524,9 @@ class EthereumFlow: self.debug.click( buttons.CORNER_BUTTON, ) - TR.assert_equals_multiple( - self.debug.read_layout().title(), - [ - "ethereum__staking_stake_address", - "ethereum__staking_claim_address", - ], + assert self.debug.read_layout().title() in ( + TR.ethereum__staking_stake_address, + TR.ethereum__staking_claim_address, ) self.debug.press_no() self.debug.press_yes() @@ -543,12 +535,8 @@ class EthereumFlow: # confirm summary if info: self.debug.press_info() - TR.assert_in( - self.debug.read_layout().text_content(), "ethereum__gas_limit" - ) - TR.assert_in( - self.debug.read_layout().text_content(), "ethereum__gas_price" - ) + assert TR.ethereum__gas_limit in self.debug.read_layout().text_content() + assert TR.ethereum__gas_price in self.debug.read_layout().text_content() self.debug.press_no() self.debug.press_yes() yield @@ -561,12 +549,9 @@ class EthereumFlow: self.debug.click(buttons.CORNER_BUTTON) self.debug.synchronize_at("VerticalMenu") self.debug.click(buttons.VERTICAL_MENU[0]) - TR.assert_equals_multiple( - self.debug.read_layout().title(), - [ - "ethereum__staking_stake_address", - "ethereum__staking_claim_address", - ], + assert self.debug.read_layout().title() in ( + TR.ethereum__staking_stake_address, + TR.ethereum__staking_claim_address, ) self.debug.click(buttons.CORNER_BUTTON) self.debug.click(buttons.CORNER_BUTTON) @@ -581,12 +566,8 @@ class EthereumFlow: self.debug.click(buttons.CORNER_BUTTON) self.debug.synchronize_at("VerticalMenu") self.debug.click(buttons.VERTICAL_MENU[0]) - TR.assert_in( - self.debug.read_layout().text_content(), "ethereum__gas_limit" - ) - TR.assert_in( - self.debug.read_layout().text_content(), "ethereum__gas_price" - ) + assert TR.ethereum__gas_limit in self.debug.read_layout().text_content() + assert TR.ethereum__gas_price in self.debug.read_layout().text_content() self.debug.click(buttons.CORNER_BUTTON) self.debug.click(buttons.CORNER_BUTTON) self.debug.swipe_up() @@ -598,12 +579,9 @@ class EthereumFlow: # confirm intro if info: self.debug.press_right() - TR.assert_equals_multiple( - self.debug.read_layout().title(), - [ - "ethereum__staking_stake_address", - "ethereum__staking_claim_address", - ], + assert self.debug.read_layout().title() in ( + TR.ethereum__staking_stake_address, + TR.ethereum__staking_claim_address, ) self.debug.press_left() self.debug.press_middle() @@ -612,13 +590,9 @@ class EthereumFlow: # confirm summary if info: self.debug.press_right() - TR.assert_in( - self.debug.read_layout().text_content(), "ethereum__gas_limit" - ) + assert TR.ethereum__gas_limit in self.debug.read_layout().text_content() self.debug.press_right() - TR.assert_in( - self.debug.read_layout().text_content(), "ethereum__gas_price" - ) + assert TR.ethereum__gas_price in self.debug.read_layout().text_content() self.debug.press_left() self.debug.press_left() self.debug.press_middle() diff --git a/tests/translations.py b/tests/translations.py index b411162ae6..2bf3489894 100644 --- a/tests/translations.py +++ b/tests/translations.py @@ -1,4 +1,6 @@ import json +import re +import threading import typing as t from hashlib import sha256 from pathlib import Path @@ -12,11 +14,13 @@ from . import common HERE = Path(__file__).resolve().parent ROOT = HERE.parent -TRANSLATIONS = ROOT / "core" / "translations" -FONTS_DIR = TRANSLATIONS / "fonts" -ORDER_FILE = TRANSLATIONS / "order.json" +TRANSLATIONS_DIR = ROOT / "core" / "translations" +FONTS_DIR = TRANSLATIONS_DIR / "fonts" +ORDER_FILE = TRANSLATIONS_DIR / "order.json" -LANGUAGES = [file.stem for file in TRANSLATIONS.glob("??.json")] +LANGUAGES = [file.stem for file in TRANSLATIONS_DIR.glob("??.json")] + +_CURRENT_TRANSLATION = threading.local() def prepare_blob( @@ -66,110 +70,57 @@ def set_language(client: Client, lang: str): language_data = build_and_sign_blob(lang, client) with client: device.change_language(client, language_data) # type: ignore + _CURRENT_TRANSLATION.TR = TRANSLATIONS[lang] def get_lang_json(lang: str) -> translations.JsonDef: assert lang in LANGUAGES - lang_json = json.loads((TRANSLATIONS / f"{lang}.json").read_text()) + lang_json = json.loads((TRANSLATIONS_DIR / f"{lang}.json").read_text()) if (fonts_safe3 := lang_json.get("fonts", {}).get("##Safe3")) is not None: lang_json["fonts"]["T2B1"] = fonts_safe3 lang_json["fonts"]["T3B1"] = fonts_safe3 return lang_json -def _get_all_language_data() -> list[dict[str, str]]: - return [_get_language_data(language) for language in LANGUAGES] +class Translation: + FORMAT_STR_RE = re.compile(r"\\{\d+\\}") + + def __init__(self, lang: str) -> None: + self.lang = lang + self.lang_json = get_lang_json(lang) + + @property + def translations(self) -> dict[str, str]: + return self.lang_json["translations"] + + def _translate_raw(self, key: str) -> str: + tr = self.translations.get(key) + if tr is not None: + return tr + if self.lang != "en": + return TRANSLATIONS["en"]._translate_raw(key) + raise KeyError(key) + + def translate(self, key: str) -> str: + tr = self._translate_raw(key) + return tr.replace("\xa0", " ").strip() + + def as_regexp(self, key: str) -> re.Pattern: + tr = self.translate(key) + re_safe = re.escape(tr) + return re.compile(self.FORMAT_STR_RE.sub(r".*?", re_safe)) -def _get_language_data(lang: str) -> dict[str, str]: - return get_lang_json(lang)["translations"] +TRANSLATIONS = {lang: Translation(lang) for lang in LANGUAGES} -all_language_data = _get_all_language_data() +def translate(key: str) -> str: + return _CURRENT_TRANSLATION.TR.translate(key) -def _resolve_path_to_texts( - path: str, template: t.Iterable[t.Any] = (), lower: bool = True -) -> list[str]: - texts: list[str] = [] - lookups = path.split(".") - for language_data in all_language_data: - language_data_missing = False - data: dict[str, t.Any] | str = language_data - for lookup in lookups: - assert isinstance(data, dict), f"{lookup} is not a dict" - if lookup not in data: - language_data_missing = True - break - data = data[lookup] - if language_data_missing: - continue - assert isinstance(data, str), f"{path} is not a string" - if template: - data = data.format(*template) - texts.append(data) - - if lower: - texts = [t.lower() for t in texts] - texts = [t.replace("\xa0", " ").strip() for t in texts] - return texts +def regexp(key: str) -> re.Pattern: + return _CURRENT_TRANSLATION.TR.as_regexp(key) -def assert_equals(text: str, path: str, template: t.Iterable[t.Any] = ()) -> None: - # TODO: we can directly pass in the current device language - texts = _resolve_path_to_texts(path, template) - assert text.lower() in texts, f"{text} not found in {texts}" - - -def assert_equals_multiple( - text: str, paths: list[str], template: t.Iterable[t.Any] = () -) -> None: - texts: list[str] = [] - for path in paths: - texts += _resolve_path_to_texts(path, template) - assert text.lower() in texts, f"{text} not found in {texts}" - - -def assert_in(text: str, path: str, template: t.Iterable[t.Any] = ()) -> None: - texts = _resolve_path_to_texts(path, template) - for tt in texts: - if tt in text.lower(): - return - assert False, f"{text} not found in {texts}" - - -def assert_in_multiple( - text: str, paths: list[str], template: t.Iterable[t.Any] = () -) -> None: - texts: list[str] = [] - for path in paths: - texts += _resolve_path_to_texts(path, template) - for tt in texts: - if tt in text.lower(): - return - assert False, f"{text} not found in {texts}" - - -def assert_startswith(text: str, path: str, template: t.Iterable[t.Any] = ()) -> None: - texts = _resolve_path_to_texts(path, template) - for tt in texts: - if text.lower().startswith(tt): - return - assert False, f"{text} not found in {texts}" - - -def assert_template(text: str, template_path: str) -> None: - templates = _resolve_path_to_texts(template_path) - for tt in templates: - # Checking at least the first part - first_part = tt.split("{")[0] - if text.lower().startswith(first_part): - return - assert False, f"{text} not found in {templates}" - - -def translate( - path: str, template: t.Iterable[t.Any] = (), lower: bool = False -) -> list[str]: - # Do not converting to lowercase, we want the exact value - return _resolve_path_to_texts(path, template, lower=lower) +def __getattr__(key: str) -> str: + return translate(key) diff --git a/tests/ui_tests/fixtures.json b/tests/ui_tests/fixtures.json index fa055b1245..85d66d8ba2 100644 --- a/tests/ui_tests/fixtures.json +++ b/tests/ui_tests/fixtures.json @@ -2140,9 +2140,9 @@ "T2T1_cs_reset_recovery-test_reset_bip39_t2.py::test_reset_device_192": "c3b4126112107622a4ae14343700000e67787f175c7273c0b81fc30320fd4659", "T2T1_cs_reset_recovery-test_reset_bip39_t2.py::test_reset_device_pin": "2e261c7367373888adc9d30baf7be99f89da114364a54dd096305ac76f5b02eb", "T2T1_cs_reset_recovery-test_reset_bip39_t2.py::test_reset_failed_check": "c15845c4d1a46c654b5bb4babed93974d4b7c68b6bb120c74d46a1ec924152ce", -"T2T1_cs_reset_recovery-test_reset_recovery_bip39.py::test_reset_recovery": "3d3c9ddad06542ed169c761779f8bd6a65484c23462aefba05b90df6135421c2", -"T2T1_cs_reset_recovery-test_reset_recovery_slip39_advanced.py::test_reset_recovery": "2d9efb84f2d69506875061f833cdf2dc5d717c006d4e021346c4c1b15a77fe17", -"T2T1_cs_reset_recovery-test_reset_recovery_slip39_basic.py::test_reset_recovery": "5af5fa1fb4e69036a2cb77234059253f539bc2024d2f5895559950876897eab8", +"T2T1_cs_reset_recovery-test_reset_recovery_bip39.py::test_reset_recovery": "7423b5a3985389a8d290b1bf46a63e895c1d10f5506c62db963cae47dc29ef54", +"T2T1_cs_reset_recovery-test_reset_recovery_slip39_advanced.py::test_reset_recovery": "3dd4bfeb88c50e5cd8cef1930c152b0d00f65a4ceed8ab47ab1915dc02c9064d", +"T2T1_cs_reset_recovery-test_reset_recovery_slip39_basic.py::test_reset_recovery": "13432d5369619793e6d362259b004a249b00ef0d0505e15b65b0b2d9f1181653", "T2T1_cs_reset_recovery-test_reset_slip39_advanced.py::test_reset_device_slip39_advanced": "747fa7c7cea4b886102440f1b56f84f00f60609243c7044c42a1d65261d6b93b", "T2T1_cs_reset_recovery-test_reset_slip39_basic.py::test_reset_device_slip39_basic": "d9f64781fddcd204ec6be552593edfbf6a9f680f6f4fd79058b94317ed29fa23", "T2T1_cs_reset_recovery-test_reset_slip39_basic.py::test_reset_device_slip39_basic_256": "8d61ac2c62b0009340d7c2a3559440a24f74af3c0a783a35df26ab72f12f7bf7",