blob: ecf6c89b243140ceb48c12fe59fcee1c3bea8282 [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// TODO(gram):
// Unfortunately I can't seem to test anything that involves timeouts, e.g.
// insufficient callbacks, because the timeout is controlled externally
// (test.dart?), and we would need to use a shorter timeout for the inner tests
// so the outer timeout doesn't fire. So I removed all such tests.
// I'd like to revisit this at some point.
#library('unittestTest');
#import('dart:isolate');
#import('../../../pkg/unittest/unittest.dart');
var tests; // array of test names
var expected; // array of test expected results (from buildStatusString)
var actual; // actual test results (from buildStatusString in config.onDone)
var _testconfig; // test configuration to capture onDone
_defer(void fn()) {
// Exploit isolate ports as a platform-independent mechanism to queue a
// message at the end of the event loop. Stolen from unittest.dart.
final port = new ReceivePort();
port.receive((msg, reply) {
fn();
port.close();
});
port.toSendPort().send(null, null);
}
String buildStatusString(int passed, int failed, int errors,
var results,
{int count: 0,
String setup: '', String teardown: '',
String uncaughtError: null,
String message: ''}) {
var totalTests = 0;
String testDetails = '';
if (results is String) {
totalTests = passed + failed + errors;
testDetails = ':$results:$message';
} else {
totalTests = results.length;
for (var i = 0; i < results.length; i++) {
testDetails = '$testDetails:${results[i].description}:'
'${collapseWhitespace(results[i].message)}';
}
}
var result = '$passed:$failed:$errors:$totalTests:$count:'
'$setup:$teardown:$uncaughtError$testDetails';
return result;
}
class TestConfiguration extends Configuration {
// Some test state that is captured
int count = 0; // a count of callbacks
String setup = ''; // the name of the test group setup function, if any
String teardown = ''; // the name of the test group teardown function, if any
// The port to communicate with the parent isolate
SendPort _port;
TestConfiguration(this._port);
void onDone(int passed, int failed, int errors, List<TestCase> results,
String uncaughtError) {
var result = buildStatusString(passed, failed, errors, results,
count: count, setup: setup, teardown: teardown,
uncaughtError: uncaughtError);
_port.send(result);
}
}
runTest() {
port.receive((testName, sendport) {
configure(_testconfig = new TestConfiguration(sendport));
if (testName == 'single correct test') {
test(testName, () => expect(2 + 3, equals(5)));
} else if (testName == 'single failing test') {
test(testName, () => expect(2 + 2, equals(5)));
} else if (testName == 'exception test') {
test(testName, () { throw new Exception('Fail.'); });
} else if (testName == 'group name test') {
group('a', () {
test('a', () {});
group('b', () {
test('b', () {});
});
});
} else if (testName == 'setup test') {
group('a', () {
setUp(() { _testconfig.setup = 'setup'; });
test(testName, () {});
});
} else if (testName == 'teardown test') {
group('a', () {
tearDown(() { _testconfig.teardown = 'teardown'; });
test(testName, () {});
});
} else if (testName == 'setup and teardown test') {
group('a', () {
setUp(() { _testconfig.setup = 'setup'; });
tearDown(() { _testconfig.teardown = 'teardown'; });
test(testName, () {});
});
} else if (testName == 'correct callback test') {
test(testName,
() =>_defer(expectAsync0((){ ++_testconfig.count;})));
} else if (testName == 'excess callback test') {
test(testName, () {
var _callback = expectAsync0((){ ++_testconfig.count;});
_defer(_callback);
_defer(_callback);
});
} else if (testName == 'completion test') {
test(testName, () {
var _callback;
_callback = expectAsyncUntil0(() {
if (++_testconfig.count < 10) {
_defer(_callback);
}
},
() => (_testconfig.count == 10));
_defer(_callback);
});
} else if (testName == 'async exception test') {
test(testName, () {
expectAsync0(() {});
_defer(() => guardAsync(() { throw "error!"; }));
});
} else if (testName == 'late exception test') {
test('testOne', () {
var f = expectAsync0(() {});
_defer(protectAsync0(() {
_defer(protectAsync0(() => expect(false, isTrue)));
expect(false, isTrue);
}));
});
test('testTwo', () {
_defer(expectAsync0(() {}));
});
} else if (testName == 'middle exception test') {
test('testOne', () { expect(true, isTrue); });
test('testTwo', () { expect(true, isFalse); });
test('testThree', () {
var done = expectAsync0((){});
_defer(() {
expect(true, isTrue);
done();
});
});
}
});
}
void nextTest(int testNum) {
SendPort sport = spawnFunction(runTest);
sport.call(tests[testNum]).then((msg) {
actual.add(msg);
if (actual.length == expected.length) {
for (var i = 0; i < tests.length; i++) {
test(tests[i], () => expect(actual[i].trim(), equals(expected[i])));
}
} else {
nextTest(testNum+1);
}
});
}
main() {
tests = [
'single correct test',
'single failing test',
'exception test',
'group name test',
'setup test',
'teardown test',
'setup and teardown test',
'correct callback test',
'excess callback test',
'completion test',
'async exception test',
'late exception test',
'middle exception test'
];
expected = [
buildStatusString(1, 0, 0, tests[0]),
buildStatusString(0, 1, 0, tests[1],
message: 'Expected: <5> but: was <4>.'),
buildStatusString(0, 1, 0, tests[2], message: 'Caught Exception: Fail.'),
buildStatusString(2, 0, 0, 'a a::a b b'),
buildStatusString(1, 0, 0, 'a ${tests[4]}', count: 0, setup: 'setup'),
buildStatusString(1, 0, 0, 'a ${tests[5]}', count: 0, setup: '',
teardown: 'teardown'),
buildStatusString(1, 0, 0, 'a ${tests[6]}', count: 0,
setup: 'setup', teardown: 'teardown'),
buildStatusString(1, 0, 0, tests[7], count: 1),
buildStatusString(0, 0, 1, tests[8], count: 1,
message: 'Callback called more times than expected (2 > 1).'),
buildStatusString(1, 0, 0, tests[9], count: 10),
buildStatusString(0, 1, 0, tests[10], message: 'Caught error!'),
buildStatusString(1, 0, 1, 'testOne', message: 'Callback called after already being marked as done (1).:testTwo:'),
buildStatusString(2, 1, 0, 'testOne::testTwo:Expected: false but: was <true>.:testThree')
];
actual = [];
nextTest(0);
}