Skip to content

Commit 61bcb37

Browse files
committed
Add integration tests for user defines
1 parent f629ae5 commit 61bcb37

File tree

7 files changed

+327
-1
lines changed

7 files changed

+327
-1
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# https://dart.dev/guides/libraries/private-files
2+
# Created by `dart pub`
3+
.dart_tool/
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Integration tests testing user-defines for the `sqlite3_native_assets` package.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# This file configures the static analysis results for your project (errors,
2+
# warnings, and lints).
3+
#
4+
# This enables the 'recommended' set of lints from `package:lints`.
5+
# This set helps identify many issues that may lead to problems when running
6+
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
7+
# style and format.
8+
#
9+
# If you want a smaller set of lints you can change this to specify
10+
# 'package:lints/core.yaml'. These are just the most critical lints
11+
# (the recommended set includes the core lints).
12+
# The core lints are also what is used by pub.dev for scoring packages.
13+
14+
include: package:lints/recommended.yaml
15+
16+
# Uncomment the following section to specify additional rules.
17+
18+
# linter:
19+
# rules:
20+
# - camel_case_types
21+
22+
# analyzer:
23+
# exclude:
24+
# - path/to/excluded/files/**
25+
26+
# For more information about the core and recommended set of lints, see
27+
# https://dart.dev/go/core-lints
28+
29+
# For additional information about configuring this file, see
30+
# https://dart.dev/guides/language/analysis-options
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
name: native_assets
2+
description: A sample command-line application.
3+
version: 1.0.0
4+
# repository: https://github.com/my_org/my_repo
5+
6+
environment:
7+
sdk: ^3.7.0
8+
9+
# Add regular dependencies here.
10+
dependencies:
11+
# Due to the way our tests work, this must have the same dependencies as
12+
# sqlite3_native_assets.
13+
# It can't depend on sqlite3_native_assets directly however
14+
sqlite3: ^2.7.4
15+
native_assets_cli: ^0.14.0
16+
native_toolchain_c: ^0.11.0
17+
logging: ^1.3.0
18+
http: ^1.3.0
19+
archive: ^4.0.2
20+
path: ^1.9.1
21+
22+
dev_dependencies:
23+
lints: ^5.0.0
24+
package_config: ^2.2.0
25+
test: ^1.24.0
26+
test_descriptor: ^2.0.2
27+
yaml: ^3.1.3
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
@TestOn('linux') // Need to update assertions for other platforms
2+
library;
3+
4+
import 'dart:convert';
5+
import 'dart:io';
6+
import 'dart:isolate';
7+
8+
import 'package:package_config/package_config.dart';
9+
import 'package:path/path.dart';
10+
import 'package:test/test.dart';
11+
import 'package:test_descriptor/test_descriptor.dart' as d;
12+
import 'package:yaml/yaml.dart';
13+
14+
void main() {
15+
test('can use sqlite from system', () async {
16+
await _setupTest('''
17+
hooks:
18+
user_defines:
19+
sqlite3_native_assets:
20+
source:
21+
system:
22+
''');
23+
24+
await _compileNativeAssets();
25+
await _expectNativeAsset({
26+
_key: ['system', 'libsqlite3.so'],
27+
});
28+
});
29+
30+
test('can use sqlite from process', () async {
31+
await _setupTest('''
32+
hooks:
33+
user_defines:
34+
sqlite3_native_assets:
35+
source:
36+
process:
37+
''');
38+
39+
await _compileNativeAssets();
40+
await _expectNativeAsset({
41+
_key: ['process'],
42+
});
43+
});
44+
45+
test('can use sqlite from executable', () async {
46+
await _setupTest('''
47+
hooks:
48+
user_defines:
49+
sqlite3_native_assets:
50+
source:
51+
executable:
52+
''');
53+
54+
await _compileNativeAssets();
55+
await _expectNativeAsset({
56+
_key: ['executable'],
57+
});
58+
});
59+
60+
test('can use custom source', () async {
61+
await _setupTest(
62+
'''
63+
hooks:
64+
user_defines:
65+
sqlite3_native_assets:
66+
source:
67+
local: my_sqlite.c
68+
defines:
69+
defines:
70+
FOO: "1"
71+
''',
72+
additionalSources: [
73+
d.file('my_sqlite.c', '''
74+
#ifdef FOO
75+
void foo() {}
76+
#endif
77+
78+
void bar() {}
79+
'''),
80+
],
81+
);
82+
83+
await _compileNativeAssets();
84+
await _expectNativeAsset({
85+
_key: [
86+
'absolute',
87+
endsWith('.dart_tool/native_assets/lib/libsqlite3.so'),
88+
],
89+
});
90+
91+
final config = loadYaml(
92+
await File(d.path('app/.dart_tool/native_assets.yaml')).readAsString(),
93+
);
94+
final sharedLibrary = File(config['native-assets'].values.single[_key][1]);
95+
final symbols = await Process.run('nm', ['-D', sharedLibrary.path]);
96+
expect(symbols.stdout, allOf(contains('foo'), contains('bar')));
97+
});
98+
}
99+
100+
Future<void> _setupTest(
101+
String options, {
102+
List<d.Descriptor> additionalSources = const [],
103+
}) async {
104+
// Instead of running `pub get` for each test, we just copy the package
105+
// config used by this test and add sqlite3_native_assets.
106+
final uri = await Isolate.packageConfig;
107+
final config = PackageConfig.parseBytes(
108+
await File.fromUri(uri!).readAsBytes(),
109+
uri,
110+
);
111+
final appRoot = join(d.sandbox, 'app');
112+
final nativeAssetsRoot = absolute('../../sqlite3_native_assets');
113+
114+
final appUri = '${File(appRoot).absolute.uri}/';
115+
final nativeAssetsUri = '${File(nativeAssetsRoot).absolute.uri}/';
116+
final newConfig = PackageConfig([
117+
...config.packages,
118+
Package(
119+
'app',
120+
Uri.parse(appUri),
121+
packageUriRoot: Uri.parse('${appUri}lib/'),
122+
),
123+
Package(
124+
'sqlite3_native_assets',
125+
Uri.parse(nativeAssetsUri),
126+
packageUriRoot: Uri.parse('${nativeAssetsUri}lib/'),
127+
),
128+
]);
129+
final configBuffer = StringBuffer();
130+
PackageConfig.writeString(newConfig, configBuffer);
131+
132+
await d.dir('app', [
133+
d.dir('.dart_tool', [
134+
d.file('package_config.json', configBuffer.toString()),
135+
d.file('package_graph.json', json.encode(_fakePackageGraph)),
136+
]),
137+
d.file('pubspec.yaml', '''
138+
name: app
139+
140+
environment:
141+
sdk: ^3.7.0
142+
143+
dependencies:
144+
sqlite3: ^10.10.10 # should not resolve
145+
sqlite3_native_assets:
146+
147+
$options
148+
'''),
149+
d.file('app.dart', '''
150+
void main() {}
151+
'''),
152+
...additionalSources,
153+
]).create();
154+
}
155+
156+
Future<void> _compileNativeAssets() async {
157+
final dart = Platform.executable;
158+
159+
// Just run some bogus command guaranteed to trigger native assets.
160+
final process = await Process.start(dart, [
161+
'--enable-experiment=native-assets',
162+
'run',
163+
'app.dart',
164+
], workingDirectory: join(d.sandbox, 'app'));
165+
final stderr = process.stderr.transform(const Utf8Decoder()).join();
166+
167+
final exitCode = await process.exitCode;
168+
if (exitCode != 0) {
169+
fail('Compiling dart failed (at ${d.sandbox}), $exitCode, ${await stderr}');
170+
}
171+
}
172+
173+
const _fakePackageGraph = {
174+
"root": "app",
175+
"packages": [
176+
{
177+
"name": "app",
178+
"version": "0.0.0",
179+
"kind": "root",
180+
"source": "root",
181+
"dependencies": ["sqlite3", "sqlite3_native_assets"],
182+
"directDependencies": ["sqlite3", "sqlite3_native_assets"],
183+
"devDependencies": [],
184+
},
185+
{
186+
"name": "sqlite3_native_assets",
187+
"version": "0.0.3",
188+
"kind": "direct",
189+
"source": "hosted",
190+
"dependencies": ["sqlite3", "native_assets_cli", "native_toolchain_c"],
191+
"directDependencies": [
192+
"sqlite3",
193+
"native_assets_cli",
194+
"native_toolchain_c",
195+
],
196+
},
197+
{
198+
"name": "native_toolchain_c",
199+
"version": "0.8.0",
200+
"kind": "transitive",
201+
"source": "hosted",
202+
"dependencies": ["native_assets_cli"],
203+
"directDependencies": ["native_assets_cli"],
204+
},
205+
{
206+
"name": "native_assets_cli",
207+
"version": "0.11.0",
208+
"kind": "transitive",
209+
"source": "hosted",
210+
"dependencies": [],
211+
"directDependencies": [],
212+
},
213+
{
214+
"name": "sqlite3",
215+
"version": "2.7.5",
216+
"kind": "direct",
217+
"source": "hosted",
218+
"dependencies": [],
219+
"directDependencies": [],
220+
},
221+
],
222+
"sdks": [
223+
{"name": "Dart", "version": "3.7.2"},
224+
],
225+
"executables": [],
226+
};
227+
228+
Future<void> _expectNativeAsset(Object? expected) async {
229+
final config = loadYaml(
230+
await File(d.path('app/.dart_tool/native_assets.yaml')).readAsString(),
231+
);
232+
233+
/*
234+
# Native assets mapping for host OS in JIT mode.
235+
# Generated by dartdev and package:native_assets_builder.
236+
237+
format-version:
238+
- 1
239+
- 0
240+
- 0
241+
native-assets:
242+
linux_x64:
243+
package:sqlite3_native_assets/sqlite3_native_assets.dart:
244+
- system
245+
- libsqlite3.so
246+
*/
247+
248+
final map = config['native-assets'].values.single;
249+
expect(map, expected);
250+
}
251+
252+
const _key = 'package:sqlite3_native_assets/sqlite3_native_assets.dart';

sqlite3_native_assets/lib/src/source.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ sealed class SqliteSource {
99
{'amalgamation': final source} => DownloadAmalgamation(
1010
uri: source as String,
1111
),
12-
{'local': final local} => ExistingAmalgamation(local as String),
12+
{'local': final local} => ExistingAmalgamation(
13+
options.inputPath(local as String),
14+
),
1315
{'system': _} => const UseFromSystem(),
1416
{'process': _} => const UseFromProcess(),
1517
{'executable': _} => const UseFromExecutable(),

sqlite3_native_assets/lib/src/user_defines.dart

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import 'dart:convert';
22

33
import 'package:native_assets_cli/native_assets_cli.dart';
4+
import 'package:path/path.dart';
45

56
/// A mockable wrapper around `HookInputUserDefines`.
67
sealed class UserDefinesOptions {
@@ -11,6 +12,8 @@ sealed class UserDefinesOptions {
1112

1213
Object? operator [](String key);
1314

15+
String inputPath(String path);
16+
1417
/// Reads [key] under the expectation that it contains a nested structure.
1518
///
1619
/// Since user-defines passed via the command line are always strings, this
@@ -31,6 +34,9 @@ final class _OptionsFromMap extends UserDefinesOptions {
3134

3235
@override
3336
Object? operator [](String key) => options[key];
37+
38+
@override
39+
String inputPath(String path) => path;
3440
}
3541

3642
final class _UserDefines extends UserDefinesOptions {
@@ -40,4 +46,9 @@ final class _UserDefines extends UserDefinesOptions {
4046

4147
@override
4248
Object? operator [](String key) => input.userDefines[key];
49+
50+
@override
51+
String inputPath(String path) => absolute(
52+
normalize(join(input.outputDirectory.path, '../../../../../../', path)),
53+
);
4354
}

0 commit comments

Comments
 (0)