github.com/sentienttechnologies/studio-go-runner@v0.0.0-20201118202441-6d21f2ced8ee/internal/runner/go.go (about)

     1  // Copyright 2018-2020 (c) Cognizant Digital Business, Evolutionary AI. All rights reserved. Issued under the Apache 2.0 License.
     2  
     3  package runner
     4  
     5  // This file contains function(s) useful for running the test suite.
     6  
     7  import (
     8  	"fmt"
     9  	"go/ast"
    10  	"go/parser"
    11  	"go/token"
    12  	"os"
    13  	"path/filepath"
    14  	"strings"
    15  
    16  	"github.com/go-stack/stack"
    17  	"github.com/jjeffery/kv" // MIT License
    18  )
    19  
    20  // IsInTest will examine the OS arguments passed into the software
    21  // being run to detect if the go test framework is present.  If varies from
    22  // the cudaInTest approach in that it will work if the tests were enabled
    23  // in another module
    24  //
    25  func IsInTest() (isTest bool) {
    26  	if strings.HasSuffix(os.Args[0], ".test") {
    27  		return true
    28  	}
    29  
    30  	for _, arg := range os.Args {
    31  		if strings.HasPrefix(arg, "-test.v=") {
    32  			return true
    33  		}
    34  	}
    35  	return false
    36  }
    37  
    38  // GoGetConst will retrieve data structures from source code within the
    39  // code directories that can contain useful information to utilities
    40  // visiting the code for testing purposes.  It is used mainly to
    41  // retrieve command line parameters used during testing that packages contain
    42  // so that when tests are run by external application neutral software the
    43  // code under test can parameterize itself.
    44  //
    45  func GoGetConst(dir string, constName string) (v [][]string, err kv.Error) {
    46  
    47  	fset := token.NewFileSet()
    48  	parserMode := parser.ParseComments
    49  
    50  	errGo := filepath.Walk(dir, func(file string, fi os.FileInfo, err error) error {
    51  		if v != nil {
    52  			return nil
    53  		}
    54  		if fi.IsDir() {
    55  			// Dont recurse into directories with a main, needs AST treatment to discover main(s)
    56  			if fi.Name() == "cmd" || fi.Name() == "vendor" {
    57  				return filepath.SkipDir
    58  			}
    59  			return nil
    60  		}
    61  		if !strings.HasSuffix(fi.Name(), ".go") {
    62  			return nil
    63  		}
    64  		fileAst, errGo := parser.ParseFile(fset, file, nil, parserMode)
    65  		if errGo != nil {
    66  			return kv.Wrap(errGo).With("stack", stack.Trace().TrimRuntime())
    67  		}
    68  
    69  		for _, d := range fileAst.Decls {
    70  			switch decl := d.(type) {
    71  			case *ast.FuncDecl:
    72  				continue
    73  			case *ast.GenDecl:
    74  				for _, spec := range decl.Specs {
    75  					switch spec := spec.(type) {
    76  					case *ast.ImportSpec:
    77  						continue
    78  					case *ast.TypeSpec:
    79  						continue
    80  					case *ast.ValueSpec:
    81  						for _, id := range spec.Names {
    82  							if id.Name == constName {
    83  								opts := []string{}
    84  								for _, value := range spec.Values {
    85  									for _, lts := range value.(*ast.CompositeLit).Elts {
    86  										if strs, ok := lts.(*ast.CompositeLit); ok {
    87  											for _, lt := range strs.Elts {
    88  												if entry, ok := lt.(*ast.BasicLit); ok {
    89  													opts = append(opts, entry.Value)
    90  												}
    91  											}
    92  										}
    93  									}
    94  								}
    95  								v = append(v, opts)
    96  							}
    97  						}
    98  					default:
    99  						fmt.Printf("Unknown token type: %s\n", decl.Tok)
   100  					}
   101  				}
   102  			default:
   103  				fmt.Print("Unknown declaration @\n", decl.Pos())
   104  			}
   105  		}
   106  		return nil
   107  	})
   108  	if errGo != nil {
   109  		return nil, kv.Wrap(errGo).With("stack", stack.Trace().TrimRuntime())
   110  	}
   111  	return v, nil
   112  }