Skip to content

Commit 50f77eb

Browse files
kostyaAry Borenszweig
authored and
Ary Borenszweig
committedDec 20, 2016
split spec files, for custom usage
1 parent 306ef6d commit 50f77eb

File tree

3 files changed

+208
-206
lines changed

3 files changed

+208
-206
lines changed
 

‎src/spec.cr

+1-176
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
require "colorize"
2-
require "option_parser"
3-
require "signal"
1+
require "./spec/dsl"
42

53
# Crystal's builtin testing library.
64
#
@@ -65,179 +63,6 @@ require "signal"
6563
# ```
6664
# crystal spec spec/my/test/file_spec.cr:14
6765
# ```
68-
module Spec
69-
private COLORS = {
70-
success: :green,
71-
fail: :red,
72-
error: :red,
73-
pending: :yellow,
74-
}
75-
76-
private LETTERS = {
77-
success: '.',
78-
fail: 'F',
79-
error: 'E',
80-
pending: '*',
81-
}
82-
83-
@@use_colors = true
84-
85-
# :nodoc:
86-
def self.color(str, status)
87-
if use_colors?
88-
str.colorize(COLORS[status])
89-
else
90-
str
91-
end
92-
end
93-
94-
# :nodoc:
95-
def self.use_colors?
96-
@@use_colors
97-
end
98-
99-
# :nodoc:
100-
def self.use_colors=(@@use_colors)
101-
end
102-
103-
# :nodoc:
104-
class AssertionFailed < Exception
105-
getter file : String
106-
getter line : Int32
107-
108-
def initialize(message, @file, @line)
109-
super(message)
110-
end
111-
end
112-
113-
@@aborted = false
114-
115-
# :nodoc:
116-
def self.abort!
117-
exit
118-
end
119-
120-
# :nodoc:
121-
def self.pattern=(pattern)
122-
@@pattern = Regex.new(Regex.escape(pattern))
123-
end
124-
125-
# :nodoc:
126-
def self.line=(@@line : Int32)
127-
end
128-
129-
# :nodoc:
130-
def self.slowest=(@@slowest : Int32)
131-
end
132-
133-
# :nodoc:
134-
def self.slowest
135-
@@slowest
136-
end
137-
138-
# :nodoc:
139-
def self.to_human(span : Time::Span)
140-
total_milliseconds = span.total_milliseconds
141-
if total_milliseconds < 1
142-
return "#{(span.total_milliseconds * 1000).round.to_i} microseconds"
143-
end
144-
145-
total_seconds = span.total_seconds
146-
if total_seconds < 1
147-
return "#{span.total_milliseconds.round(2)} milliseconds"
148-
end
149-
150-
if total_seconds < 60
151-
return "#{total_seconds.round(2)} seconds"
152-
end
153-
154-
minutes = span.minutes
155-
seconds = span.seconds
156-
"#{minutes}:#{seconds < 10 ? "0" : ""}#{seconds} minutes"
157-
end
158-
159-
# :nodoc:
160-
def self.add_location(file, line)
161-
locations = @@locations ||= {} of String => Array(Int32)
162-
lines = locations[File.expand_path(file)] ||= [] of Int32
163-
lines << line
164-
end
165-
166-
# :nodoc:
167-
def self.matches?(description, file, line, end_line = line)
168-
spec_pattern = @@pattern
169-
spec_line = @@line
170-
locations = @@locations
171-
172-
# When a method invokes `it` and only forwards line information,
173-
# not end_line information (this can happen in code before we
174-
# introduced the end_line feature) then running a spec by giving
175-
# a line won't work because end_line might be located before line.
176-
# So, we also check `line == spec_line` to somehow preserve
177-
# backwards compatibility.
178-
if spec_line && (line == spec_line || line <= spec_line <= end_line)
179-
return true
180-
end
181-
182-
if locations
183-
lines = locations[file]?
184-
return true if lines && lines.any? { |l| line == l || line <= l <= end_line }
185-
end
186-
187-
if spec_pattern || spec_line || locations
188-
Spec::RootContext.matches?(description, spec_pattern, spec_line, locations)
189-
else
190-
true
191-
end
192-
end
193-
194-
@@fail_fast = false
195-
196-
# :nodoc:
197-
def self.fail_fast=(@@fail_fast)
198-
end
199-
200-
# :nodoc:
201-
def self.fail_fast?
202-
@@fail_fast
203-
end
204-
205-
# Instructs the spec runner to execute the given block
206-
# before each spec, regardless of where this method is invoked.
207-
def self.before_each(&block)
208-
before_each = @@before_each ||= [] of ->
209-
before_each << block
210-
end
211-
212-
# Instructs the spec runner to execute the given block
213-
# after each spec, regardless of where this method is invoked.
214-
def self.after_each(&block)
215-
after_each = @@after_each ||= [] of ->
216-
after_each << block
217-
end
218-
219-
# :nodoc:
220-
def self.run_before_each_hooks
221-
@@before_each.try &.each &.call
222-
end
223-
224-
# :nodoc:
225-
def self.run_after_each_hooks
226-
@@after_each.try &.each &.call
227-
end
228-
229-
# :nodoc:
230-
def self.run
231-
start_time = Time.now
232-
at_exit do
233-
elapsed_time = Time.now - start_time
234-
Spec::RootContext.print_results(elapsed_time)
235-
exit 1 unless Spec::RootContext.succeeded
236-
end
237-
end
238-
end
239-
240-
require "./spec/*"
24166

24267
OptionParser.parse! do |opts|
24368
opts.banner = "crystal spec runner"

‎src/spec/dsl.cr

+159-30
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,177 @@
1-
module Spec::DSL
2-
def describe(description, file = __FILE__, line = __LINE__, &block)
3-
Spec::RootContext.describe(description.to_s, file, line, &block)
1+
require "colorize"
2+
require "option_parser"
3+
require "signal"
4+
5+
module Spec
6+
private COLORS = {
7+
success: :green,
8+
fail: :red,
9+
error: :red,
10+
pending: :yellow,
11+
}
12+
13+
private LETTERS = {
14+
success: '.',
15+
fail: 'F',
16+
error: 'E',
17+
pending: '*',
18+
}
19+
20+
@@use_colors = true
21+
22+
# :nodoc:
23+
def self.color(str, status)
24+
if use_colors?
25+
str.colorize(COLORS[status])
26+
else
27+
str
28+
end
429
end
530

6-
def context(description, file = __FILE__, line = __LINE__, &block)
7-
describe(description.to_s, file, line, &block)
31+
# :nodoc:
32+
def self.use_colors?
33+
@@use_colors
834
end
935

10-
def it(description, file = __FILE__, line = __LINE__, end_line = __END_LINE__, &block)
11-
return unless Spec.matches?(description, file, line, end_line)
36+
# :nodoc:
37+
def self.use_colors=(@@use_colors)
38+
end
1239

13-
Spec.formatters.each(&.before_example(description))
40+
# :nodoc:
41+
class AssertionFailed < Exception
42+
getter file : String
43+
getter line : Int32
1444

15-
start = Time.now
16-
begin
17-
Spec.run_before_each_hooks
18-
block.call
19-
Spec::RootContext.report(:success, description, file, line, Time.now - start)
20-
rescue ex : Spec::AssertionFailed
21-
Spec::RootContext.report(:fail, description, file, line, Time.now - start, ex)
22-
Spec.abort! if Spec.fail_fast?
23-
rescue ex
24-
Spec::RootContext.report(:error, description, file, line, Time.now - start, ex)
25-
Spec.abort! if Spec.fail_fast?
26-
ensure
27-
Spec.run_after_each_hooks
45+
def initialize(message, @file, @line)
46+
super(message)
2847
end
2948
end
3049

31-
def pending(description, file = __FILE__, line = __LINE__, end_line = __END_LINE__, &block)
32-
return unless Spec.matches?(description, file, line, end_line)
50+
@@aborted = false
51+
52+
# :nodoc:
53+
def self.abort!
54+
exit
55+
end
56+
57+
# :nodoc:
58+
def self.pattern=(pattern)
59+
@@pattern = Regex.new(Regex.escape(pattern))
60+
end
61+
62+
# :nodoc:
63+
def self.line=(@@line : Int32)
64+
end
3365

34-
Spec.formatters.each(&.before_example(description))
66+
# :nodoc:
67+
def self.slowest=(@@slowest : Int32)
68+
end
3569

36-
Spec::RootContext.report(:pending, description, file, line)
70+
# :nodoc:
71+
def self.slowest
72+
@@slowest
3773
end
3874

39-
def assert(file = __FILE__, line = __LINE__, end_line = __END_LINE__, &block)
40-
it("assert", file, line, end_line, &block)
75+
# :nodoc:
76+
def self.to_human(span : Time::Span)
77+
total_milliseconds = span.total_milliseconds
78+
if total_milliseconds < 1
79+
return "#{(span.total_milliseconds * 1000).round.to_i} microseconds"
80+
end
81+
82+
total_seconds = span.total_seconds
83+
if total_seconds < 1
84+
return "#{span.total_milliseconds.round(2)} milliseconds"
85+
end
86+
87+
if total_seconds < 60
88+
return "#{total_seconds.round(2)} seconds"
89+
end
90+
91+
minutes = span.minutes
92+
seconds = span.seconds
93+
"#{minutes}:#{seconds < 10 ? "0" : ""}#{seconds} minutes"
4194
end
4295

43-
def fail(msg, file = __FILE__, line = __LINE__)
44-
raise Spec::AssertionFailed.new(msg, file, line)
96+
# :nodoc:
97+
def self.add_location(file, line)
98+
locations = @@locations ||= {} of String => Array(Int32)
99+
lines = locations[File.expand_path(file)] ||= [] of Int32
100+
lines << line
101+
end
102+
103+
# :nodoc:
104+
def self.matches?(description, file, line, end_line = line)
105+
spec_pattern = @@pattern
106+
spec_line = @@line
107+
locations = @@locations
108+
109+
# When a method invokes `it` and only forwards line information,
110+
# not end_line information (this can happen in code before we
111+
# introduced the end_line feature) then running a spec by giving
112+
# a line won't work because end_line might be located before line.
113+
# So, we also check `line == spec_line` to somehow preserve
114+
# backwards compatibility.
115+
if spec_line && (line == spec_line || line <= spec_line <= end_line)
116+
return true
117+
end
118+
119+
if locations
120+
lines = locations[file]?
121+
return true if lines && lines.any? { |l| line == l || line <= l <= end_line }
122+
end
123+
124+
if spec_pattern || spec_line || locations
125+
Spec::RootContext.matches?(description, spec_pattern, spec_line, locations)
126+
else
127+
true
128+
end
129+
end
130+
131+
@@fail_fast = false
132+
133+
# :nodoc:
134+
def self.fail_fast=(@@fail_fast)
135+
end
136+
137+
# :nodoc:
138+
def self.fail_fast?
139+
@@fail_fast
140+
end
141+
142+
# Instructs the spec runner to execute the given block
143+
# before each spec, regardless of where this method is invoked.
144+
def self.before_each(&block)
145+
before_each = @@before_each ||= [] of ->
146+
before_each << block
147+
end
148+
149+
# Instructs the spec runner to execute the given block
150+
# after each spec, regardless of where this method is invoked.
151+
def self.after_each(&block)
152+
after_each = @@after_each ||= [] of ->
153+
after_each << block
154+
end
155+
156+
# :nodoc:
157+
def self.run_before_each_hooks
158+
@@before_each.try &.each &.call
159+
end
160+
161+
# :nodoc:
162+
def self.run_after_each_hooks
163+
@@after_each.try &.each &.call
164+
end
165+
166+
# :nodoc:
167+
def self.run
168+
start_time = Time.now
169+
at_exit do
170+
elapsed_time = Time.now - start_time
171+
Spec::RootContext.print_results(elapsed_time)
172+
exit 1 unless Spec::RootContext.succeeded
173+
end
45174
end
46175
end
47176

48-
include Spec::DSL
177+
require "./*"

‎src/spec/methods.cr

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
module Spec::Methods
2+
def describe(description, file = __FILE__, line = __LINE__, &block)
3+
Spec::RootContext.describe(description.to_s, file, line, &block)
4+
end
5+
6+
def context(description, file = __FILE__, line = __LINE__, &block)
7+
describe(description.to_s, file, line, &block)
8+
end
9+
10+
def it(description, file = __FILE__, line = __LINE__, end_line = __END_LINE__, &block)
11+
return unless Spec.matches?(description, file, line, end_line)
12+
13+
Spec.formatters.each(&.before_example(description))
14+
15+
start = Time.now
16+
begin
17+
Spec.run_before_each_hooks
18+
block.call
19+
Spec::RootContext.report(:success, description, file, line, Time.now - start)
20+
rescue ex : Spec::AssertionFailed
21+
Spec::RootContext.report(:fail, description, file, line, Time.now - start, ex)
22+
Spec.abort! if Spec.fail_fast?
23+
rescue ex
24+
Spec::RootContext.report(:error, description, file, line, Time.now - start, ex)
25+
Spec.abort! if Spec.fail_fast?
26+
ensure
27+
Spec.run_after_each_hooks
28+
end
29+
end
30+
31+
def pending(description, file = __FILE__, line = __LINE__, end_line = __END_LINE__, &block)
32+
return unless Spec.matches?(description, file, line, end_line)
33+
34+
Spec.formatters.each(&.before_example(description))
35+
36+
Spec::RootContext.report(:pending, description, file, line)
37+
end
38+
39+
def assert(file = __FILE__, line = __LINE__, end_line = __END_LINE__, &block)
40+
it("assert", file, line, end_line, &block)
41+
end
42+
43+
def fail(msg, file = __FILE__, line = __LINE__)
44+
raise Spec::AssertionFailed.new(msg, file, line)
45+
end
46+
end
47+
48+
include Spec::Methods

0 commit comments

Comments
 (0)
Please sign in to comment.