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,8 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ class Platform
4
+ def self.android?
5
+ defined?(NSObject) ? false : true
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,88 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ class Should
4
+ # Kills ==, ===, =~, eql?, equal?, frozen?, instance_of?, is_a?,
5
+ # kind_of?, nil?, respond_to?, tainted?
6
+ #
7
+ # The reason that these methods are killed is so that method_missing
8
+ # will catch them and push them through `satisfy`. The satisfy method
9
+ # handles chaining and negation (eg .should.not.eq).
10
+ instance_methods.each { |name| undef_method name if name =~ /\?|^\W+$/ }
11
+
12
+ def initialize(object)
13
+ @object = object
14
+ @negated = false
15
+ end
16
+
17
+ def not(*args, &block)
18
+ @negated = !@negated
19
+
20
+ return self if args.empty?
21
+
22
+ be(*args, &block)
23
+ end
24
+
25
+ def be(*args, &block)
26
+ return self if args.empty?
27
+
28
+ block = args.shift unless block_given?
29
+ satisfy(*args, &block)
30
+ end
31
+ alias_method :a, :be
32
+ alias_method :an, :be
33
+
34
+ def satisfy(*args, &block)
35
+ if args.size == 1 && String === args.first
36
+ description = args.shift
37
+ else
38
+ description = ''
39
+ end
40
+
41
+ result = yield(@object, *args)
42
+
43
+ if Counter[:depth] > 0
44
+ Counter[:requirements] += 1
45
+ flunk(description) unless @negated ^ result
46
+ result
47
+ else
48
+ @negated ? !result : !!result
49
+ end
50
+ end
51
+
52
+ def method_missing(name, *args, &block)
53
+ name = "#{name}?" if name.to_s =~ /\w[^?]\z/
54
+
55
+ desc = @negated ? 'not ' : ''
56
+ desc << @object.inspect << '.' << name.to_s
57
+ desc << '(' << args.map(&:inspect).join(', ') << ') failed'
58
+
59
+ satisfy(desc) do |object|
60
+ object.__send__(name, *args, &block)
61
+ end
62
+ end
63
+
64
+ def equal(value)
65
+ self == value
66
+ end
67
+ alias_method :eq, :equal
68
+
69
+ def match(value)
70
+ self =~ value
71
+ end
72
+
73
+ def identical_to(value)
74
+ self.equal? value
75
+ end
76
+ alias_method :same_as, :identical_to
77
+
78
+ # TODO: This was in the MacBacon specs and kept for backwards compatibilty
79
+ # but I've never seen this used before so possibly kill this.
80
+ def eq=(value)
81
+ self === value
82
+ end
83
+
84
+ def flunk(reason = 'Flunked')
85
+ raise Error.new(:failed, reason)
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,208 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module MotionSpec
3
+ class Specification
4
+ MULTIPLE_POSTPONES_ERROR_MESSAGE =
5
+ "Only one indefinite `wait' block at the same time is allowed!"
6
+
7
+ attr_reader :description
8
+
9
+ def initialize(context, description, block, before_filters, after_filters)
10
+ @context = context
11
+ @description = description
12
+ @block = block
13
+ @before_filters = before_filters.dup
14
+ @after_filters = after_filters.dup
15
+
16
+ @postponed_blocks_count = 0
17
+ @ran_spec_block = false
18
+ @ran_after_filters = false
19
+ @exception_occurred = false
20
+ @error = ''
21
+ end
22
+
23
+ def postponed?
24
+ @postponed_blocks_count != 0
25
+ end
26
+
27
+ def run_before_filters
28
+ execute_block { @before_filters.each { |f| @context.instance_eval(&f) } }
29
+ end
30
+
31
+ def run_spec_block
32
+ @ran_spec_block = true
33
+ # If an exception occurred, we definitely don't need to perform the actual spec anymore
34
+ unless @exception_occurred
35
+ execute_block { @context.instance_eval(&@block) }
36
+ end
37
+ finish_spec unless postponed?
38
+ end
39
+
40
+ def run_after_filters
41
+ @ran_after_filters = true
42
+ execute_block { @after_filters.each { |f| @context.instance_eval(&f) } }
43
+ end
44
+
45
+ def run
46
+ MotionSpec.handle_requirement_begin(@description)
47
+ Counter[:depth] += 1
48
+ run_before_filters
49
+ @number_of_requirements_before = Counter[:requirements]
50
+ run_spec_block unless postponed?
51
+ end
52
+
53
+ def schedule_block(seconds, &block)
54
+ # If an exception occurred, we definitely don't need to schedule any more blocks
55
+ return if @exception_occurred
56
+
57
+ @postponed_blocks_count += 1
58
+ if Platform.android?
59
+ sleep seconds
60
+ run_postponed_block(block)
61
+ else
62
+ performSelector('run_postponed_block:', withObject: block, afterDelay: seconds)
63
+ end
64
+ end
65
+
66
+ def postpone_block(timeout = 1, &block)
67
+ # If an exception occurred, we definitely don't need to schedule any more blocks
68
+ return if @exception_occurred
69
+ raise MULTIPLE_POSTPONES_ERROR_MESSAGE if @postponed_block
70
+
71
+ @postponed_blocks_count += 1
72
+ @postponed_block = block
73
+
74
+ return performSelector(
75
+ 'postponed_block_timeout_exceeded',
76
+ withObject: nil,
77
+ afterDelay: timeout
78
+ ) unless Platform.android?
79
+
80
+ sleep timeout
81
+ postponed_block_timeout_exceeded
82
+ end
83
+
84
+ def postpone_block_until_change(object_to_observe, key_path, timeout = 1, &block)
85
+ # If an exception occurred, we definitely don't need to schedule any more blocks
86
+ return if @exception_occurred
87
+ raise MULTIPLE_POSTPONES_ERROR_MESSAGE if @postponed_block
88
+
89
+ @postponed_blocks_count += 1
90
+ @postponed_block = block
91
+ @observed_object_and_key_path = [object_to_observe, key_path]
92
+ object_to_observe.addObserver(self, forKeyPath: key_path, options: 0, context: nil)
93
+
94
+ return performSelector(
95
+ 'postponed_change_block_timeout_exceeded',
96
+ withObject: nil,
97
+ afterDelay: timeout
98
+ ) unless Platform.android?
99
+
100
+ sleep timeout
101
+ postponed_change_block_timeout_exceeded
102
+ end
103
+
104
+ def observeValueForKeyPath(key_path, ofObject:object, change:_, context:__)
105
+ resume
106
+ end
107
+
108
+ def postponed_change_block_timeout_exceeded
109
+ remove_observer!
110
+ postponed_block_timeout_exceeded
111
+ end
112
+
113
+ def remove_observer!
114
+ if @observed_object_and_key_path
115
+ object, key_path = @observed_object_and_key_path
116
+ object.removeObserver(self, forKeyPath: key_path)
117
+ @observed_object_and_key_path = nil
118
+ end
119
+ end
120
+
121
+ def postponed_block_timeout_exceeded
122
+ cancel_scheduled_requests!
123
+ execute_block { raise Error.new(:failed, "timeout exceeded: #{@context.name} - #{@description}") }
124
+ @postponed_blocks_count = 0
125
+ finish_spec
126
+ end
127
+
128
+ def resume
129
+ unless Platform.android?
130
+ NSObject.cancelPreviousPerformRequestsWithTarget(self, selector: 'postponed_block_timeout_exceeded', object: nil)
131
+ NSObject.cancelPreviousPerformRequestsWithTarget(self, selector: 'postponed_change_block_timeout_exceeded', object: nil)
132
+ end
133
+ remove_observer!
134
+ block, @postponed_block = @postponed_block, nil
135
+ run_postponed_block(block)
136
+ end
137
+
138
+ def run_postponed_block(block)
139
+ # If an exception occurred, we definitely don't need execute any more blocks
140
+ execute_block(&block) unless @exception_occurred
141
+ @postponed_blocks_count -= 1
142
+ unless postponed?
143
+ if @ran_after_filters
144
+ exit_spec
145
+ elsif @ran_spec_block
146
+ finish_spec
147
+ else
148
+ run_spec_block
149
+ end
150
+ end
151
+ end
152
+
153
+ def finish_spec
154
+ if !@exception_occurred && Counter[:requirements] == @number_of_requirements_before
155
+ # the specification did not contain any requirements, so it flunked
156
+ execute_block { raise Error.new(:missing, "empty specification: #{@context.name} #{@description}") }
157
+ end
158
+ run_after_filters
159
+ exit_spec unless postponed?
160
+ end
161
+
162
+ def cancel_scheduled_requests!
163
+ unless Platform.android?
164
+ NSObject.cancelPreviousPerformRequestsWithTarget(@context)
165
+ NSObject.cancelPreviousPerformRequestsWithTarget(self)
166
+ end
167
+ end
168
+
169
+ def exit_spec
170
+ cancel_scheduled_requests!
171
+ Counter[:depth] -= 1
172
+ MotionSpec.handle_requirement_end(@error)
173
+ @context.specification_did_finish(self)
174
+ end
175
+
176
+ def execute_block
177
+ yield
178
+ rescue Object => e
179
+ @exception_occurred = true
180
+
181
+ if e.is_a?(Exception)
182
+ ErrorLog << "#{e.class}: #{e.message}\n"
183
+ lines = $DEBUG ? e.backtrace : e.backtrace.find_all { |line| line !~ /bin\/macbacon|\/mac_bacon\.rb:\d+/ }
184
+ lines.each_with_index { |line, i|
185
+ ErrorLog << "\t#{line}#{i == 0 ? ": #{@context.name} - #{@description}" : ''}\n"
186
+ }
187
+ ErrorLog << "\n"
188
+ else
189
+ if defined?(NSException)
190
+ # Pure NSException.
191
+ ErrorLog << "#{e.name}: #{e.reason}\n"
192
+ else
193
+ # Pure Java exception.
194
+ ErrorLog << "#{e.class.toString} : #{e.getMessage}"
195
+ end
196
+ end
197
+
198
+ @error =
199
+ if e.is_a? Error
200
+ Counter[e.count_as] += 1
201
+ "#{e.count_as.to_s.upcase} - #{e}"
202
+ else
203
+ Counter[:errors] += 1
204
+ "ERROR: #{e.class} - #{e}"
205
+ end
206
+ end
207
+ end
208
+ end
@@ -0,0 +1,5 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ module MotionSpec
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+ require File.expand_path('../lib/motion-spec/version', __FILE__)
3
+
4
+ Gem::Specification.new do |spec|
5
+ spec.name = 'motion-spec'
6
+ spec.version = MotionSpec::VERSION
7
+ spec.authors = ['Jonathan Bender']
8
+ spec.email = ['jlbender@gmail.com']
9
+
10
+ spec.summary = 'RubyMotion derivative of Bacon, which is a derivative of RSpec'
11
+ spec.description = 'RubyMotion derivative of Bacon, which is a derivative of RSpec'
12
+ spec.homepage = 'https://github.com/jbender/motion-spec'
13
+ spec.license = 'MIT'
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
16
+ spec.require_paths = ['lib']
17
+
18
+ spec.add_dependency 'motion-require', '>= 0.0.6'
19
+
20
+ spec.add_development_dependency 'rake', '~> 10.0'
21
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: motion-spec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Jonathan Bender
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: motion-require
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 0.0.6
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 0.0.6
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: RubyMotion derivative of Bacon, which is a derivative of RSpec
42
+ email:
43
+ - jlbender@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - .codeclimate.yml
49
+ - .gitignore
50
+ - .rubocop.yml
51
+ - .travis.yml
52
+ - Gemfile
53
+ - Gemfile.lock
54
+ - LICENSE
55
+ - README.md
56
+ - Rakefile
57
+ - app/app_delegate.rb
58
+ - lib/motion-spec.rb
59
+ - lib/motion-spec/context.rb
60
+ - lib/motion-spec/core.rb
61
+ - lib/motion-spec/error.rb
62
+ - lib/motion-spec/extensions/boolean.rb
63
+ - lib/motion-spec/extensions/exception.rb
64
+ - lib/motion-spec/extensions/kernel.rb
65
+ - lib/motion-spec/extensions/numeric.rb
66
+ - lib/motion-spec/extensions/object.rb
67
+ - lib/motion-spec/extensions/proc.rb
68
+ - lib/motion-spec/output/colorized.rb
69
+ - lib/motion-spec/output/fast.rb
70
+ - lib/motion-spec/output/knock.rb
71
+ - lib/motion-spec/output/ruby_mine.rb
72
+ - lib/motion-spec/output/spec_dox.rb
73
+ - lib/motion-spec/output/tap.rb
74
+ - lib/motion-spec/output/test_unit.rb
75
+ - lib/motion-spec/platform.rb
76
+ - lib/motion-spec/should.rb
77
+ - lib/motion-spec/specification.rb
78
+ - lib/motion-spec/version.rb
79
+ - motion-spec.gemspec
80
+ homepage: https://github.com/jbender/motion-spec
81
+ licenses:
82
+ - MIT
83
+ metadata: {}
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ! '>='
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubyforge_project:
100
+ rubygems_version: 2.4.8
101
+ signing_key:
102
+ specification_version: 4
103
+ summary: RubyMotion derivative of Bacon, which is a derivative of RSpec
104
+ test_files: []