Skip to content

Commit cb40f80

Browse files
authored
Merge pull request #6 from okmsbun/test
Test
2 parents 6f535d7 + a2977f0 commit cb40f80

7 files changed

Lines changed: 684 additions & 2 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: only-develop-to-main
2+
3+
on:
4+
pull_request:
5+
branches: ["main"]
6+
7+
jobs:
8+
enforce:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Allow only develop -> main PRs
12+
run: |
13+
echo "head_ref: ${{ github.head_ref }}"
14+
echo "base_ref: ${{ github.base_ref }}"
15+
if [ "${{ github.base_ref }}" = "main" ] && [ "${{ github.head_ref }}" != "develop" ]; then
16+
echo "Only PRs from 'develop' to 'main' are allowed."
17+
exit 1
18+
fi

.github/workflows/quality.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: Quality
2+
3+
on:
4+
pull_request:
5+
branches: ["develop"]
6+
7+
jobs:
8+
quality:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- name: Setup Dart
15+
uses: dart-lang/setup-dart@v1
16+
with:
17+
sdk: stable
18+
19+
- name: Cache pub
20+
uses: actions/cache@v4
21+
with:
22+
path: |
23+
~/.pub-cache
24+
.dart_tool
25+
key: ${{ runner.os }}-pub-${{ hashFiles('**/pubspec.lock') }}
26+
restore-keys: |
27+
${{ runner.os }}-pub-
28+
29+
- name: Install dependencies
30+
run: dart pub get
31+
32+
- name: Check formatting
33+
run: dart format --set-exit-if-changed .
34+
35+
- name: Static analysis
36+
run: dart analyze
37+
38+
- name: pub.dev dry-run
39+
run: dart pub publish --dry-run

.github/workflows/test.yml

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
name: Test
2+
3+
on:
4+
pull_request:
5+
branches: ["develop"]
6+
7+
jobs:
8+
test:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- name: Setup Dart
15+
uses: dart-lang/setup-dart@v1
16+
with:
17+
sdk: stable
18+
19+
- name: Cache pub
20+
uses: actions/cache@v4
21+
with:
22+
path: |
23+
~/.pub-cache
24+
.dart_tool
25+
key: ${{ runner.os }}-pub-${{ hashFiles('**/pubspec.lock') }}
26+
restore-keys: |
27+
${{ runner.os }}-pub-
28+
29+
- name: Install dependencies
30+
run: dart pub get
31+
32+
- name: Run tests
33+
run: dart test

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
## 0.6.0
2+
- **BREAKING**: Removed `requestedPermissions` field from `AppInfo` class to improve performance and reduce memory usage
3+
- Added new API: `getRequestedPermissions(String packageName)` to fetch app permissions on demand
4+
- Added comprehensive unit tests for `AppInfo`, `AppChangeType`, and `AppChangeEvent` classes
5+
16
## 0.5.1
27
- Expanded `AppInfo` with additional Android-facing fields: `category`, `targetSdkVersion`, `minSdkVersion`, `enabled`, `processName`, `installLocation`, `requestedPermissions`.
38

pubspec.yaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: flutter_device_apps_platform_interface
22
description: Platform-agnostic API contract for flutter_device_apps (federated).
3-
version: 0.5.1
3+
version: 0.6.0
44
repository: https://github.com/okmsbun/flutter_device_apps_platform_interface
55
issue_tracker: https://github.com/okmsbun/flutter_device_apps_platform_interface/issues
66
topics:
@@ -17,4 +17,5 @@ dependencies:
1717
plugin_platform_interface: ^2.1.8
1818

1919
dev_dependencies:
20-
lints: ^6.0.0
20+
lints: ^6.1.0
21+
test: ^1.29.0

test/app_change_event_test.dart

Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
import 'package:flutter_device_apps_platform_interface/flutter_device_apps_app_change_event.dart';
2+
import 'package:test/test.dart';
3+
4+
void main() {
5+
group('AppChangeType', () {
6+
test('has all expected values', () {
7+
expect(AppChangeType.values, hasLength(3));
8+
expect(AppChangeType.values, contains(AppChangeType.installed));
9+
expect(AppChangeType.values, contains(AppChangeType.removed));
10+
expect(AppChangeType.values, contains(AppChangeType.updated));
11+
});
12+
13+
test('enum names match expected strings', () {
14+
expect(AppChangeType.installed.name, 'installed');
15+
expect(AppChangeType.removed.name, 'removed');
16+
expect(AppChangeType.updated.name, 'updated');
17+
});
18+
});
19+
20+
group('AppChangeEvent', () {
21+
group('constructor', () {
22+
test('creates instance with all null values', () {
23+
const event = AppChangeEvent();
24+
25+
expect(event.packageName, isNull);
26+
expect(event.type, isNull);
27+
expect(event.isReplacing, isNull);
28+
});
29+
30+
test('creates instance with all values', () {
31+
const event = AppChangeEvent(
32+
packageName: 'com.example.app',
33+
type: AppChangeType.installed,
34+
isReplacing: false,
35+
);
36+
37+
expect(event.packageName, 'com.example.app');
38+
expect(event.type, AppChangeType.installed);
39+
expect(event.isReplacing, false);
40+
});
41+
42+
test('creates instance with partial values', () {
43+
const event = AppChangeEvent(
44+
packageName: 'com.example.app',
45+
);
46+
47+
expect(event.packageName, 'com.example.app');
48+
expect(event.type, isNull);
49+
expect(event.isReplacing, isNull);
50+
});
51+
});
52+
53+
group('fromMap', () {
54+
test('parses empty map', () {
55+
final event = AppChangeEvent.fromMap({});
56+
57+
expect(event.packageName, isNull);
58+
expect(event.type, isNull);
59+
expect(event.isReplacing, isNull);
60+
});
61+
62+
test('parses packageName correctly', () {
63+
final event = AppChangeEvent.fromMap({
64+
'packageName': 'com.test.app',
65+
});
66+
67+
expect(event.packageName, 'com.test.app');
68+
});
69+
70+
test('parses type "installed" correctly', () {
71+
final event = AppChangeEvent.fromMap({
72+
'type': 'installed',
73+
});
74+
75+
expect(event.type, AppChangeType.installed);
76+
});
77+
78+
test('parses type "removed" correctly', () {
79+
final event = AppChangeEvent.fromMap({
80+
'type': 'removed',
81+
});
82+
83+
expect(event.type, AppChangeType.removed);
84+
});
85+
86+
test('parses type "updated" correctly', () {
87+
final event = AppChangeEvent.fromMap({
88+
'type': 'updated',
89+
});
90+
91+
expect(event.type, AppChangeType.updated);
92+
});
93+
94+
test('returns null type for invalid type string', () {
95+
final event = AppChangeEvent.fromMap({
96+
'type': 'unknown',
97+
});
98+
99+
expect(event.type, isNull);
100+
});
101+
102+
test('returns null type for empty type string', () {
103+
final event = AppChangeEvent.fromMap({
104+
'type': '',
105+
});
106+
107+
expect(event.type, isNull);
108+
});
109+
110+
test('parses isReplacing from bool value', () {
111+
final eventTrue = AppChangeEvent.fromMap({
112+
'isReplacing': true,
113+
});
114+
final eventFalse = AppChangeEvent.fromMap({
115+
'isReplacing': false,
116+
});
117+
118+
expect(eventTrue.isReplacing, true);
119+
expect(eventFalse.isReplacing, false);
120+
});
121+
122+
test('parses isReplacing from string value', () {
123+
final eventTrue = AppChangeEvent.fromMap({
124+
'isReplacing': 'true',
125+
});
126+
final eventFalse = AppChangeEvent.fromMap({
127+
'isReplacing': 'false',
128+
});
129+
130+
expect(eventTrue.isReplacing, true);
131+
expect(eventFalse.isReplacing, false);
132+
});
133+
134+
test('returns null isReplacing for invalid string', () {
135+
final event = AppChangeEvent.fromMap({
136+
'isReplacing': 'yes',
137+
});
138+
139+
expect(event.isReplacing, isNull);
140+
});
141+
142+
test('parses complete map with all fields', () {
143+
final event = AppChangeEvent.fromMap({
144+
'packageName': 'com.example.fullapp',
145+
'type': 'updated',
146+
'isReplacing': true,
147+
});
148+
149+
expect(event.packageName, 'com.example.fullapp');
150+
expect(event.type, AppChangeType.updated);
151+
expect(event.isReplacing, true);
152+
});
153+
});
154+
155+
group('toMap', () {
156+
test('converts empty event to map', () {
157+
const event = AppChangeEvent();
158+
final Map<String, Object?> map = event.toMap();
159+
160+
expect(map['packageName'], isNull);
161+
expect(map['type'], isNull);
162+
expect(map['isReplacing'], isNull);
163+
});
164+
165+
test('converts full event to map', () {
166+
const event = AppChangeEvent(
167+
packageName: 'com.example.app',
168+
type: AppChangeType.installed,
169+
isReplacing: false,
170+
);
171+
final Map<String, Object?> map = event.toMap();
172+
173+
expect(map['packageName'], 'com.example.app');
174+
expect(map['type'], 'installed');
175+
expect(map['isReplacing'], false);
176+
});
177+
178+
test('converts removed type correctly', () {
179+
const event = AppChangeEvent(type: AppChangeType.removed);
180+
final Map<String, Object?> map = event.toMap();
181+
182+
expect(map['type'], 'removed');
183+
});
184+
185+
test('converts updated type correctly', () {
186+
const event = AppChangeEvent(type: AppChangeType.updated);
187+
final Map<String, Object?> map = event.toMap();
188+
189+
expect(map['type'], 'updated');
190+
});
191+
192+
test('converts partial event to map', () {
193+
const event = AppChangeEvent(
194+
packageName: 'com.partial.app',
195+
isReplacing: true,
196+
);
197+
final Map<String, Object?> map = event.toMap();
198+
199+
expect(map['packageName'], 'com.partial.app');
200+
expect(map['type'], isNull);
201+
expect(map['isReplacing'], true);
202+
});
203+
});
204+
205+
group('round-trip (fromMap -> toMap)', () {
206+
test('installed event survives round-trip', () {
207+
final originalMap = <String, Object?>{
208+
'packageName': 'com.roundtrip.installed',
209+
'type': 'installed',
210+
'isReplacing': false,
211+
};
212+
213+
final event = AppChangeEvent.fromMap(originalMap);
214+
final Map<String, Object?> resultMap = event.toMap();
215+
216+
expect(resultMap['packageName'], originalMap['packageName']);
217+
expect(resultMap['type'], originalMap['type']);
218+
expect(resultMap['isReplacing'], originalMap['isReplacing']);
219+
});
220+
221+
test('removed event survives round-trip', () {
222+
final originalMap = <String, Object?>{
223+
'packageName': 'com.roundtrip.removed',
224+
'type': 'removed',
225+
'isReplacing': false,
226+
};
227+
228+
final event = AppChangeEvent.fromMap(originalMap);
229+
final Map<String, Object?> resultMap = event.toMap();
230+
231+
expect(resultMap['packageName'], originalMap['packageName']);
232+
expect(resultMap['type'], originalMap['type']);
233+
expect(resultMap['isReplacing'], originalMap['isReplacing']);
234+
});
235+
236+
test('updated event with replacing survives round-trip', () {
237+
final originalMap = <String, Object?>{
238+
'packageName': 'com.roundtrip.updated',
239+
'type': 'updated',
240+
'isReplacing': true,
241+
};
242+
243+
final event = AppChangeEvent.fromMap(originalMap);
244+
final Map<String, Object?> resultMap = event.toMap();
245+
246+
expect(resultMap['packageName'], originalMap['packageName']);
247+
expect(resultMap['type'], originalMap['type']);
248+
expect(resultMap['isReplacing'], originalMap['isReplacing']);
249+
});
250+
251+
test('empty event survives round-trip', () {
252+
final originalMap = <String, Object?>{};
253+
254+
final event = AppChangeEvent.fromMap(originalMap);
255+
final Map<String, Object?> resultMap = event.toMap();
256+
257+
expect(resultMap['packageName'], isNull);
258+
expect(resultMap['type'], isNull);
259+
expect(resultMap['isReplacing'], isNull);
260+
});
261+
});
262+
});
263+
}

0 commit comments

Comments
 (0)