github.com/jmigpin/editor@v1.6.0/core/godebug/scripts_test.go (about)

     1  package godebug
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"go/parser"
     8  	"go/token"
     9  	"log"
    10  	"os"
    11  	"path/filepath"
    12  	"strings"
    13  	"sync"
    14  	"testing"
    15  
    16  	"github.com/jmigpin/editor/core/godebug/debug"
    17  	"github.com/jmigpin/editor/util/flagutil"
    18  	"github.com/jmigpin/editor/util/pathutil"
    19  	"github.com/jmigpin/editor/util/testutil"
    20  	"golang.org/x/tools/txtar"
    21  )
    22  
    23  func TestScripts(t *testing.T) {
    24  	scr := testutil.NewScript(os.Args)
    25  
    26  	// uncomment to access work dir
    27  	//scr.Work = true
    28  
    29  	scr.ScriptsDir = "testdata"
    30  	scr.Cmds = []*testutil.ScriptCmd{
    31  		&testutil.ScriptCmd{"godebugtester", godebugTester},
    32  	}
    33  	scr.Run(t)
    34  }
    35  func godebugTester(t *testing.T, args []string) error {
    36  	log.SetFlags(0)
    37  	log.SetPrefix("godebugtester: ")
    38  
    39  	args = args[1:]
    40  
    41  	cmd := NewCmd()
    42  
    43  	dir, _ := os.Getwd()
    44  	cmd.Dir = dir
    45  
    46  	ctx := context.Background()
    47  	done, err := cmd.Start(ctx, args)
    48  	if err != nil {
    49  		return err
    50  	}
    51  	if done { // ex: "build", "-help"
    52  		return nil
    53  	}
    54  
    55  	wg := sync.WaitGroup{}
    56  	wg.Add(1)
    57  	go func() {
    58  		defer wg.Done()
    59  		// util func
    60  		add := func(s string) {
    61  			fmt.Printf("recv: %v\n", s)
    62  		}
    63  		for msg := range cmd.Messages() {
    64  			switch mt := msg.(type) {
    65  			case *debug.LineMsg:
    66  				add(StringifyItem(mt.Item))
    67  			case []*debug.LineMsg:
    68  				for _, m := range mt {
    69  					add(StringifyItem(m.Item))
    70  				}
    71  			default:
    72  				add(fmt.Sprintf("(%T)%v", msg, msg))
    73  			}
    74  		}
    75  	}()
    76  
    77  	err = cmd.Wait()
    78  	wg.Wait()
    79  	return err
    80  }
    81  
    82  //----------
    83  //----------
    84  //----------
    85  
    86  func TestAnnotator(t *testing.T) {
    87  	testsFilename := "testdata/annotator/annotator_in_out.txt"
    88  	ar, err := txtar.ParseFile(testsFilename)
    89  	if err != nil {
    90  		t.Fatal()
    91  	}
    92  
    93  	// map files
    94  	m := map[string]txtar.File{}
    95  	for _, file := range ar.Files {
    96  		m[file.Name] = file
    97  	}
    98  
    99  	countLines := func(b []byte) int {
   100  		return bytes.Count(b, []byte("\n"))
   101  	}
   102  
   103  	line := countLines(ar.Comment) + 1 // start at line 1
   104  	nextLines := 0
   105  	for iar, file := range ar.Files {
   106  		line += nextLines
   107  		nextLines = countLines(file.Data) + 1 // add name line
   108  
   109  		// only start a test with a ".in" ext
   110  		if !strings.HasSuffix(file.Name, ".in") {
   111  			continue
   112  		}
   113  		// find ".out"
   114  		outName := pathutil.ReplaceExt(file.Name, ".out")
   115  		file2, ok := m[outName]
   116  		if !ok {
   117  			t.Logf("warning: missing *.out for %v", file.Name)
   118  			continue
   119  		}
   120  
   121  		name := filepath.Base(file.Name)
   122  		ok2 := t.Run(name, func(t2 *testing.T) {
   123  			if err := testAnnotator2(t2, name, file.Data, file2.Data, testsFilename, line, ar, iar+1); err != nil {
   124  				t2.Fatal(err)
   125  			}
   126  		})
   127  		if !ok2 {
   128  			break // stop on first failed test
   129  		}
   130  	}
   131  }
   132  func testAnnotator2(t *testing.T, name string, in, out []byte, filename string, line int, ar *txtar.Archive, iarOut int) error {
   133  	t.Logf("name: %v\n", name)
   134  
   135  	fset := token.NewFileSet()
   136  
   137  	// parse input ast
   138  	mode := parser.ParseComments
   139  	astFile, err := parser.ParseFile(fset, "a.go", in, mode)
   140  	if err != nil {
   141  		return err
   142  	}
   143  
   144  	// annotate
   145  	ann := NewAnnotator(fset)
   146  	ann.simpleTestMode = true
   147  	ann.debugPkgName = "Σ"   // expected by tests
   148  	ann.debugVarPrefix = "Σ" // expected by tests
   149  
   150  	_, _, _ = testutil.CollectLog(t, func() error {
   151  		// TODO: types and other? anntype?
   152  		ann.AnnotateAstFile(astFile)
   153  		return nil
   154  	})
   155  
   156  	// output result to string for comparison
   157  	res := ann.sprintNode(astFile)
   158  	//_ := parseutil.TrimLineSpaces(res) // old way of comparing
   159  
   160  	fail := res != string(out)
   161  
   162  	overwrite := false
   163  	if !overwrite {
   164  		// use after flag "--":
   165  		// ex: go test -run=Annotator -- -overwriteoutput=TestAnnotator1.in
   166  		v, ok := flagutil.GetFlagString(os.Args, "owout")
   167  		overwrite = ok && v == name
   168  	}
   169  	if !overwrite {
   170  		v := flagutil.GetFlagBool(os.Args, "owoutFirstFail")
   171  		overwrite = v && fail
   172  	}
   173  	continueOnOverwrite := false
   174  	if !overwrite {
   175  		v := flagutil.GetFlagBool(os.Args, "owoutAllFail")
   176  		overwrite = v && fail
   177  		if overwrite {
   178  			continueOnOverwrite = true
   179  		}
   180  	}
   181  	if overwrite {
   182  		fmt.Printf("overwriting output for test: %v\n", name)
   183  		ar.Files[iarOut].Data = []byte(res)
   184  		b := txtar.Format(ar)
   185  		//fmt.Println(string(b)) // DEBUG
   186  		if err := os.WriteFile(filename, b, 0o644); err != nil {
   187  			return err
   188  		}
   189  		if continueOnOverwrite {
   190  			return nil
   191  		}
   192  		return fmt.Errorf("tests file overwriten")
   193  	}
   194  
   195  	if fail {
   196  		location := fmt.Sprintf("%s:%d", filename, line)
   197  		err := fmt.Errorf(""+ //"\n"+
   198  			"%s\n"+
   199  			"-- input --\n%s"+ // has ending newline (go fmt)
   200  			"-- result --\n%s"+ // has ending newline (go fmt)
   201  			"-- expected --\n%s", // has ending newline (go fmt)
   202  			location, in, res, out)
   203  		return err
   204  	}
   205  	return nil
   206  }