blob: 43c8c61c0c9857b5c8b29235b08c743024174fe8 [file] [log] [blame]
// Copyright 2016 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
import 'dart:async';
import 'dart:convert';
import '../mobile/device_spec.dart';
import '../mobile/device.dart';
import 'test_result.dart';
import '../globals.dart';
import '../util.dart';
class TAPReporter {
int currentTestNum;
int passingTestsNum;
Map<int, TestMethodResult> testMethodResultMapping;
Map<int, GroupResult> groupResultMapping;
List<TestSuiteResult> suites;
StringBuffer roundHighlight;
TAPReporter(Map<DeviceSpec, Device> deviceMapping) {
this.currentTestNum = 0;
this.passingTestsNum = 0;
this.testMethodResultMapping = <int, TestMethodResult>{};
this.groupResultMapping = <int, GroupResult>{};
this.suites = <TestSuiteResult>[];
roundHighlight = new StringBuffer();
int diffFrom = beginOfDiff(
deviceMapping.keys.map((DeviceSpec spec) => spec.groupKey()).toList()
);
deviceMapping.forEach((DeviceSpec spec, Device device) {
roundHighlight.writeln(
'<Spec Group Key: ${spec.groupKey().substring(diffFrom)}>'
' -> '
'<Device Group Key: ${device.groupKey()}> (${spec.nickName})'
);
});
}
void printHeader() {
print(
'\n'
'TAP version 13'
);
}
Future<bool> report(String testScriptPath, Stream jsonOutput) async {
testMethodResultMapping.clear();
groupResultMapping.clear();
suites.add(new TestSuiteResult(testScriptPath));
bool hasTestOutput = false;
await for (var line in jsonOutput) {
convertToTAPFormat(line.toString().trim());
hasTestOutput = true;
}
return hasTestOutput;
}
void printSummary() {
print(
'\n'
'1..$currentTestNum\n'
'# tests $currentTestNum\n'
'# pass $passingTestsNum\n'
);
}
void convertToTAPFormat(var jsonLine) {
if (jsonLine == null)
return;
dynamic event;
try {
event = JSON.decode(jsonLine);
} on FormatException {
printError('File ${jsonLine.toString()} is not in JSON format.');
return;
}
TestSuiteResult lastSuite = suites.last;
if (_isGroupEvent(event) && !_isGroupRootEvent(event)) {
dynamic groupInfo = event['group'];
String name = groupInfo['name'];
bool skip = groupInfo['metadata']['skip'];
String skipReason = groupInfo['metadata']['skipReason'] ?? '';
if (skip) {
print('# skip ${groupInfo['name']} $skipReason');
} else {
print('# ${groupInfo['name']}');
}
int groupID = groupInfo['id'];
GroupResult groupEvent = new GroupResult(name, skip, skipReason);
groupResultMapping[groupID] = groupEvent;
lastSuite.addEvent(groupEvent);
} else if (_isTestStartEvent(event)) {
dynamic testInfo = event['test'];
int testID = testInfo['id'];
String name = testInfo['name'];
List<int> groupIDs = testInfo['groupIDs'];
int directParentGroupID;
// Associate the test event to its parent group event if any
if (groupIDs.isNotEmpty) {
directParentGroupID = groupIDs.last;
// Remove group name prefix if any
GroupResult directParentGroup = groupResultMapping[directParentGroupID];
String groupName = directParentGroup.name;
if (name.startsWith(groupName)) {
name = name.substring(groupName.length).trim();
}
}
bool skip = testInfo['metadata']['skip'];
String skipReason = testInfo['metadata']['skipReason'] ?? '';
testMethodResultMapping[testID]
= new TestMethodResult(name, directParentGroupID, skip, skipReason);
} else if (_isErrorEvent(event)) {
int testID = event['testID'];
TestMethodResult testEvent = testMethodResultMapping[testID];
String errorReason = event['error'];
testEvent.fillError(errorReason);
} else if (_isTestDoneEvent(event)) {
int testID = event['testID'];
TestMethodResult testEvent = testMethodResultMapping[testID];
testEvent.hidden = event['hidden'];
testEvent.result = event['result'];
printTestResult(testEvent);
if (testEvent.hidden) {
return;
}
int directParentGroupID = testEvent.directParentGroupID;
if (!groupResultMapping.containsKey(directParentGroupID)) {
lastSuite.addEvent(testEvent);
} else {
GroupResult groupEvent = groupResultMapping[directParentGroupID];
groupEvent.addTestEvent(testEvent);
}
}
}
bool _isGroupEvent(dynamic event) {
return event['type'] == 'group';
}
bool _isGroupRootEvent(dynamic event) {
dynamic groupInfo = event['group'];
return _isGroupEvent(event)
&&
groupInfo['name'] == null
&&
groupInfo['parentID'] == null;
}
bool _isTestStartEvent(dynamic event) {
return event['type'] == 'testStart';
}
bool _isErrorEvent(dynamic event) {
return event['type'] == 'error';
}
bool _isTestDoneEvent(dynamic event) {
return event['type'] == 'testDone';
}
void printTestResult(TestMethodResult event) {
if (event.hidden)
return;
if (event.result != 'success') {
if (event.error) {
print('not ok ${++currentTestNum} - ${event.name}');
String tab = '${' ' * 2}';
// Print error message
event.errorReason.split('\n').forEach((String line) {
print('$tab$line');
});
return;
}
print('not ok ${++currentTestNum} - ${event.name}');
return;
}
if (event.skip) {
print('ok ${++currentTestNum} - # SKIP ${event.skipReason}');
}
print('ok ${++currentTestNum} - ${event.name}');
passingTestsNum++;
}
int skipNum() {
return sum(suites.map((TestSuiteResult e) => e.skipNum()));
}
int failNum() {
return sum(suites.map((TestSuiteResult e) => e.failNum()));
}
int passNum() {
return sum(suites.map((TestSuiteResult e) => e.passNum()));
}
dynamic toJson() {
int failures = failNum();
return {
'type': 'test-round',
'highlight': roundHighlight.toString(),
'skip-num': skipNum(),
'fail-num': failures,
'pass-num': passNum(),
'status': failures > 0 ? 'fail' : 'pass',
'suites-info': suites.map((TestSuiteResult suite) => suite.toJson()).toList()
};
}
}