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 = "&#x332;"
    35  	hardPercent    = "&#xFE6A;"
    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  }