build icon indicating copy to clipboard operation
build copied to clipboard

Add a testPostProcessingBuilder helper to build_test

Open Fox32 opened this issue 3 years ago • 2 comments

While testing builders I noticed that testBuilder only work for normal builders, but not for PostProcessBuilder. Having a testPostProcessingBuilder would be a nice addition. We have something like this in our code right now:


Future testPostProcessingBuilder(PostProcessBuilder builder,
    Map<String, /*String|List<int>*/ dynamic> sourceAssets,
    {Set<String> generateFor,
    bool Function(String assetId) isInput,
    String rootPackage,
    MultiPackageAssetReader reader,
    RecordingAssetWriter writer,
    Map<
            String,
            /*String|List<int>|Matcher<String|List<int>>*/
            dynamic>
        outputs,
    void Function(LogRecord log) onLog}) async {
  writer ??= InMemoryAssetWriter();
  final inMemoryReader = InMemoryAssetReader(rootPackage: rootPackage);
  if (reader != null) {
    reader = MultiAssetReader([inMemoryReader, reader]);
  } else {
    reader = inMemoryReader;
  }

  var inputIds = <AssetId>[];
  sourceAssets.forEach((serializedId, contents) {
    var id = makeAssetId(serializedId);
    if (contents is String) {
      inMemoryReader.cacheStringAsset(id, contents);
    } else if (contents is List<int>) {
      inMemoryReader.cacheBytesAsset(id, contents);
    }
    inputIds.add(id);
  });

  var allPackages = inMemoryReader.assets.keys.map((a) => a.package).toSet();
  for (var pkg in allPackages) {
    for (var dir in const ['lib', 'web', 'test']) {
      var asset = AssetId(pkg, '$dir/\$$dir\$');
      inputIds.add(asset);
    }
  }

  isInput ??= generateFor?.contains ?? (_) => true;
  inputIds = inputIds.where((id) => isInput('$id')).toList();

  var writerSpy = AssetWriterSpy(writer);
  var logger = Logger('testPostProcessingBuilder');
  var logSubscription = logger.onRecord.listen(onLog);

  var actualOutputs = {for (var i in inputIds) i.path: i};

  for (var inputId in inputIds) {
    await runPostProcessBuilder(builder, inputId, reader, writerSpy, logger,
        addAsset: (a) => actualOutputs[a.path] = a,
        deleteAsset: (a) => actualOutputs.remove(a.path));
  }

  await logSubscription.cancel();

  writerSpy.assetsWritten.forEach((a) => actualOutputs[a.path] = a);

  checkOutputs(outputs, actualOutputs.values, writer);
}

Which can be used like:


      await testPostProcessingBuilder(
          builder,
          {
            'builders|test/delete.txt': 'delete.txt',
            'builders|test/keep.txt': 'keep.txt',
            'builders|delete/test.json': 'delete.json',
          },
          outputs: {'builders|test/keep.txt': isNull},
          onLog: print);

Do you think this is worth a PR? How do you test post processing builders, did I miss something?

Fox32 avatar Dec 19 '20 10:12 Fox32

@Fox32 this seems reasonable to me - I think we just rely on integration testing for our post processing builders (we have very few and they do very little).

But some unit testing helpers would definitely be good!

jakemac53 avatar Jan 05 '21 16:01 jakemac53

I will prepare a PR 🙂

Fox32 avatar Jan 05 '21 16:01 Fox32

I will prepare a PR 🙂

Did you ever manage to finish your PR?

BenVercammen avatar Feb 07 '23 13:02 BenVercammen

Actually not 😆 I was working on it and noticed that is a bit more complex than I expected. On the other hand I noticed that I also might lack understanding of the internals to really implement a test harness that works as the real code. The code I posted above is wrong on so many levels 😆

Fox32 avatar Feb 07 '23 17:02 Fox32