Skip to content

Commit 29fefdf

Browse files
committed
Introduce stdlib specs
These specs are written in Lit itself. While the test runner is not great and we don't have imports yet, it is enough to test the language in a real world scenario. As the language evolves, it will be rewritten in more idiomatic ways
1 parent 81793b1 commit 29fefdf

File tree

2 files changed

+254
-0
lines changed

2 files changed

+254
-0
lines changed

spec/stdlib/array.lit

Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
type TestRunner {
2+
init {
3+
self.tests = []
4+
self.current_group = nil
5+
}
6+
7+
fn test { |name, block|
8+
self.tests.push({ name: name, block: block })
9+
}
10+
11+
fn describe { |group_name, group_block|
12+
self.current_group = group_name
13+
group_block(self)
14+
self
15+
}
16+
17+
fn run {
18+
let start_time = clock()
19+
var failed_tests = []
20+
var tests_without_assertions = []
21+
22+
self.tests.each(fn { |t|
23+
let result = t[:block](Should())
24+
25+
if result && result[:ok] == false {
26+
print("F")
27+
failed_tests.push({ name: "{self.current_group} {t[:name]}", message: result[:message] })
28+
} else {
29+
if result {
30+
print(".")
31+
} else {
32+
print("?")
33+
tests_without_assertions.push(t[:name])
34+
}
35+
}
36+
})
37+
38+
println()
39+
40+
failed_tests.each(fn { |f|
41+
println()
42+
println("{f[:name]}:")
43+
println(" {f[:message]}")
44+
})
45+
let end_time = clock()
46+
let elapsed = end_time - start_time
47+
var total_time = ""
48+
if elapsed < 1 {
49+
total_time = "{elapsed * 1000}ms"
50+
} else {
51+
total_time = "{elapsed}s"
52+
}
53+
54+
println()
55+
println("Finished in {total_time}")
56+
print("{self.tests.size()} examples, {failed_tests.size()} failures")
57+
if tests_without_assertions.size() > 0 {
58+
println(", {tests_without_assertions.size()} without assertions")
59+
} else {
60+
println()
61+
}
62+
63+
let status = if failed_tests.is_empty?() do 0 else do 1
64+
exit(status)
65+
}
66+
}
67+
68+
type Should {
69+
init {
70+
self.negated = false
71+
}
72+
73+
fn not {
74+
let s = Should()
75+
s.negated = !self.negated
76+
return s
77+
}
78+
79+
fn eq { |actual, expected|
80+
let ok = actual == expected
81+
82+
if self.negated {
83+
if ok {
84+
return self.fail("Did not expect {expected}, but got {actual}")
85+
}
86+
} else {
87+
if !ok {
88+
return self.fail("Expected {expected}, got {actual}")
89+
}
90+
}
91+
92+
return self.pass()
93+
}
94+
95+
fn greater_than { |actual, value|
96+
let ok = actual > value
97+
98+
if self.negated {
99+
if ok {
100+
return self.fail("Expected {actual} to not be greater than {value}")
101+
}
102+
} else {
103+
if !ok {
104+
return self.fail("Expected {actual} to be greater than {value}")
105+
}
106+
}
107+
108+
return self.pass()
109+
}
110+
111+
fn greater_than_or_equal { |actual, value|
112+
let ok = actual >= value
113+
114+
if self.negated {
115+
if ok {
116+
return self.fail("Expected {actual} to not be >= {value}")
117+
}
118+
} else {
119+
if !ok {
120+
return self.fail("Expected {actual} to be >= {value}")
121+
}
122+
}
123+
124+
self.pass()
125+
}
126+
127+
fn less_than { |actual, value|
128+
let ok = actual < value
129+
130+
if self.negated {
131+
if ok {
132+
return self.fail("Expected {actual} to not be less than {value}")
133+
}
134+
} else {
135+
if !ok {
136+
return self.fail("Expected {actual} to be less than {value}")
137+
}
138+
}
139+
140+
self.pass()
141+
}
142+
143+
fn less_than_or_equal { |actual, value|
144+
let ok = actual <= value
145+
146+
if self.negated {
147+
if ok {
148+
return self.fail("Expected {actual} to not be <= {value}")
149+
}
150+
} else {
151+
if !ok {
152+
return self.fail("Expected {actual} to be <= {value}")
153+
}
154+
}
155+
156+
self.pass()
157+
}
158+
159+
fn include { |actual, item|
160+
let ok = actual.includes?(item)
161+
162+
if self.negated {
163+
if ok {
164+
return self.fail("Expected {actual} to not include {item}")
165+
}
166+
} else {
167+
if !ok {
168+
return self.fail("Expected {actual} to include {item}")
169+
}
170+
}
171+
172+
self.pass()
173+
}
174+
175+
fn have_size { |actual, expected_size|
176+
let len = actual.size()
177+
let ok = len == expected_size
178+
179+
if self.negated {
180+
if ok {
181+
return self.fail("Expected size to not be {expected_size}, but got {len}")
182+
}
183+
} else {
184+
if !ok {
185+
return self.fail("Expected size {expected_size}, got {len}")
186+
}
187+
}
188+
189+
self.pass()
190+
}
191+
192+
fn be_empty { |actual|
193+
let ok = actual.size() == 0
194+
195+
if self.negated {
196+
if ok {
197+
return self.fail("Expected {inspect(actual)} not to be empty")
198+
}
199+
} else {
200+
if !ok {
201+
return self.fail("Expected {inspect(actual)} to be empty")
202+
}
203+
}
204+
205+
self.pass()
206+
}
207+
208+
fn be_of_type { |actual, expected_type|
209+
let t = typeof(actual)
210+
let ok = t == expected_type
211+
212+
if self.negated {
213+
if ok {
214+
return self.fail("Expected {actual} to not be of type {expected_type}")
215+
}
216+
} else {
217+
if !ok {
218+
return self.fail("Expected {actual} to be of type {expected_type}, but got {t}")
219+
}
220+
}
221+
222+
self.pass()
223+
}
224+
225+
fn pass do {ok: true, message: ""}
226+
fn fail do {ok: false, message: it}
227+
}
228+
229+
230+
TestRunner().
231+
describe("Lit Array", fn { |t|
232+
t.test("is_empty? when array is empty", fn { |should|
233+
[].is_empty?() |> should.eq(true)
234+
})
235+
t.test("is_empty? when array is not empty", fn { |should|
236+
[1].is_empty?() |> should.eq(false)
237+
})
238+
}).
239+
run()

spec/stdlib_spec.cr

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
require "./spec_helper"
2+
3+
describe "stdlib tests", tags: "e2e" do
4+
test_files = Dir.glob("spec/stdlib/**/*.lit").sort!
5+
6+
test_files.each do |file|
7+
it "interprets #{file} correctly" do
8+
status, output = run_lit(file)
9+
10+
unless status.success?
11+
fail "Failed spec:\n#{output}"
12+
end
13+
end
14+
end
15+
end

0 commit comments

Comments
 (0)