-
Notifications
You must be signed in to change notification settings - Fork 0
/
main_test.go
152 lines (135 loc) · 3.68 KB
/
main_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
package main
import (
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"strings"
"testing"
)
var regex = regexp.MustCompile("^.*?//\\sEXPECT:\\s(.*)$")
type expectation struct {
val string
line int
}
func TestPanic(t *testing.T) {
files, err := filepath.Glob("./tests/panic/*.clara")
if err != nil {
log.Fatal(err)
}
// Process each test case
for _, f := range files {
t.Run(filepath.Base(f), func(t *testing.T) {
f := f
t.Parallel()
expects := ParseExpectations(f, t)
if len(expects) != 1 {
t.Fatalf("Only one expectation allowed for panic tests - found %d\n", len(expects))
}
expect := expects[0]
out := CompileAndRun(f, t, true)
if !strings.Contains(out, expect.val) {
t.Errorf("\n- ./%v:\n - contains: '%v'\n - got : '%v'\n", f, expect.val, out)
}
})
}
}
func TestE2E(t *testing.T) {
files, err := filepath.Glob("./tests/*.clara")
if err != nil {
log.Fatal(err)
}
// Process each test case
for _, f := range files {
t.Run(filepath.Base(f), func(t *testing.T) {
f := f
t.Parallel()
expects := ParseExpectations(f, t)
// Compile test, execute test & parse output
output := CompileAndRun(f, t, false)
lines := strings.Split(output, "\n")
lines = lines[:len(lines)-1] // Trim empty final line
// Match output against expectations
pos := 0
var builder strings.Builder
for _, expect := range expects {
if pos < len(lines) {
if expect.val != lines[pos] {
builder.WriteString(fmt.Sprintf("- ./%v:%d:, expected: '%v', got: '%v'\n", f, expect.line, expect.val, lines[pos]))
}
} else {
builder.WriteString(fmt.Sprintf("- ./%v:%d:, expected: '%v', got: <nothing>\n", f, expect.line, expect.val))
}
pos += 1
}
if pos < len(lines) {
builder.WriteString(fmt.Sprintf(" - ./%v:, expected: <nothing>, got: ['%v']\n", f, strings.Join(lines[pos:], "', '")))
}
if builder.Len() > 0 {
t.Errorf("\n%v\n", builder.String())
}
})
}
}
func CompileAndRun(progPath string, t *testing.T, allowExecErr bool) string {
defer func() {
if r := recover(); r != nil {
t.Fatalf("\nCompiler Crash: %s\n", progPath)
}
}()
// Compile program
binary, errs := Compile(
options{}, // Defaults
glob("./install/lib/*.clara"),
progPath,
glob("./install/init/*.c"),
os.TempDir(),
ioutil.Discard)
if len(errs) > 0 {
buf := bytes.NewBufferString("\n\nCompilation failure(s):\n")
for _, err := range errs {
buf.WriteString(fmt.Sprintf("\n%v", err))
}
buf.WriteString("\n────────────────────────────────────────────────────────────────────────────────────────")
t.Fatalf(buf.String())
}
defer os.Remove(binary)
// Always set var
err := os.Setenv("CLARA_ENV_KEY", "CLARA_ENV_VAL")
if err != nil {
t.Fatalf("Execution failure: %v\n", err)
}
// Execute binary
cmd := exec.Command(binary)
outBytes, err := cmd.CombinedOutput()
out := string(outBytes)
if err != nil && !allowExecErr {
t.Log(out)
t.Fatalf("Execution failure: %v\n", err)
}
return out
}
func ParseExpectations(filename string, t *testing.T) []*expectation {
// Read file
content, err := ioutil.ReadFile(filename)
if err != nil {
t.Fatal(err)
}
steps := strings.Split(string(content), "\n")
// Gather all expectations
var expects []*expectation
for i, step := range steps {
if strings.HasPrefix(step, "//") { // Skip commented out lines
continue
}
match := regex.FindStringSubmatch(step)
if match != nil {
expects = append(expects, &expectation{val: match[1], line: i+1})
}
}
return expects
}