Home | History | Annotate | Download | only in errors
      1 // Copyright 2017 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package errorstest
      6 
      7 import (
      8 	"bytes"
      9 	"fmt"
     10 	"io/ioutil"
     11 	"os"
     12 	"os/exec"
     13 	"path/filepath"
     14 	"regexp"
     15 	"strconv"
     16 	"strings"
     17 	"testing"
     18 )
     19 
     20 func path(file string) string {
     21 	return filepath.Join("src", file)
     22 }
     23 
     24 func check(t *testing.T, file string) {
     25 	t.Run(file, func(t *testing.T) {
     26 		t.Parallel()
     27 
     28 		contents, err := ioutil.ReadFile(path(file))
     29 		if err != nil {
     30 			t.Fatal(err)
     31 		}
     32 		var errors []*regexp.Regexp
     33 		for i, line := range bytes.Split(contents, []byte("\n")) {
     34 			if bytes.HasSuffix(line, []byte("ERROR HERE")) {
     35 				re := regexp.MustCompile(regexp.QuoteMeta(fmt.Sprintf("%s:%d:", file, i+1)))
     36 				errors = append(errors, re)
     37 				continue
     38 			}
     39 
     40 			frags := bytes.SplitAfterN(line, []byte("ERROR HERE: "), 2)
     41 			if len(frags) == 1 {
     42 				continue
     43 			}
     44 			re, err := regexp.Compile(string(frags[1]))
     45 			if err != nil {
     46 				t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frags[1])
     47 				continue
     48 			}
     49 			errors = append(errors, re)
     50 		}
     51 		if len(errors) == 0 {
     52 			t.Fatalf("cannot find ERROR HERE")
     53 		}
     54 		expect(t, file, errors)
     55 	})
     56 }
     57 
     58 func expect(t *testing.T, file string, errors []*regexp.Regexp) {
     59 	dir, err := ioutil.TempDir("", filepath.Base(t.Name()))
     60 	if err != nil {
     61 		t.Fatal(err)
     62 	}
     63 	defer os.RemoveAll(dir)
     64 
     65 	dst := filepath.Join(dir, strings.TrimSuffix(file, ".go"))
     66 	cmd := exec.Command("go", "build", "-gcflags=-L", "-o="+dst, path(file)) // TODO(gri) no need for -gcflags=-L if go tool is adjusted
     67 	out, err := cmd.CombinedOutput()
     68 	if err == nil {
     69 		t.Errorf("expected cgo to fail but it succeeded")
     70 	}
     71 
     72 	lines := bytes.Split(out, []byte("\n"))
     73 	for _, re := range errors {
     74 		found := false
     75 		for _, line := range lines {
     76 			if re.Match(line) {
     77 				t.Logf("found match for %#q: %q", re, line)
     78 				found = true
     79 				break
     80 			}
     81 		}
     82 		if !found {
     83 			t.Errorf("expected error output to contain %#q", re)
     84 		}
     85 	}
     86 
     87 	if t.Failed() {
     88 		t.Logf("actual output:\n%s", out)
     89 	}
     90 }
     91 
     92 func sizeofLongDouble(t *testing.T) int {
     93 	cmd := exec.Command("go", "run", path("long_double_size.go"))
     94 	out, err := cmd.CombinedOutput()
     95 	if err != nil {
     96 		t.Fatalf("%#q: %v:\n%s", strings.Join(cmd.Args, " "), err, out)
     97 	}
     98 
     99 	i, err := strconv.Atoi(strings.TrimSpace(string(out)))
    100 	if err != nil {
    101 		t.Fatalf("long_double_size.go printed invalid size: %s", out)
    102 	}
    103 	return i
    104 }
    105 
    106 func TestReportsTypeErrors(t *testing.T) {
    107 	for _, file := range []string{
    108 		"err1.go",
    109 		"err2.go",
    110 		"err3.go",
    111 		"issue7757.go",
    112 		"issue8442.go",
    113 		"issue11097a.go",
    114 		"issue11097b.go",
    115 		"issue13129.go",
    116 		"issue13423.go",
    117 		"issue13467.go",
    118 		"issue13635.go",
    119 		"issue13830.go",
    120 		"issue16116.go",
    121 		"issue16591.go",
    122 		"issue18452.go",
    123 		"issue18889.go",
    124 	} {
    125 		check(t, file)
    126 	}
    127 
    128 	if sizeofLongDouble(t) > 8 {
    129 		check(t, "err4.go")
    130 	}
    131 }
    132 
    133 func TestToleratesOptimizationFlag(t *testing.T) {
    134 	for _, cflags := range []string{
    135 		"",
    136 		"-O",
    137 	} {
    138 		cflags := cflags
    139 		t.Run(cflags, func(t *testing.T) {
    140 			t.Parallel()
    141 
    142 			cmd := exec.Command("go", "build", path("issue14669.go"))
    143 			cmd.Env = append(os.Environ(), "CGO_CFLAGS="+cflags)
    144 			out, err := cmd.CombinedOutput()
    145 			if err != nil {
    146 				t.Errorf("%#q: %v:\n%s", strings.Join(cmd.Args, " "), err, out)
    147 			}
    148 		})
    149 	}
    150 }
    151 
    152 func TestMallocCrashesOnNil(t *testing.T) {
    153 	t.Parallel()
    154 
    155 	cmd := exec.Command("go", "run", path("malloc.go"))
    156 	out, err := cmd.CombinedOutput()
    157 	if err == nil {
    158 		t.Logf("%#q:\n%s", strings.Join(cmd.Args, " "), out)
    159 		t.Fatalf("succeeded unexpectedly")
    160 	}
    161 }
    162