1
2
3
4
5 package constraints
6
7 import (
8 "fmt"
9 "os"
10 "os/exec"
11 "path/filepath"
12 "regexp"
13 "runtime"
14 "testing"
15 )
16
17 type (
18 testSigned[T Signed] struct{ f T }
19 testUnsigned[T Unsigned] struct{ f T }
20 testInteger[T Integer] struct{ f T }
21 testFloat[T Float] struct{ f T }
22 testComplex[T Complex] struct{ f T }
23 testOrdered[T Ordered] struct{ f T }
24 )
25
26
27 type TestTypes struct {
28 _ testSigned[int]
29 _ testSigned[int64]
30 _ testUnsigned[uint]
31 _ testUnsigned[uintptr]
32 _ testInteger[int8]
33 _ testInteger[uint8]
34 _ testInteger[uintptr]
35 _ testFloat[float32]
36 _ testComplex[complex64]
37 _ testOrdered[int]
38 _ testOrdered[float64]
39 _ testOrdered[string]
40 }
41
42 var prolog = []byte(`
43 package constrainttest
44
45 import "golang.org/x/exp/constraints"
46
47 type (
48 testSigned[T constraints.Signed] struct{ f T }
49 testUnsigned[T constraints.Unsigned] struct{ f T }
50 testInteger[T constraints.Integer] struct{ f T }
51 testFloat[T constraints.Float] struct{ f T }
52 testComplex[T constraints.Complex] struct{ f T }
53 testOrdered[T constraints.Ordered] struct{ f T }
54 )
55 `)
56
57 func TestFailure(t *testing.T) {
58 switch runtime.GOOS {
59 case "android", "js", "ios":
60 t.Skipf("can't run go tool on %s", runtime.GOOS)
61 }
62
63 var exeSuffix string
64 if runtime.GOOS == "windows" {
65 exeSuffix = ".exe"
66 }
67 gocmd := filepath.Join(runtime.GOROOT(), "bin", "go"+exeSuffix)
68 if _, err := os.Stat(gocmd); err != nil {
69 t.Skipf("skipping because can't stat %s: %v", gocmd, err)
70 }
71
72 tmpdir := t.TempDir()
73
74 cwd, err := os.Getwd()
75 if err != nil {
76 t.Fatal(err)
77 }
78
79
80 expModDir := filepath.Dir(cwd)
81
82 modFile := fmt.Sprintf(`module constraintest
83
84 go 1.18
85
86 replace golang.org/x/exp => %s
87 `, expModDir)
88 if err := os.WriteFile(filepath.Join(tmpdir, "go.mod"), []byte(modFile), 0666); err != nil {
89 t.Fatal(err)
90 }
91
92
93
94
95
96 if err := os.WriteFile(filepath.Join(tmpdir, "prolog.go"), []byte(prolog), 0666); err != nil {
97 t.Fatal(err)
98 }
99
100 tidyCmd := exec.Command(gocmd, "mod", "tidy")
101 tidyCmd.Dir = tmpdir
102 tidyCmd.Env = append(os.Environ(), "PWD="+tmpdir)
103 if out, err := tidyCmd.CombinedOutput(); err != nil {
104 t.Fatalf("%v: %v\n%s", tidyCmd, err, out)
105 } else {
106 t.Logf("%v:\n%s", tidyCmd, out)
107 }
108
109
110
111
112
113
114
115
116
117 for i, test := range []struct {
118 constraint, typ string
119 }{
120 {"testSigned", "uint"},
121 {"testUnsigned", "int"},
122 {"testInteger", "float32"},
123 {"testFloat", "int8"},
124 {"testComplex", "float64"},
125 {"testOrdered", "bool"},
126 } {
127 i := i
128 test := test
129 t.Run(fmt.Sprintf("%s %d", test.constraint, i), func(t *testing.T) {
130 t.Parallel()
131 name := fmt.Sprintf("go%d.go", i)
132 f, err := os.Create(filepath.Join(tmpdir, name))
133 if err != nil {
134 t.Fatal(err)
135 }
136 if _, err := f.Write(prolog); err != nil {
137 t.Fatal(err)
138 }
139 if _, err := fmt.Fprintf(f, "var V %s[%s]\n", test.constraint, test.typ); err != nil {
140 t.Fatal(err)
141 }
142 if err := f.Close(); err != nil {
143 t.Fatal(err)
144 }
145 cmd := exec.Command(gocmd, "build", name)
146 cmd.Dir = tmpdir
147 if out, err := cmd.CombinedOutput(); err == nil {
148 t.Error("build succeeded, but expected to fail")
149 } else if len(out) > 0 {
150 t.Logf("%s", out)
151 if !wantRx.Match(out) {
152 t.Errorf("output does not match %q", wantRx)
153 }
154 } else {
155 t.Error("no error output, expected something")
156 }
157 })
158 }
159 }
160
161 var wantRx = regexp.MustCompile("does not (implement|satisfy)")
162
View as plain text