Skip to content

Commit 7c9e117

Browse files
fix: log expected device errors at warning & dart format to satisfy CI format gate
1 parent 56c6dd0 commit 7c9e117

4 files changed

Lines changed: 68 additions & 79 deletions

File tree

lib/core/ledger/data/repositories/ledger_device_repository_impl.dart

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -179,8 +179,13 @@ class LedgerDeviceRepositoryImpl implements LedgerDeviceRepository {
179179
LedgerUnexpectedFailure('connection type not initialized'),
180180
);
181181
} catch (e, st) {
182-
log.severe(message: 'Ledger operation failed', error: e, trace: st);
183-
return Err(_interpretRawError(e));
182+
final failure = _interpretRawError(e);
183+
if (failure is LedgerUnexpectedFailure) {
184+
log.severe(message: 'Ledger operation failed', error: e, trace: st);
185+
} else {
186+
log.warning('Ledger operation failed', error: e, trace: st);
187+
}
188+
return Err(failure);
184189
}
185190
}
186191

lib/core/ledger/domain/errors/ledger_exception.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ final class DeviceNotFoundLedgerException extends LedgerException {
2626
const DeviceNotFoundLedgerException();
2727
}
2828

29-
final class ConnectionTypeNotInitializedLedgerException extends LedgerException {
29+
final class ConnectionTypeNotInitializedLedgerException
30+
extends LedgerException {
3031
const ConnectionTypeNotInitializedLedgerException();
3132
}
3233

lib/features/ledger/presentation/cubit/ledger_operation_cubit.dart

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -71,20 +71,15 @@ class LedgerOperationCubit extends Cubit<LedgerOperationState> {
7171
switch (await operation()) {
7272
case Ok(:final value):
7373
emit(
74-
state.copyWith(
75-
status: LedgerOperationStatus.success,
76-
result: value,
77-
),
74+
state.copyWith(status: LedgerOperationStatus.success, result: value),
7875
);
7976
case Err(:final failure):
8077
_emitFailure(failure);
8178
}
8279
}
8380

8481
void _emitFailure(LedgerFailure failure) {
85-
emit(
86-
state.copyWith(status: LedgerOperationStatus.error, failure: failure),
87-
);
82+
emit(state.copyWith(status: LedgerOperationStatus.error, failure: failure));
8883
}
8984

9085
void reset() {

test/core_test/ledger/ledger_device_repository_test.dart

Lines changed: 57 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -51,62 +51,53 @@ void main() {
5151
final result = await repository.connectDevice(device);
5252

5353
expect(result, isA<Err<Null, LedgerFailure>>());
54-
expect(
55-
(result as Err).failure,
56-
isA<LedgerPermissionDeniedFailure>(),
54+
expect((result as Err).failure, isA<LedgerPermissionDeniedFailure>());
55+
});
56+
57+
test('interprets a raw APDU 6985 device string as rejected-by-user, '
58+
'keeping the raw reason for logs only', () async {
59+
when(
60+
() => datasource.signPsbt(
61+
any(),
62+
psbt: any(named: 'psbt'),
63+
derivationPath: any(named: 'derivationPath'),
64+
scriptType: any(named: 'scriptType'),
65+
),
66+
).thenThrow(Exception('Ledger error: 0x6985 rejected'));
67+
68+
final result = await repository.signPsbt(
69+
device,
70+
psbt: 'psbt',
71+
derivationPath: "m/84'/0'/0'",
72+
scriptType: ScriptType.bip84,
5773
);
74+
75+
final failure = (result as Err).failure;
76+
expect(failure, isA<LedgerRejectedByUserFailure>());
77+
// The raw reason is retained for logs/Sentry, never rendered by the UI.
78+
expect(failure.logMessage, contains('6985'));
5879
});
5980

60-
test(
61-
'interprets a raw APDU 6985 device string as rejected-by-user, '
62-
'keeping the raw reason for logs only',
63-
() async {
64-
when(
65-
() => datasource.signPsbt(
66-
any(),
67-
psbt: any(named: 'psbt'),
68-
derivationPath: any(named: 'derivationPath'),
69-
scriptType: any(named: 'scriptType'),
70-
),
71-
).thenThrow(Exception('Ledger error: 0x6985 rejected'));
72-
73-
final result = await repository.signPsbt(
74-
device,
75-
psbt: 'psbt',
76-
derivationPath: "m/84'/0'/0'",
77-
scriptType: ScriptType.bip84,
78-
);
79-
80-
final failure = (result as Err).failure;
81-
expect(failure, isA<LedgerRejectedByUserFailure>());
82-
// The raw reason is retained for logs/Sentry, never rendered by the UI.
83-
expect(failure.logMessage, contains('6985'));
84-
},
85-
);
81+
test('maps an unrecognized raw exception to a sanitized unexpected failure '
82+
'without leaking the message to the UI surface', () async {
83+
when(
84+
() => datasource.signPsbt(
85+
any(),
86+
psbt: any(named: 'psbt'),
87+
derivationPath: any(named: 'derivationPath'),
88+
scriptType: any(named: 'scriptType'),
89+
),
90+
).thenThrow(Exception('bdk: internal descriptor parse blew up'));
8691

87-
test(
88-
'maps an unrecognized raw exception to a sanitized unexpected failure '
89-
'without leaking the message to the UI surface',
90-
() async {
91-
when(
92-
() => datasource.signPsbt(
93-
any(),
94-
psbt: any(named: 'psbt'),
95-
derivationPath: any(named: 'derivationPath'),
96-
scriptType: any(named: 'scriptType'),
97-
),
98-
).thenThrow(Exception('bdk: internal descriptor parse blew up'));
99-
100-
final result = await repository.signPsbt(
101-
device,
102-
psbt: 'psbt',
103-
derivationPath: "m/84'/0'/0'",
104-
scriptType: ScriptType.bip84,
105-
);
106-
107-
expect((result as Err).failure, isA<LedgerUnexpectedFailure>());
108-
},
109-
);
92+
final result = await repository.signPsbt(
93+
device,
94+
psbt: 'psbt',
95+
derivationPath: "m/84'/0'/0'",
96+
scriptType: ScriptType.bip84,
97+
);
98+
99+
expect((result as Err).failure, isA<LedgerUnexpectedFailure>());
100+
});
110101

111102
test('returns Ok with the value on success', () async {
112103
when(
@@ -129,22 +120,19 @@ void main() {
129120
expect((result as Ok).value, 'deadbeef');
130121
});
131122

132-
test(
133-
'getWatchOnlyWallet sanitizes a throwing foreign dependency '
134-
'(settings fetch) into an unexpected failure',
135-
() async {
136-
when(
137-
() => settingsRepository.fetch(),
138-
).thenThrow(Exception('STORAGE UNAVAILABLE'));
139-
140-
final result = await repository.getWatchOnlyWallet(
141-
device,
142-
label: 'Ledger',
143-
);
144-
145-
expect(result, isA<Err<WatchOnlyWalletEntity, LedgerFailure>>());
146-
expect((result as Err).failure, isA<LedgerUnexpectedFailure>());
147-
},
148-
);
123+
test('getWatchOnlyWallet sanitizes a throwing foreign dependency '
124+
'(settings fetch) into an unexpected failure', () async {
125+
when(
126+
() => settingsRepository.fetch(),
127+
).thenThrow(Exception('STORAGE UNAVAILABLE'));
128+
129+
final result = await repository.getWatchOnlyWallet(
130+
device,
131+
label: 'Ledger',
132+
);
133+
134+
expect(result, isA<Err<WatchOnlyWalletEntity, LedgerFailure>>());
135+
expect((result as Err).failure, isA<LedgerUnexpectedFailure>());
136+
});
149137
});
150138
}

0 commit comments

Comments
 (0)