Skip to content

Commit 6bce827

Browse files
committed
Add Filesystem underneath Reader, simplify tests further.
1 parent c959516 commit 6bce827

26 files changed

+326
-198
lines changed

_test_common/lib/in_memory_reader_writer.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class InMemoryRunnerAssetReaderWriter extends InMemoryAssetReaderWriter
1616
Stream<AssetId> get onCanRead => _onCanReadController.stream;
1717
void Function(AssetId)? onDelete;
1818

19-
InMemoryRunnerAssetReaderWriter({super.sourceAssets, super.rootPackage});
19+
InMemoryRunnerAssetReaderWriter({super.rootPackage});
2020

2121
@override
2222
Future<bool> canRead(AssetId id) {

build/lib/src/builder/build_step_impl.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import '../asset/writer.dart';
2020
import '../resource/resource.dart';
2121
import '../state/asset_finder.dart';
2222
import '../state/asset_path_provider.dart';
23+
import '../state/filesystem.dart';
2324
import '../state/input_tracker.dart';
2425
import '../state/reader_state.dart';
2526
import 'build_step.dart';
@@ -82,6 +83,9 @@ class BuildStepImpl implements BuildStep, AssetReaderState {
8283
_stageTracker = stageTracker ?? NoOpStageTracker.instance,
8384
_reportUnusedAssets = reportUnusedAssets;
8485

86+
@override
87+
Filesystem get filesystem => _reader.filesystem;
88+
8589
@override
8690
AssetFinder get assetFinder => _reader.assetFinder;
8791

build/lib/src/internal.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ library;
88

99
export 'state/asset_finder.dart';
1010
export 'state/asset_path_provider.dart';
11+
export 'state/filesystem.dart';
1112
export 'state/input_tracker.dart';
1213
export 'state/reader_state.dart';

build/lib/src/state/filesystem.dart

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:convert';
6+
import 'dart:typed_data';
7+
8+
import '../asset/id.dart';
9+
10+
/// The filesystem the build is running on.
11+
abstract interface class Filesystem {
12+
Future<bool> exists(AssetId id);
13+
14+
Future<String> readAsString(AssetId id, {Encoding encoding = utf8});
15+
Future<Uint8List> readAsBytes(AssetId id);
16+
17+
Future<void> delete(AssetId id);
18+
void deleteSync(AssetId id);
19+
20+
void writeAsStringSync(AssetId id, String contents,
21+
{Encoding encoding = utf8});
22+
Future<void> writeAsString(AssetId id, String contents,
23+
{Encoding encoding = utf8});
24+
25+
void writeAsBytesSync(AssetId id, List<int> contents);
26+
Future<void> writeAsBytes(AssetId id, List<int> contents);
27+
}

build/lib/src/state/reader_state.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,16 @@
55
import '../asset/reader.dart';
66
import 'asset_finder.dart';
77
import 'asset_path_provider.dart';
8+
import 'filesystem.dart';
89
import 'input_tracker.dart';
910

1011
/// Provides access to the state backing an [AssetReader].
1112
extension AssetReaderStateExtension on AssetReader {
13+
Filesystem get filesystem {
14+
_requireIsAssetReaderState();
15+
return (this as AssetReaderState).filesystem;
16+
}
17+
1218
AssetFinder get assetFinder {
1319
_requireIsAssetReaderState();
1420
return (this as AssetReaderState).assetFinder;
@@ -43,6 +49,12 @@ extension AssetReaderStateExtension on AssetReader {
4349

4450
/// The state backing an [AssetReader].
4551
abstract interface class AssetReaderState {
52+
/// The [Filesystem] that this reader reads from.
53+
///
54+
/// Warning: this access to the filesystem bypasses reader functionality
55+
/// such as read tracking, caching and visibility restriction.
56+
Filesystem get filesystem;
57+
4658
/// The [AssetFinder] associated with this reader.
4759
///
4860
/// All readers have an [AssetFinder], but the functionality it provides,

build/test/generate/run_post_process_builder_test.dart

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import '../common/builders.dart';
1111

1212
void main() {
1313
group('runPostProcessBuilder', () {
14-
late InMemoryAssetReader reader;
15-
late InMemoryAssetWriter writer;
14+
late InMemoryAssetReaderWriter readerWriter;
1615
final copyBuilder = CopyingPostProcessBuilder();
1716
final deleteBuilder = DeletePostProcessBuilder();
1817
final aTxt = makeAssetId('a|lib/a.txt');
@@ -24,38 +23,37 @@ void main() {
2423
void addAsset(AssetId id) => adds[id] = true;
2524
void deleteAsset(AssetId id) => deletes[id] = true;
2625

27-
Map<AssetId, String> sourceAssets;
28-
2926
setUp(() async {
30-
sourceAssets = {
31-
aTxt: 'a',
32-
};
33-
reader = InMemoryAssetReader(sourceAssets: sourceAssets);
34-
writer = InMemoryAssetWriter();
27+
readerWriter = InMemoryAssetReaderWriter()
28+
..filesystem.writeAsStringSync(aTxt, 'a');
3529
adds.clear();
3630
deletes.clear();
3731
});
3832

3933
test('can delete assets', () async {
40-
await runPostProcessBuilder(copyBuilder, aTxt, reader, writer, logger,
34+
await runPostProcessBuilder(
35+
copyBuilder, aTxt, readerWriter, readerWriter, logger,
4136
addAsset: addAsset, deleteAsset: deleteAsset);
42-
await runPostProcessBuilder(deleteBuilder, aTxt, reader, writer, logger,
37+
await runPostProcessBuilder(
38+
deleteBuilder, aTxt, readerWriter, readerWriter, logger,
4339
addAsset: addAsset, deleteAsset: deleteAsset);
4440
expect(deletes, contains(aTxt));
4541
expect(deletes, isNot(contains(aTxtCopy)));
4642
});
4743

4844
test('can create assets and read the primary asset', () async {
49-
await runPostProcessBuilder(copyBuilder, aTxt, reader, writer, logger,
45+
await runPostProcessBuilder(
46+
copyBuilder, aTxt, readerWriter, readerWriter, logger,
5047
addAsset: addAsset, deleteAsset: deleteAsset);
51-
expect(writer.assets, contains(aTxtCopy));
52-
expect(writer.assets[aTxtCopy], decodedMatches('a'));
48+
expect(readerWriter.assets, contains(aTxtCopy));
49+
expect(readerWriter.assets[aTxtCopy], decodedMatches('a'));
5350
expect(adds, contains(aTxtCopy));
5451
});
5552

5653
test('throws if addAsset throws', () async {
5754
expect(
58-
() => runPostProcessBuilder(copyBuilder, aTxt, reader, writer, logger,
55+
() => runPostProcessBuilder(
56+
copyBuilder, aTxt, readerWriter, readerWriter, logger,
5957
addAsset: (id) => throw InvalidOutputException(id, ''),
6058
deleteAsset: deleteAsset),
6159
throwsA(const TypeMatcher<InvalidOutputException>()));

build_modules/test/decoding_cache_test.dart

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,53 +39,64 @@ void main() {
3939

4040
test('can fetch from disk', () async {
4141
final id = AssetId('foo', 'lib/foo');
42-
final reader = InMemoryAssetReader(sourceAssets: {id: 'foo'});
42+
final reader = InMemoryAssetReaderWriter()
43+
..filesystem.writeAsStringSync(id, 'foo');
4344
expect(await cache.find(id, reader), 'foo');
44-
expect(reader.assetsRead, contains(id));
45+
expect(reader.inputTracker.assetsRead, contains(id));
4546
expect(fromBytesCalls, contains('foo'));
4647
});
4748

4849
test('skips read for value written this build', () async {
4950
final id = AssetId('foo', 'lib/foo');
50-
final reader = InMemoryAssetReader(sourceAssets: {id: 'foo'});
51+
final reader = InMemoryAssetReaderWriter()
52+
..filesystem.writeAsStringSync(id, 'foo');
5153
await cache.write(id, InMemoryAssetWriter(), 'bar');
5254
expect(await cache.find(id, reader), 'bar');
53-
expect(reader.assetsRead, contains(id), reason: 'Should call canRead');
55+
expect(reader.inputTracker.assetsRead, contains(id),
56+
reason: 'Should call canRead');
5457
expect(fromBytesCalls, isNot(contains('bar')));
5558
});
5659

5760
test('skips read on subsequent fetches', () async {
5861
final id = AssetId('foo', 'lib/foo');
59-
final reader1 = InMemoryAssetReader(sourceAssets: {id: 'foo'});
62+
final reader1 = InMemoryAssetReaderWriter()
63+
..filesystem.writeAsStringSync(id, 'foo');
6064
await cache.find(id, reader1);
6165
expect(fromBytesCalls['foo'], 1);
62-
final reader2 = InMemoryAssetReader(sourceAssets: {id: 'foo'});
66+
final reader2 = InMemoryAssetReaderWriter()
67+
..filesystem.writeAsStringSync(id, 'foo');
6368
expect(await cache.find(id, reader2), 'foo');
64-
expect(reader2.assetsRead, contains(id), reason: 'Should call canRead');
69+
expect(reader2.inputTracker.assetsRead, contains(id),
70+
reason: 'Should call canRead');
6571
expect(fromBytesCalls['foo'], 1, reason: 'No extra call to deserialize');
6672
});
6773

6874
test('skips read on subsequent builds if digest has not changed', () async {
6975
final id = AssetId('foo', 'lib/foo');
70-
final reader1 = InMemoryAssetReader(sourceAssets: {id: 'foo'});
76+
final reader1 = InMemoryAssetReaderWriter()
77+
..filesystem.writeAsStringSync(id, 'foo');
7178
await cache.find(id, reader1);
7279
expect(fromBytesCalls['foo'], 1);
7380
await resourceManager.disposeAll();
74-
final reader2 = InMemoryAssetReader(sourceAssets: {id: 'foo'});
81+
final reader2 = InMemoryAssetReaderWriter()
82+
..filesystem.writeAsStringSync(id, 'foo');
7583
expect(await cache.find(id, reader2), 'foo');
76-
expect(reader2.assetsRead, contains(id), reason: 'Should call canRead');
84+
expect(reader2.inputTracker.assetsRead, contains(id),
85+
reason: 'Should call canRead');
7786
expect(fromBytesCalls['foo'], 1, reason: 'No extra call to deserialize');
7887
});
7988

8089
test('rereads on subsequent builds if digest has changed', () async {
8190
final id = AssetId('foo', 'lib/foo');
82-
final reader1 = InMemoryAssetReader(sourceAssets: {id: 'foo'});
91+
final reader1 = InMemoryAssetReaderWriter()
92+
..filesystem.writeAsStringSync(id, 'foo');
8393
await cache.find(id, reader1);
8494
expect(fromBytesCalls['foo'], 1);
8595
await resourceManager.disposeAll();
86-
final reader2 = InMemoryAssetReader(sourceAssets: {id: 'bar'});
96+
final reader2 = InMemoryAssetReaderWriter()
97+
..filesystem.writeAsStringSync(id, 'bar');
8798
expect(await cache.find(id, reader2), 'bar');
88-
expect(reader2.assetsRead, contains(id));
99+
expect(reader2.inputTracker.assetsRead, contains(id));
89100
expect(fromBytesCalls['bar'], 1, reason: 'Deserialize with new value');
90101
});
91102
});

build_resolvers/test/resolver_test.dart

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ void runTests(ResolversFactory resolversFactory) {
138138
}, (resolver) async {
139139
await resolver.libraryFor(entryPoint);
140140
}, assetReaderChecks: (reader) {
141-
expect(reader.assetsRead, {
141+
expect(reader.inputTracker!.assetsRead, {
142142
AssetId('a', 'web/main.dart'),
143143
AssetId('a', 'web/main.dart.transitive_digest'),
144144
AssetId('a', 'web/a.dart'),
@@ -181,7 +181,7 @@ void runTests(ResolversFactory resolversFactory) {
181181
await resolveSources(sources, (resolver) async {
182182
await resolver.libraryFor(entryPoint);
183183
}, assetReaderChecks: (reader) {
184-
expect(reader.assetsRead, {
184+
expect(reader.inputTracker!.assetsRead, {
185185
AssetId('a', 'web/main.dart'),
186186
AssetId('a', 'web/main.dart.transitive_digest'),
187187
AssetId('a', 'web/a.dart'),
@@ -194,7 +194,7 @@ void runTests(ResolversFactory resolversFactory) {
194194
await resolveSources(sources, (resolver) async {
195195
await resolver.libraryFor(entryPoint);
196196
}, assetReaderChecks: (reader) {
197-
expect(reader.assetsRead, {
197+
expect(reader.inputTracker!.assetsRead, {
198198
AssetId('a', 'web/main.dart'),
199199
AssetId('a', 'web/main.dart.transitive_digest'),
200200
AssetId('a', 'web/a.dart'),

build_runner/test/generate/watch_test.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import 'package:build_runner/src/generate/watch_impl.dart' as watch_impl;
1414
import 'package:build_runner_core/build_runner_core.dart';
1515
import 'package:build_runner_core/src/asset_graph/graph.dart';
1616
import 'package:build_runner_core/src/asset_graph/node.dart';
17-
import 'package:build_test/build_test.dart';
1817
import 'package:logging/logging.dart';
1918
import 'package:path/path.dart' as path;
2019
import 'package:test/test.dart';
@@ -284,7 +283,7 @@ void main() {
284283
<AssetId>{},
285284
{packageConfigId},
286285
buildPackageGraph({rootPackage('a'): []}),
287-
InMemoryAssetReader(sourceAssets: readerWriter.assets));
286+
readerWriter);
288287

289288
var builderOptionsId = makeAssetId('a|Phase0.builderOptions');
290289
var builderOptionsNode = BuilderOptionsAssetNode(builderOptionsId,

build_runner_core/lib/src/asset/batch.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ final class BatchReader extends AssetReader implements AssetReaderState {
8181

8282
BatchReader(this._inner, this._batch);
8383

84+
@override
85+
Filesystem get filesystem => _inner.filesystem;
86+
8487
@override
8588
AssetPathProvider? get assetPathProvider => _inner.assetPathProvider;
8689

build_runner_core/lib/src/asset/build_cache.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ class BuildCacheReader implements AssetReader, AssetReaderState {
3333
delegate: delegate.assetPathProvider!,
3434
overlay: (id) => _cacheLocation(id, assetGraph, rootPackage));
3535

36+
@override
37+
Filesystem get filesystem => _delegate.filesystem;
38+
3639
@override
3740
AssetFinder get assetFinder => _delegate.assetFinder;
3841

build_runner_core/lib/src/asset/cache.dart

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ class CachingAssetReader implements AssetReader, AssetReaderState {
4747

4848
CachingAssetReader(this._delegate);
4949

50+
@override
51+
Filesystem get filesystem => _delegate.filesystem;
52+
5053
@override
5154
AssetPathProvider? get assetPathProvider => _delegate.assetPathProvider;
5255

0 commit comments

Comments
 (0)