1// Copyright 2018 The BoringSSL Authors 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// https://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// testresult is an implementation of Chromium's JSON test result format. See 16// https://chromium.googlesource.com/chromium/src/+/main/docs/testing/json_test_results_format.md 17package testresult 18 19import ( 20 "encoding/json" 21 "fmt" 22 "os" 23 "time" 24) 25 26// Results stores the top-level test results. 27type Results struct { 28 Version int `json:"version"` 29 Interrupted bool `json:"interrupted"` 30 PathDelimiter string `json:"path_delimiter"` 31 SecondsSinceEpoch float64 `json:"seconds_since_epoch"` 32 NumFailuresByType map[string]int `json:"num_failures_by_type"` 33 Tests map[string]Result `json:"tests"` 34} 35 36func NewResults() *Results { 37 return &Results{ 38 Version: 3, 39 PathDelimiter: ".", 40 SecondsSinceEpoch: float64(time.Now().UnixNano()) / float64(time.Second/time.Nanosecond), 41 NumFailuresByType: make(map[string]int), 42 Tests: make(map[string]Result), 43 } 44} 45 46func (t *Results) addResult(name, result, expected string, err error) { 47 if _, found := t.Tests[name]; found { 48 panic(fmt.Sprintf("duplicate test name %q", name)) 49 } 50 r := Result{ 51 Actual: result, 52 Expected: expected, 53 IsUnexpected: result != expected, 54 } 55 if err != nil { 56 r.Error = err.Error() 57 } 58 t.Tests[name] = r 59 t.NumFailuresByType[result]++ 60} 61 62// AddResult records a test result with the given result string. The test is a 63// failure if the result is not "PASS". 64func (t *Results) AddResult(name, result string, err error) { 65 t.addResult(name, result, "PASS", err) 66} 67 68// AddSkip marks a test as being skipped. It is not considered a failure. 69func (t *Results) AddSkip(name string) { 70 t.addResult(name, "SKIP", "SKIP", nil) 71} 72 73func (t *Results) HasUnexpectedResults() bool { 74 for _, r := range t.Tests { 75 if r.IsUnexpected { 76 return false 77 } 78 } 79 return true 80} 81 82func (t *Results) WriteToFile(name string) error { 83 file, err := os.Create(name) 84 if err != nil { 85 return err 86 } 87 defer file.Close() 88 out, err := json.MarshalIndent(t, "", " ") 89 if err != nil { 90 return err 91 } 92 _, err = file.Write(out) 93 return err 94} 95 96type Result struct { 97 Actual string `json:"actual"` 98 Expected string `json:"expected"` 99 IsUnexpected bool `json:"is_unexpected"` 100 // Error is not part of the Chromium test results schema, but is useful for 101 // BoGo output. 102 Error string `json:"error,omitempty"` 103} 104