github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/runner/gtest/gtest.go (about) 1 // Copyright 2018 The gVisor 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 // http://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 // Package gtest contains helpers for running google-test tests from Go. 16 package gtest 17 18 import ( 19 "fmt" 20 "os/exec" 21 "strings" 22 ) 23 24 var ( 25 // listTestFlag is the flag that will list tests in gtest binaries. 26 listTestFlag = "--gtest_list_tests" 27 28 // filterTestFlag is the flag that will filter tests in gtest binaries. 29 filterTestFlag = "--gtest_filter" 30 31 // listBechmarkFlag is the flag that will list benchmarks in gtest binaries. 32 listBenchmarkFlag = "--benchmark_list_tests" 33 34 // filterBenchmarkFlag is the flag that will run specified benchmarks. 35 filterBenchmarkFlag = "--benchmark_filter" 36 ) 37 38 // TestCase is a single gtest test case. 39 type TestCase struct { 40 // Suite is the suite for this test. 41 Suite string 42 43 // Name is the name of this individual test. 44 Name string 45 46 // all indicates that this will run without flags. This takes 47 // precendence over benchmark below. 48 all bool 49 50 // benchmark indicates that this is a benchmark. In this case, the 51 // suite will be empty, and we will use the appropriate test and 52 // benchmark flags. 53 benchmark bool 54 } 55 56 // FullName returns the name of the test including the suite. It is suitable to 57 // pass to "-gtest_filter". 58 func (tc TestCase) FullName() string { 59 return fmt.Sprintf("%s.%s", tc.Suite, tc.Name) 60 } 61 62 // Args returns arguments to be passed when invoking the test. 63 func (tc TestCase) Args() []string { 64 if tc.all { 65 return []string{} // No arguments. 66 } 67 if tc.benchmark { 68 return []string{ 69 fmt.Sprintf("%s=^%s$", filterBenchmarkFlag, tc.Name), 70 fmt.Sprintf("%s=", filterTestFlag), 71 } 72 } 73 return []string{ 74 fmt.Sprintf("%s=%s", filterTestFlag, tc.FullName()), 75 } 76 } 77 78 // ParseTestCases calls a gtest test binary to list its test and returns a 79 // slice with the name and suite of each test. 80 // 81 // If benchmarks is true, then benchmarks will be included in the list of test 82 // cases provided. Note that this requires the binary to support the 83 // benchmarks_list_tests flag. 84 func ParseTestCases(testBin string, benchmarks bool, extraArgs ...string) ([]TestCase, error) { 85 // Run to extract test cases. 86 args := append([]string{listTestFlag}, extraArgs...) 87 cmd := exec.Command(testBin, args...) 88 out, err := cmd.Output() 89 if err != nil { 90 // We failed to list tests with the given flags. Just 91 // return something that will run the binary with no 92 // flags, which should execute all tests. 93 return []TestCase{ 94 { 95 Suite: "Default", 96 Name: "All", 97 all: true, 98 }, 99 }, nil 100 } 101 102 // Parse test output. 103 var t []TestCase 104 var suite string 105 for _, line := range strings.Split(string(out), "\n") { 106 // Strip comments. 107 line = strings.Split(line, "#")[0] 108 109 // New suite? 110 if !strings.HasPrefix(line, " ") { 111 suite = strings.TrimSuffix(strings.TrimSpace(line), ".") 112 continue 113 } 114 115 // Individual test. 116 name := strings.TrimSpace(line) 117 118 // Do we have a suite yet? 119 if suite == "" { 120 return nil, fmt.Errorf("test without a suite: %v", name) 121 } 122 123 // Add this individual test. 124 t = append(t, TestCase{ 125 Suite: suite, 126 Name: name, 127 }) 128 } 129 130 // Finished? 131 if !benchmarks { 132 return t, nil 133 } 134 135 // Run again to extract benchmarks. 136 args = append([]string{listBenchmarkFlag}, extraArgs...) 137 cmd = exec.Command(testBin, args...) 138 out, err = cmd.Output() 139 if err != nil { 140 // We were able to enumerate tests above, but not benchmarks? 141 // We requested them, so we return an error in this case. 142 exitErr, ok := err.(*exec.ExitError) 143 if !ok { 144 return nil, fmt.Errorf("could not enumerate gtest benchmarks: %v", err) 145 } 146 return nil, fmt.Errorf("could not enumerate gtest benchmarks: %v\nstderr\n%s", err, exitErr.Stderr) 147 } 148 149 benches := strings.Trim(string(out), "\n") 150 if len(benches) == 0 { 151 return t, nil 152 } 153 154 // Parse benchmark output. 155 for _, line := range strings.Split(benches, "\n") { 156 // Strip comments. 157 line = strings.Split(line, "#")[0] 158 159 // Single benchmark. 160 name := strings.TrimSpace(line) 161 162 // Add the single benchmark. 163 t = append(t, TestCase{ 164 Suite: "Benchmarks", 165 Name: name, 166 benchmark: true, 167 }) 168 } 169 return t, nil 170 }