1
0
mirror of https://github.com/trezor/trezor-firmware.git synced 2024-12-22 14:28:07 +00:00

tests: test that trailing data in translations header will be accepted

This commit is contained in:
matejcik 2024-02-28 11:01:32 +01:00 committed by matejcik
parent 22beadc1b7
commit 802958bc05
3 changed files with 49 additions and 4 deletions

View File

@ -25,7 +25,14 @@ from trezorlib import debuglink, device, exceptions, messages, models
from trezorlib.debuglink import TrezorClientDebugLink as Client from trezorlib.debuglink import TrezorClientDebugLink as Client
from trezorlib.debuglink import message_filters from trezorlib.debuglink import message_filters
from ..translations import LANGUAGES, build_and_sign_blob, get_lang_json, set_language from ..translations import (
LANGUAGES,
build_and_sign_blob,
get_lang_json,
prepare_blob,
set_language,
sign_blob,
)
pytestmark = pytest.mark.skip_t1b1 pytestmark = pytest.mark.skip_t1b1
@ -339,3 +346,21 @@ def test_switch_language(client: Client):
# switch back to Czech with display, implicitly # switch back to Czech with display, implicitly
_maybe_confirm_set_language(client, "cs", None, True) _maybe_confirm_set_language(client, "cs", None, True)
def test_header_trailing_data(client: Client):
"""Adding trailing data to _header_ section specifically must be accepted by
firmware, as long as the blob is otherwise valid and signed.
(this ensures forwards compatibility if we extend the header)
"""
assert client.features.language == "en-US"
lang = "cs"
blob = prepare_blob(lang, client.model)
blob.header_bytes += b"trailing dataa"
assert len(blob.header_bytes) % 2 == 0, "Trailing data must keep the 2-alignment"
language_data = sign_blob(blob)
device.change_language(client, language_data)
assert client.features.language == "cs-CZ"
_check_ping_screen_texts(client, get_ping_title(lang), get_ping_button(lang))

View File

@ -19,10 +19,10 @@ ORDER_FILE = TRANSLATIONS / "order.json"
LANGUAGES = [file.stem for file in TRANSLATIONS.glob("??.json")] LANGUAGES = [file.stem for file in TRANSLATIONS.glob("??.json")]
def build_and_sign_blob( def prepare_blob(
lang_or_def: translations.JsonDef | Path | str, lang_or_def: translations.JsonDef | Path | str,
model: models.TrezorModel, model: models.TrezorModel,
) -> bytes: ) -> translations.TranslationsBlob:
order = translations.order_from_json(json.loads(ORDER_FILE.read_text())) order = translations.order_from_json(json.loads(ORDER_FILE.read_text()))
if isinstance(lang_or_def, str): if isinstance(lang_or_def, str):
lang_or_def = get_lang_json(lang_or_def) lang_or_def = get_lang_json(lang_or_def)
@ -31,8 +31,10 @@ def build_and_sign_blob(
# generate raw blob # generate raw blob
version = translations.version_from_json(lang_or_def["header"]["version"]) version = translations.version_from_json(lang_or_def["header"]["version"])
blob = translations.blob_from_defs(lang_or_def, order, model, version, FONTS_DIR) return translations.blob_from_defs(lang_or_def, order, model, version, FONTS_DIR)
def sign_blob(blob: translations.TranslationsBlob) -> bytes:
# build 0-item Merkle proof # build 0-item Merkle proof
digest = sha256(b"\x00" + blob.header_bytes).digest() digest = sha256(b"\x00" + blob.header_bytes).digest()
signature = cosi.sign_with_privkeys(digest, common.PRIVATE_KEYS_DEV) signature = cosi.sign_with_privkeys(digest, common.PRIVATE_KEYS_DEV)
@ -44,6 +46,14 @@ def build_and_sign_blob(
return blob.build() return blob.build()
def build_and_sign_blob(
lang_or_def: translations.JsonDef | Path | str,
model: models.TrezorModel,
) -> bytes:
blob = prepare_blob(lang_or_def, model)
return sign_blob(blob)
def set_language(client: Client, lang: str): def set_language(client: Client, lang: str):
if lang.startswith("en"): if lang.startswith("en"):
language_data = b"" language_data = b""

View File

@ -3656,6 +3656,7 @@
"TR_cs_test_language.py::test_full_language_change[en]": "f88a93b5fc559b5b3ad60f8db835f0c887fa6db9ef7532066d6dad96c5efac83", "TR_cs_test_language.py::test_full_language_change[en]": "f88a93b5fc559b5b3ad60f8db835f0c887fa6db9ef7532066d6dad96c5efac83",
"TR_cs_test_language.py::test_full_language_change[es]": "6c6f5261a3b2feeb2cb1393cddbccfff23bef9ef9b9803eed80a503a3cdc4a20", "TR_cs_test_language.py::test_full_language_change[es]": "6c6f5261a3b2feeb2cb1393cddbccfff23bef9ef9b9803eed80a503a3cdc4a20",
"TR_cs_test_language.py::test_full_language_change[fr]": "18ef4870bf5ee29d49ece9e92910bf3772e5bebde6c642929126d22a84086557", "TR_cs_test_language.py::test_full_language_change[fr]": "18ef4870bf5ee29d49ece9e92910bf3772e5bebde6c642929126d22a84086557",
"TR_cs_test_language.py::test_header_trailing_data": "ca1ce911f38488122f34815eae9545bdff0b625c53b6936e442a30a4b15655b5",
"TR_cs_test_language.py::test_language_is_removed_after_wipe": "3fed5c087d565830eae7c0647a4c1ef9350595f550062ae575a97f50cdd7d826", "TR_cs_test_language.py::test_language_is_removed_after_wipe": "3fed5c087d565830eae7c0647a4c1ef9350595f550062ae575a97f50cdd7d826",
"TR_cs_test_language.py::test_reject_update": "94873b672e55ac3a766fe78cce140e27fe5fbbe4a837bc0e64bb46592ec5d4e3", "TR_cs_test_language.py::test_reject_update": "94873b672e55ac3a766fe78cce140e27fe5fbbe4a837bc0e64bb46592ec5d4e3",
"TR_cs_test_language.py::test_silent_first_install[False-False]": "cfca3550117beb0f44e6fecb844dfbbf2a182dd440a117398ff04603b6d365f2", "TR_cs_test_language.py::test_silent_first_install[False-False]": "cfca3550117beb0f44e6fecb844dfbbf2a182dd440a117398ff04603b6d365f2",
@ -5023,6 +5024,7 @@
"TR_de_test_language.py::test_full_language_change[en]": "a35bc4501de8bae861d757421e17440a21f7d4f3ce1a56bfadabe9e5b467e4a2", "TR_de_test_language.py::test_full_language_change[en]": "a35bc4501de8bae861d757421e17440a21f7d4f3ce1a56bfadabe9e5b467e4a2",
"TR_de_test_language.py::test_full_language_change[es]": "2fd72d78dd1d1176ac6aecdfd3ea790aa2aafac0d705b406d44c0e9c9545002c", "TR_de_test_language.py::test_full_language_change[es]": "2fd72d78dd1d1176ac6aecdfd3ea790aa2aafac0d705b406d44c0e9c9545002c",
"TR_de_test_language.py::test_full_language_change[fr]": "fda57886e4c371f3219a29dd54b01de43e96bbb94a6fcc7d6c9e1bd1e7e30ace", "TR_de_test_language.py::test_full_language_change[fr]": "fda57886e4c371f3219a29dd54b01de43e96bbb94a6fcc7d6c9e1bd1e7e30ace",
"TR_de_test_language.py::test_header_trailing_data": "15ee794395d4ad28ebb80396491249c29fbab5e810ac6413a27788f0ce9d1217",
"TR_de_test_language.py::test_language_is_removed_after_wipe": "f330e4d64e824ff1f20541ccedba6fbb80ccdf61a3a5197eed59789db8f3216e", "TR_de_test_language.py::test_language_is_removed_after_wipe": "f330e4d64e824ff1f20541ccedba6fbb80ccdf61a3a5197eed59789db8f3216e",
"TR_de_test_language.py::test_reject_update": "c030eaa1b84ee548a68f0e20ad74201cbbeea1f09095dfafe0465020f3215a7a", "TR_de_test_language.py::test_reject_update": "c030eaa1b84ee548a68f0e20ad74201cbbeea1f09095dfafe0465020f3215a7a",
"TR_de_test_language.py::test_silent_first_install[False-False]": "84a63e9be7b085d0b8ce087df8d575342a90157a52811decea69ba2083be41c1", "TR_de_test_language.py::test_silent_first_install[False-False]": "84a63e9be7b085d0b8ce087df8d575342a90157a52811decea69ba2083be41c1",
@ -6390,6 +6392,7 @@
"TR_en_test_language.py::test_full_language_change[en]": "a9c383b584d24c5aa9623b7955fe3e45dcf6016dbc0327a7ce9176ecb0e4d5d3", "TR_en_test_language.py::test_full_language_change[en]": "a9c383b584d24c5aa9623b7955fe3e45dcf6016dbc0327a7ce9176ecb0e4d5d3",
"TR_en_test_language.py::test_full_language_change[es]": "94ead6f9d0f308f60ffd135c9bbd5012a30f05b4f44fdb22286ae259bef9e205", "TR_en_test_language.py::test_full_language_change[es]": "94ead6f9d0f308f60ffd135c9bbd5012a30f05b4f44fdb22286ae259bef9e205",
"TR_en_test_language.py::test_full_language_change[fr]": "2f3a0e8541cc7b96dc983d4de2149e4e2b230b43e1971153ec6bc82e7dadafb8", "TR_en_test_language.py::test_full_language_change[fr]": "2f3a0e8541cc7b96dc983d4de2149e4e2b230b43e1971153ec6bc82e7dadafb8",
"TR_en_test_language.py::test_header_trailing_data": "e914c45909bd3226fbdbeae1b28507b68b87effb09df537b52adbdf87d8586e4",
"TR_en_test_language.py::test_language_is_removed_after_wipe": "5363564a612486602f3e6c94cb5d18ef82c2253dfe51df4623d56b5bab920a2e", "TR_en_test_language.py::test_language_is_removed_after_wipe": "5363564a612486602f3e6c94cb5d18ef82c2253dfe51df4623d56b5bab920a2e",
"TR_en_test_language.py::test_reject_update": "949fb112e684d3fb8a204a8ce15a202ebe9613bd3a453408138b3e54bb42e99a", "TR_en_test_language.py::test_reject_update": "949fb112e684d3fb8a204a8ce15a202ebe9613bd3a453408138b3e54bb42e99a",
"TR_en_test_language.py::test_silent_first_install[False-False]": "8c6d7a8d499e4ede3d42cb6ef67cbde9f7dd35d518bacaa538e900bf3944b250", "TR_en_test_language.py::test_silent_first_install[False-False]": "8c6d7a8d499e4ede3d42cb6ef67cbde9f7dd35d518bacaa538e900bf3944b250",
@ -7757,6 +7760,7 @@
"TR_es_test_language.py::test_full_language_change[en]": "5684c4f7e6ca01d85d83549d892ecc4fc0277b46dd7294d0d7ef436a2f4bbf6d", "TR_es_test_language.py::test_full_language_change[en]": "5684c4f7e6ca01d85d83549d892ecc4fc0277b46dd7294d0d7ef436a2f4bbf6d",
"TR_es_test_language.py::test_full_language_change[es]": "51aee9f7f7e76839471274c909bcdd2c117e3fe6d9ca634ef71f1209dcb2271a", "TR_es_test_language.py::test_full_language_change[es]": "51aee9f7f7e76839471274c909bcdd2c117e3fe6d9ca634ef71f1209dcb2271a",
"TR_es_test_language.py::test_full_language_change[fr]": "0f7df785e611deec165dcce914efbabb497cba640795c8b90f396c223af7f3f0", "TR_es_test_language.py::test_full_language_change[fr]": "0f7df785e611deec165dcce914efbabb497cba640795c8b90f396c223af7f3f0",
"TR_es_test_language.py::test_header_trailing_data": "fce69490d11c51a6e3cc9d1f045e5e8b75ef3c5b4519aa702da40ea1d03a11e5",
"TR_es_test_language.py::test_language_is_removed_after_wipe": "7a7d05f7feed0938e23ec6ac76133246f6dbd626969efe43b0122bb2801e4e93", "TR_es_test_language.py::test_language_is_removed_after_wipe": "7a7d05f7feed0938e23ec6ac76133246f6dbd626969efe43b0122bb2801e4e93",
"TR_es_test_language.py::test_reject_update": "72b5cc4bb1d3a1024ef5348356565e711392fc379afee08a9d4275b7d627c213", "TR_es_test_language.py::test_reject_update": "72b5cc4bb1d3a1024ef5348356565e711392fc379afee08a9d4275b7d627c213",
"TR_es_test_language.py::test_silent_first_install[False-False]": "fe722b1d027ca3b5af955c350722176de874b9d22446492a1b80d3f74d5bebfe", "TR_es_test_language.py::test_silent_first_install[False-False]": "fe722b1d027ca3b5af955c350722176de874b9d22446492a1b80d3f74d5bebfe",
@ -9124,6 +9128,7 @@
"TR_fr_test_language.py::test_full_language_change[en]": "5c8ccc0eb1be8baebf3d2cd0a60b022728933ac4180f27a0caa73a5b9fb0f642", "TR_fr_test_language.py::test_full_language_change[en]": "5c8ccc0eb1be8baebf3d2cd0a60b022728933ac4180f27a0caa73a5b9fb0f642",
"TR_fr_test_language.py::test_full_language_change[es]": "e27434b09eef1556fe6fa0b050fb2b43eed6b4f37d622b7831a5fcbcde3f72bd", "TR_fr_test_language.py::test_full_language_change[es]": "e27434b09eef1556fe6fa0b050fb2b43eed6b4f37d622b7831a5fcbcde3f72bd",
"TR_fr_test_language.py::test_full_language_change[fr]": "7fae72778d7111b0d7746ce3fdfdae724415f651b2c3e195da55dc3cf6e24f8e", "TR_fr_test_language.py::test_full_language_change[fr]": "7fae72778d7111b0d7746ce3fdfdae724415f651b2c3e195da55dc3cf6e24f8e",
"TR_fr_test_language.py::test_header_trailing_data": "68923fb1c4fc87822131d1c543c1ccb1f730f56d7dc0ae81a01109d6b8cb3a7f",
"TR_fr_test_language.py::test_language_is_removed_after_wipe": "9c12ba731cef7dd8a2fbb421aa328af48ed383b9d4ea4edb6cfbe6bd7a594115", "TR_fr_test_language.py::test_language_is_removed_after_wipe": "9c12ba731cef7dd8a2fbb421aa328af48ed383b9d4ea4edb6cfbe6bd7a594115",
"TR_fr_test_language.py::test_reject_update": "4c1d851a4f7ca6075e71d096a4b124b31f8ff280d609cc2495ded9750f057b51", "TR_fr_test_language.py::test_reject_update": "4c1d851a4f7ca6075e71d096a4b124b31f8ff280d609cc2495ded9750f057b51",
"TR_fr_test_language.py::test_silent_first_install[False-False]": "79baf3cf0b204f265a80ce571552b1fb082aeb72cc37d515b6682365a6ebeae4", "TR_fr_test_language.py::test_silent_first_install[False-False]": "79baf3cf0b204f265a80ce571552b1fb082aeb72cc37d515b6682365a6ebeae4",
@ -10798,6 +10803,7 @@
"TT_cs_test_language.py::test_full_language_change[en]": "4221be0ec3ac6b31d53878bd3cf2d216b962b06c6bd793cbc8f4228594d391f5", "TT_cs_test_language.py::test_full_language_change[en]": "4221be0ec3ac6b31d53878bd3cf2d216b962b06c6bd793cbc8f4228594d391f5",
"TT_cs_test_language.py::test_full_language_change[es]": "1d021e60c0a5a25950064ab3159df74bf477bec6db1d05a62568dd195b7f6a0a", "TT_cs_test_language.py::test_full_language_change[es]": "1d021e60c0a5a25950064ab3159df74bf477bec6db1d05a62568dd195b7f6a0a",
"TT_cs_test_language.py::test_full_language_change[fr]": "5b6297ad7b03664e18a95b8eb32ff4f0fd76f827da64559e09815fa506812440", "TT_cs_test_language.py::test_full_language_change[fr]": "5b6297ad7b03664e18a95b8eb32ff4f0fd76f827da64559e09815fa506812440",
"TT_cs_test_language.py::test_header_trailing_data": "919fd0107366fe4dab3b7216a758a24ddb22a9c61ba669e05892df43a08d6b38",
"TT_cs_test_language.py::test_language_is_removed_after_wipe": "a3ae02a5a95dbfa4ffde27c66ab3b5a766aa0e84e04c64504c19a3ae432d0e8b", "TT_cs_test_language.py::test_language_is_removed_after_wipe": "a3ae02a5a95dbfa4ffde27c66ab3b5a766aa0e84e04c64504c19a3ae432d0e8b",
"TT_cs_test_language.py::test_reject_update": "baabea339f79af37b0184349a1d1e360cbbf111fc8fe8c7bf89f6ee8b6091cbb", "TT_cs_test_language.py::test_reject_update": "baabea339f79af37b0184349a1d1e360cbbf111fc8fe8c7bf89f6ee8b6091cbb",
"TT_cs_test_language.py::test_silent_first_install[False-False]": "b8494f22dfd7426af61780d585cedbdfbdd20c65721cc50e599e6f0c97aec1cb", "TT_cs_test_language.py::test_silent_first_install[False-False]": "b8494f22dfd7426af61780d585cedbdfbdd20c65721cc50e599e6f0c97aec1cb",
@ -12245,6 +12251,7 @@
"TT_de_test_language.py::test_full_language_change[en]": "4471ecae299a6e26d3708a189c9cfcb706f21ef21639a978a04c28e6c478f9c4", "TT_de_test_language.py::test_full_language_change[en]": "4471ecae299a6e26d3708a189c9cfcb706f21ef21639a978a04c28e6c478f9c4",
"TT_de_test_language.py::test_full_language_change[es]": "ebe595cee2832bd1e7ad4ef6476ff9dba50ccd26f3119c5cda9c17b1dd178ae4", "TT_de_test_language.py::test_full_language_change[es]": "ebe595cee2832bd1e7ad4ef6476ff9dba50ccd26f3119c5cda9c17b1dd178ae4",
"TT_de_test_language.py::test_full_language_change[fr]": "256177588435bf75d7bb339e835a6e79f8d10314f155784047b9d5a77a5c5e72", "TT_de_test_language.py::test_full_language_change[fr]": "256177588435bf75d7bb339e835a6e79f8d10314f155784047b9d5a77a5c5e72",
"TT_de_test_language.py::test_header_trailing_data": "b7c2dcfbac8e5261d83ebac9fba426ce682af350c7b2aa44e230ef31749180cf",
"TT_de_test_language.py::test_language_is_removed_after_wipe": "5b9f5817ba4e243d41262887aa338bb674f700ce47e1b50bc564cfd665876799", "TT_de_test_language.py::test_language_is_removed_after_wipe": "5b9f5817ba4e243d41262887aa338bb674f700ce47e1b50bc564cfd665876799",
"TT_de_test_language.py::test_reject_update": "adef723d293c68592689b4fafbe87e6811656e6ea962484474594ce8f2407b4b", "TT_de_test_language.py::test_reject_update": "adef723d293c68592689b4fafbe87e6811656e6ea962484474594ce8f2407b4b",
"TT_de_test_language.py::test_silent_first_install[False-False]": "629c908f9d1d76b1248297c5a2eb9ee4933d54c53003329599312d6f292d4c7d", "TT_de_test_language.py::test_silent_first_install[False-False]": "629c908f9d1d76b1248297c5a2eb9ee4933d54c53003329599312d6f292d4c7d",
@ -13692,6 +13699,7 @@
"TT_en_test_language.py::test_full_language_change[en]": "5f6cec419aad5e5658f6fda45c2cd40fa4581823e7f9f0c4199970cd179bfd4e", "TT_en_test_language.py::test_full_language_change[en]": "5f6cec419aad5e5658f6fda45c2cd40fa4581823e7f9f0c4199970cd179bfd4e",
"TT_en_test_language.py::test_full_language_change[es]": "fcb472f8786ab55cc7b90450a002165fd74ed88edc0d41a0dffd741b801d7f0b", "TT_en_test_language.py::test_full_language_change[es]": "fcb472f8786ab55cc7b90450a002165fd74ed88edc0d41a0dffd741b801d7f0b",
"TT_en_test_language.py::test_full_language_change[fr]": "a6b00695cb76f4fcc7197d37df49c3b1997da6ed23f2c21330d30e0f28dc910d", "TT_en_test_language.py::test_full_language_change[fr]": "a6b00695cb76f4fcc7197d37df49c3b1997da6ed23f2c21330d30e0f28dc910d",
"TT_en_test_language.py::test_header_trailing_data": "83ef1fdc5cc38aa181c9bf68099ed5ba827a8cf9fcc6bf6a7bc5c9d1ac6a9d78",
"TT_en_test_language.py::test_language_is_removed_after_wipe": "20955fc2d8ae93c616be7041440c1e86a6a92e3235b352abdf0f17d95319d600", "TT_en_test_language.py::test_language_is_removed_after_wipe": "20955fc2d8ae93c616be7041440c1e86a6a92e3235b352abdf0f17d95319d600",
"TT_en_test_language.py::test_reject_update": "78b8f16e00c5d653a7d5c0929d21ae8ae1c76798fe28f0eb6edee8e2ee8b0202", "TT_en_test_language.py::test_reject_update": "78b8f16e00c5d653a7d5c0929d21ae8ae1c76798fe28f0eb6edee8e2ee8b0202",
"TT_en_test_language.py::test_silent_first_install[False-False]": "bbd64861dce4334f1d4a49cdccf981c854b72fe6807adfa516d115337eb60a36", "TT_en_test_language.py::test_silent_first_install[False-False]": "bbd64861dce4334f1d4a49cdccf981c854b72fe6807adfa516d115337eb60a36",
@ -15157,6 +15165,7 @@
"TT_es_test_language.py::test_full_language_change[en]": "b156bab790f73a90410c6951b8d1e0f1cafc9b1f7c33b0d90cc6fde86583c093", "TT_es_test_language.py::test_full_language_change[en]": "b156bab790f73a90410c6951b8d1e0f1cafc9b1f7c33b0d90cc6fde86583c093",
"TT_es_test_language.py::test_full_language_change[es]": "dc724987f4e89000676d39cda877fd25cb2d8d1360eb28be9683b19b48a7aa0f", "TT_es_test_language.py::test_full_language_change[es]": "dc724987f4e89000676d39cda877fd25cb2d8d1360eb28be9683b19b48a7aa0f",
"TT_es_test_language.py::test_full_language_change[fr]": "a8d92d89b104b2fc3ee65e17d870366fd22fa910d2971d1c61319078a15244bc", "TT_es_test_language.py::test_full_language_change[fr]": "a8d92d89b104b2fc3ee65e17d870366fd22fa910d2971d1c61319078a15244bc",
"TT_es_test_language.py::test_header_trailing_data": "d3928eb02ac97f9fd3a62919bb14fc7f1c6a8aaaffba842518a32e74a2a754cb",
"TT_es_test_language.py::test_language_is_removed_after_wipe": "6a92f98a10478ddc916f0b8f6c56b13cae1f458a9ad86eb6c8f46a9033abcdec", "TT_es_test_language.py::test_language_is_removed_after_wipe": "6a92f98a10478ddc916f0b8f6c56b13cae1f458a9ad86eb6c8f46a9033abcdec",
"TT_es_test_language.py::test_reject_update": "107634fbdacc72337abd7de1291904e6297bf5dd9551163780a1438b6d965949", "TT_es_test_language.py::test_reject_update": "107634fbdacc72337abd7de1291904e6297bf5dd9551163780a1438b6d965949",
"TT_es_test_language.py::test_silent_first_install[False-False]": "b307450f1f7e6118118b631c8354e9acb89f90f5755294ebb45b610ee8fc23c2", "TT_es_test_language.py::test_silent_first_install[False-False]": "b307450f1f7e6118118b631c8354e9acb89f90f5755294ebb45b610ee8fc23c2",
@ -16604,6 +16613,7 @@
"TT_fr_test_language.py::test_full_language_change[en]": "f77bf50157ba8e718b35af18003b8ebd296c076949cb138abba570d04159ce46", "TT_fr_test_language.py::test_full_language_change[en]": "f77bf50157ba8e718b35af18003b8ebd296c076949cb138abba570d04159ce46",
"TT_fr_test_language.py::test_full_language_change[es]": "dee01837c5deb4758a4fdcc1c10da654bd7da2917d371b2188e01dcce6574458", "TT_fr_test_language.py::test_full_language_change[es]": "dee01837c5deb4758a4fdcc1c10da654bd7da2917d371b2188e01dcce6574458",
"TT_fr_test_language.py::test_full_language_change[fr]": "f59be182fa1ff0bfb9230b69a49dabfed30394618e2eaf11597c8a109a7bab95", "TT_fr_test_language.py::test_full_language_change[fr]": "f59be182fa1ff0bfb9230b69a49dabfed30394618e2eaf11597c8a109a7bab95",
"TT_fr_test_language.py::test_header_trailing_data": "abf21ee323be4a9fe145d080b404778daf06f4148a43bfa2528856cbb4310a9b",
"TT_fr_test_language.py::test_language_is_removed_after_wipe": "a474ebb565e9e2fc01647fe2ae739519f25807562abe757ac55d20814b3458af", "TT_fr_test_language.py::test_language_is_removed_after_wipe": "a474ebb565e9e2fc01647fe2ae739519f25807562abe757ac55d20814b3458af",
"TT_fr_test_language.py::test_reject_update": "1ea4e3f645e5d788714b61525c0eee446a306f2844fec383460e45574f9a5de5", "TT_fr_test_language.py::test_reject_update": "1ea4e3f645e5d788714b61525c0eee446a306f2844fec383460e45574f9a5de5",
"TT_fr_test_language.py::test_silent_first_install[False-False]": "d0046d29c419e87c0f3881d7c9308c9621dc111a6b5a914eb8bd63266a7d7b91", "TT_fr_test_language.py::test_silent_first_install[False-False]": "d0046d29c419e87c0f3881d7c9308c9621dc111a6b5a914eb8bd63266a7d7b91",