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.
@@ -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: []