Skip to content

Commit

Permalink
Use builders to generate showcase test files
Browse files Browse the repository at this point in the history
`source_gen` parses all classese annotated with `@Showcased` and generates test files with cases to generate screenshots of those annotated widgets.
  • Loading branch information
comigor committed Oct 7, 2018
1 parent 0ac1ceb commit 4a028f5
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 40 deletions.
7 changes: 7 additions & 0 deletions build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
builders:
showcase:
import: 'package:showcase/showcase_generator.dart'
builder_factories: ['showcaseBuilder']
# build_to: 'source'
build_extensions: {'.dart': ['.showcased.dart']}
auto_apply: dependents
8 changes: 8 additions & 0 deletions example/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# showcase_example

A new Flutter project.

## Getting Started

For help getting started with Flutter, view our online
[documentation](https://flutter.io/).
49 changes: 49 additions & 0 deletions example/lib/my_widget.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'package:flutter/material.dart';
import 'package:showcase/showcase.dart';

@Showcased()
class MyWidget extends StatelessWidget {
final bool anotherBuild;
final double sliderValue;

MyWidget({
this.anotherBuild = false,
this.sliderValue = 2.0,
});

@override
Widget build(BuildContext context) {
if (anotherBuild) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(color: Colors.red, width: 40.0, height: 40.0),
Container(color: Colors.green, width: 40.0, height: 40.0),
Container(color: Colors.blue, width: 40.0, height: 40.0),
],
);
}

return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('This is my text'),
Text('This is another text'),
RaisedButton(
onPressed: () {},
child: Text('This should be a button'),
color: Colors.amber,
),
Switch(
onChanged: (_) {},
value: true,
),
Slider(
value: sliderValue,
max: 7.0,
onChanged: (_) {},
),
],
);
}
}
21 changes: 21 additions & 0 deletions example/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name: showcase_example
description: A new Flutter project.

version: 1.0.0+1

environment:
sdk: ">=2.0.0-dev.68.0 <3.0.0"

dependencies:
flutter:
sdk: flutter

dev_dependencies:
flutter_test:
sdk: flutter
build_runner: ^0.10.0
showcase:
path: ../.

flutter:
uses-material-design: true
12 changes: 12 additions & 0 deletions example/test/my_widget_test.showcased.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion lib/showcase.dart
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export './showcase_widgets.dart' show showcaseWidgets;
export 'package:showcase/showcase_widgets.dart' show showcaseWidgets;
export 'package:showcase/showcased.dart' show Showcased;
66 changes: 66 additions & 0 deletions lib/showcase_generator.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import 'dart:async';
import 'dart:io';

import 'package:analyzer/dart/element/element.dart';
import 'package:source_gen/source_gen.dart';
import 'package:build/build.dart';
import 'package:showcase/showcased.dart';

class ShowcaseGenerator extends Generator {
TypeChecker get _typeChecker => const TypeChecker.fromRuntime(Showcased);

File generatedFilePath(Uri originalFile) {
var butFirst = originalFile.pathSegments.skip(1).toList()..insert(0, 'test');
var filename = butFirst.removeLast();
butFirst.add(filename.replaceAllMapped(RegExp(r'^(.*)\.dart$'), (match) {
return '${match[1]}_test.showcased.dart';
}));
var newPath = originalFile.replace(pathSegments: butFirst);
return File(newPath.path);
}

@override
FutureOr<String> generate(LibraryReader library, BuildStep buildStep) {
for (var annotatedElement in library.annotatedWith(_typeChecker)) {
// TODO(igor): filter Widgets only
var generatedValue = generateForAnnotatedElement(
annotatedElement.element, annotatedElement.annotation, buildStep, library);
return generatedValue;
}
}

Future<String> generateForAnnotatedElement(
Element element, ConstantReader annotation, BuildStep buildStep, LibraryReader library) async {
var buffer = StringBuffer();

Uri assetUri = library.pathToAsset(buildStep.inputId);

TypeChecker a = const TypeChecker.fromUrl('package:flutter/widgets.dart#Widget');
TypeChecker b = const TypeChecker.fromUrl('package:showcase/showcase.dart#Showcased');

buffer.writeln('''
// GENERATED CODE - DO NOT MODIFY BY HAND
import 'package:flutter_test/flutter_test.dart';
import 'package:showcase/showcase.dart';
import '${assetUri.toString()}';
void main() {
group('Showcase ${element.name}', () {
showcaseWidgets([${element.name}()]);
});
}
''');

File file = generatedFilePath(assetUri);
await file.create(recursive: true);

await file.writeAsString(buffer.toString());

return null;
}
}

Builder showcaseBuilder(BuilderOptions options) {
return LibraryBuilder(ShowcaseGenerator(), generatedExtension: '.showcased.dart');
}
3 changes: 3 additions & 0 deletions lib/showcased.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class Showcased {
const Showcased();
}
10 changes: 0 additions & 10 deletions test/showcase_generator.dart

This file was deleted.

29 changes: 0 additions & 29 deletions test/widget_test.dart

This file was deleted.

0 comments on commit 4a028f5

Please sign in to comment.