Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
language: dart
dart:
- stable
with_content_shell: true
before_install:
- export DISPLAY=:99.0
- sh -e /etc/init.d/xvfb start
script:
- pub run dart_dev format --check
- pub run dart_dev analyze
- pub run dart_dev test --integration
- pub run dart_dev coverage --integration --no-html
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Dart Dev Tools
[![Build Status](https://travis-ci.org/Workiva/dart_dev.svg?branch=master)](https://travis-ci.org/Workiva/dart_dev)

> Centralized tooling for Dart projects. Consistent interface across projects. Easily configurable.

Expand Down Expand Up @@ -211,6 +212,7 @@ All configuration options for the `test` task are found on the `config.test` obj

Name | Type | Default | Description
------------------ | -------------- | ----------- | -----------
`concurrency` | `int` | `4` | Number of concurrent test suites run.
`integrationTests` | `List<String>` | `[]` | Integration test locations. Items in this list can be directories and/or files.
`platforms` | `List<String>` | `[]` | Platforms on which to run the tests (handled by the Dart test runner). See https://github.com/dart-lang/test#platform-selector-syntax for a full list of supported platforms.
`unitTests` | `List<String>` | `['test/']` | Unit test locations. Items in this list can be directories and/or files.
Expand Down
40 changes: 30 additions & 10 deletions lib/src/tasks/coverage/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,18 @@ class CoverageResult extends TaskResult {
{Directory report})
: super.fail(),
this.report = report,
reportIndex =
report != null ? new File('${report.path}/index.html') : null;
reportIndex = report != null
? new File(path.join(report.path, 'index.html'))
: null;

CoverageResult.success(
Iterable<String> this.tests, File this.collection, File this.lcov,
{Directory report})
: super.success(),
this.report = report,
reportIndex =
report != null ? new File('${report.path}/index.html') : null;
reportIndex = report != null
? new File(path.join(report.path, 'index.html'))
: null;
}

class CoverageTask extends Task {
Expand Down Expand Up @@ -204,7 +206,7 @@ class CoverageTask extends Task {
List<File> collections = [];
for (int i = 0; i < _files.length; i++) {
File collection = new File(path.join(
'${_outputDirectory.path}/collection', '${_files[i].path}.json'));
_outputDirectory.path, 'collection', '${_files[i].path}.json'));
int observatoryPort;

// Run the test and obtain the observatory port for coverage collection.
Expand Down Expand Up @@ -243,8 +245,7 @@ class CoverageTask extends Task {
}

Future _format(List<String> reportOn) async {
_lcov = new File('${_outputDirectory.path}/coverage.lcov');
_lcov.createSync();
_lcov = new File(path.join(_outputDirectory.path, 'coverage.lcov'));

String executable = 'pub';
List args = [
Expand All @@ -268,6 +269,16 @@ class CoverageTask extends Task {
process.stdout.listen((l) => _coverageOutput.add(' $l'));
process.stderr.listen((l) => _coverageErrorOutput.add(' $l'));
await process.done;

if (lcov.existsSync()) {
_coverageOutput.add('');
_coverageOutput.add('Coverage formatted to LCOV: ${lcov.path}');
} else {
String error =
'Coverage formatting failed. Could not generate ${lcov.path}';
_coverageErrorOutput.add(error);
throw new Exception(error);
}
}

Future _generateReport() async {
Expand Down Expand Up @@ -303,7 +314,7 @@ class CoverageTask extends Task {
collections[i].deleteSync();
}

File coverage = new File('${_outputDirectory.path}/coverage.json');
File coverage = new File(path.join(_outputDirectory.path, 'coverage.json'));
if (coverage.existsSync()) {
coverage.deleteSync();
}
Expand Down Expand Up @@ -392,10 +403,19 @@ class CoverageTask extends Task {
_coverageOutput.add('$executable ${args.join(' ')}\n');
TaskProcess process =
_lastTestProcess = new TaskProcess('content_shell', args);
process.stdout.listen((l) => _coverageOutput.add(' $l'));

// Content-shell dumps render tree to stderr, which is where the test
// results will be. The observatory port should be output to stderr as
// well, but it is sometimes malformed. In those cases, the correct
// observatory port is output to stdout. So we listen to both.
int observatoryPort;
// Note: content-shell dumps render tree to stderr.
process.stdout.listen((line) {
_coverageOutput.add(' $line');
if (line.contains(_observatoryPortPattern)) {
Match m = _observatoryPortPattern.firstMatch(line);
observatoryPort = int.parse(m.group(2));
}
});
await for (String line in process.stderr) {
_coverageOutput.add(' $line');
if (line.contains(_observatoryFailPattern)) {
Expand Down
2 changes: 1 addition & 1 deletion lib/src/tasks/coverage/cli.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class CoverageCli extends TaskCli {
reporter.logGroup('Collecting coverage',
outputStream: task.output, errorStream: task.errorOutput);
CoverageResult result = await task.done;
if (result.successful && open) {
if (result.successful && html && open) {
Process.run('open', [result.reportIndex.path]);
}
return result.successful
Expand Down
9 changes: 7 additions & 2 deletions lib/src/tasks/test/api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,19 @@ import 'package:dart_dev/util.dart' show TaskProcess;
import 'package:dart_dev/src/tasks/task.dart';

TestTask test(
{List<String> platforms: const [], List<String> tests: const []}) {
{int concurrency,
List<String> platforms: const [],
List<String> tests: const []}) {
var executable = 'pub';
var args = ['run', 'test'];
if (concurrency != null) {
args.add('--concurrency=$concurrency');
}
platforms.forEach((p) {
args.addAll(['-p', p]);
});
args.addAll(tests);
args.addAll(['--reporter=expanded']);
args.addAll(tests);

TaskProcess process = new TaskProcess(executable, args);
Completer outputProcessed = new Completer();
Expand Down
12 changes: 11 additions & 1 deletion lib/src/tasks/test/cli.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ class TestCli extends TaskCli {
..addFlag('integration',
defaultsTo: defaultIntegration,
help: 'Includes the integration test suite.')
..addOption('concurrency',
abbr: 'j',
defaultsTo: '$defaultConcurrency',
help: 'The number of concurrent test suites run.')
..addOption('platform',
abbr: 'p',
allowMultiple: true,
Expand All @@ -46,6 +50,11 @@ class TestCli extends TaskCli {

bool unit = parsedArgs['unit'];
bool integration = parsedArgs['integration'];
var concurrency =
TaskCli.valueOf('concurrency', parsedArgs, config.test.concurrency);
if (concurrency is String) {
concurrency = int.parse(concurrency);
}
List<String> platforms =
TaskCli.valueOf('platform', parsedArgs, config.test.platforms);

Expand All @@ -72,7 +81,8 @@ class TestCli extends TaskCli {
}
}

TestTask task = test(platforms: platforms, tests: tests);
TestTask task =
test(tests: tests, concurrency: concurrency, platforms: platforms);
reporter.logGroup(task.testCommand, outputStream: task.testOutput);
await task.done;
return task.successful
Expand Down
2 changes: 2 additions & 0 deletions lib/src/tasks/test/config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ library dart_dev.src.tasks.test.config;

import 'package:dart_dev/src/tasks/config.dart';

const int defaultConcurrency = 4;
const bool defaultIntegration = false;
const List<String> defaultIntegrationTests = const [];
const bool defaultUnit = true;
const List<String> defaultUnitTests = const ['test/'];
const List<String> defaultPlatforms = const [];

class TestConfig extends TaskConfig {
int concurrency = defaultConcurrency;
List<String> integrationTests = defaultIntegrationTests;
List<String> platforms = defaultPlatforms;
List<String> unitTests = defaultUnitTests;
Expand Down
26 changes: 26 additions & 0 deletions lib/src/util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,34 @@ library dart_dev.src.util;
import 'dart:async';
import 'dart:io';

import 'package:path/path.dart' as path;
import 'package:yaml/yaml.dart';

void copyDirectory(Directory source, Directory dest) {
if (!dest.existsSync()) {
dest.createSync(recursive: true);
}

source.listSync(recursive: true).forEach((entity) {
if (FileSystemEntity.isDirectorySync(entity.path)) {
Directory orig = entity;
String p = path.relative(orig.path, from: source.path);
p = path.join(dest.path, p);
Directory copy = new Directory(p);
if (!copy.existsSync()) {
copy.createSync(recursive: true);
}
} else if (FileSystemEntity.isFileSync(entity.path)) {
File orig = entity;
String p = path.relative(orig.path, from: source.path);
p = path.join(dest.path, p);
File copy = new File(p);
copy.createSync(recursive: true);
copy.writeAsBytesSync(orig.readAsBytesSync());
}
});
}

/// Returns an open port by creating a temporary Socket.
/// Borrowed from coverage package https://github.com/dart-lang/coverage/blob/master/lib/src/util.dart#L49-L66
Future<int> getOpenPort() async {
Expand Down
1 change: 1 addition & 0 deletions lib/util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export 'package:dart_dev/src/reporter.dart' show Reporter, reporter;
export 'package:dart_dev/src/task_process.dart' show TaskProcess;
export 'package:dart_dev/src/util.dart'
show
copyDirectory,
getOpenPort,
hasImmediateDependency,
parseArgsFromCommand,
Expand Down
6 changes: 3 additions & 3 deletions test/integration/copy_license_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.

@TestOn('vm')
library dart_dev.test.integration.copy_license_test;

import 'dart:async';
import 'dart:io';

import 'package:dart_dev/util.dart' show TaskProcess;
import 'package:dart_dev/util.dart' show TaskProcess, copyDirectory;
import 'package:test/test.dart';

const String projectWithLicenses = 'test/fixtures/copy_license/has_licenses';
Expand All @@ -28,8 +29,7 @@ const String projectWithoutLicenses = 'test/fixtures/copy_license/no_licenses';
Future<String> createTemporaryProject(String source) async {
String tempProject = '${source}_temp';
Directory temp = new Directory(tempProject);
temp.createSync();
await Process.run('cp', ['-R', '$source/', tempProject]);
copyDirectory(new Directory(source), temp);
return tempProject;
}

Expand Down
2 changes: 1 addition & 1 deletion test/integration/coverage_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Future<bool> runCoverage(String projectPath) async {
oldCoverage.deleteSync(recursive: true);
}

List args = ['run', 'dart_dev', 'coverage', '--no-open'];
List args = ['run', 'dart_dev', 'coverage', '--no-html'];
TaskProcess process =
new TaskProcess('pub', args, workingDirectory: projectPath);

Expand Down
6 changes: 2 additions & 4 deletions test/integration/format_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ library dart_dev.test.integration.format_test;
import 'dart:async';
import 'dart:io';

import 'package:dart_dev/util.dart' show TaskProcess;
import 'package:dart_dev/util.dart' show TaskProcess, copyDirectory;
import 'package:test/test.dart';

const String projectWithChangesNeeded = 'test/fixtures/format/changes_needed';
Expand Down Expand Up @@ -71,9 +71,7 @@ void main() {
// testing purposes (necessary since formatter will make changes).
String testProject = '${projectWithChangesNeeded}_temp';
Directory temp = new Directory(testProject);
temp.createSync();
await Process.run(
'cp', ['-R', '$projectWithChangesNeeded/', testProject]);
copyDirectory(new Directory(projectWithChangesNeeded), temp);

File dirtyFile = new File('$testProject/lib/main.dart');
File cleanFile = new File('$projectWithNoChangesNeeded/lib/main.dart');
Expand Down
6 changes: 4 additions & 2 deletions tool/dev.dart
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,10 @@ main(args) async {
config.coverage.reportOn = ['bin/', 'lib/'];
config.format.directories = directories;
config.test
..unitTests = []
..integrationTests = ['test/integration/'];
..concurrency = 1
..platforms = ['vm']
..integrationTests = ['test/integration/']
..unitTests = [];

await dev(args);
}