Skip to content

Commit ab52744

Browse files
committed
add transformer tests
1 parent de90a36 commit ab52744

File tree

7 files changed

+190
-27
lines changed

7 files changed

+190
-27
lines changed

lib/src/builder/build_step_impl.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class BuildStepImpl implements BuildStep {
4242
final AssetWriter _writer;
4343

4444
BuildStepImpl(
45-
this.input, List<AssetId> expectedOutputs, this._reader, this._writer)
45+
this.input, Iterable<AssetId> expectedOutputs, this._reader, this._writer)
4646
: expectedOutputs = new List.unmodifiable(expectedOutputs) {
4747
/// The [input] is always a dependency.
4848
_dependencies.add(input.id);

lib/src/transformer/transformer.dart

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@ import '../asset/writer.dart';
1414
import '../builder/builder.dart';
1515
import '../builder/build_step_impl.dart';
1616

17-
abstract class BuilderTransformer implements Transformer, DeclaringTransformer {
17+
/// A [Transformer] which runs multiple [Builder]s. Extend this class and define
18+
/// the [builders] getter to create a [Transformer] out of your custom builders.
19+
abstract class BuilderTransformer implements Transformer {
20+
/// The only thing you need to implement when extending this class. This
21+
/// declares which builders should be ran.
1822
List<Builder> get builders;
1923

2024
@override
@@ -30,23 +34,32 @@ abstract class BuilderTransformer implements Transformer, DeclaringTransformer {
3034
var reader = new _TransformAssetReader(transform);
3135
var writer = new _TransformAssetWriter(transform);
3236

33-
var futures = <Future>[];
34-
for (var builder in builders) {
37+
var allExpected = new Set<build.AssetId>();
38+
await Future.forEach(builders, (builder) async {
3539
var expected = _expectedOutputs(transform.primaryInput.id, [builder]);
36-
if (expected.isEmpty) continue;
37-
40+
if (expected.isEmpty) return;
41+
42+
// Check that no expected outputs already exist.
43+
var preExistingFiles = [];
44+
for (var output in expected) {
45+
if (!allExpected.add(output) ||
46+
await transform.hasInput(_toBarbackAssetId(output))) {
47+
preExistingFiles.add(_toBarbackAssetId(output));
48+
}
49+
}
50+
if (preExistingFiles.isNotEmpty) {
51+
transform.logger.error(
52+
'Builder `$builder` declared outputs `$preExistingFiles` but those '
53+
'files already exist. That build step has been skipped.',
54+
asset: transform.primaryInput.id);
55+
return;
56+
}
57+
58+
// Run the build step.
3859
var buildStep = new BuildStepImpl(input, expected, reader, writer);
39-
futures.add(builder.build(buildStep));
40-
}
41-
42-
await Future.wait(futures);
43-
}
44-
45-
@override
46-
void declareOutputs(DeclaringTransform transform) {
47-
for (var outputId in _expectedOutputs(transform.primaryId, builders)) {
48-
transform.declareOutput(_toBarbackAssetId(outputId));
49-
}
60+
await builder.build(buildStep);
61+
await buildStep.outputsCompleted;
62+
});
5063
}
5164
}
5265

@@ -68,8 +81,9 @@ class _TransformAssetWriter implements AssetWriter {
6881
_TransformAssetWriter(this.transform);
6982

7083
@override
71-
Future writeAsString(build.Asset asset, {Encoding encoding: UTF8}) async =>
72-
transform.addOutput(_toBarbackAsset(asset));
84+
Future writeAsString(build.Asset asset, {Encoding encoding: UTF8}) async {
85+
transform.addOutput(_toBarbackAsset(asset));
86+
}
7387
}
7488

7589
/// All the expected outputs for [id] given [builders].

pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ dependencies:
1616

1717
dev_dependencies:
1818
test: ^0.12.0
19+
transformer_test: ^0.1.0

test/common/common.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright (c) 2016, 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+
export 'copy_builder.dart';
5+
export 'generic_builder_transformer.dart';

test/common/copy_builder.dart

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (c) 2016, 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+
import 'dart:async';
5+
6+
import 'package:build/build.dart';
7+
8+
class CopyBuilder implements Builder {
9+
int numCopies;
10+
11+
CopyBuilder({this.numCopies: 1});
12+
13+
Future build(BuildStep buildStep) async {
14+
var ids = declareOutputs(buildStep.input.id);
15+
for (var id in ids) {
16+
buildStep.writeAsString(new Asset(id, buildStep.input.stringContents));
17+
}
18+
}
19+
20+
List<AssetId> declareOutputs(AssetId input) {
21+
var outputs = [];
22+
for (int i = 0; i < numCopies; i++) {
23+
outputs.add(_copiedAssetId(input, numCopies == 1 ? null : i));
24+
}
25+
return outputs;
26+
}
27+
}
28+
29+
AssetId _copiedAssetId(AssetId inputId, int copyNum) =>
30+
inputId.addExtension('.copy${copyNum == null ? '' : '.$copyNum'}');
Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
11
// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
4-
54
import 'package:build/build.dart';
6-
import 'package:test/test.dart';
75

8-
main() {
9-
group('A group of tests', () {
10-
test('First Test', () {
11-
expect(true, isTrue);
12-
});
13-
});
6+
class GenericBuilderTransformer extends BuilderTransformer {
7+
final List<Builder> builders;
8+
9+
GenericBuilderTransformer(this.builders);
1410
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Copyright (c) 2016, 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+
@TestOn('vm')
5+
import 'package:test/test.dart';
6+
import 'package:transformer_test/utils.dart';
7+
8+
import '../common/common.dart';
9+
10+
main() {
11+
var singleCopyTransformer =
12+
new GenericBuilderTransformer([new CopyBuilder()]);
13+
var multiCopyTransformer =
14+
new GenericBuilderTransformer([new CopyBuilder(numCopies: 2)]);
15+
var singleAndMultiCopyTransformer = new GenericBuilderTransformer(
16+
[new CopyBuilder(), new CopyBuilder(numCopies: 2)]);
17+
18+
testPhases('single builder, single output', [
19+
[singleCopyTransformer],
20+
], {
21+
'a|web/a.txt': 'hello',
22+
}, {
23+
'a|web/a.txt.copy': 'hello',
24+
});
25+
26+
testPhases('single builder, multiple outputs', [
27+
[multiCopyTransformer],
28+
], {
29+
'a|web/a.txt': 'hello',
30+
}, {
31+
'a|web/a.txt.copy.0': 'hello',
32+
'a|web/a.txt.copy.1': 'hello',
33+
});
34+
35+
testPhases('multiple builders, different outputs', [
36+
[singleAndMultiCopyTransformer],
37+
], {
38+
'a|web/a.txt': 'hello',
39+
}, {
40+
'a|web/a.txt.copy': 'hello',
41+
'a|web/a.txt.copy.0': 'hello',
42+
'a|web/a.txt.copy.1': 'hello',
43+
});
44+
45+
testPhases('multiple builders, same outputs', [
46+
[
47+
new GenericBuilderTransformer([new CopyBuilder(), new CopyBuilder()])
48+
],
49+
], {
50+
'a|web/a.txt': 'hello',
51+
}, {}, [
52+
_fileExistsError('CopyBuilder', ['a|web/a.txt.copy']),
53+
]);
54+
55+
testPhases('multiple phases', [
56+
[singleCopyTransformer],
57+
[multiCopyTransformer],
58+
], {
59+
'a|web/a.txt': 'hello',
60+
}, {
61+
'a|web/a.txt.copy': 'hello',
62+
'a|web/a.txt.copy.0': 'hello',
63+
'a|web/a.txt.copy.1': 'hello',
64+
'a|web/a.txt.copy.copy.0': 'hello',
65+
'a|web/a.txt.copy.copy.1': 'hello',
66+
});
67+
68+
testPhases('multiple transformers in the same phase', [
69+
[singleCopyTransformer, multiCopyTransformer],
70+
], {
71+
'a|web/a.txt': 'hello',
72+
}, {
73+
'a|web/a.txt.copy': 'hello',
74+
'a|web/a.txt.copy.0': 'hello',
75+
'a|web/a.txt.copy.1': 'hello',
76+
});
77+
78+
testPhases('cant overwrite files', [
79+
[singleCopyTransformer]
80+
], {
81+
'a|web/a.txt': 'hello',
82+
'a|web/a.txt.copy': 'hello',
83+
}, {}, [
84+
_fileExistsError("CopyBuilder", ["a|web/a.txt.copy"]),
85+
]);
86+
87+
// TODO(jakemac): Skipped because we can't detect this situation today.
88+
// Instead you get a barback error, see
89+
// https://github.com/dart-lang/transformer_test/issues/2
90+
//
91+
// testPhases('builders in the same phase can\'t output the same file', [
92+
// [singleCopyTransformer, new GenericBuilderTransformer([new CopyBuilder()])]
93+
// ], {
94+
// 'a|web/a.txt': 'hello',
95+
// }, {
96+
// 'a|web/a.txt.copy': 'hello',
97+
// }, [
98+
// _fileExistsError("CopyBuilder", ["a|web/a.txt.copy"]),
99+
// ]);
100+
101+
testPhases('builders in separate phases can\'t output the same file', [
102+
[singleCopyTransformer],
103+
[singleCopyTransformer],
104+
], {
105+
'a|web/a.txt': 'hello',
106+
}, {
107+
'a|web/a.txt.copy': 'hello',
108+
}, [
109+
_fileExistsError("CopyBuilder", ["a|web/a.txt.copy"]),
110+
]);
111+
}
112+
113+
String _fileExistsError(String builder, List<String> files) {
114+
return "error: Builder `Instance of '$builder'` declared outputs "
115+
"`$files` but those files already exist. That build step has been "
116+
"skipped.";
117+
}

0 commit comments

Comments
 (0)