github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/monitor_test.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "os/exec" 6 "path/filepath" 7 "runtime" 8 "testing" 9 "time" 10 11 "github.com/tinygo-org/tinygo/builder" 12 "github.com/tinygo-org/tinygo/compileopts" 13 ) 14 15 func TestTraceback(t *testing.T) { 16 if runtime.GOOS != "linux" { 17 // We care about testing the ELF format, which is only used on Linux 18 // (not on MacOS or Windows). 19 t.Skip("Test only works on Linux") 20 } 21 22 // Build a small binary that only panics. 23 tmpdir := t.TempDir() 24 config, err := builder.NewConfig(&compileopts.Options{ 25 GOOS: runtime.GOOS, 26 GOARCH: runtime.GOARCH, 27 Opt: "z", 28 InterpTimeout: time.Minute, 29 Debug: true, 30 }) 31 if err != nil { 32 t.Fatal(err) 33 } 34 result, err := builder.Build("testdata/trivialpanic.go", ".elf", tmpdir, config) 35 if err != nil { 36 t.Fatal(err) 37 } 38 39 // Run this binary, and capture the output. 40 buf := &bytes.Buffer{} 41 cmd := exec.Command(result.Binary) 42 cmd.Stdout = buf 43 cmd.Stderr = buf 44 cmd.Run() // this will return an error because of the panic, ignore it 45 46 // Extract the "runtime error at" address. 47 line := bytes.TrimSpace(buf.Bytes()) 48 address := extractPanicAddress(line) 49 if address == 0 { 50 t.Fatalf("could not extract panic address from %#v", string(line)) 51 } 52 53 // Look up the source location for this address. 54 location, err := addressToLine(result.Executable, address) 55 if err != nil { 56 t.Fatal("could not read source location:", err) 57 } 58 59 // Verify that the source location is as expected. 60 if filepath.Base(location.Filename) != "trivialpanic.go" { 61 t.Errorf("expected path to end with trivialpanic.go, got %#v", location.Filename) 62 } 63 if location.Line != 6 { 64 t.Errorf("expected panic location to be line 6, got line %d", location.Line) 65 } 66 }