motion-spec 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/.codeclimate.yml +12 -0
- data/.gitignore +38 -0
- data/.rubocop.yml +58 -0
- data/.travis.yml +18 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +21 -0
- data/LICENSE +23 -0
- data/README.md +37 -0
- data/Rakefile +14 -0
- data/app/app_delegate.rb +6 -0
- data/lib/motion-spec.rb +77 -0
- data/lib/motion-spec/context.rb +135 -0
- data/lib/motion-spec/core.rb +92 -0
- data/lib/motion-spec/error.rb +11 -0
- data/lib/motion-spec/extensions/boolean.rb +13 -0
- data/lib/motion-spec/extensions/exception.rb +2 -0
- data/lib/motion-spec/extensions/kernel.rb +13 -0
- data/lib/motion-spec/extensions/numeric.rb +6 -0
- data/lib/motion-spec/extensions/object.rb +6 -0
- data/lib/motion-spec/extensions/proc.rb +25 -0
- data/lib/motion-spec/output/colorized.rb +36 -0
- data/lib/motion-spec/output/fast.rb +21 -0
- data/lib/motion-spec/output/knock.rb +23 -0
- data/lib/motion-spec/output/ruby_mine.rb +86 -0
- data/lib/motion-spec/output/spec_dox.rb +30 -0
- data/lib/motion-spec/output/tap.rb +39 -0
- data/lib/motion-spec/output/test_unit.rb +24 -0
- data/lib/motion-spec/platform.rb +8 -0
- data/lib/motion-spec/should.rb +88 -0
- data/lib/motion-spec/specification.rb +208 -0
- data/lib/motion-spec/version.rb +5 -0
- data/motion-spec.gemspec +21 -0
- metadata +104 -0
@@ -0,0 +1,92 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
# MotionSpec is built off of MacBacon, which is derived from Bacon, which is a
|
3
|
+
# micro-port of Rspec. See the LICENSE for core contributors and copyright years
|
4
|
+
|
5
|
+
module MotionSpec
|
6
|
+
DEFAULT_OUTPUT_MODULE = SpecDoxOutput
|
7
|
+
|
8
|
+
Counter = Hash.new(0)
|
9
|
+
ErrorLog = ''
|
10
|
+
Shared = Hash.new { |_, name|
|
11
|
+
raise NameError, "no such context: #{name.inspect}"
|
12
|
+
}
|
13
|
+
|
14
|
+
RestrictName = // unless defined? RestrictName
|
15
|
+
RestrictContext = // unless defined? RestrictContext
|
16
|
+
|
17
|
+
Backtraces = true unless defined? Backtraces
|
18
|
+
|
19
|
+
Outputs = {
|
20
|
+
'spec_dox' => SpecDoxOutput,
|
21
|
+
'fast' => FastOutput,
|
22
|
+
'test_unit' => TestUnitOutput,
|
23
|
+
'tap' => TapOutput,
|
24
|
+
'knock' => KnockOutput,
|
25
|
+
'rubymine' => RubyMineOutput,
|
26
|
+
'colorized' => ColorizedOutput
|
27
|
+
}
|
28
|
+
|
29
|
+
def self.add_context(context)
|
30
|
+
(@contexts ||= []) << context
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.current_context_index
|
34
|
+
@current_context_index ||= 0
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.current_context
|
38
|
+
@contexts[current_context_index]
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.run(arg = nil)
|
42
|
+
unless respond_to?(:handle_specification_begin)
|
43
|
+
extend(Outputs[ENV['output']] || DEFAULT_OUTPUT_MODULE)
|
44
|
+
end
|
45
|
+
|
46
|
+
@timer ||= Time.now
|
47
|
+
|
48
|
+
if Platform.android?
|
49
|
+
@main_activity ||= arg
|
50
|
+
|
51
|
+
@contexts.each { |context| execute_context(context) }
|
52
|
+
return handle_summary
|
53
|
+
end
|
54
|
+
|
55
|
+
Counter[:context_depth] += 1
|
56
|
+
handle_specification_begin(current_context.name)
|
57
|
+
current_context.performSelector('run', withObject: nil, afterDelay: 0)
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.execute_context(context)
|
61
|
+
unless respond_to?(:handle_specification_begin)
|
62
|
+
extend(Outputs[ENV['output']] || DEFAULT_OUTPUT_MODULE)
|
63
|
+
end
|
64
|
+
|
65
|
+
Counter[:context_depth] += 1
|
66
|
+
handle_specification_begin(context.name)
|
67
|
+
context.run
|
68
|
+
handle_specification_end
|
69
|
+
Counter[:context_depth] -= 1
|
70
|
+
end
|
71
|
+
|
72
|
+
# Android-only.
|
73
|
+
def self.main_activity
|
74
|
+
@main_activity
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.context_did_finish(context)
|
78
|
+
return if Platform.android?
|
79
|
+
|
80
|
+
handle_specification_end
|
81
|
+
|
82
|
+
Counter[:context_depth] -= 1
|
83
|
+
|
84
|
+
if (@current_context_index + 1) < @contexts.size
|
85
|
+
@current_context_index += 1
|
86
|
+
return run
|
87
|
+
end
|
88
|
+
|
89
|
+
handle_summary
|
90
|
+
exit(Counter.values_at(:failed, :errors).inject(:+))
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module Kernel
|
3
|
+
private
|
4
|
+
|
5
|
+
def describe(*args, &block)
|
6
|
+
MotionSpec::Context.new(args.join(' '), &block)
|
7
|
+
end
|
8
|
+
alias_method :context, :describe
|
9
|
+
|
10
|
+
def shared(name, &block)
|
11
|
+
MotionSpec::Shared[name] = block
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
class Proc
|
3
|
+
def raise?(*exceptions)
|
4
|
+
call
|
5
|
+
rescue *(exceptions.empty? ? RuntimeError : exceptions) => e
|
6
|
+
e
|
7
|
+
else
|
8
|
+
false
|
9
|
+
end
|
10
|
+
|
11
|
+
def throw?(sym)
|
12
|
+
catch(sym) {
|
13
|
+
call
|
14
|
+
return false
|
15
|
+
}
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
def change?
|
20
|
+
pre_result = yield
|
21
|
+
call
|
22
|
+
post_result = yield
|
23
|
+
pre_result != post_result
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module MotionSpec
|
3
|
+
module ColorizedOutput
|
4
|
+
GREEN = "\033[0;32m"
|
5
|
+
RED = "\033[0;31m"
|
6
|
+
RESET = "\033[00m"
|
7
|
+
|
8
|
+
def handle_specification_begin(name); end
|
9
|
+
def handle_specification_end; end
|
10
|
+
|
11
|
+
def handle_requirement_begin(description); end
|
12
|
+
|
13
|
+
def handle_requirement_end(error)
|
14
|
+
if error.empty?
|
15
|
+
print "#{GREEN}.#{RESET}"
|
16
|
+
else
|
17
|
+
print "#{RED}#{error[0..0]}#{RESET}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def handle_summary
|
22
|
+
puts ''
|
23
|
+
puts '', ErrorLog if Backtraces && !ErrorLog.empty?
|
24
|
+
|
25
|
+
duration = '%0.2f' % (Time.now - @timer)
|
26
|
+
puts '', "Finished in #{duration} seconds."
|
27
|
+
|
28
|
+
failure = Counter[:errors] > 0 || Counter[:failed] > 0
|
29
|
+
color = failure ? RED : GREEN
|
30
|
+
|
31
|
+
puts "#{color}%d tests, %d assertions, %d failures, %d errors#{RESET}" %
|
32
|
+
Counter.values_at(:specifications, :requirements, :failed, :errors)
|
33
|
+
puts ''
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module MotionSpec
|
3
|
+
module FastOutput
|
4
|
+
def handle_specification_begin(name); end
|
5
|
+
def handle_specification_end; end
|
6
|
+
|
7
|
+
def handle_requirement_begin(description); end
|
8
|
+
|
9
|
+
def handle_requirement_end(error)
|
10
|
+
return if error.empty?
|
11
|
+
print error[0..0]
|
12
|
+
end
|
13
|
+
|
14
|
+
def handle_summary
|
15
|
+
puts '', "Finished in #{Time.now - @timer} seconds."
|
16
|
+
puts ErrorLog if Backtraces
|
17
|
+
puts '%d tests, %d assertions, %d failures, %d errors' %
|
18
|
+
Counter.values_at(:specifications, :requirements, :failed, :errors)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module MotionSpec
|
3
|
+
module KnockOutput
|
4
|
+
def handle_specification_begin(name); end
|
5
|
+
def handle_specification_end; end
|
6
|
+
|
7
|
+
def handle_requirement_begin(description)
|
8
|
+
@description = description
|
9
|
+
ErrorLog.replace ''
|
10
|
+
end
|
11
|
+
|
12
|
+
def handle_requirement_end(error)
|
13
|
+
if error.empty?
|
14
|
+
puts 'ok - %s' % [@description]
|
15
|
+
else
|
16
|
+
puts 'not ok - %s: %s' % [@description, error]
|
17
|
+
puts ErrorLog.strip.gsub(/^/, '# ') if Backtraces
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def handle_summary; end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module MotionSpec
|
3
|
+
module RubyMineOutput
|
4
|
+
@@entered = false
|
5
|
+
@@description = nil
|
6
|
+
@@specification = nil
|
7
|
+
@@started = nil
|
8
|
+
|
9
|
+
def handle_specification_begin(name)
|
10
|
+
unless @@entered
|
11
|
+
puts "##teamcity[enteredTheMatrix timestamp = '#{java_time}']\n\n"
|
12
|
+
@@entered = true
|
13
|
+
end
|
14
|
+
@@specification = name
|
15
|
+
puts "##teamcity[testSuiteStarted timestamp = '#{java_time}' name = '#{escape_message(name)}']\n\n"
|
16
|
+
end
|
17
|
+
|
18
|
+
def handle_specification_end
|
19
|
+
puts "##teamcity[testSuiteFinished timestamp = '#{java_time}' name = '#{escape_message(@@specification)}']\n\n" if Counter[:context_depth] == 1
|
20
|
+
end
|
21
|
+
|
22
|
+
def handle_requirement_begin(description)
|
23
|
+
@@description = description
|
24
|
+
@@started = Time.now
|
25
|
+
puts "##teamcity[testStarted timestamp = '#{java_time}' captureStandardOutput = 'true' name = '#{escape_message(description)}']\n\n"
|
26
|
+
end
|
27
|
+
|
28
|
+
def handle_requirement_end(error)
|
29
|
+
if !error.empty?
|
30
|
+
puts "##teamcity[testFailed timestamp = '#{java_time}' message = '#{escape_message(error)}' name = '#{escape_message(@@description)}']\n\n"
|
31
|
+
end
|
32
|
+
duration = ((Time.now - @@started) * 1000).to_i
|
33
|
+
puts "##teamcity[testFinished timestamp = '#{java_time}' duration = '#{duration}' name = '#{escape_message(@@description)}']\n\n"
|
34
|
+
end
|
35
|
+
|
36
|
+
def handle_summary
|
37
|
+
print ErrorLog if Backtraces
|
38
|
+
puts '%d specifications (%d requirements), %d failures, %d errors' %
|
39
|
+
Counter.values_at(:specifications, :requirements, :failed, :errors)
|
40
|
+
end
|
41
|
+
|
42
|
+
def spaces
|
43
|
+
' ' * (Counter[:context_depth] - 1)
|
44
|
+
end
|
45
|
+
|
46
|
+
def java_time
|
47
|
+
convert_time_to_java_simple_date(Time.now)
|
48
|
+
end
|
49
|
+
|
50
|
+
def escape_message(message)
|
51
|
+
copy_of_text = String.new(message)
|
52
|
+
|
53
|
+
copy_of_text.gsub!(/\|/, '||')
|
54
|
+
|
55
|
+
copy_of_text.gsub!(/'/, "|'")
|
56
|
+
copy_of_text.gsub!(/\n/, '|n')
|
57
|
+
copy_of_text.gsub!(/\r/, '|r')
|
58
|
+
copy_of_text.gsub!(/\]/, '|]')
|
59
|
+
|
60
|
+
copy_of_text.gsub!(/\[/, '|[')
|
61
|
+
|
62
|
+
begin
|
63
|
+
copy_of_text.encode!('UTF-8') if copy_of_text.respond_to? :encode!
|
64
|
+
copy_of_text.gsub!(/\u0085/, '|x') # next line
|
65
|
+
copy_of_text.gsub!(/\u2028/, '|l') # line separator
|
66
|
+
copy_of_text.gsub!(/\u2029/, '|p') # paragraph separator
|
67
|
+
rescue
|
68
|
+
# it is not an utf-8 compatible string :(
|
69
|
+
end
|
70
|
+
|
71
|
+
copy_of_text
|
72
|
+
end
|
73
|
+
|
74
|
+
def convert_time_to_java_simple_date(time)
|
75
|
+
gmt_offset = time.gmt_offset
|
76
|
+
gmt_sign = gmt_offset < 0 ? '-' : '+'
|
77
|
+
gmt_hours = gmt_offset.abs / 3600
|
78
|
+
gmt_minutes = gmt_offset.abs % 3600
|
79
|
+
|
80
|
+
millisec = time.usec == 0 ? 0 : time.usec / 1000
|
81
|
+
|
82
|
+
# Time string in Java SimpleDateFormat
|
83
|
+
sprintf("#{time.strftime('%Y-%m-%dT%H:%M:%S.')}%03d#{gmt_sign}%02d%02d", millisec, gmt_hours, gmt_minutes)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module MotionSpec
|
3
|
+
module SpecDoxOutput
|
4
|
+
def handle_specification_begin(name)
|
5
|
+
puts spaces + name
|
6
|
+
end
|
7
|
+
|
8
|
+
def handle_specification_end
|
9
|
+
puts if Counter[:context_depth] == 1
|
10
|
+
end
|
11
|
+
|
12
|
+
def handle_requirement_begin(description)
|
13
|
+
print "#{spaces} - #{description}"
|
14
|
+
end
|
15
|
+
|
16
|
+
def handle_requirement_end(error)
|
17
|
+
puts error.empty? ? '' : " [#{error}]"
|
18
|
+
end
|
19
|
+
|
20
|
+
def handle_summary
|
21
|
+
print ErrorLog if Backtraces
|
22
|
+
puts '%d specifications (%d requirements), %d failures, %d errors' %
|
23
|
+
Counter.values_at(:specifications, :requirements, :failed, :errors)
|
24
|
+
end
|
25
|
+
|
26
|
+
def spaces
|
27
|
+
' ' * (Counter[:context_depth] - 1)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module MotionSpec
|
3
|
+
module TapOutput
|
4
|
+
@@count = 1
|
5
|
+
@@describe = ''
|
6
|
+
|
7
|
+
def handle_specification_begin(name)
|
8
|
+
@@describe << "#{name} "
|
9
|
+
end
|
10
|
+
|
11
|
+
def handle_specification_end
|
12
|
+
@@describe = ''
|
13
|
+
end
|
14
|
+
|
15
|
+
def handle_requirement_begin(description)
|
16
|
+
@description = @@describe + description
|
17
|
+
@description.sub!(/^[#\s]+/, '')
|
18
|
+
ErrorLog.replace ''
|
19
|
+
end
|
20
|
+
|
21
|
+
def handle_requirement_end(error)
|
22
|
+
if error.empty?
|
23
|
+
puts 'ok %-3d - %s' % [@@count, @description]
|
24
|
+
else
|
25
|
+
puts 'not ok %d - %s: %s' %
|
26
|
+
[@@count, @description, error]
|
27
|
+
puts ErrorLog.strip.gsub(/^/, '# ') if Backtraces
|
28
|
+
end
|
29
|
+
|
30
|
+
@@count += 1
|
31
|
+
end
|
32
|
+
|
33
|
+
def handle_summary
|
34
|
+
puts "1..#{Counter[:specifications]}"
|
35
|
+
puts '# %d tests, %d assertions, %d failures, %d errors' %
|
36
|
+
Counter.values_at(:specifications, :requirements, :failed, :errors)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
module MotionSpec
|
3
|
+
module TestUnitOutput
|
4
|
+
def handle_specification_begin(name); end
|
5
|
+
def handle_specification_end; end
|
6
|
+
|
7
|
+
def handle_requirement_begin(description); end
|
8
|
+
|
9
|
+
def handle_requirement_end(error)
|
10
|
+
if error.empty?
|
11
|
+
print '.'
|
12
|
+
else
|
13
|
+
print error[0..0]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def handle_summary
|
18
|
+
puts '', "Finished in #{Time.now - @timer} seconds."
|
19
|
+
puts ErrorLog if Backtraces
|
20
|
+
puts '%d tests, %d assertions, %d failures, %d errors' %
|
21
|
+
Counter.values_at(:specifications, :requirements, :failed, :errors)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|