Merge pull request #703 from Foundation-Devices/sft-8192-rename-fake-test-doubles-to-mock-across-the-passport-test
What changed, and why it matters
This commit is a simple renaming of test helper classes from 'Fake*' to 'Mock*' across seven test files. It does not change any production firmware code, behavior, or security logic. It is purely a code-style/test-maintenance change.
No security action needed. This is a non-functional test refactoring change.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit renames test double classes (e.g., FakePin -> MockPin, FakeSPIFlash -> MockSPIFlash, FakeSettings -> MockSettings) and their references in unit tests for SPI flash, multisig xpub validation, PSBT handling, backup restore, and signing flows. All changes are within ports/stm32/boards/Passport/modules/tests/. No runtime firmware logic is modified.
Changed components
ports/stm32/boards/Passport/modules/tests/test_sflash.pyports/stm32/boards/Passport/modules/tests/unit/multisig_xpub_validation.pyports/stm32/boards/Passport/modules/tests/unit/psbt_amounts.pyports/stm32/boards/Passport/modules/tests/unit/psbt_fee.pyports/stm32/boards/Passport/modules/tests/unit/psbt_multisig_approval.pyports/stm32/boards/Passport/modules/tests/unit/restore_backup.pyports/stm32/boards/Passport/modules/tests/unit/sign_psbt.pyInspect captured patch +116 / −116
### ports/stm32/boards/Passport/modules/tests/test_sflash.py
@@ -11,7 +11,7 @@
sys.path.insert(1, os.path.join(sys.path[0], '..'))
-class FakePin:
+class MockPin:
def __init__(self) -> None:
self.level = True
@@ -22,12 +22,12 @@ def high(self):
self.level = True
-class FakeSPIFlash:
+class MockSPIFlash:
# 64 MBit memory - 8 KiB
_MEMORY_SIZE = 8 * 1024 * 1024
def __init__(self) -> None:
- self.cs = FakePin()
+ self.cs = MockPin()
self.write_enable = False
self.write_in_progress = False
self.addr = None
@@ -115,15 +115,15 @@ def readinto(self, buf):
@pytest.fixture
-def fake_spi_flash():
- return FakeSPIFlash()
+def mock_spi_flash():
+ return MockSPIFlash()
@pytest.fixture
-def spi_flash(fake_spi_flash):
+def spi_flash(mock_spi_flash):
from sflash import SPIFlash
- return SPIFlash(fake_spi_flash, fake_spi_flash.cs)
+ return SPIFlash(mock_spi_flash, mock_spi_flash.cs)
def test_wait(spi_flash):
### ports/stm32/boards/Passport/modules/tests/unit/multisig_xpub_validation.py
@@ -14,7 +14,7 @@
CHAIN_CODE = b'\x22' * 32
-class FakeNode:
+class MockNode:
def __init__(self, public_key, chain_code):
self._public_key = public_key
self._chain_code = chain_code
@@ -29,7 +29,7 @@ def chain_code(self):
return self._chain_code
-class FakeChain:
+class MockChain:
ctype = 'BTC'
@staticmethod
@@ -38,7 +38,7 @@ def serialize_public(_node, addr_fmt):
return 'normalized-xpub'
-class FakeSensitiveValues:
+class MockSensitiveValues:
def __enter__(self):
return self
@@ -48,16 +48,16 @@ def __exit__(self, _exc_type, _exc, _traceback):
@staticmethod
def derive_path(derivation):
assert derivation == DERIVATION
- return FakeNode(PUBLIC_KEY, CHAIN_CODE)
+ return MockNode(PUBLIC_KEY, CHAIN_CODE)
def check_node(node):
original_import_xpub = multisig_wallet.import_xpub
original_sensitive_values = stash.SensitiveValues
try:
- multisig_wallet.import_xpub = lambda _xpub: (node, FakeChain, AF_P2SH)
- stash.SensitiveValues = FakeSensitiveValues
+ multisig_wallet.import_xpub = lambda _xpub: (node, MockChain, AF_P2SH)
+ stash.SensitiveValues = MockSensitiveValues
xpubs = []
is_mine = MultisigWallet.check_xpub(
MY_XFP,
@@ -73,12 +73,12 @@ def check_node(node):
stash.SensitiveValues = original_sensitive_values
-is_mine, xpubs = check_node(FakeNode(PUBLIC_KEY, CHAIN_CODE))
+is_mine, xpubs = check_node(MockNode(PUBLIC_KEY, CHAIN_CODE))
assert is_mine
assert xpubs == [(MY_XFP, DERIVATION, 'normalized-xpub')]
try:
- check_node(FakeNode(PUBLIC_KEY, b'\x33' * 32))
+ check_node(MockNode(PUBLIC_KEY, b'\x33' * 32))
except AssertionError as exc:
assert 'wrong xpub' in str(exc)
else:
### ports/stm32/boards/Passport/modules/tests/unit/psbt_amounts.py
@@ -14,23 +14,23 @@
P2WPKH_SCRIPT = b'\x00\x14' + (b'\x11' * 20)
-class FakePSBT:
+class MockPSBT:
def __init__(self, values):
self.fd = BytesIO(b''.join(CTxOut(value, P2WPKH_SCRIPT).serialize() for value in values))
self.vout_start = 0
self.num_outputs = len(values)
self.total_value_out = None
-class FakePrevout:
+class MockPrevout:
n = 0
-class FakeTxIn:
- prevout = FakePrevout()
+class MockTxIn:
+ prevout = MockPrevout()
-class FakeInput:
+class MockInput:
def __init__(self, value):
self.value = value
self.fully_signed = False
@@ -49,9 +49,9 @@ def determine_my_signing_key(self, _idx, _utxo, _xfp, _psbt):
pass
-class FakeInputPSBT:
+class MockInputPSBT:
def __init__(self, values):
- self.inputs = [FakeInput(value) for value in values]
+ self.inputs = [MockInput(value) for value in values]
self.my_xfp = 0
self.total_value_in = None
self.fee_is_verified = True
@@ -61,23 +61,23 @@ def __init__(self, values):
def input_iter(self):
for idx in range(self.num_inputs):
- yield idx, FakeTxIn()
+ yield idx, MockTxIn()
def read_outputs(values):
- psbt = FakePSBT(values)
+ psbt = MockPSBT(values)
parsed = [tx_out.nValue for _, tx_out in psbtObject.output_iter(psbt)]
return psbt, parsed
def read_inputs(values):
- psbt = FakeInputPSBT(values)
+ psbt = MockInputPSBT(values)
psbtObject.consider_inputs(psbt)
return psbt
def assert_invalid_outputs(values, invalid_idx):
- psbt = FakePSBT(values)
+ psbt = MockPSBT(values)
try:
list(psbtObject.output_iter(psbt))
except FatalPSBTIssue as exc:
@@ -88,7 +88,7 @@ def assert_invalid_outputs(values, invalid_idx):
def assert_invalid_inputs(values, invalid_idx):
- psbt = FakeInputPSBT(values)
+ psbt = MockInputPSBT(values)
try:
psbtObject.consider_inputs(psbt)
except FatalPSBTIssue as exc:
### ports/stm32/boards/Passport/modules/tests/unit/psbt_fee.py
@@ -76,23 +76,23 @@ def assert_raises(exc_type, callback):
assert_raises(AssertionError, lambda: script_mismatch.get_utxo(0))
-class FakePrevout:
+class MockPrevout:
n = 0
-class FakeTxIn:
- prevout = FakePrevout()
+class MockTxIn:
+ prevout = MockPrevout()
-class FakeNode:
+class MockNode:
def __init__(self, public_key):
self._public_key = public_key
def public_key(self):
return self._public_key
-class FakeSensitiveValues:
+class MockSensitiveValues:
def __enter__(self):
return self
@@ -102,14 +102,14 @@ def __exit__(self, _exc_type, _exc, _traceback):
@staticmethod
def derive_path(path, register=True):
assert register
- return FakeNode(DERIVED_PUBKEYS[path])
+ return MockNode(DERIVED_PUBKEYS[path])
-class FakeSigningInput:
+class MockSigningInput:
pass
-class FakeInputPSBT:
+class MockInputPSBT:
def __init__(self, psbt_input, my_xfp=0):
self.inputs = [psbt_input]
self.my_xfp = my_xfp
@@ -120,78 +120,78 @@ def __init__(self, psbt_input, my_xfp=0):
self.warnings = []
def input_iter(self):
- yield 0, FakeTxIn()
+ yield 0, MockTxIn()
verified_amounts = []
original_verify_amount = history.verify_amount
original_sensitive_values = stash.SensitiveValues
history.verify_amount = lambda _prevout, amount, idx: verified_amounts.append((amount, idx))
-stash.SensitiveValues = FakeSensitiveValues
+stash.SensitiveValues = MockSensitiveValues
try:
- external_input_psbt = FakeInputPSBT(make_input(CTxOut(2000, P2WPKH_SCRIPT)))
+ external_input_psbt = MockInputPSBT(make_input(CTxOut(2000, P2WPKH_SCRIPT)))
psbtObject.consider_inputs(external_input_psbt)
assert not external_input_psbt.fee_is_verified
owned_input = make_owned_input()
- owned_input.validate(0, FakeTxIn(), MY_XFP)
- owned_input_psbt = FakeInputPSBT(owned_input, MY_XFP)
+ owned_input.validate(0, MockTxIn(), MY_XFP)
+ owned_input_psbt = MockInputPSBT(owned_input, MY_XFP)
psbtObject.consider_inputs(owned_input_psbt)
assert owned_input_psbt.fee_is_verified
assert owned_input.num_our_keys == 1
assert owned_input.required_key == OWNED_PUBKEY
forged_input = make_owned_input(FORGED_PUBKEY)
- forged_input.validate(0, FakeTxIn(), MY_XFP)
- forged_input_psbt = FakeInputPSBT(forged_input, MY_XFP)
+ forged_input.validate(0, MockTxIn(), MY_XFP)
+ forged_input_psbt = MockInputPSBT(forged_input, MY_XFP)
assert_raises(AssertionError, lambda: psbtObject.consider_inputs(forged_input_psbt))
finally:
history.verify_amount = original_verify_amount
stash.SensitiveValues = original_sensitive_values
assert verified_amounts == [(2000, 0), (2000, 0)]
-multisig_input = FakeSigningInput()
+multisig_input = MockSigningInput()
multisig_input.is_multisig = True
multisig_input.required_key = {OWNED_PUBKEY}
multisig_input.subpaths = {OWNED_PUBKEY: [MY_XFP, 0]}
node, which_key = psbtInputProxy.get_signing_node(
- multisig_input, FakeSensitiveValues(), MY_XFP, 0)
+ multisig_input, MockSensitiveValues(), MY_XFP, 0)
assert node.public_key() == OWNED_PUBKEY
assert which_key == OWNED_PUBKEY
-taproot_input = FakeSigningInput()
+taproot_input = MockSigningInput()
taproot_input.is_multisig = False
taproot_input.required_key = TAPROOT_PUBKEY
taproot_input.subpaths = {}
taproot_input.tap_subpaths = {TAPROOT_PUBKEY: ([MY_XFP, 1], [])}
node, which_key = psbtInputProxy.get_signing_node(
- taproot_input, FakeSensitiveValues(), MY_XFP, 0)
+ taproot_input, MockSensitiveValues(), MY_XFP, 0)
assert node.public_key()[1:] == TAPROOT_PUBKEY
assert which_key == TAPROOT_PUBKEY
-missing_path_input = FakeSigningInput()
+missing_path_input = MockSigningInput()
missing_path_input.is_multisig = False
missing_path_input.required_key = OWNED_PUBKEY
missing_path_input.subpaths = {}
missing_path_input.tap_subpaths = {}
assert_raises(
AssertionError,
lambda: psbtInputProxy.get_signing_node(
- missing_path_input, FakeSensitiveValues(), MY_XFP, 0),
+ missing_path_input, MockSensitiveValues(), MY_XFP, 0),
)
-class FakeOutputProxy:
+class MockOutputProxy:
is_change = False
def validate(self, _idx, _txout, _xfp, _active_multisig):
pass
-class FakeOutputPSBT:
+class MockOutputPSBT:
def __init__(self, fee_is_verified):
- self.outputs = [FakeOutputProxy()]
+ self.outputs = [MockOutputProxy()]
self.total_value_out = 1000
self.total_value_in = 5000
self.fee_is_verified = fee_is_verified
@@ -210,33 +210,33 @@ def consider_dangerous_change(self, _xfp):
pass
-unverified_fee_psbt = FakeOutputPSBT(external_input_psbt.fee_is_verified)
+unverified_fee_psbt = MockOutputPSBT(external_input_psbt.fee_is_verified)
psbtObject.consider_outputs(unverified_fee_psbt)
assert unverified_fee_psbt.warnings[0][0] == 'Unverified Fee'
assert all(label not in {'Big Fee', 'Huge Fee'} for label, _text in unverified_fee_psbt.warnings)
-verified_fee_psbt = FakeOutputPSBT(owned_input_psbt.fee_is_verified)
+verified_fee_psbt = MockOutputPSBT(owned_input_psbt.fee_is_verified)
psbtObject.consider_outputs(verified_fee_psbt)
assert verified_fee_psbt.warnings[0][0] == 'Huge Fee'
-class FakeChain:
+class MockChain:
def render_value(self, value):
return str(value), 'sats'
-class FakeFlow:
- chain = FakeChain()
+class MockFlow:
+ chain = MockChain()
def __init__(self, psbt):
self.psbt = psbt
-review = SignPsbtCommonFlow.render_warnings(FakeFlow(unverified_fee_psbt))
+review = SignPsbtCommonFlow.render_warnings(MockFlow(unverified_fee_psbt))
assert 'Unverified' in review
assert '4000 sats' not in review
-review = SignPsbtCommonFlow.render_warnings(FakeFlow(verified_fee_psbt))
+review = SignPsbtCommonFlow.render_warnings(MockFlow(verified_fee_psbt))
assert '4000 sats' in review
return_value.write(b'OK')
### ports/stm32/boards/Passport/modules/tests/unit/psbt_multisig_approval.py
@@ -28,28 +28,28 @@
events = []
-class FakeImportMultisigWalletFlow:
+class MockImportMultisigWalletFlow:
result = None
calls = 0
def __init__(self, wallet):
assert wallet == 'proposed-wallet'
- FakeImportMultisigWalletFlow.calls += 1
+ MockImportMultisigWalletFlow.calls += 1
async def run(self):
events.append('import')
return self.result
-class FakePsbt:
+class MockPsbt:
def __init__(self, needs_approval):
self.multisig_import_needs_approval = needs_approval
self.active_multisig = 'proposed-wallet'
self.my_xfp = MY_XFP
self.outputs = []
-class FakeOutput:
+class MockOutput:
is_change = True
def __init__(self, path, key):
@@ -64,15 +64,15 @@ def __init__(self, path, key):
self.subpaths[key] = str_to_keypath(MY_XFP, path)
-class FakeNode:
+class MockNode:
def __init__(self, key):
self.key = key
def public_key(self):
return self.key
-class FakeSensitiveValues:
+class MockSensitiveValues:
def __enter__(self):
events.append('verify')
return self
@@ -83,10 +83,10 @@ def __exit__(self, *_args):
def derive_path(self, path):
assert path in PATHS
events.append(path)
- return FakeNode(OWNED_KEYS[PATHS.index(path)])
+ return MockNode(OWNED_KEYS[PATHS.index(path)])
-class FakeErrorPage:
+class MockErrorPage:
def __init__(self, text):
assert text == ('Transaction rejected. Passport could not verify that the change address '
'belongs to this wallet.')
@@ -95,7 +95,7 @@ async def show(self):
events.append('error')
-class FakeQuestionPage:
+class MockQuestionPage:
def __init__(self, **_kwargs):
pass
@@ -104,7 +104,7 @@ async def show(self):
return True
-async def fake_spinner_task(_text, task, args=()):
+async def mock_spinner_task(_text, task, args=()):
results = []
async def on_done(*result):
@@ -115,12 +115,12 @@ async def on_done(*result):
return results[0]
-async def fake_sign_psbt_task(on_done, _psbt):
+async def mock_sign_psbt_task(on_done, _psbt):
events.append('sign')
await on_done(None, None)
-class FakeSettings:
+class MockSettings:
temporary_mode = True
def __init__(self, policy=None):
@@ -134,11 +134,11 @@ def get(self, key, default=None):
return default
-class FakeSignFlow(SignPsbtCommonFlow):
+class MockSignFlow(SignPsbtCommonFlow):
def __init__(self, needs_approval):
# Exercise state ordering without rendering pages or accessing device settings.
Flow.__init__(self, initial_state=self.check_multisig_import)
- self.psbt = FakePsbt(needs_approval)
+ self.psbt = MockPsbt(needs_approval)
self.cancel_review = False
async def show_transaction_details(self):
@@ -152,51 +152,51 @@ async def show_transaction_details(self):
async def run_tests():
original_settings = common.settings
replacements = (
- (flows, 'ImportMultisigWalletFlow', FakeImportMultisigWalletFlow),
- (pages, 'ErrorPage', FakeErrorPage),
- (pages, 'QuestionPage', FakeQuestionPage),
- (stash, 'SensitiveValues', FakeSensitiveValues),
- (utils, 'spinner_task', fake_spinner_task),
- (sign_psbt_common_flow, 'spinner_task', fake_spinner_task),
- (sign_psbt_common_flow, 'sign_psbt_task', fake_sign_psbt_task),
+ (flows, 'ImportMultisigWalletFlow', MockImportMultisigWalletFlow),
+ (pages, 'ErrorPage', MockErrorPage),
+ (pages, 'QuestionPage', MockQuestionPage),
+ (stash, 'SensitiveValues', MockSensitiveValues),
+ (utils, 'spinner_task', mock_spinner_task),
+ (sign_psbt_common_flow, 'spinner_task', mock_spinner_task),
+ (sign_psbt_common_flow, 'sign_psbt_task', mock_sign_psbt_task),
)
originals = [(module, name, getattr(module, name)) for module, name, _ in replacements]
try:
for module, name, replacement in replacements:
setattr(module, name, replacement)
- FakeImportMultisigWalletFlow.result = False
- FakeImportMultisigWalletFlow.calls = 0
+ MockImportMultisigWalletFlow.result = False
+ MockImportMultisigWalletFlow.calls = 0
events.clear()
- flow = FakeSignFlow(needs_approval=True)
+ flow = MockSignFlow(needs_approval=True)
assert await flow.run() is None
- assert FakeImportMultisigWalletFlow.calls == 1
+ assert MockImportMultisigWalletFlow.calls == 1
assert events == ['import']
- FakeImportMultisigWalletFlow.result = True
+ MockImportMultisigWalletFlow.result = True
for needs_approval in (True, False):
events.clear()
- flow = FakeSignFlow(needs_approval)
- flow.psbt.outputs = [FakeOutput(PATHS[0], OWNED_KEYS[0])]
+ flow = MockSignFlow(needs_approval)
+ flow.psbt.outputs = [MockOutput(PATHS[0], OWNED_KEYS[0])]
assert await flow.run() is flow.psbt
expected = ['import'] if needs_approval else []
assert events == expected + ['verify', PATHS[0], 'clear', 'review', 'confirm', 'sign']
# Reviewing and cancelling a transaction without change must not open the key store.
- payment = FakeOutput(PATHS[0], OTHER_KEY)
+ payment = MockOutput(PATHS[0], OTHER_KEY)
payment.is_change = False
for outputs in ([], [payment]):
events.clear()
- flow = FakeSignFlow(needs_approval=False)
+ flow = MockSignFlow(needs_approval=False)
flow.psbt.outputs = outputs
flow.cancel_review = True
assert await flow.run() is None
assert events == ['review']
events.clear()
- flow = FakeSignFlow(needs_approval=False)
- flow.psbt.outputs = [FakeOutput(PATHS[0], OWNED_KEYS[0])]
+ flow = MockSignFlow(needs_approval=False)
+ flow.psbt.outputs = [MockOutput(PATHS[0], OWNED_KEYS[0])]
flow.cancel_review = True
assert await flow.run() is None
assert events == ['verify', PATHS[0], 'clear', 'review']
@@ -206,8 +206,8 @@ async def run_tests():
for path, owned_key in zip(PATHS, OWNED_KEYS):
for key in (owned_key, OTHER_KEY):
events.clear()
- flow = FakeSignFlow(needs_approval=False)
- flow.psbt.outputs = [FakeOutput(path, key)]
+ flow = MockSignFlow(needs_approval=False)
+ flow.psbt.outputs = [MockOutput(path, key)]
result = await flow.run()
if key == owned_key:
assert result is flow.psbt
@@ -216,10 +216,10 @@ async def run_tests():
assert result is None
assert events == ['verify', path, 'clear', 'error']
- common.settings = FakeSettings()
+ common.settings = MockSettings()
assert get_multisig_policy() == MUSIG_ASK
- common.settings = FakeSettings(policy=MUSIG_SKIP)
+ common.settings = MockSettings(policy=MUSIG_SKIP)
assert get_multisig_policy() == MUSIG_SKIP
return_value.write(b'OK')
### ports/stm32/boards/Passport/modules/tests/unit/restore_backup.py
@@ -7,7 +7,7 @@
from tasks.restore_backup_task import restore_settings_from_backup
-class FakeSettings:
+class MockSettings:
def __init__(self):
self.values = {}
@@ -26,7 +26,7 @@ def set(self, key, value):
'setting.backup_quiz': True,
}
-settings = FakeSettings()
+settings = MockSettings()
restore_settings_from_backup(vals, settings)
assert settings.values == {
@@ -107,7 +107,7 @@ def clear_volatile(self):
self.volatile.clear()
-class FakePa:
+class MockPa:
def __init__(self):
self.calls = []
@@ -118,26 +118,26 @@ async def new_main_secret(self, raw, chain):
self.calls.append('new_main_secret')
-class FakeCardSlot:
+class MockCardSlot:
def __enter__(self):
return self
def __exit__(self, *_args):
return False
-class FakeFile:
+class MockFile:
def close(self):
pass
-class FakeBuilder:
+class MockBuilder:
def read_file(self, fd, password, maxsize, progress_fcn=None):
return ('backup.txt', BACKUP_CONTENTS)
-class FakeCompat7z:
- Builder = FakeBuilder
+class MockCompat7z:
+ Builder = MockBuilder
@staticmethod
def check_file_headers(fd):
@@ -155,16 +155,16 @@ async def on_done(error):
stored = StoredSettings()
-pa = FakePa()
+pa = MockPa()
# Set the module-level open() before the try, so the finally can always undo it.
-restore_module.open = lambda path, mode: FakeFile()
+restore_module.open = lambda path, mode: MockFile()
originals = (common.settings, common.pa, restore_module.compat7z, restore_module.CardSlot)
try:
common.settings = stored
common.pa = pa
- restore_module.compat7z = FakeCompat7z
- restore_module.CardSlot = FakeCardSlot
+ restore_module.compat7z = MockCompat7z
+ restore_module.CardSlot = MockCardSlot
assert asyncio.run(run_restore()) == [None]
finally:
### ports/stm32/boards/Passport/modules/tests/unit/sign_psbt.py
@@ -8,35 +8,35 @@
from utils import escape_text, recolor, stylize_address
-class FakeChain:
+class MockChain:
def render_value(self, value):
return (str(value), 'sats')
def render_address(self, script):
return 'OP_RETURN:\n{}'.format(script)
-class FakeFlow:
- chain = FakeChain()
+class MockFlow:
+ chain = MockChain()
-class FakeAddressChain(FakeChain):
+class MockAddressChain(MockChain):
def render_address(self, script):
return script
-class FakeAddressFlow:
- chain = FakeAddressChain()
+class MockAddressFlow:
+ chain = MockAddressChain()
-class FakeOutput:
+class MockOutput:
def __init__(self, value, message):
self.nValue = value
self.scriptPubKey = message
def assert_op_return_output(value, message):
- rendered = SignPsbtCommonFlow.render_output(FakeFlow(), FakeOutput(value, message))
+ rendered = SignPsbtCommonFlow.render_output(MockFlow(), MockOutput(value, message))
amount_label = rendered.find('Amount')
amount = rendered.find('{} sats'.format(value))
@@ -55,15 +55,15 @@ def assert_op_return_output(value, message):
destination_heading = recolor(HIGHLIGHT_TEXT_HEX, 'Destination')
malicious_message = '{}\n0.00000001 BTC\n\n{}\nbc1qattacker'.format(
amount_heading, destination_heading)
-rendered = SignPsbtCommonFlow.render_output(FakeFlow(), FakeOutput(1, malicious_message))
+rendered = SignPsbtCommonFlow.render_output(MockFlow(), MockOutput(1, malicious_message))
assert escape_text(malicious_message) in rendered
assert rendered.count('\n{}\n'.format(amount_heading)) == 1
assert rendered.count('\n{}\n'.format(message_heading)) == 1
assert rendered.count('\n{}\n'.format(destination_heading)) == 0
assert malicious_message not in rendered
address = 'bc1qvaliddestination'
-rendered = SignPsbtCommonFlow.render_output(FakeAddressFlow(), FakeOutput(42, address))
+rendered = SignPsbtCommonFlow.render_output(MockAddressFlow(), MockOutput(42, address))
assert rendered == '\n{}\n42 sats\n\n{}\n{}'.format(
amount_heading, destination_heading, stylize_address(address))
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.