github.com/dancsecs/gotomd@v0.0.0-20240310162206-65c4805cf510/get_go_tst.go (about) 1 /* 2 Golang To Github Markdown Utility: gotomd 3 Copyright (C) 2023, 2024 Leslie Dancsecs 4 5 This program is free software: you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation, either version 3 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program. If not, see <https://www.gnu.org/licenses/>. 17 */ 18 19 package main 20 21 import ( 22 "bytes" 23 "os" 24 "os/exec" 25 "regexp" 26 "strings" 27 28 "github.com/dancsecs/sztest" 29 ) 30 31 const ( 32 tabSPaces = " " 33 hardSpace = "\\unicode{160}" 34 hardUnderscore = "̲" 35 hardPercent = "﹪" 36 ) 37 38 // "--- PASS: Test_PASS_Example1 (0.0s)". 39 // "--- FAIL: Test_FAIL_Example1 (0.0s)". 40 var squashTestTime = regexp.MustCompile( 41 `(?m)^(--- (?:PASS|FAIL): .+?) \(\d+\.\d+s\)$`, 42 ) 43 44 // Squash runtimes for all tests. 45 // "FAIL\tgithub.com/dancsecs/sztestToMarkdown/example1\t0.0s". 46 var squashAllTestTime = regexp.MustCompile(`(?m)^FAIL\s(.+?)\s\d+\.\d+s$`) 47 48 // Squash (cached) indicator on tests. 49 // "ok example (cached) coverage: 100.0% of statements". 50 // "ok example 0.269s coverage: 100.0% of statements". 51 52 var squashCached = regexp.MustCompile( 53 `(?m)^(ok\s+.+?\s+)(?:\(cached\)|\d+\.\d+s)\s+(.*)$`, 54 ) 55 56 func setupEnv(env []string) []string { 57 szEnv := szEnvSetup 58 newEnv := make([]string, 0, len(env)+len(szEnv)) 59 60 for _, e := range env { 61 add := !strings.HasPrefix(e, "\"SZTEST_") && 62 e != "\""+sztest.EnvTmpDir+"=" 63 if add { 64 newEnv = append(newEnv, e) 65 } 66 } 67 68 return append(newEnv, szEnv...) 69 } 70 71 //nolint:funlen // Ok. 72 func runTest(dir, tests string) (string, string, error) { 73 var ( 74 rawRes []byte 75 args []string 76 res string 77 ) 78 79 stat, err := os.Stat(dir) 80 if err == nil && !stat.IsDir() { 81 err = ErrInvalidDirectory 82 } 83 84 if err == nil { 85 args = []string{"test", "-v", "-cover"} 86 87 if tests != pkgLabel { 88 args = append(args, "-run", tests) 89 } 90 91 args = append(args, dir) 92 c := exec.Command("go", args...) //nolint:gosec // Ok. 93 // c.Dir = dir 94 c.Env = setupEnv(os.Environ()) 95 rawRes, _ = c.CombinedOutput() // We expect a general task error. 96 97 if bytes.HasPrefix( 98 rawRes, 99 []byte("testing: warning: no tests to run"), 100 ) { 101 err = ErrNoTestToRun 102 } 103 } 104 105 if err == nil { 106 if szColorize { 107 res = translateToTestSymbols(string(rawRes)) 108 res = squashTestTime.ReplaceAllString(res, `${1} (0.0s)`) 109 res = squashAllTestTime.ReplaceAllString(res, `FAIL ${1} 0.0s`) 110 res = squashCached.ReplaceAllString(res, `${1}${2}`) 111 res = strings.ReplaceAll(res, "\t", tabSPaces) 112 res = strings.ReplaceAll(res, "%", hardPercent) 113 res = strings.ReplaceAll(res, " ", hardSpace) 114 res = strings.ReplaceAll(res, "_", hardUnderscore) 115 116 latexRes := "" 117 lines := strings.Split(res, "\n") 118 119 for _, line := range lines[:len(lines)-1] { 120 if latexRes != "" { 121 latexRes += "\n" 122 } 123 124 latexRes += "$\\small{\\texttt{" + line + "}}$\n<br>" 125 } 126 127 res = latexRes 128 } else { 129 res = translateToBlankSymbols(string(rawRes)) 130 res = "<pre>\n" + strings.TrimRight(res, "\n") + "\n</pre>" 131 res = squashTestTime.ReplaceAllString(res, `${1} (0.0s)`) 132 res = squashAllTestTime.ReplaceAllString(res, `FAIL ${1} 0.0s`) 133 res = squashCached.ReplaceAllString(res, `${1}${2}`) 134 res = strings.ReplaceAll(res, "\t", tabSPaces) 135 res = strings.ReplaceAll(res, "%", hardPercent) 136 } 137 138 return "go " + strings.Join(args, " "), 139 strings.TrimRight(res, "\n"), 140 nil 141 } 142 143 return "", "", err 144 } 145 146 func buildTestCmds(dir, action []string) ([]string, []string) { 147 if len(dir) < 1 { 148 return nil, nil 149 } 150 151 var ( 152 newDir []string 153 newAction []string 154 cDir string 155 cAction string 156 i, mi int 157 ) 158 159 cDir = dir[0] 160 cAction = action[0] 161 162 for i, mi = 1, len(dir); i < mi; i++ { 163 if dir[i] == cDir { 164 cAction += " " + action[i] 165 } else { 166 newDir = append(newDir, cDir) 167 newAction = append(newAction, cAction) 168 cDir = dir[i] 169 cAction = action[i] 170 } 171 } 172 173 if cDir != "" { 174 newDir = append(newDir, cDir) 175 newAction = append(newAction, cAction) 176 } 177 178 return newDir, newAction 179 } 180 181 func getGoTst(cmd string) (string, error) { 182 var ( 183 res string 184 tstRes string 185 tstCmd string 186 ) 187 188 dir, action, err := parseCmds(cmd) 189 if err == nil { 190 dir, action = buildTestCmds(dir, action) 191 } 192 193 for i, mi := 0, len(dir); i < mi && err == nil; i++ { 194 tstCmd, tstRes, err = runTest(dir[i], action[i]) 195 if err == nil { 196 if res != "" { 197 res += "\n\n" 198 } 199 200 res += markBashCode(tstCmd) + "\n\n" + tstRes 201 } 202 } 203 204 if err == nil { 205 return res, nil 206 } 207 208 return "", err 209 }