Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5fc26057d7 |
@@ -616,6 +616,11 @@ Future<String> _resolveDatabasePath() async {
|
||||
);
|
||||
}
|
||||
|
||||
// These two functions are only called from unit tests (database_path_test.dart).
|
||||
// They expose internals that cannot be reached via the public API.
|
||||
Future<String> resolveDatabasePathForTesting() => _resolveDatabasePath();
|
||||
void resetDatabasePathForTesting() => _dbPath = null;
|
||||
|
||||
LazyDatabase _openConnection() {
|
||||
return LazyDatabase(() async {
|
||||
final file = File(await _resolveDatabasePath());
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:fake_async/fake_async.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
|
||||
@@ -19,6 +22,30 @@ class _UnavailablePathProvider extends Fake
|
||||
}
|
||||
}
|
||||
|
||||
// Fake PathProviderPlatform that fails the first [failCount] calls, then
|
||||
// returns a fixed path. Used to exercise the retry loop in
|
||||
// _resolveDatabasePath() without waiting for real timers.
|
||||
class _SucceedAfterNPathProvider extends Fake
|
||||
with MockPlatformInterfaceMixin
|
||||
implements PathProviderPlatform {
|
||||
_SucceedAfterNPathProvider({required this.failCount});
|
||||
|
||||
final int failCount;
|
||||
int _callCount = 0;
|
||||
|
||||
@override
|
||||
Future<String?> getApplicationSupportPath() async {
|
||||
_callCount++;
|
||||
if (_callCount <= failCount) {
|
||||
throw PlatformException(
|
||||
code: 'channel-error',
|
||||
message: 'Simulated: path_provider channel not ready',
|
||||
);
|
||||
}
|
||||
return '/tmp/test_app_support';
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
TestWidgetsFlutterBinding.ensureInitialized();
|
||||
|
||||
@@ -38,4 +65,69 @@ void main() {
|
||||
await expectLater(initDatabasePath(), completes);
|
||||
},
|
||||
);
|
||||
|
||||
// Tests for _resolveDatabasePath() — the lazy retry path called on first DB
|
||||
// access when initDatabasePath() already failed. fake_async lets us advance
|
||||
// the back-off timers without waiting real-world milliseconds.
|
||||
|
||||
test(
|
||||
'_resolveDatabasePath retries and eventually succeeds after transient failures',
|
||||
() {
|
||||
resetDatabasePathForTesting();
|
||||
final prev = PathProviderPlatform.instance;
|
||||
// Fail 3 times, succeed on the 4th call. The delays in
|
||||
// _resolveDatabasePath are [200, 500, 1000, 2000, 4000] ms, so three
|
||||
// failures cost 200+500+1000 = 1700 ms before the fourth attempt.
|
||||
PathProviderPlatform.instance = _SucceedAfterNPathProvider(failCount: 3);
|
||||
addTearDown(() {
|
||||
PathProviderPlatform.instance = prev;
|
||||
resetDatabasePathForTesting();
|
||||
});
|
||||
|
||||
fakeAsync((fake) {
|
||||
String? result;
|
||||
unawaited(resolveDatabasePathForTesting().then((r) => result = r));
|
||||
|
||||
// Advance fake time through the three back-off delays.
|
||||
fake.elapse(const Duration(milliseconds: 200 + 500 + 1000 + 1));
|
||||
|
||||
expect(result, isNotNull);
|
||||
expect(result, endsWith('sharedinbox.db'));
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'_resolveDatabasePath throws PlatformException after exhausting all retries',
|
||||
() {
|
||||
resetDatabasePathForTesting();
|
||||
final prev = PathProviderPlatform.instance;
|
||||
PathProviderPlatform.instance = _UnavailablePathProvider();
|
||||
addTearDown(() {
|
||||
PathProviderPlatform.instance = prev;
|
||||
resetDatabasePathForTesting();
|
||||
});
|
||||
|
||||
fakeAsync((fake) {
|
||||
Object? caughtError;
|
||||
unawaited(
|
||||
resolveDatabasePathForTesting().catchError((Object e) {
|
||||
caughtError = e;
|
||||
return ''; // ignored; satisfies the Future<String> return type
|
||||
}),
|
||||
);
|
||||
|
||||
// Advance past all five back-off delays: 200+500+1000+2000+4000 ms.
|
||||
fake.elapse(
|
||||
const Duration(milliseconds: 200 + 500 + 1000 + 2000 + 4000 + 1),
|
||||
);
|
||||
|
||||
expect(caughtError, isA<PlatformException>());
|
||||
expect(
|
||||
(caughtError! as PlatformException).message,
|
||||
contains('cannot open database'),
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user