main (test): add tests to tinygo test
				
					
				
			Этот коммит содержится в:
		
							родитель
							
								
									21b89ef327
								
							
						
					
					
						коммит
						d86dd642b3
					
				
					 6 изменённых файлов: 234 добавлений и 46 удалений
				
			
		
							
								
								
									
										238
									
								
								main_test.go
									
										
									
									
									
								
							
							
						
						
									
										238
									
								
								main_test.go
									
										
									
									
									
								
							|  | @ -9,12 +9,14 @@ import ( | |||
| 	"errors" | ||||
| 	"flag" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"os/exec" | ||||
| 	"path/filepath" | ||||
| 	"runtime" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| 
 | ||||
|  | @ -27,7 +29,11 @@ const TESTDATA = "testdata" | |||
| 
 | ||||
| var testTarget = flag.String("target", "", "override test target") | ||||
| 
 | ||||
| func TestCompiler(t *testing.T) { | ||||
| var sema = make(chan struct{}, runtime.NumCPU()) | ||||
| 
 | ||||
| func TestBuild(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	tests := []string{ | ||||
| 		"alias.go", | ||||
| 		"atomic.go", | ||||
|  | @ -62,8 +68,6 @@ func TestCompiler(t *testing.T) { | |||
| 		tests = append(tests, "go1.17.go") | ||||
| 	} | ||||
| 
 | ||||
| 	sema := make(chan struct{}, runtime.NumCPU()) | ||||
| 
 | ||||
| 	if *testTarget != "" { | ||||
| 		// This makes it possible to run one specific test (instead of all), | ||||
| 		// which is especially useful to quickly check whether some changes | ||||
|  | @ -84,41 +88,29 @@ func TestCompiler(t *testing.T) { | |||
| 		// Test with few optimizations enabled (no inlining, etc). | ||||
| 		t.Run("opt=1", func(t *testing.T) { | ||||
| 			t.Parallel() | ||||
| 			runTestWithConfig("stdlib.go", t, compileopts.Options{ | ||||
| 				GOOS:      goenv.Get("GOOS"), | ||||
| 				GOARCH:    goenv.Get("GOARCH"), | ||||
| 				GOARM:     goenv.Get("GOARM"), | ||||
| 				Opt:       "1", | ||||
| 				Semaphore: sema, | ||||
| 			}, nil, nil) | ||||
| 			opts := optionsFromTarget("", sema) | ||||
| 			opts.Opt = "1" | ||||
| 			runTestWithConfig("stdlib.go", t, opts, nil, nil) | ||||
| 		}) | ||||
| 
 | ||||
| 		// Test with only the bare minimum of optimizations enabled. | ||||
| 		// TODO: fix this for stdlib.go, which currently fails. | ||||
| 		t.Run("opt=0", func(t *testing.T) { | ||||
| 			t.Parallel() | ||||
| 			runTestWithConfig("print.go", t, compileopts.Options{ | ||||
| 				GOOS:      goenv.Get("GOOS"), | ||||
| 				GOARCH:    goenv.Get("GOARCH"), | ||||
| 				GOARM:     goenv.Get("GOARM"), | ||||
| 				Opt:       "0", | ||||
| 				Semaphore: sema, | ||||
| 			}, nil, nil) | ||||
| 			opts := optionsFromTarget("", sema) | ||||
| 			opts.Opt = "0" | ||||
| 			runTestWithConfig("print.go", t, opts, nil, nil) | ||||
| 		}) | ||||
| 
 | ||||
| 		t.Run("ldflags", func(t *testing.T) { | ||||
| 			t.Parallel() | ||||
| 			runTestWithConfig("ldflags.go", t, compileopts.Options{ | ||||
| 				GOOS:   goenv.Get("GOOS"), | ||||
| 				GOARCH: goenv.Get("GOARCH"), | ||||
| 				GOARM:  goenv.Get("GOARM"), | ||||
| 				GlobalValues: map[string]map[string]string{ | ||||
| 			opts := optionsFromTarget("", sema) | ||||
| 			opts.GlobalValues = map[string]map[string]string{ | ||||
| 				"main": { | ||||
| 					"someGlobal": "foobar", | ||||
| 				}, | ||||
| 				}, | ||||
| 				Semaphore: sema, | ||||
| 			}, nil, nil) | ||||
| 			} | ||||
| 			runTestWithConfig("ldflags.go", t, opts, nil, nil) | ||||
| 		}) | ||||
| 	}) | ||||
| 
 | ||||
|  | @ -211,22 +203,12 @@ func TestCompiler(t *testing.T) { | |||
| } | ||||
| 
 | ||||
| func runPlatTests(options compileopts.Options, tests []string, t *testing.T) { | ||||
| 	// Check if the emulator is installed. | ||||
| 	emuCheck(t, options) | ||||
| 
 | ||||
| 	spec, err := compileopts.LoadTarget(&options) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("failed to load target spec:", err) | ||||
| 	} | ||||
| 	if len(spec.Emulator) != 0 { | ||||
| 		_, err := exec.LookPath(spec.Emulator[0]) | ||||
| 		if err != nil { | ||||
| 			if errors.Is(err, exec.ErrNotFound) { | ||||
| 				t.Skipf("emulator not installed: %q", spec.Emulator[0]) | ||||
| 			} | ||||
| 
 | ||||
| 			t.Errorf("searching for emulator: %v", err) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	for _, name := range tests { | ||||
| 		name := name // redefine to avoid race condition | ||||
|  | @ -263,6 +245,25 @@ func runPlatTests(options compileopts.Options, tests []string, t *testing.T) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func emuCheck(t *testing.T, options compileopts.Options) { | ||||
| 	// Check if the emulator is installed. | ||||
| 	spec, err := compileopts.LoadTarget(&options) | ||||
| 	if err != nil { | ||||
| 		t.Fatal("failed to load target spec:", err) | ||||
| 	} | ||||
| 	if len(spec.Emulator) != 0 { | ||||
| 		_, err := exec.LookPath(spec.Emulator[0]) | ||||
| 		if err != nil { | ||||
| 			if errors.Is(err, exec.ErrNotFound) { | ||||
| 				t.Skipf("emulator not installed: %q", spec.Emulator[0]) | ||||
| 			} | ||||
| 
 | ||||
| 			t.Errorf("searching for emulator: %v", err) | ||||
| 			return | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func optionsFromTarget(target string, sema chan struct{}) compileopts.Options { | ||||
| 	return compileopts.Options{ | ||||
| 		// GOOS/GOARCH are only used if target == "" | ||||
|  | @ -271,6 +272,9 @@ func optionsFromTarget(target string, sema chan struct{}) compileopts.Options { | |||
| 		GOARM:     goenv.Get("GOARM"), | ||||
| 		Target:    target, | ||||
| 		Semaphore: sema, | ||||
| 		Debug:     true, | ||||
| 		VerifyIR:  true, | ||||
| 		Opt:       "z", | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -283,6 +287,9 @@ func optionsFromOSARCH(osarch string, sema chan struct{}) compileopts.Options { | |||
| 		GOOS:      parts[0], | ||||
| 		GOARCH:    parts[1], | ||||
| 		Semaphore: sema, | ||||
| 		Debug:     true, | ||||
| 		VerifyIR:  true, | ||||
| 		Opt:       "z", | ||||
| 	} | ||||
| 	if options.GOARCH == "arm" { | ||||
| 		options.GOARM = parts[2] | ||||
|  | @ -295,13 +302,6 @@ func runTest(name string, options compileopts.Options, t *testing.T, cmdArgs, en | |||
| } | ||||
| 
 | ||||
| func runTestWithConfig(name string, t *testing.T, options compileopts.Options, cmdArgs, environmentVars []string) { | ||||
| 	// Set default config. | ||||
| 	options.Debug = true | ||||
| 	options.VerifyIR = true | ||||
| 	if options.Opt == "" { | ||||
| 		options.Opt = "z" | ||||
| 	} | ||||
| 
 | ||||
| 	// Get the expected output for this test. | ||||
| 	// Note: not using filepath.Join as it strips the path separator at the end | ||||
| 	// of the path. | ||||
|  | @ -466,6 +466,156 @@ func runTestWithConfig(name string, t *testing.T, options compileopts.Options, c | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestTest(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 
 | ||||
| 	type targ struct { | ||||
| 		name string | ||||
| 		opts compileopts.Options | ||||
| 	} | ||||
| 	targs := []targ{ | ||||
| 		// Host | ||||
| 		{"Host", optionsFromTarget("", sema)}, | ||||
| 	} | ||||
| 	if !testing.Short() { | ||||
| 		if runtime.GOOS == "linux" { | ||||
| 			targs = append(targs, | ||||
| 				// Linux | ||||
| 				targ{"X86Linux", optionsFromOSARCH("linux/386", sema)}, | ||||
| 				targ{"ARMLinux", optionsFromOSARCH("linux/arm/6", sema)}, | ||||
| 				targ{"ARM64Linux", optionsFromOSARCH("linux/arm64", sema)}, | ||||
| 			) | ||||
| 		} | ||||
| 
 | ||||
| 		targs = append(targs, | ||||
| 			// QEMU microcontrollers | ||||
| 			targ{"EmulatedCortexM3", optionsFromTarget("cortex-m-qemu", sema)}, | ||||
| 			targ{"EmulatedRISCV", optionsFromTarget("riscv-qemu", sema)}, | ||||
| 
 | ||||
| 			// Node/Wasmtime | ||||
| 			targ{"WASM", optionsFromTarget("wasm", sema)}, | ||||
| 			targ{"WASI", optionsFromTarget("wasi", sema)}, | ||||
| 		) | ||||
| 	} | ||||
| 	for _, targ := range targs { | ||||
| 		targ := targ | ||||
| 		t.Run(targ.name, func(t *testing.T) { | ||||
| 			t.Parallel() | ||||
| 
 | ||||
| 			emuCheck(t, targ.opts) | ||||
| 
 | ||||
| 			t.Run("Pass", func(t *testing.T) { | ||||
| 				t.Parallel() | ||||
| 
 | ||||
| 				// Test a package which builds and passes normally. | ||||
| 
 | ||||
| 				var wg sync.WaitGroup | ||||
| 				defer wg.Wait() | ||||
| 
 | ||||
| 				out := ioLogger(t, &wg) | ||||
| 				defer out.Close() | ||||
| 
 | ||||
| 				opts := targ.opts | ||||
| 				passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/pass", out, out, &opts, false, false, false, "", "") | ||||
| 				if err != nil { | ||||
| 					t.Errorf("test error: %v", err) | ||||
| 				} | ||||
| 				if !passed { | ||||
| 					t.Error("test failed") | ||||
| 				} | ||||
| 			}) | ||||
| 
 | ||||
| 			t.Run("Fail", func(t *testing.T) { | ||||
| 				t.Parallel() | ||||
| 
 | ||||
| 				// Test a package which builds fine but fails. | ||||
| 
 | ||||
| 				var wg sync.WaitGroup | ||||
| 				defer wg.Wait() | ||||
| 
 | ||||
| 				out := ioLogger(t, &wg) | ||||
| 				defer out.Close() | ||||
| 
 | ||||
| 				opts := targ.opts | ||||
| 				passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/fail", out, out, &opts, false, false, false, "", "") | ||||
| 				if err != nil { | ||||
| 					t.Errorf("test error: %v", err) | ||||
| 				} | ||||
| 				if passed { | ||||
| 					t.Error("test passed") | ||||
| 				} | ||||
| 			}) | ||||
| 
 | ||||
| 			if targ.name != "Host" { | ||||
| 				// Emulated tests are somewhat slow, and these do not need to be run across every platform. | ||||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 			t.Run("Nothing", func(t *testing.T) { | ||||
| 				t.Parallel() | ||||
| 
 | ||||
| 				// Test a package with no test files. | ||||
| 
 | ||||
| 				var wg sync.WaitGroup | ||||
| 				defer wg.Wait() | ||||
| 
 | ||||
| 				out := ioLogger(t, &wg) | ||||
| 				defer out.Close() | ||||
| 
 | ||||
| 				var output bytes.Buffer | ||||
| 				opts := targ.opts | ||||
| 				passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/nothing", io.MultiWriter(&output, out), out, &opts, false, false, false, "", "") | ||||
| 				if err != nil { | ||||
| 					t.Errorf("test error: %v", err) | ||||
| 				} | ||||
| 				if !passed { | ||||
| 					t.Error("test failed") | ||||
| 				} | ||||
| 				if !strings.Contains(output.String(), "[no test files]") { | ||||
| 					t.Error("missing [no test files] in output") | ||||
| 				} | ||||
| 			}) | ||||
| 
 | ||||
| 			t.Run("BuildErr", func(t *testing.T) { | ||||
| 				t.Parallel() | ||||
| 
 | ||||
| 				// Test a package which fails to build. | ||||
| 
 | ||||
| 				var wg sync.WaitGroup | ||||
| 				defer wg.Wait() | ||||
| 
 | ||||
| 				out := ioLogger(t, &wg) | ||||
| 				defer out.Close() | ||||
| 
 | ||||
| 				opts := targ.opts | ||||
| 				passed, err := Test("github.com/tinygo-org/tinygo/tests/testing/builderr", out, out, &opts, false, false, false, "", "") | ||||
| 				if err == nil { | ||||
| 					t.Error("test did not error") | ||||
| 				} | ||||
| 				if passed { | ||||
| 					t.Error("test passed") | ||||
| 				} | ||||
| 			}) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func ioLogger(t *testing.T, wg *sync.WaitGroup) io.WriteCloser { | ||||
| 	r, w := io.Pipe() | ||||
| 	wg.Add(1) | ||||
| 	go func() { | ||||
| 		defer wg.Done() | ||||
| 		defer r.Close() | ||||
| 
 | ||||
| 		scanner := bufio.NewScanner(r) | ||||
| 		for scanner.Scan() { | ||||
| 			t.Log(scanner.Text()) | ||||
| 		} | ||||
| 	}() | ||||
| 
 | ||||
| 	return w | ||||
| } | ||||
| 
 | ||||
| // This TestMain is necessary because TinyGo may also be invoked to run certain | ||||
| // LLVM tools in a separate process. Not capturing these invocations would lead | ||||
| // to recursive tests. | ||||
|  |  | |||
							
								
								
									
										10
									
								
								tests/testing/builderr/builderr.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										10
									
								
								tests/testing/builderr/builderr.go
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,10 @@ | |||
| package builderr | ||||
| 
 | ||||
| import _ "unsafe" | ||||
| 
 | ||||
| //go:linkname x notARealFunction | ||||
| func x() | ||||
| 
 | ||||
| func Thing() { | ||||
| 	x() | ||||
| } | ||||
							
								
								
									
										11
									
								
								tests/testing/builderr/builderr_test.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										11
									
								
								tests/testing/builderr/builderr_test.go
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,11 @@ | |||
| package builderr_test | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/tinygo-org/tinygo/tests/testing/builderr" | ||||
| ) | ||||
| 
 | ||||
| func TestThing(t *testing.T) { | ||||
| 	builderr.Thing() | ||||
| } | ||||
							
								
								
									
										7
									
								
								tests/testing/fail/fail_test.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										7
									
								
								tests/testing/fail/fail_test.go
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,7 @@ | |||
| package fail_test | ||||
| 
 | ||||
| import "testing" | ||||
| 
 | ||||
| func TestFail(t *testing.T) { | ||||
| 	t.Error("fail") | ||||
| } | ||||
							
								
								
									
										3
									
								
								tests/testing/nothing/nothing.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										3
									
								
								tests/testing/nothing/nothing.go
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,3 @@ | |||
| package nothing | ||||
| 
 | ||||
| // This package has no tests. | ||||
							
								
								
									
										7
									
								
								tests/testing/pass/pass_test.go
									
										
									
									
									
										Обычный файл
									
								
							
							
						
						
									
										7
									
								
								tests/testing/pass/pass_test.go
									
										
									
									
									
										Обычный файл
									
								
							|  | @ -0,0 +1,7 @@ | |||
| package pass_test | ||||
| 
 | ||||
| import "testing" | ||||
| 
 | ||||
| func TestPass(t *testing.T) { | ||||
| 	// This test passes. | ||||
| } | ||||
		Загрузка…
	
	Создание таблицы
		
		Сослаться в новой задаче
	
	 Nia Waldvogel
						Nia Waldvogel