Skip to content

Commit 0fa8879

Browse files
stuartmorgan-gadsonpleal
authored andcommitted
[path_provider] Update to stable NNBD (flutter#3582)
Bumps the versions in the app-facing package to make it stable NNBD. Changes the interface of four core methods to non-nullable, and adds a new exceptions if they aren't provided by the platform implementations. The list is somewhat arbitrary, but these seem like the four that are core enough that any implementation should either provide them, or explicitly say they don't have such a concept via UnsupportedError, since there isn't an obvious way for a developer to fall back if they are unexpectedly missing.
1 parent e7191e7 commit 0fa8879

File tree

5 files changed

+165
-47
lines changed

5 files changed

+165
-47
lines changed

packages/path_provider/path_provider/CHANGELOG.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
## 2.0.0-nullsafety.1
2-
3-
* Require latest path_provider_windows to avoid potential issues
4-
with breaking changes in `ffi` and `win32`.
5-
6-
## 2.0.0-nullsafety
1+
## 2.0.0
72

83
* Migrate to null safety.
4+
* BREAKING CHANGE: Path accessors that return non-nullable results will throw
5+
a `MissingPlatformDirectoryException` if the platform implementation is unable
6+
to get the corresponding directory (except on platforms where the method is
7+
explicitly unsupported, where they will continue to throw `UnsupportedError`).
98

109
## 1.6.28
1110

packages/path_provider/path_provider/example/pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ dev_dependencies:
1717
path: ../../../integration_test
1818
flutter_driver:
1919
sdk: flutter
20-
pedantic: ^1.8.0
20+
pedantic: ^1.10.0
2121

2222
flutter:
2323
uses-material-design: true
2424

2525
environment:
26-
sdk: ">=2.12.0-0 <3.0.0"
26+
sdk: ">=2.12.0-259.9.beta <3.0.0"
2727
flutter: ">=1.12.13+hotfix.5"

packages/path_provider/path_provider/lib/path_provider.dart

Lines changed: 44 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,27 @@ set disablePathProviderPlatformOverride(bool override) {}
2020

2121
bool _manualDartRegistrationNeeded = true;
2222

23+
/// An exception thrown when a directory that should always be available on
24+
/// the current platform cannot be obtained.
25+
class MissingPlatformDirectoryException implements Exception {
26+
/// Creates a new exception
27+
MissingPlatformDirectoryException(this.message, {this.details});
28+
29+
/// The explanation of the exception.
30+
final String message;
31+
32+
/// Added details, if any.
33+
///
34+
/// E.g., an error object from the platform implementation.
35+
final Object? details;
36+
37+
@override
38+
String toString() {
39+
String detailsAddition = details == null ? '' : ': $details';
40+
return 'MissingPlatformDirectoryException($message)$detailsAddition';
41+
}
42+
}
43+
2344
PathProviderPlatform get _platform {
2445
// This is to manually endorse Dart implementations until automatic
2546
// registration of Dart plugins is implemented. For details see
@@ -51,10 +72,14 @@ PathProviderPlatform get _platform {
5172
/// On iOS, this uses the `NSCachesDirectory` API.
5273
///
5374
/// On Android, this uses the `getCacheDir` API on the context.
54-
Future<Directory?> getTemporaryDirectory() async {
75+
///
76+
/// Throws a `MissingPlatformDirectoryException` if the system is unable to
77+
/// provide the directory.
78+
Future<Directory> getTemporaryDirectory() async {
5579
final String? path = await _platform.getTemporaryPath();
5680
if (path == null) {
57-
return null;
81+
throw MissingPlatformDirectoryException(
82+
'Unable to get temporary directory');
5883
}
5984
return Directory(path);
6085
}
@@ -69,10 +94,14 @@ Future<Directory?> getTemporaryDirectory() async {
6994
/// If this directory does not exist, it is created automatically.
7095
///
7196
/// On Android, this function uses the `getFilesDir` API on the context.
72-
Future<Directory?> getApplicationSupportDirectory() async {
97+
///
98+
/// Throws a `MissingPlatformDirectoryException` if the system is unable to
99+
/// provide the directory.
100+
Future<Directory> getApplicationSupportDirectory() async {
73101
final String? path = await _platform.getApplicationSupportPath();
74102
if (path == null) {
75-
return null;
103+
throw MissingPlatformDirectoryException(
104+
'Unable to get application support directory');
76105
}
77106

78107
return Directory(path);
@@ -83,10 +112,13 @@ Future<Directory?> getApplicationSupportDirectory() async {
83112
///
84113
/// On Android, this function throws an [UnsupportedError] as no equivalent
85114
/// path exists.
86-
Future<Directory?> getLibraryDirectory() async {
115+
///
116+
/// Throws a `MissingPlatformDirectoryException` if the system is unable to
117+
/// provide the directory on a supported platform.
118+
Future<Directory> getLibraryDirectory() async {
87119
final String? path = await _platform.getLibraryPath();
88120
if (path == null) {
89-
return null;
121+
throw MissingPlatformDirectoryException('Unable to get library directory');
90122
}
91123
return Directory(path);
92124
}
@@ -100,10 +132,14 @@ Future<Directory?> getLibraryDirectory() async {
100132
/// On Android, this uses the `getDataDirectory` API on the context. Consider
101133
/// using [getExternalStorageDirectory] instead if data is intended to be visible
102134
/// to the user.
103-
Future<Directory?> getApplicationDocumentsDirectory() async {
135+
///
136+
/// Throws a `MissingPlatformDirectoryException` if the system is unable to
137+
/// provide the directory.
138+
Future<Directory> getApplicationDocumentsDirectory() async {
104139
final String? path = await _platform.getApplicationDocumentsPath();
105140
if (path == null) {
106-
return null;
141+
throw MissingPlatformDirectoryException(
142+
'Unable to get application documents directory');
107143
}
108144
return Directory(path);
109145
}

packages/path_provider/path_provider/pubspec.yaml

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: path_provider
22
description: Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories.
33
homepage: https://github.com/flutter/plugins/tree/master/packages/path_provider/path_provider
4-
version: 2.0.0-nullsafety.1
4+
version: 2.0.0
55

66
flutter:
77
plugin:
@@ -21,10 +21,10 @@ flutter:
2121
dependencies:
2222
flutter:
2323
sdk: flutter
24-
path_provider_platform_interface: ^2.0.0-nullsafety
25-
path_provider_macos: ^0.0.5-nullsafety
26-
path_provider_linux: ^0.2.0-nullsafety
27-
path_provider_windows: ^0.1.0-nullsafety.3
24+
path_provider_platform_interface: ^2.0.0
25+
path_provider_macos: ^2.0.0
26+
path_provider_linux: ^2.0.0
27+
path_provider_windows: ^2.0.0
2828

2929
dev_dependencies:
3030
integration_test:
@@ -33,10 +33,10 @@ dev_dependencies:
3333
sdk: flutter
3434
flutter_driver:
3535
sdk: flutter
36-
pedantic: ^1.10.0-nullsafety
37-
mockito: ^5.0.0-nullsafety.0
38-
plugin_platform_interface: ^1.1.0-nullsafety
36+
pedantic: ^1.10.0
37+
plugin_platform_interface: ">=1.0.0 <3.0.0"
38+
test: ^1.16.0
3939

4040
environment:
41-
sdk: ">=2.12.0-0 <3.0.0"
41+
sdk: ">=2.12.0-259.9.beta <3.0.0"
4242
flutter: ">=1.12.13+hotfix.5"

packages/path_provider/path_provider/test/path_provider_test.dart

Lines changed: 105 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import 'dart:io' show Directory;
66
import 'dart:async';
77

88
import 'package:flutter_test/flutter_test.dart';
9-
import 'package:mockito/mockito.dart';
109
import 'package:path_provider/path_provider.dart';
1110
import 'package:path_provider_platform_interface/path_provider_platform_interface.dart';
1211
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
12+
import 'package:test/fake.dart';
1313

1414
const String kTemporaryPath = 'temporaryPath';
1515
const String kApplicationSupportPath = 'applicationSupportPath';
@@ -20,31 +20,30 @@ const String kExternalCachePath = 'externalCachePath';
2020
const String kExternalStoragePath = 'externalStoragePath';
2121

2222
void main() {
23-
group('PathProvider', () {
24-
TestWidgetsFlutterBinding.ensureInitialized();
25-
23+
TestWidgetsFlutterBinding.ensureInitialized();
24+
group('PathProvider full implementation', () {
2625
setUp(() async {
27-
PathProviderPlatform.instance = MockPathProviderPlatform();
26+
PathProviderPlatform.instance = FakePathProviderPlatform();
2827
});
2928

3029
test('getTemporaryDirectory', () async {
31-
Directory? result = await getTemporaryDirectory();
32-
expect(result?.path, kTemporaryPath);
30+
Directory result = await getTemporaryDirectory();
31+
expect(result.path, kTemporaryPath);
3332
});
3433

3534
test('getApplicationSupportDirectory', () async {
36-
Directory? result = await getApplicationSupportDirectory();
37-
expect(result?.path, kApplicationSupportPath);
35+
Directory result = await getApplicationSupportDirectory();
36+
expect(result.path, kApplicationSupportPath);
3837
});
3938

4039
test('getLibraryDirectory', () async {
41-
Directory? result = await getLibraryDirectory();
42-
expect(result?.path, kLibraryPath);
40+
Directory result = await getLibraryDirectory();
41+
expect(result.path, kLibraryPath);
4342
});
4443

4544
test('getApplicationDocumentsDirectory', () async {
46-
Directory? result = await getApplicationDocumentsDirectory();
47-
expect(result?.path, kApplicationDocumentsPath);
45+
Directory result = await getApplicationDocumentsDirectory();
46+
expect(result.path, kApplicationDocumentsPath);
4847
});
4948

5049
test('getExternalStorageDirectory', () async {
@@ -69,42 +68,126 @@ void main() {
6968
expect(result?.path, kDownloadsPath);
7069
});
7170
});
71+
72+
group('PathProvider null implementation', () {
73+
setUp(() async {
74+
PathProviderPlatform.instance = AllNullFakePathProviderPlatform();
75+
});
76+
77+
test('getTemporaryDirectory throws on null', () async {
78+
expect(getTemporaryDirectory(),
79+
throwsA(isA<MissingPlatformDirectoryException>()));
80+
});
81+
82+
test('getApplicationSupportDirectory throws on null', () async {
83+
expect(getApplicationSupportDirectory(),
84+
throwsA(isA<MissingPlatformDirectoryException>()));
85+
});
86+
87+
test('getLibraryDirectory throws on null', () async {
88+
expect(getLibraryDirectory(),
89+
throwsA(isA<MissingPlatformDirectoryException>()));
90+
});
91+
92+
test('getApplicationDocumentsDirectory throws on null', () async {
93+
expect(getApplicationDocumentsDirectory(),
94+
throwsA(isA<MissingPlatformDirectoryException>()));
95+
});
96+
97+
test('getExternalStorageDirectory passes null through', () async {
98+
Directory? result = await getExternalStorageDirectory();
99+
expect(result, isNull);
100+
});
101+
102+
test('getExternalCacheDirectories passes null through', () async {
103+
List<Directory>? result = await getExternalCacheDirectories();
104+
expect(result, isNull);
105+
});
106+
107+
test('getExternalStorageDirectories passes null through', () async {
108+
List<Directory>? result = await getExternalStorageDirectories();
109+
expect(result, isNull);
110+
});
111+
112+
test('getDownloadsDirectory passses null through', () async {
113+
Directory? result = await getDownloadsDirectory();
114+
expect(result, isNull);
115+
});
116+
});
72117
}
73118

74-
class MockPathProviderPlatform extends Mock
119+
class FakePathProviderPlatform extends Fake
75120
with MockPlatformInterfaceMixin
76121
implements PathProviderPlatform {
77-
Future<String> getTemporaryPath() async {
122+
Future<String?> getTemporaryPath() async {
78123
return kTemporaryPath;
79124
}
80125

81-
Future<String> getApplicationSupportPath() async {
126+
Future<String?> getApplicationSupportPath() async {
82127
return kApplicationSupportPath;
83128
}
84129

85-
Future<String> getLibraryPath() async {
130+
Future<String?> getLibraryPath() async {
86131
return kLibraryPath;
87132
}
88133

89-
Future<String> getApplicationDocumentsPath() async {
134+
Future<String?> getApplicationDocumentsPath() async {
90135
return kApplicationDocumentsPath;
91136
}
92137

93-
Future<String> getExternalStoragePath() async {
138+
Future<String?> getExternalStoragePath() async {
94139
return kExternalStoragePath;
95140
}
96141

97-
Future<List<String>> getExternalCachePaths() async {
142+
Future<List<String>?> getExternalCachePaths() async {
98143
return <String>[kExternalCachePath];
99144
}
100145

101-
Future<List<String>> getExternalStoragePaths({
146+
Future<List<String>?> getExternalStoragePaths({
102147
StorageDirectory? type,
103148
}) async {
104149
return <String>[kExternalStoragePath];
105150
}
106151

107-
Future<String> getDownloadsPath() async {
152+
Future<String?> getDownloadsPath() async {
108153
return kDownloadsPath;
109154
}
110155
}
156+
157+
class AllNullFakePathProviderPlatform extends Fake
158+
with MockPlatformInterfaceMixin
159+
implements PathProviderPlatform {
160+
Future<String?> getTemporaryPath() async {
161+
return null;
162+
}
163+
164+
Future<String?> getApplicationSupportPath() async {
165+
return null;
166+
}
167+
168+
Future<String?> getLibraryPath() async {
169+
return null;
170+
}
171+
172+
Future<String?> getApplicationDocumentsPath() async {
173+
return null;
174+
}
175+
176+
Future<String?> getExternalStoragePath() async {
177+
return null;
178+
}
179+
180+
Future<List<String>?> getExternalCachePaths() async {
181+
return null;
182+
}
183+
184+
Future<List<String>?> getExternalStoragePaths({
185+
StorageDirectory? type,
186+
}) async {
187+
return null;
188+
}
189+
190+
Future<String?> getDownloadsPath() async {
191+
return null;
192+
}
193+
}

0 commit comments

Comments
 (0)