motion-spec 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,11 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ class Error < RuntimeError
4
+ attr_accessor :count_as
5
+
6
+ def initialize(count_as, message)
7
+ @count_as = count_as
8
+ super message
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,13 @@
1
+ # -*- encoding : utf-8 -*-
2
+ class Object
3
+ def true?; false; end
4
+ def false?; false; end
5
+ end
6
+
7
+ class TrueClass
8
+ def true?; true; end
9
+ end
10
+
11
+ class FalseClass
12
+ def false?; true; end
13
+ end
@@ -0,0 +1,2 @@
1
+ # -*- encoding : utf-8 -*-
2
+ Exception.log_exceptions = false if Exception.respond_to? :log_exceptions
@@ -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,6 @@
1
+ # -*- encoding : utf-8 -*-
2
+ class Numeric
3
+ def close?(to, delta)
4
+ (to.to_f - self).abs <= delta.to_f rescue false
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ # -*- encoding : utf-8 -*-
2
+ class Object
3
+ def should(*args, &block)
4
+ MotionSpec::Should.new(self).be(*args, &block)
5
+ end
6
+ 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