SFT-8192: rename Fake* test doubles to Mock*
What changed, and why it matters
This commit only renames test helper classes from 'Fake*' to 'Mock*' across seven test files. It does not change any actual product code or test behavior, so it has no security relevance on its own.
No security action needed. Treat as routine code hygiene / test maintainability.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff is a pure identifier rename: 28 class names, three lowercase helper functions, and one pytest fixture are changed from Fake to Mock. All references are updated consistently. There are no changes to logic, control flow, cryptography, input validation, or hardware interfaces. The commit message explicitly states ‘No behaviour change.’
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.