blob: 18b357676029a82d0683a6247413fb7593be481d [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Package testparser parses test stdout into structured results.
package testparser
import (
"bytes"
"fmt"
"regexp"
"go.fuchsia.dev/fuchsia/src/connectivity/network/testing/conformance/parseoutput"
"go.fuchsia.dev/fuchsia/tools/testing/runtests"
)
var (
// LINT.IfChange(mobly_test_start)
moblyTestPreamblePatternStr = `^======== Mobly config content ========$`
// LINT.ThenChange(//src/testing/end_to_end/mobly_driver/mobly_driver/api/api_infra.py:mobly_test_start)
moblyTestPreamblePattern = regexp.MustCompile(moblyTestPreamblePatternStr)
ctsTestPreamblePattern = regexp.MustCompile(`^dEQP Core .* starting\.\.$`)
dartSystemTestPreamblePattern = regexp.MustCompile(`^\[----------\] Test results JSON:$`)
trfTestPreamblePattern = regexp.MustCompile(`^Running test 'fuchsia-pkg:\/\/.*$`)
googleTestPreamblePattern = regexp.MustCompile(`^\[==========\] Running \d* tests? from \d* test (?:(?:suites?)|(?:cases?))\.$`)
zirconUtestPreamblePattern = regexp.MustCompile(`^CASE\s*(.*?)\s*\[STARTED\]$`)
)
// Parse takes stdout from a test program and returns structured results.
// Internally, a variety of test program stdout formats are supported.
// If no structured results were identified, an empty slice is returned.
func Parse(stdout []byte) ([]runtests.TestCaseResult, error) {
lines := bytes.Split(stdout, []byte{'\n'})
res := []*regexp.Regexp{
moblyTestPreamblePattern,
ctsTestPreamblePattern,
dartSystemTestPreamblePattern,
trfTestPreamblePattern,
googleTestPreamblePattern,
zirconUtestPreamblePattern,
parseoutput.TestPreamblePattern,
}
remainingLines, match := firstMatch(lines, res)
// TODO(https://fxbug.dev/435723394): Replace each case with
// `return nil, fmt.Errorf("this test did not parse its own test cases")`
// when removing support for the test type.
var cases []runtests.TestCaseResult
switch match {
case moblyTestPreamblePattern:
cases = parseMoblyTest(remainingLines)
case ctsTestPreamblePattern:
cases = parseVulkanCtsTest(remainingLines)
case dartSystemTestPreamblePattern:
cases = parseDartSystemTest(remainingLines)
case trfTestPreamblePattern:
cases = parseTrfTest(lines)
case googleTestPreamblePattern:
cases = parseGoogleTest(remainingLines)
case zirconUtestPreamblePattern:
cases = parseZirconUtest(remainingLines)
case parseoutput.TestPreamblePattern:
return nil, fmt.Errorf("this test did not parse its own test cases")
}
// Ensure that an empty set of cases is serialized to JSON as an empty
// array, not as null.
if cases == nil {
cases = []runtests.TestCaseResult{}
}
return cases, nil
}
func firstMatch(
lines [][]byte,
res []*regexp.Regexp,
) ([][]byte, *regexp.Regexp) {
for num, line := range lines {
for _, re := range res {
if re.Match(line) {
return lines[num:], re
}
}
}
return nil, nil
}