libuv 0.10.0 → 0.10.2

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.
Files changed (55) hide show
  1. data/.gitignore +17 -17
  2. data/.gitmodules +3 -3
  3. data/.rspec +1 -1
  4. data/.travis.yml +16 -16
  5. data/Gemfile +2 -2
  6. data/LICENSE +23 -23
  7. data/README.md +82 -73
  8. data/Rakefile +31 -31
  9. data/lib/libuv.rb +53 -34
  10. data/lib/libuv/async.rb +47 -33
  11. data/lib/libuv/check.rb +55 -48
  12. data/lib/libuv/error.rb +70 -70
  13. data/lib/libuv/ext/ext.rb +264 -256
  14. data/lib/libuv/ext/platform/darwin_x64.rb +12 -12
  15. data/lib/libuv/ext/platform/linux.rb +7 -7
  16. data/lib/libuv/ext/platform/unix.rb +13 -13
  17. data/lib/libuv/ext/platform/windows.rb +26 -26
  18. data/lib/libuv/ext/tasks.rb +27 -27
  19. data/lib/libuv/ext/tasks/mac.rb +23 -23
  20. data/lib/libuv/ext/tasks/unix.rb +23 -23
  21. data/lib/libuv/ext/tasks/win.rb +11 -11
  22. data/lib/libuv/ext/types.rb +234 -229
  23. data/lib/libuv/file.rb +192 -0
  24. data/lib/libuv/filesystem.rb +233 -0
  25. data/lib/libuv/fs_event.rb +31 -31
  26. data/lib/libuv/handle.rb +85 -81
  27. data/lib/libuv/idle.rb +56 -49
  28. data/lib/libuv/loop.rb +338 -310
  29. data/lib/libuv/{assertions.rb → mixins/assertions.rb} +23 -23
  30. data/lib/libuv/mixins/fs_checks.rb +55 -0
  31. data/lib/libuv/{listener.rb → mixins/listener.rb} +34 -34
  32. data/lib/libuv/{net.rb → mixins/net.rb} +37 -37
  33. data/lib/libuv/{resource.rb → mixins/resource.rb} +27 -27
  34. data/lib/libuv/{stream.rb → mixins/stream.rb} +143 -123
  35. data/lib/libuv/pipe.rb +197 -97
  36. data/lib/libuv/prepare.rb +56 -49
  37. data/lib/libuv/q.rb +1 -1
  38. data/lib/libuv/signal.rb +51 -0
  39. data/lib/libuv/tcp.rb +204 -193
  40. data/lib/libuv/timer.rb +88 -75
  41. data/lib/libuv/tty.rb +37 -34
  42. data/lib/libuv/udp.rb +273 -255
  43. data/lib/libuv/version.rb +3 -3
  44. data/lib/libuv/work.rb +63 -61
  45. data/libuv.gemspec +54 -54
  46. data/spec/async_spec.rb +60 -60
  47. data/spec/cpu_spec.rb +10 -0
  48. data/spec/defer_spec.rb +980 -980
  49. data/spec/filesystem_spec.rb +119 -0
  50. data/spec/idle_spec.rb +56 -56
  51. data/spec/pipe_spec.rb +153 -148
  52. data/spec/tcp_spec.rb +203 -188
  53. metadata +73 -49
  54. checksums.yaml +0 -15
  55. data/lib/libuv/simple_async.rb +0 -28
data/lib/libuv/version.rb CHANGED
@@ -1,3 +1,3 @@
1
- module Libuv
2
- VERSION = '0.10.0'
3
- end
1
+ module Libuv
2
+ VERSION = '0.10.2'
3
+ end
data/lib/libuv/work.rb CHANGED
@@ -1,62 +1,64 @@
1
- module Libuv
2
- class Work < Q::DeferredPromise
3
- include Resource, Listener
4
-
5
-
6
- def initialize(loop, work)
7
- super(loop, loop.defer)
8
-
9
- @work = work
10
- @complete = false
11
- @pointer = ::Libuv::Ext.create_request(:uv_work)
12
- @error = nil # error in callback
13
-
14
- error = check_result ::Libuv::Ext.queue_work(@loop, @pointer, callback(:on_work), callback(:on_complete))
15
- if error
16
- ::Libuv::Ext.free(@pointer)
17
- @complete = true
18
- @defer.reject(error)
19
- end
20
- end
21
-
22
- # Attempt to cancel the pending work. Returns true if the work has completed or was canceled.
23
- #
24
- # @return [true, false]
25
- def cancel
26
- if not @complete
27
- @complete = ::Libuv::Ext.cancel(@pointer) >= 0
28
- end
29
- @complete
30
- end
31
-
32
- # Indicates is the work has completed yet or not.
33
- #
34
- # @return [true, false]
35
- def completed?
36
- return @complete
37
- end
38
-
39
-
40
- private
41
-
42
-
43
- def on_complete(req, status)
44
- @complete = true
45
- ::Libuv::Ext.free(req)
46
-
47
- if @error
48
- @defer.reject(@error)
49
- else
50
- resolve @defer, status
51
- end
52
- end
53
-
54
- def on_work(req)
55
- begin
56
- @work.call
57
- rescue Exception => e
58
- @error = e # Catch errors for promise resolution
59
- end
60
- end
61
- end
1
+ module Libuv
2
+ class Work < Q::DeferredPromise
3
+ include Resource, Listener
4
+
5
+
6
+ # @param loop [::Libuv::Loop] loop this work request will be associated
7
+ # @param work [Proc] callback to be called in the thread pool
8
+ def initialize(loop, work)
9
+ super(loop, loop.defer)
10
+
11
+ @work = work
12
+ @complete = false
13
+ @pointer = ::Libuv::Ext.create_request(:uv_work)
14
+ @error = nil # error in callback
15
+
16
+ error = check_result ::Libuv::Ext.queue_work(@loop, @pointer, callback(:on_work), callback(:on_complete))
17
+ if error
18
+ ::Libuv::Ext.free(@pointer)
19
+ @complete = true
20
+ @defer.reject(error)
21
+ end
22
+ end
23
+
24
+ # Attempt to cancel the pending work. Returns true if the work has completed or was canceled.
25
+ #
26
+ # @return [true, false]
27
+ def cancel
28
+ if not @complete
29
+ @complete = ::Libuv::Ext.cancel(@pointer) >= 0
30
+ end
31
+ @complete
32
+ end
33
+
34
+ # Indicates is the work has completed yet or not.
35
+ #
36
+ # @return [true, false]
37
+ def completed?
38
+ return @complete
39
+ end
40
+
41
+
42
+ private
43
+
44
+
45
+ def on_complete(req, status)
46
+ @complete = true
47
+ ::Libuv::Ext.free(req)
48
+
49
+ if @error
50
+ @defer.reject(@error)
51
+ else
52
+ resolve @defer, status
53
+ end
54
+ end
55
+
56
+ def on_work(req)
57
+ begin
58
+ @work.call
59
+ rescue Exception => e
60
+ @error = e # Catch errors for promise resolution
61
+ end
62
+ end
63
+ end
62
64
  end
data/libuv.gemspec CHANGED
@@ -1,54 +1,54 @@
1
- require File.expand_path("../lib/libuv/version", __FILE__)
2
-
3
- Gem::Specification.new do |gem|
4
- gem.name = "libuv"
5
- gem.version = Libuv::VERSION
6
- gem.license = 'MIT'
7
- gem.authors = ["Bulat Shakirzyanov", "Stephen von Takach"]
8
- gem.email = ["mallluhuct@gmail.com", "steve@cotag.me"]
9
- gem.homepage = "https://github.com/cotag/libuv"
10
- gem.summary = "libuv bindings for Ruby"
11
- gem.description = "An opinionated wrapper around libuv for Ruby"
12
-
13
- gem.extensions << "ext/Rakefile"
14
-
15
- gem.required_ruby_version = '>= 1.9.2'
16
- gem.require_paths = ["lib"]
17
-
18
- gem.add_runtime_dependency 'ffi', '>= 1.9'
19
- gem.add_runtime_dependency 'thread_safe'
20
- gem.add_development_dependency 'rspec', '>= 2.14'
21
- gem.add_development_dependency 'rake', '>= 10.1'
22
- gem.add_development_dependency 'yard'
23
-
24
- gem.files = `git ls-files`.split("\n")
25
- gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
-
27
- # Add the submodule to the gem
28
- relative_path = File.expand_path("../", __FILE__) + '/'
29
- `git submodule --quiet foreach pwd`.split($\).each do |submodule_path|
30
-
31
- if (ENV['OS'] == 'Windows_NT') && submodule_path[0] == '/'
32
- # Detect if cygwin path is being used by git
33
- submodule_path = submodule_path[1..-1]
34
- submodule_path.insert(1, ':')
35
- end
36
-
37
- # for each submodule, change working directory to that submodule
38
- Dir.chdir(submodule_path) do
39
- # Make the submodule path relative
40
- submodule_path = submodule_path.gsub(/#{relative_path}/i, '')
41
-
42
- # issue git ls-files in submodule's directory
43
- submodule_files = `git ls-files`.split($\)
44
-
45
- # prepend the submodule path to create relative file paths
46
- submodule_files_paths = submodule_files.map do |filename|
47
- File.join(submodule_path, filename)
48
- end
49
-
50
- # add relative paths to gem.files
51
- gem.files += submodule_files_paths
52
- end
53
- end
54
- end
1
+ require File.expand_path("../lib/libuv/version", __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "libuv"
5
+ gem.version = Libuv::VERSION
6
+ gem.license = 'MIT'
7
+ gem.authors = ["Bulat Shakirzyanov", "Stephen von Takach"]
8
+ gem.email = ["mallluhuct@gmail.com", "steve@cotag.me"]
9
+ gem.homepage = "https://github.com/cotag/libuv"
10
+ gem.summary = "libuv bindings for Ruby"
11
+ gem.description = "An opinionated wrapper around libuv for Ruby"
12
+
13
+ gem.extensions << "ext/Rakefile"
14
+
15
+ gem.required_ruby_version = '>= 1.9.2'
16
+ gem.require_paths = ["lib"]
17
+
18
+ gem.add_runtime_dependency 'ffi', '>= 1.9'
19
+ gem.add_runtime_dependency 'thread_safe'
20
+ gem.add_development_dependency 'rspec', '>= 2.14'
21
+ gem.add_development_dependency 'rake', '>= 10.1'
22
+ gem.add_development_dependency 'yard'
23
+
24
+ gem.files = `git ls-files`.split("\n")
25
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
26
+
27
+ # Add the submodule to the gem
28
+ relative_path = File.expand_path("../", __FILE__) + '/'
29
+ `git submodule --quiet foreach pwd`.split($\).each do |submodule_path|
30
+
31
+ if (ENV['OS'] == 'Windows_NT') && submodule_path[0] == '/'
32
+ # Detect if cygwin path is being used by git
33
+ submodule_path = submodule_path[1..-1]
34
+ submodule_path.insert(1, ':')
35
+ end
36
+
37
+ # for each submodule, change working directory to that submodule
38
+ Dir.chdir(submodule_path) do
39
+ # Make the submodule path relative
40
+ submodule_path = submodule_path.gsub(/#{relative_path}/i, '')
41
+
42
+ # issue git ls-files in submodule's directory
43
+ submodule_files = `git ls-files`.split($\)
44
+
45
+ # prepend the submodule path to create relative file paths
46
+ submodule_files_paths = submodule_files.map do |filename|
47
+ File.join(submodule_path, filename)
48
+ end
49
+
50
+ # add relative paths to gem.files
51
+ gem.files += submodule_files_paths
52
+ end
53
+ end
54
+ end
data/spec/async_spec.rb CHANGED
@@ -1,60 +1,60 @@
1
- require 'libuv'
2
-
3
-
4
- describe Libuv::Async do
5
- before :each do
6
- @log = []
7
- @general_failure = []
8
-
9
- @loop = Libuv::Loop.new
10
- @call = @loop.pipe
11
- @timeout = @loop.timer do
12
- @loop.stop
13
- @general_failure << "test timed out"
14
- end
15
- @timeout.start(5000)
16
-
17
- @loop.all(@server, @client, @timeout).catch do |reason|
18
- @general_failure << reason.inspect
19
- p "Failed with: #{reason.message}\n#{reason.backtrace.join("\n")}\n"
20
- end
21
- end
22
-
23
- it "Should call the async function from the thread pool stopping the counter" do
24
- @loop.run { |logger|
25
- logger.progress do |level, errorid, error|
26
- begin
27
- p "Log called: #{level}: #{errorid}\n#{error.message}\n#{error.backtrace.join("\n")}\n"
28
- rescue Exception
29
- p 'error in logger'
30
- end
31
- end
32
-
33
- @count = 0
34
-
35
- timer = @loop.timer do
36
- @count += 1
37
- end
38
- timer.start(0, 200)
39
-
40
- callback = @loop.async do
41
- stopper = @loop.timer do
42
- timer.close
43
- callback.close
44
- stopper.close
45
- @loop.stop
46
- end
47
- stopper.start(1000)
48
- end
49
-
50
- @loop.work(proc {
51
- callback.call
52
- }).catch do |err|
53
- @general_failure << err
54
- end
55
- }
56
-
57
- @general_failure.should == []
58
- (@count < 7 && @count > 3).should == true
59
- end
60
- end
1
+ require 'libuv'
2
+
3
+
4
+ describe Libuv::Async do
5
+ before :each do
6
+ @log = []
7
+ @general_failure = []
8
+
9
+ @loop = Libuv::Loop.new
10
+ @call = @loop.pipe
11
+ @timeout = @loop.timer do
12
+ @loop.stop
13
+ @general_failure << "test timed out"
14
+ end
15
+ @timeout.start(5000)
16
+
17
+ @loop.all(@server, @client, @timeout).catch do |reason|
18
+ @general_failure << reason.inspect
19
+ p "Failed with: #{reason.message}\n#{reason.backtrace.join("\n")}\n"
20
+ end
21
+ end
22
+
23
+ it "Should call the async function from the thread pool stopping the counter" do
24
+ @loop.run { |logger|
25
+ logger.progress do |level, errorid, error|
26
+ begin
27
+ p "Log called: #{level}: #{errorid}\n#{error.message}\n#{error.backtrace.join("\n")}\n"
28
+ rescue Exception
29
+ p 'error in logger'
30
+ end
31
+ end
32
+
33
+ @count = 0
34
+
35
+ timer = @loop.timer do
36
+ @count += 1
37
+ end
38
+ timer.start(0, 200)
39
+
40
+ callback = @loop.async do
41
+ stopper = @loop.timer do
42
+ timer.close
43
+ callback.close
44
+ stopper.close
45
+ @loop.stop
46
+ end
47
+ stopper.start(1000)
48
+ end
49
+
50
+ @loop.work(proc {
51
+ callback.call
52
+ }).catch do |err|
53
+ @general_failure << err
54
+ end
55
+ }
56
+
57
+ @general_failure.should == []
58
+ (@count < 7 && @count > 3).should == true
59
+ end
60
+ end
data/spec/cpu_spec.rb ADDED
@@ -0,0 +1,10 @@
1
+ require 'libuv'
2
+
3
+
4
+ describe ::Libuv do
5
+ it "Should return the number of CPU cores on the platform" do
6
+ count = Libuv.cpu_count
7
+
8
+ (count != nil && count > 0).should == true
9
+ end
10
+ end
data/spec/defer_spec.rb CHANGED
@@ -1,980 +1,980 @@
1
- require 'libuv'
2
-
3
-
4
- describe Libuv::Q do
5
-
6
- before :each do
7
- @loop = Libuv::Loop.new
8
- @deferred = @loop.defer
9
- @promise = @deferred.promise
10
- @log = []
11
- @default_fail = proc { |reason|
12
- @loop.stop
13
- }
14
- end
15
-
16
-
17
- describe 'resolve' do
18
-
19
-
20
- it "should call the callback in the next turn" do
21
- @loop.run {
22
- @promise.then nil, @default_fail do |result|
23
- @log << result
24
- end
25
-
26
- @deferred.resolve(:foo)
27
-
28
- @loop.next_tick do
29
- @loop.stop
30
- end
31
- }
32
-
33
- @log.should == [:foo]
34
- end
35
-
36
-
37
-
38
- it "should be able to resolve the callback after it has already been resolved" do
39
- @loop.run {
40
- @promise.then nil, @default_fail do |result|
41
- @log << result
42
- @promise.then nil, @default_fail do |result|
43
- @log << result
44
- end
45
- end
46
-
47
- @deferred.resolve(:foo)
48
-
49
- @loop.next_tick do
50
- @loop.next_tick do
51
- @loop.stop
52
- end
53
- end
54
- }
55
- @log.should == [:foo, :foo]
56
- end
57
-
58
-
59
-
60
- it "should fulfill success callbacks in the registration order" do
61
- @loop.run {
62
- @promise.then nil, @default_fail do |result|
63
- @log << :first
64
- end
65
-
66
- @promise.then nil, @default_fail do |result|
67
- @log << :second
68
- end
69
-
70
- @deferred.resolve(:foo)
71
-
72
- @loop.next_tick do
73
- @loop.stop
74
- end
75
- }
76
- @log.should == [:first, :second]
77
- end
78
-
79
-
80
- it "should do nothing if a promise was previously resolved" do
81
- @loop.run {
82
- @promise.then nil, @default_fail do |result|
83
- @log << result
84
- @log.should == [:foo]
85
- @deferred.resolve(:bar)
86
- end
87
-
88
- @deferred.resolve(:foo)
89
- @deferred.reject(:baz)
90
-
91
- #
92
- # 4 ticks should detect any errors
93
- #
94
- @loop.next_tick do
95
- @loop.next_tick do
96
- @loop.next_tick do
97
- @loop.next_tick do
98
- @loop.stop
99
- end
100
- end
101
- end
102
- end
103
- }
104
- @log.should == [:foo]
105
- end
106
-
107
-
108
- it "should allow deferred resolution with a new promise" do
109
- deferred2 = @loop.defer
110
- @loop.run {
111
- @promise.then nil, @default_fail do |result|
112
- @log << result
113
- @loop.stop
114
- end
115
-
116
- @deferred.resolve(deferred2.promise)
117
- deferred2.resolve(:foo)
118
- }
119
- @log.should == [:foo]
120
- end
121
-
122
-
123
- it "should not break if a callbacks registers another callback" do
124
- @loop.run {
125
- @promise.then nil, @default_fail do |result|
126
- @log << :outer
127
- @promise.then nil, @default_fail do |result|
128
- @log << :inner
129
- end
130
- end
131
-
132
- @deferred.resolve(:foo)
133
-
134
- @loop.next_tick do
135
- @loop.next_tick do
136
- @loop.stop
137
- end
138
- end
139
- }
140
-
141
- @log.should == [:outer, :inner]
142
- end
143
-
144
-
145
-
146
- it "can modify the result of a promise before returning" do
147
- @loop.run {
148
- proc { |name|
149
- @loop.work { @deferred.resolve("Hello #{name}") }
150
- @promise.then nil, @default_fail do |result|
151
- @log << result
152
- result += "?"
153
- result
154
- end
155
- }.call('Robin Hood').then nil, @default_fail do |greeting|
156
- @log << greeting
157
- @loop.stop
158
- end
159
- }
160
-
161
- @log.should == ['Hello Robin Hood', 'Hello Robin Hood?']
162
- end
163
-
164
- end
165
-
166
-
167
- describe 'reject' do
168
-
169
- it "should reject the promise and execute all error callbacks" do
170
- @loop.run {
171
- @promise.then(@default_fail, proc {|result|
172
- @log << :first
173
- })
174
- @promise.then(@default_fail, proc {|result|
175
- @log << :second
176
- })
177
-
178
- @deferred.reject(:foo)
179
-
180
- @loop.next_tick do
181
- @loop.stop
182
- end
183
- }
184
- @log.should == [:first, :second]
185
- end
186
-
187
-
188
- it "should do nothing if a promise was previously rejected" do
189
- @loop.run {
190
- @promise.then(@default_fail, proc {|result|
191
- @log << result
192
- @deferred.resolve(:bar)
193
- })
194
-
195
- @deferred.reject(:baz)
196
- @deferred.resolve(:foo)
197
-
198
- #
199
- # 4 ticks should detect any errors
200
- #
201
- @loop.next_tick do
202
- @loop.next_tick do
203
- @loop.next_tick do
204
- @loop.next_tick do
205
- @loop.stop
206
- end
207
- end
208
- end
209
- end
210
- }
211
- @log.should == [:baz]
212
- end
213
-
214
-
215
- it "should not defer rejection with a new promise" do
216
- deferred2 = @loop.defer
217
- @loop.run {
218
- @promise.then(@default_fail, @default_fail)
219
- begin
220
- @deferred.reject(deferred2.promise)
221
- rescue => e
222
- @log << e.is_a?(ArgumentError)
223
- @loop.stop
224
- end
225
- }
226
-
227
- @log.should == [true]
228
- end
229
-
230
- end
231
-
232
-
233
- describe 'notify' do
234
- it "should execute all progress callbacks in the registration order" do
235
- @loop.run {
236
- @promise.progress do |update|
237
- @log << :first
238
- end
239
-
240
- @promise.progress do |update|
241
- @log << :second
242
- end
243
-
244
- @deferred.notify(:foo)
245
-
246
- @loop.next_tick do
247
- @loop.stop
248
- end
249
- }
250
-
251
- @log.should == [:first, :second]
252
- end
253
-
254
- it "should do nothing if a promise was previously resolved" do
255
- @loop.run {
256
-
257
- @promise.progress do |update|
258
- @log << update
259
- end
260
-
261
- @deferred.resolve(:foo)
262
- @deferred.notify(:baz)
263
-
264
-
265
- #
266
- # 4 ticks should detect any errors
267
- #
268
- @loop.next_tick do
269
- @loop.next_tick do
270
- @loop.next_tick do
271
- @loop.next_tick do
272
- @loop.stop
273
- end
274
- end
275
- end
276
- end
277
- }
278
-
279
- @log.should == []
280
- end
281
-
282
- it "should do nothing if a promise was previously rejected" do
283
- @loop.run {
284
-
285
- @promise.progress do |update|
286
- @log << update
287
- end
288
- @deferred.reject(:foo)
289
- @deferred.notify(:baz)
290
-
291
-
292
-
293
- #
294
- # 4 ticks should detect any errors
295
- #
296
- @loop.next_tick do
297
- @loop.next_tick do
298
- @loop.next_tick do
299
- @loop.next_tick do
300
- @loop.stop
301
- end
302
- end
303
- end
304
- end
305
- }
306
-
307
- @log.should == []
308
- end
309
-
310
-
311
- it "should not apply any special treatment to promises passed to notify" do
312
- @loop.run {
313
- deferred2 = @loop.defer
314
-
315
- @promise.progress do |update|
316
- @log << update.is_a?(::Libuv::Q::Promise)
317
- end
318
- @deferred.notify(deferred2.promise)
319
-
320
- @loop.next_tick do
321
- @loop.stop
322
- end
323
- }
324
-
325
- @log.should == [true]
326
- end
327
-
328
-
329
- it "should call the progress callbacks in the next turn" do
330
- @loop.run {
331
- @promise.progress do |update|
332
- @log << :first
333
- end
334
-
335
- @promise.progress do |update|
336
- @log << :second
337
- end
338
-
339
- @deferred.notify(:foo)
340
-
341
- @log << @log.length # Has notify run in this tick
342
- @loop.stop # Stop will run through the next tick before stopping
343
- }
344
-
345
- @log.should == [0, :first, :second]
346
- end
347
-
348
- it "should ignore notifications sent out in the same turn before listener registration" do
349
- @loop.run {
350
- @deferred.notify(:foo)
351
-
352
- @promise.progress do |update|
353
- @log << :first
354
- end
355
-
356
- @promise.progress do |update|
357
- @log << :second
358
- end
359
-
360
- @loop.next_tick do
361
- @loop.stop
362
- end
363
- }
364
-
365
- @log.should == []
366
- end
367
- end
368
-
369
-
370
- describe Libuv::Q::Promise do
371
-
372
- describe 'then' do
373
-
374
- it "should allow registration of a success callback without an errback and resolve" do
375
- @loop.run {
376
- @promise.then do |result|
377
- @log << result
378
- end
379
-
380
- @deferred.resolve(:foo)
381
-
382
- @loop.next_tick do
383
- @loop.stop
384
- end
385
- }
386
-
387
- @log.should == [:foo]
388
- end
389
-
390
-
391
- it "should allow registration of a success callback without an errback and reject" do
392
- @loop.run {
393
- @promise.then do |result|
394
- @log << result
395
- end
396
-
397
- @deferred.reject(:foo)
398
-
399
- @loop.next_tick do
400
- @loop.stop
401
- end
402
- }
403
-
404
- @log.should == []
405
- end
406
-
407
-
408
- it "should allow registration of an errback without a success callback and reject" do
409
- @loop.run {
410
- @promise.catch(proc {|reason|
411
- @log << reason
412
- })
413
-
414
- @deferred.reject(:foo)
415
-
416
- @loop.next_tick do
417
- @loop.stop
418
- end
419
- }
420
-
421
- @log.should == [:foo]
422
- end
423
-
424
-
425
- it "should allow registration of an errback without a success callback and resolve" do
426
- @loop.run {
427
- @promise.catch(proc {|reason|
428
- @log << reason
429
- })
430
-
431
- @deferred.resolve(:foo)
432
-
433
- @loop.next_tick do
434
- @loop.stop
435
- end
436
- }
437
-
438
- @log.should == []
439
- end
440
-
441
-
442
- it "should resolve all callbacks with the original value" do
443
- @loop.run {
444
- @promise.then nil, @default_fail do |result|
445
- @log << result
446
- :alt1
447
- end
448
- @promise.then nil, @default_fail do |result|
449
- @log << result
450
- 'ERROR'
451
- end
452
- @promise.then nil, @default_fail do |result|
453
- @log << result
454
- Libuv::Q.reject(@loop, 'some reason')
455
- end
456
- @promise.then nil, @default_fail do |result|
457
- @log << result
458
- :alt2
459
- end
460
-
461
- @deferred.resolve(:foo)
462
-
463
- @loop.next_tick do
464
- @loop.stop
465
- end
466
- }
467
-
468
- @log.should == [:foo, :foo, :foo, :foo]
469
- end
470
-
471
-
472
- it "should notify all callbacks with the original value" do
473
- @loop.run { |loop_promise|
474
- @promise.progress do |result|
475
- @log << result
476
- :alt1
477
- end
478
- @promise.progress do |result|
479
- @log << result
480
- 'ERROR'
481
- end
482
- @promise.progress do |result|
483
- @log << result
484
- Libuv::Q.reject(@loop, 'some reason')
485
- end
486
- @promise.progress do |result|
487
- @log << result
488
- :alt2
489
- end
490
-
491
-
492
- @deferred.notify(:foo)
493
-
494
- @loop.next_tick do
495
- @loop.next_tick do
496
- @loop.next_tick do
497
- @loop.next_tick do
498
- @loop.next_tick do
499
- @loop.stop
500
- end
501
- end
502
- end
503
- end
504
- end
505
- }
506
-
507
- @log.should == [:foo, :foo, :foo, :foo]
508
- end
509
-
510
-
511
- it "should reject all callbacks with the original reason" do
512
- @loop.run {
513
- @promise.then(@default_fail, proc {|result|
514
- @log << result
515
- :alt1
516
- })
517
- @promise.then(@default_fail, proc {|result|
518
- @log << result
519
- 'ERROR'
520
- })
521
- @promise.then(@default_fail, proc {|result|
522
- @log << result
523
- Libuv::Q.reject(@loop, 'some reason')
524
- })
525
- @promise.then(@default_fail, proc {|result|
526
- @log << result
527
- :alt2
528
- })
529
-
530
- @deferred.reject(:foo)
531
-
532
- @loop.next_tick do
533
- @loop.stop
534
- end
535
- }
536
-
537
- @log.should == [:foo, :foo, :foo, :foo]
538
- end
539
-
540
-
541
- it "should propagate resolution and rejection between dependent promises" do
542
- @loop.run {
543
- @promise.then(proc { |result|
544
- @log << result
545
- :bar
546
- }, @default_fail).then(proc { |result|
547
- @log << result
548
- raise 'baz'
549
- }, @default_fail).then(@default_fail, proc {|result|
550
- @log << result.message
551
- raise 'bob'
552
- }).then(@default_fail, proc {|result|
553
- @log << result.message
554
- :done
555
- }).then(proc { |result|
556
- @log << result
557
- }, @default_fail)
558
-
559
- @deferred.resolve(:foo)
560
-
561
- @loop.next_tick do
562
- @loop.next_tick do
563
- @loop.next_tick do
564
- @loop.next_tick do
565
- @loop.next_tick do
566
- @loop.next_tick do # extra tick?
567
- @loop.stop
568
- end
569
- end
570
- end
571
- end
572
- end
573
- end
574
- }
575
-
576
- @log.should == [:foo, :bar, 'baz', 'bob', :done]
577
- end
578
-
579
-
580
- it "should propagate notification between dependent promises" do
581
- @loop.run { |loop_promise|
582
- loop_promise.progress do |type, id, error|
583
- @log << id
584
- end
585
-
586
-
587
- @promise.progress(proc { |result|
588
- @log << result
589
- :bar
590
- }).progress(proc { |result|
591
- @log << result
592
- result
593
- }).progress(proc {|result|
594
- @log << result
595
- result
596
- }).progress(proc {|result|
597
- @log << result
598
- :done
599
- }).progress(proc { |result|
600
- @log << result
601
- result
602
- })
603
-
604
-
605
- @deferred.notify(:foo)
606
-
607
- @loop.next_tick do
608
- @loop.next_tick do
609
- @loop.next_tick do
610
- @loop.next_tick do
611
- @loop.next_tick do
612
- @loop.next_tick do # extra tick?
613
- @loop.stop
614
- end
615
- end
616
- end
617
- end
618
- end
619
- end
620
- }
621
-
622
- @log.should == [:foo, :bar, :bar, :bar, :done]
623
- end
624
-
625
-
626
- it "should stop notification propagation in case of error" do
627
- @loop.run { |loop_logger|
628
- loop_logger.progress do |type, id, error|
629
- @log << id
630
- end
631
-
632
-
633
- @promise.progress(proc { |result|
634
- @log << result
635
- :bar
636
- }).progress(proc { |result|
637
- @log << result
638
- raise 'err'
639
- result
640
- }).progress(proc {|result|
641
- @log << result
642
- result
643
- }).progress(proc {|result|
644
- @log << result
645
- :done
646
- }).progress(proc { |result|
647
- @log << result
648
- result
649
- })
650
-
651
-
652
- @deferred.notify(:foo)
653
-
654
- @loop.next_tick do
655
- @loop.next_tick do
656
- @loop.next_tick do
657
- @loop.next_tick do
658
- @loop.next_tick do
659
- @loop.stop
660
- end
661
- end
662
- end
663
- end
664
- end
665
- }
666
-
667
- @log.should == [:foo, :bar, :q_progress_cb]
668
- end
669
-
670
-
671
- it "should call error callback in the next turn even if promise is already rejected" do
672
- @loop.run {
673
- @deferred.reject(:foo)
674
-
675
- @promise.catch(proc {|reason|
676
- @log << reason
677
- })
678
-
679
- @loop.next_tick do
680
- @loop.stop
681
- end
682
- }
683
-
684
- @log.should == [:foo]
685
- end
686
-
687
-
688
- end
689
-
690
-
691
- describe 'finally' do
692
-
693
- describe 'when the promise is fulfilled' do
694
-
695
- it "should call the callback" do
696
- @loop.run {
697
- @promise.finally do
698
- @log << :finally
699
- end
700
-
701
- @deferred.resolve(:foo)
702
-
703
- @loop.next_tick do
704
- @loop.stop
705
- end
706
- }
707
-
708
- @log.should == [:finally]
709
- end
710
-
711
- it "should fulfill with the original value" do
712
- @loop.run {
713
- @promise.finally(proc {
714
- @log << :finally
715
- :finally
716
- }).then do |result|
717
- @log << result
718
- end
719
-
720
-
721
- @deferred.resolve(:foo)
722
-
723
- @loop.next_tick do
724
- @loop.next_tick do
725
- @loop.stop
726
- end
727
- end
728
- }
729
-
730
- @log.should == [:finally, :foo]
731
- end
732
-
733
- it "should fulfill with the original value (larger test)" do
734
- @loop.run {
735
- @promise.then(proc { |result|
736
- @log << result
737
- result
738
- }).finally(proc {
739
- @log << :finally
740
- :finally
741
- }).then(proc { |result|
742
- @log << result
743
- :change
744
- }).then(proc { |result|
745
- @log << result
746
- result
747
- }).finally(proc {
748
- @log << :finally
749
- :finally
750
- }).then(proc { |result|
751
- @log << result
752
- result
753
- })
754
-
755
-
756
- @deferred.resolve(:foo)
757
-
758
-
759
- @loop.next_tick do
760
- @loop.next_tick do
761
- @loop.next_tick do
762
- @loop.next_tick do
763
- @loop.next_tick do
764
- @loop.next_tick do
765
- @loop.next_tick do
766
- @loop.next_tick do
767
- @loop.stop
768
- end
769
- end
770
- end
771
- end
772
- end
773
- end
774
- end
775
- end
776
- }
777
-
778
- @log.should == [:foo, :finally, :foo, :change, :finally, :change]
779
- end
780
-
781
- describe "when the callback throws an exception" do
782
- it "should reject with this new exception" do
783
- @loop.run {
784
- @promise.finally(proc {
785
- @log << :finally
786
- raise 'error'
787
- }).catch do |reason|
788
- @log.push reason.is_a?(Exception)
789
- end
790
-
791
- @deferred.resolve(:foo)
792
-
793
- @loop.next_tick do
794
- @loop.next_tick do
795
- @loop.stop
796
- end
797
- end
798
- }
799
-
800
- @log.should == [:finally, true]
801
- end
802
- end
803
-
804
- describe "when the callback returns a promise" do
805
- it "should fulfill with the original reason after that promise resolves" do
806
- @loop.run {
807
- deferred2 = @loop.defer
808
-
809
- @promise.finally(proc {
810
- @log << :finally
811
- deferred2.promise
812
- }).then do |result|
813
- @log << result
814
- end
815
-
816
- @deferred.resolve(:foo)
817
-
818
- @loop.next_tick do
819
- @loop.next_tick do
820
- @loop.next_tick do
821
- @loop.next_tick do
822
- @log << :resolving
823
- deferred2.resolve('working')
824
- @loop.next_tick do
825
- @loop.next_tick do
826
- @loop.stop
827
- end
828
- end
829
- end
830
- end
831
- end
832
- end
833
- }
834
-
835
- @log.should == [:finally, :resolving, :foo]
836
- end
837
-
838
-
839
- it "should reject with the new reason when it is rejected" do
840
- @loop.run {
841
- deferred2 = @loop.defer
842
-
843
- @promise.finally(proc {
844
- @log << :finally
845
- deferred2.promise
846
- }).catch do |result|
847
- @log << result
848
- end
849
-
850
- @deferred.resolve(:foo)
851
-
852
- @loop.next_tick do
853
- @loop.next_tick do
854
- @loop.next_tick do
855
- @loop.next_tick do
856
- @log << :rejecting
857
- deferred2.reject(:rejected)
858
- @loop.next_tick do
859
- @loop.next_tick do
860
- @loop.stop
861
- end
862
- end
863
- end
864
- end
865
- end
866
- end
867
- }
868
-
869
- @log.should == [:finally, :rejecting, :rejected]
870
- end
871
- end
872
-
873
- end
874
-
875
- end
876
-
877
- end
878
-
879
-
880
-
881
- describe 'reject' do
882
-
883
- it "should package a string into a rejected promise" do
884
- @loop.run {
885
- rejectedPromise = Libuv::Q.reject(@loop, 'not gonna happen')
886
-
887
- @promise.then(@default_fail, proc {|reason|
888
- @log << reason
889
- })
890
-
891
- @deferred.resolve(rejectedPromise)
892
-
893
- @loop.next_tick do
894
- @loop.stop
895
- end
896
- }
897
-
898
- @log.should == ['not gonna happen']
899
- end
900
-
901
-
902
- it "should return a promise that forwards callbacks if the callbacks are missing" do
903
- @loop.run {
904
- rejectedPromise = Libuv::Q.reject(@loop, 'not gonna happen')
905
-
906
- @promise.then(@default_fail, proc {|reason|
907
- @log << reason
908
- })
909
-
910
- @deferred.resolve(rejectedPromise.then())
911
-
912
- @loop.next_tick do
913
- @loop.next_tick do
914
- @loop.stop
915
- end
916
- end
917
- }
918
-
919
- @log.should == ['not gonna happen']
920
- end
921
-
922
- end
923
-
924
-
925
-
926
- describe 'all' do
927
-
928
- it "should resolve all of nothing" do
929
- @loop.run {
930
- Libuv::Q.all(@loop).then nil, @default_fail do |result|
931
- @log << result
932
- end
933
-
934
- @loop.next_tick do
935
- @loop.stop
936
- end
937
- }
938
-
939
- @log.should == [[]]
940
- end
941
-
942
- it "should take an array of promises and return a promise for an array of results" do
943
- @loop.run {
944
- deferred1 = @loop.defer
945
- deferred2 = @loop.defer
946
-
947
- Libuv::Q.all(@loop, @promise, deferred1.promise, deferred2.promise).then nil, @default_fail do |result|
948
- @log = result
949
- @loop.stop
950
- end
951
-
952
- @loop.work { @deferred.resolve(:foo) }
953
- @loop.work { deferred2.resolve(:baz) }
954
- @loop.work { deferred1.resolve(:bar) }
955
- }
956
-
957
- @log.should == [:foo, :bar, :baz]
958
- end
959
-
960
-
961
- it "should reject the derived promise if at least one of the promises in the array is rejected" do
962
- @loop.run {
963
- deferred1 = @loop.defer
964
- deferred2 = @loop.defer
965
-
966
- Libuv::Q.all(@loop, @promise, deferred1.promise, deferred2.promise).then(@default_fail, proc {|reason|
967
- @log << reason
968
- @loop.stop
969
- })
970
-
971
- @loop.work { @deferred.resolve(:foo) }
972
- @loop.work { deferred2.reject(:baz) }
973
- }
974
-
975
- @log.should == [:baz]
976
- end
977
-
978
- end
979
-
980
- end
1
+ require 'libuv'
2
+
3
+
4
+ describe Libuv::Q do
5
+
6
+ before :each do
7
+ @loop = Libuv::Loop.new
8
+ @deferred = @loop.defer
9
+ @promise = @deferred.promise
10
+ @log = []
11
+ @default_fail = proc { |reason|
12
+ @loop.stop
13
+ }
14
+ end
15
+
16
+
17
+ describe 'resolve' do
18
+
19
+
20
+ it "should call the callback in the next turn" do
21
+ @loop.run {
22
+ @promise.then nil, @default_fail do |result|
23
+ @log << result
24
+ end
25
+
26
+ @deferred.resolve(:foo)
27
+
28
+ @loop.next_tick do
29
+ @loop.stop
30
+ end
31
+ }
32
+
33
+ @log.should == [:foo]
34
+ end
35
+
36
+
37
+
38
+ it "should be able to resolve the callback after it has already been resolved" do
39
+ @loop.run {
40
+ @promise.then nil, @default_fail do |result|
41
+ @log << result
42
+ @promise.then nil, @default_fail do |result|
43
+ @log << result
44
+ end
45
+ end
46
+
47
+ @deferred.resolve(:foo)
48
+
49
+ @loop.next_tick do
50
+ @loop.next_tick do
51
+ @loop.stop
52
+ end
53
+ end
54
+ }
55
+ @log.should == [:foo, :foo]
56
+ end
57
+
58
+
59
+
60
+ it "should fulfill success callbacks in the registration order" do
61
+ @loop.run {
62
+ @promise.then nil, @default_fail do |result|
63
+ @log << :first
64
+ end
65
+
66
+ @promise.then nil, @default_fail do |result|
67
+ @log << :second
68
+ end
69
+
70
+ @deferred.resolve(:foo)
71
+
72
+ @loop.next_tick do
73
+ @loop.stop
74
+ end
75
+ }
76
+ @log.should == [:first, :second]
77
+ end
78
+
79
+
80
+ it "should do nothing if a promise was previously resolved" do
81
+ @loop.run {
82
+ @promise.then nil, @default_fail do |result|
83
+ @log << result
84
+ @log.should == [:foo]
85
+ @deferred.resolve(:bar)
86
+ end
87
+
88
+ @deferred.resolve(:foo)
89
+ @deferred.reject(:baz)
90
+
91
+ #
92
+ # 4 ticks should detect any errors
93
+ #
94
+ @loop.next_tick do
95
+ @loop.next_tick do
96
+ @loop.next_tick do
97
+ @loop.next_tick do
98
+ @loop.stop
99
+ end
100
+ end
101
+ end
102
+ end
103
+ }
104
+ @log.should == [:foo]
105
+ end
106
+
107
+
108
+ it "should allow deferred resolution with a new promise" do
109
+ deferred2 = @loop.defer
110
+ @loop.run {
111
+ @promise.then nil, @default_fail do |result|
112
+ @log << result
113
+ @loop.stop
114
+ end
115
+
116
+ @deferred.resolve(deferred2.promise)
117
+ deferred2.resolve(:foo)
118
+ }
119
+ @log.should == [:foo]
120
+ end
121
+
122
+
123
+ it "should not break if a callbacks registers another callback" do
124
+ @loop.run {
125
+ @promise.then nil, @default_fail do |result|
126
+ @log << :outer
127
+ @promise.then nil, @default_fail do |result|
128
+ @log << :inner
129
+ end
130
+ end
131
+
132
+ @deferred.resolve(:foo)
133
+
134
+ @loop.next_tick do
135
+ @loop.next_tick do
136
+ @loop.stop
137
+ end
138
+ end
139
+ }
140
+
141
+ @log.should == [:outer, :inner]
142
+ end
143
+
144
+
145
+
146
+ it "can modify the result of a promise before returning" do
147
+ @loop.run {
148
+ proc { |name|
149
+ @loop.work { @deferred.resolve("Hello #{name}") }
150
+ @promise.then nil, @default_fail do |result|
151
+ @log << result
152
+ result += "?"
153
+ result
154
+ end
155
+ }.call('Robin Hood').then nil, @default_fail do |greeting|
156
+ @log << greeting
157
+ @loop.stop
158
+ end
159
+ }
160
+
161
+ @log.should == ['Hello Robin Hood', 'Hello Robin Hood?']
162
+ end
163
+
164
+ end
165
+
166
+
167
+ describe 'reject' do
168
+
169
+ it "should reject the promise and execute all error callbacks" do
170
+ @loop.run {
171
+ @promise.then(@default_fail, proc {|result|
172
+ @log << :first
173
+ })
174
+ @promise.then(@default_fail, proc {|result|
175
+ @log << :second
176
+ })
177
+
178
+ @deferred.reject(:foo)
179
+
180
+ @loop.next_tick do
181
+ @loop.stop
182
+ end
183
+ }
184
+ @log.should == [:first, :second]
185
+ end
186
+
187
+
188
+ it "should do nothing if a promise was previously rejected" do
189
+ @loop.run {
190
+ @promise.then(@default_fail, proc {|result|
191
+ @log << result
192
+ @deferred.resolve(:bar)
193
+ })
194
+
195
+ @deferred.reject(:baz)
196
+ @deferred.resolve(:foo)
197
+
198
+ #
199
+ # 4 ticks should detect any errors
200
+ #
201
+ @loop.next_tick do
202
+ @loop.next_tick do
203
+ @loop.next_tick do
204
+ @loop.next_tick do
205
+ @loop.stop
206
+ end
207
+ end
208
+ end
209
+ end
210
+ }
211
+ @log.should == [:baz]
212
+ end
213
+
214
+
215
+ it "should not defer rejection with a new promise" do
216
+ deferred2 = @loop.defer
217
+ @loop.run {
218
+ @promise.then(@default_fail, @default_fail)
219
+ begin
220
+ @deferred.reject(deferred2.promise)
221
+ rescue => e
222
+ @log << e.is_a?(ArgumentError)
223
+ @loop.stop
224
+ end
225
+ }
226
+
227
+ @log.should == [true]
228
+ end
229
+
230
+ end
231
+
232
+
233
+ describe 'notify' do
234
+ it "should execute all progress callbacks in the registration order" do
235
+ @loop.run {
236
+ @promise.progress do |update|
237
+ @log << :first
238
+ end
239
+
240
+ @promise.progress do |update|
241
+ @log << :second
242
+ end
243
+
244
+ @deferred.notify(:foo)
245
+
246
+ @loop.next_tick do
247
+ @loop.stop
248
+ end
249
+ }
250
+
251
+ @log.should == [:first, :second]
252
+ end
253
+
254
+ it "should do nothing if a promise was previously resolved" do
255
+ @loop.run {
256
+
257
+ @promise.progress do |update|
258
+ @log << update
259
+ end
260
+
261
+ @deferred.resolve(:foo)
262
+ @deferred.notify(:baz)
263
+
264
+
265
+ #
266
+ # 4 ticks should detect any errors
267
+ #
268
+ @loop.next_tick do
269
+ @loop.next_tick do
270
+ @loop.next_tick do
271
+ @loop.next_tick do
272
+ @loop.stop
273
+ end
274
+ end
275
+ end
276
+ end
277
+ }
278
+
279
+ @log.should == []
280
+ end
281
+
282
+ it "should do nothing if a promise was previously rejected" do
283
+ @loop.run {
284
+
285
+ @promise.progress do |update|
286
+ @log << update
287
+ end
288
+ @deferred.reject(:foo)
289
+ @deferred.notify(:baz)
290
+
291
+
292
+
293
+ #
294
+ # 4 ticks should detect any errors
295
+ #
296
+ @loop.next_tick do
297
+ @loop.next_tick do
298
+ @loop.next_tick do
299
+ @loop.next_tick do
300
+ @loop.stop
301
+ end
302
+ end
303
+ end
304
+ end
305
+ }
306
+
307
+ @log.should == []
308
+ end
309
+
310
+
311
+ it "should not apply any special treatment to promises passed to notify" do
312
+ @loop.run {
313
+ deferred2 = @loop.defer
314
+
315
+ @promise.progress do |update|
316
+ @log << update.is_a?(::Libuv::Q::Promise)
317
+ end
318
+ @deferred.notify(deferred2.promise)
319
+
320
+ @loop.next_tick do
321
+ @loop.stop
322
+ end
323
+ }
324
+
325
+ @log.should == [true]
326
+ end
327
+
328
+
329
+ it "should call the progress callbacks in the next turn" do
330
+ @loop.run {
331
+ @promise.progress do |update|
332
+ @log << :first
333
+ end
334
+
335
+ @promise.progress do |update|
336
+ @log << :second
337
+ end
338
+
339
+ @deferred.notify(:foo)
340
+
341
+ @log << @log.length # Has notify run in this tick
342
+ @loop.stop # Stop will run through the next tick before stopping
343
+ }
344
+
345
+ @log.should == [0, :first, :second]
346
+ end
347
+
348
+ it "should ignore notifications sent out in the same turn before listener registration" do
349
+ @loop.run {
350
+ @deferred.notify(:foo)
351
+
352
+ @promise.progress do |update|
353
+ @log << :first
354
+ end
355
+
356
+ @promise.progress do |update|
357
+ @log << :second
358
+ end
359
+
360
+ @loop.next_tick do
361
+ @loop.stop
362
+ end
363
+ }
364
+
365
+ @log.should == []
366
+ end
367
+ end
368
+
369
+
370
+ describe Libuv::Q::Promise do
371
+
372
+ describe 'then' do
373
+
374
+ it "should allow registration of a success callback without an errback and resolve" do
375
+ @loop.run {
376
+ @promise.then do |result|
377
+ @log << result
378
+ end
379
+
380
+ @deferred.resolve(:foo)
381
+
382
+ @loop.next_tick do
383
+ @loop.stop
384
+ end
385
+ }
386
+
387
+ @log.should == [:foo]
388
+ end
389
+
390
+
391
+ it "should allow registration of a success callback without an errback and reject" do
392
+ @loop.run {
393
+ @promise.then do |result|
394
+ @log << result
395
+ end
396
+
397
+ @deferred.reject(:foo)
398
+
399
+ @loop.next_tick do
400
+ @loop.stop
401
+ end
402
+ }
403
+
404
+ @log.should == []
405
+ end
406
+
407
+
408
+ it "should allow registration of an errback without a success callback and reject" do
409
+ @loop.run {
410
+ @promise.catch(proc {|reason|
411
+ @log << reason
412
+ })
413
+
414
+ @deferred.reject(:foo)
415
+
416
+ @loop.next_tick do
417
+ @loop.stop
418
+ end
419
+ }
420
+
421
+ @log.should == [:foo]
422
+ end
423
+
424
+
425
+ it "should allow registration of an errback without a success callback and resolve" do
426
+ @loop.run {
427
+ @promise.catch(proc {|reason|
428
+ @log << reason
429
+ })
430
+
431
+ @deferred.resolve(:foo)
432
+
433
+ @loop.next_tick do
434
+ @loop.stop
435
+ end
436
+ }
437
+
438
+ @log.should == []
439
+ end
440
+
441
+
442
+ it "should resolve all callbacks with the original value" do
443
+ @loop.run {
444
+ @promise.then nil, @default_fail do |result|
445
+ @log << result
446
+ :alt1
447
+ end
448
+ @promise.then nil, @default_fail do |result|
449
+ @log << result
450
+ 'ERROR'
451
+ end
452
+ @promise.then nil, @default_fail do |result|
453
+ @log << result
454
+ Libuv::Q.reject(@loop, 'some reason')
455
+ end
456
+ @promise.then nil, @default_fail do |result|
457
+ @log << result
458
+ :alt2
459
+ end
460
+
461
+ @deferred.resolve(:foo)
462
+
463
+ @loop.next_tick do
464
+ @loop.stop
465
+ end
466
+ }
467
+
468
+ @log.should == [:foo, :foo, :foo, :foo]
469
+ end
470
+
471
+
472
+ it "should notify all callbacks with the original value" do
473
+ @loop.run { |loop_promise|
474
+ @promise.progress do |result|
475
+ @log << result
476
+ :alt1
477
+ end
478
+ @promise.progress do |result|
479
+ @log << result
480
+ 'ERROR'
481
+ end
482
+ @promise.progress do |result|
483
+ @log << result
484
+ Libuv::Q.reject(@loop, 'some reason')
485
+ end
486
+ @promise.progress do |result|
487
+ @log << result
488
+ :alt2
489
+ end
490
+
491
+
492
+ @deferred.notify(:foo)
493
+
494
+ @loop.next_tick do
495
+ @loop.next_tick do
496
+ @loop.next_tick do
497
+ @loop.next_tick do
498
+ @loop.next_tick do
499
+ @loop.stop
500
+ end
501
+ end
502
+ end
503
+ end
504
+ end
505
+ }
506
+
507
+ @log.should == [:foo, :foo, :foo, :foo]
508
+ end
509
+
510
+
511
+ it "should reject all callbacks with the original reason" do
512
+ @loop.run {
513
+ @promise.then(@default_fail, proc {|result|
514
+ @log << result
515
+ :alt1
516
+ })
517
+ @promise.then(@default_fail, proc {|result|
518
+ @log << result
519
+ 'ERROR'
520
+ })
521
+ @promise.then(@default_fail, proc {|result|
522
+ @log << result
523
+ Libuv::Q.reject(@loop, 'some reason')
524
+ })
525
+ @promise.then(@default_fail, proc {|result|
526
+ @log << result
527
+ :alt2
528
+ })
529
+
530
+ @deferred.reject(:foo)
531
+
532
+ @loop.next_tick do
533
+ @loop.stop
534
+ end
535
+ }
536
+
537
+ @log.should == [:foo, :foo, :foo, :foo]
538
+ end
539
+
540
+
541
+ it "should propagate resolution and rejection between dependent promises" do
542
+ @loop.run {
543
+ @promise.then(proc { |result|
544
+ @log << result
545
+ :bar
546
+ }, @default_fail).then(proc { |result|
547
+ @log << result
548
+ raise 'baz'
549
+ }, @default_fail).then(@default_fail, proc {|result|
550
+ @log << result.message
551
+ raise 'bob'
552
+ }).then(@default_fail, proc {|result|
553
+ @log << result.message
554
+ :done
555
+ }).then(proc { |result|
556
+ @log << result
557
+ }, @default_fail)
558
+
559
+ @deferred.resolve(:foo)
560
+
561
+ @loop.next_tick do
562
+ @loop.next_tick do
563
+ @loop.next_tick do
564
+ @loop.next_tick do
565
+ @loop.next_tick do
566
+ @loop.next_tick do # extra tick?
567
+ @loop.stop
568
+ end
569
+ end
570
+ end
571
+ end
572
+ end
573
+ end
574
+ }
575
+
576
+ @log.should == [:foo, :bar, 'baz', 'bob', :done]
577
+ end
578
+
579
+
580
+ it "should propagate notification between dependent promises" do
581
+ @loop.run { |loop_promise|
582
+ loop_promise.progress do |type, id, error|
583
+ @log << id
584
+ end
585
+
586
+
587
+ @promise.progress(proc { |result|
588
+ @log << result
589
+ :bar
590
+ }).progress(proc { |result|
591
+ @log << result
592
+ result
593
+ }).progress(proc {|result|
594
+ @log << result
595
+ result
596
+ }).progress(proc {|result|
597
+ @log << result
598
+ :done
599
+ }).progress(proc { |result|
600
+ @log << result
601
+ result
602
+ })
603
+
604
+
605
+ @deferred.notify(:foo)
606
+
607
+ @loop.next_tick do
608
+ @loop.next_tick do
609
+ @loop.next_tick do
610
+ @loop.next_tick do
611
+ @loop.next_tick do
612
+ @loop.next_tick do # extra tick?
613
+ @loop.stop
614
+ end
615
+ end
616
+ end
617
+ end
618
+ end
619
+ end
620
+ }
621
+
622
+ @log.should == [:foo, :bar, :bar, :bar, :done]
623
+ end
624
+
625
+
626
+ it "should stop notification propagation in case of error" do
627
+ @loop.run { |loop_logger|
628
+ loop_logger.progress do |type, id, error|
629
+ @log << id
630
+ end
631
+
632
+
633
+ @promise.progress(proc { |result|
634
+ @log << result
635
+ :bar
636
+ }).progress(proc { |result|
637
+ @log << result
638
+ raise 'err'
639
+ result
640
+ }).progress(proc {|result|
641
+ @log << result
642
+ result
643
+ }).progress(proc {|result|
644
+ @log << result
645
+ :done
646
+ }).progress(proc { |result|
647
+ @log << result
648
+ result
649
+ })
650
+
651
+
652
+ @deferred.notify(:foo)
653
+
654
+ @loop.next_tick do
655
+ @loop.next_tick do
656
+ @loop.next_tick do
657
+ @loop.next_tick do
658
+ @loop.next_tick do
659
+ @loop.stop
660
+ end
661
+ end
662
+ end
663
+ end
664
+ end
665
+ }
666
+
667
+ @log.should == [:foo, :bar, :q_progress_cb]
668
+ end
669
+
670
+
671
+ it "should call error callback in the next turn even if promise is already rejected" do
672
+ @loop.run {
673
+ @deferred.reject(:foo)
674
+
675
+ @promise.catch(proc {|reason|
676
+ @log << reason
677
+ })
678
+
679
+ @loop.next_tick do
680
+ @loop.stop
681
+ end
682
+ }
683
+
684
+ @log.should == [:foo]
685
+ end
686
+
687
+
688
+ end
689
+
690
+
691
+ describe 'finally' do
692
+
693
+ describe 'when the promise is fulfilled' do
694
+
695
+ it "should call the callback" do
696
+ @loop.run {
697
+ @promise.finally do
698
+ @log << :finally
699
+ end
700
+
701
+ @deferred.resolve(:foo)
702
+
703
+ @loop.next_tick do
704
+ @loop.stop
705
+ end
706
+ }
707
+
708
+ @log.should == [:finally]
709
+ end
710
+
711
+ it "should fulfill with the original value" do
712
+ @loop.run {
713
+ @promise.finally(proc {
714
+ @log << :finally
715
+ :finally
716
+ }).then do |result|
717
+ @log << result
718
+ end
719
+
720
+
721
+ @deferred.resolve(:foo)
722
+
723
+ @loop.next_tick do
724
+ @loop.next_tick do
725
+ @loop.stop
726
+ end
727
+ end
728
+ }
729
+
730
+ @log.should == [:finally, :foo]
731
+ end
732
+
733
+ it "should fulfill with the original value (larger test)" do
734
+ @loop.run {
735
+ @promise.then(proc { |result|
736
+ @log << result
737
+ result
738
+ }).finally(proc {
739
+ @log << :finally
740
+ :finally
741
+ }).then(proc { |result|
742
+ @log << result
743
+ :change
744
+ }).then(proc { |result|
745
+ @log << result
746
+ result
747
+ }).finally(proc {
748
+ @log << :finally
749
+ :finally
750
+ }).then(proc { |result|
751
+ @log << result
752
+ result
753
+ })
754
+
755
+
756
+ @deferred.resolve(:foo)
757
+
758
+
759
+ @loop.next_tick do
760
+ @loop.next_tick do
761
+ @loop.next_tick do
762
+ @loop.next_tick do
763
+ @loop.next_tick do
764
+ @loop.next_tick do
765
+ @loop.next_tick do
766
+ @loop.next_tick do
767
+ @loop.stop
768
+ end
769
+ end
770
+ end
771
+ end
772
+ end
773
+ end
774
+ end
775
+ end
776
+ }
777
+
778
+ @log.should == [:foo, :finally, :foo, :change, :finally, :change]
779
+ end
780
+
781
+ describe "when the callback throws an exception" do
782
+ it "should reject with this new exception" do
783
+ @loop.run {
784
+ @promise.finally(proc {
785
+ @log << :finally
786
+ raise 'error'
787
+ }).catch do |reason|
788
+ @log.push reason.is_a?(Exception)
789
+ end
790
+
791
+ @deferred.resolve(:foo)
792
+
793
+ @loop.next_tick do
794
+ @loop.next_tick do
795
+ @loop.stop
796
+ end
797
+ end
798
+ }
799
+
800
+ @log.should == [:finally, true]
801
+ end
802
+ end
803
+
804
+ describe "when the callback returns a promise" do
805
+ it "should fulfill with the original reason after that promise resolves" do
806
+ @loop.run {
807
+ deferred2 = @loop.defer
808
+
809
+ @promise.finally(proc {
810
+ @log << :finally
811
+ deferred2.promise
812
+ }).then do |result|
813
+ @log << result
814
+ end
815
+
816
+ @deferred.resolve(:foo)
817
+
818
+ @loop.next_tick do
819
+ @loop.next_tick do
820
+ @loop.next_tick do
821
+ @loop.next_tick do
822
+ @log << :resolving
823
+ deferred2.resolve('working')
824
+ @loop.next_tick do
825
+ @loop.next_tick do
826
+ @loop.stop
827
+ end
828
+ end
829
+ end
830
+ end
831
+ end
832
+ end
833
+ }
834
+
835
+ @log.should == [:finally, :resolving, :foo]
836
+ end
837
+
838
+
839
+ it "should reject with the new reason when it is rejected" do
840
+ @loop.run {
841
+ deferred2 = @loop.defer
842
+
843
+ @promise.finally(proc {
844
+ @log << :finally
845
+ deferred2.promise
846
+ }).catch do |result|
847
+ @log << result
848
+ end
849
+
850
+ @deferred.resolve(:foo)
851
+
852
+ @loop.next_tick do
853
+ @loop.next_tick do
854
+ @loop.next_tick do
855
+ @loop.next_tick do
856
+ @log << :rejecting
857
+ deferred2.reject(:rejected)
858
+ @loop.next_tick do
859
+ @loop.next_tick do
860
+ @loop.stop
861
+ end
862
+ end
863
+ end
864
+ end
865
+ end
866
+ end
867
+ }
868
+
869
+ @log.should == [:finally, :rejecting, :rejected]
870
+ end
871
+ end
872
+
873
+ end
874
+
875
+ end
876
+
877
+ end
878
+
879
+
880
+
881
+ describe 'reject' do
882
+
883
+ it "should package a string into a rejected promise" do
884
+ @loop.run {
885
+ rejectedPromise = Libuv::Q.reject(@loop, 'not gonna happen')
886
+
887
+ @promise.then(@default_fail, proc {|reason|
888
+ @log << reason
889
+ })
890
+
891
+ @deferred.resolve(rejectedPromise)
892
+
893
+ @loop.next_tick do
894
+ @loop.stop
895
+ end
896
+ }
897
+
898
+ @log.should == ['not gonna happen']
899
+ end
900
+
901
+
902
+ it "should return a promise that forwards callbacks if the callbacks are missing" do
903
+ @loop.run {
904
+ rejectedPromise = Libuv::Q.reject(@loop, 'not gonna happen')
905
+
906
+ @promise.then(@default_fail, proc {|reason|
907
+ @log << reason
908
+ })
909
+
910
+ @deferred.resolve(rejectedPromise.then())
911
+
912
+ @loop.next_tick do
913
+ @loop.next_tick do
914
+ @loop.stop
915
+ end
916
+ end
917
+ }
918
+
919
+ @log.should == ['not gonna happen']
920
+ end
921
+
922
+ end
923
+
924
+
925
+
926
+ describe 'all' do
927
+
928
+ it "should resolve all of nothing" do
929
+ @loop.run {
930
+ Libuv::Q.all(@loop).then nil, @default_fail do |result|
931
+ @log << result
932
+ end
933
+
934
+ @loop.next_tick do
935
+ @loop.stop
936
+ end
937
+ }
938
+
939
+ @log.should == [[]]
940
+ end
941
+
942
+ it "should take an array of promises and return a promise for an array of results" do
943
+ @loop.run {
944
+ deferred1 = @loop.defer
945
+ deferred2 = @loop.defer
946
+
947
+ Libuv::Q.all(@loop, @promise, deferred1.promise, deferred2.promise).then nil, @default_fail do |result|
948
+ @log = result
949
+ @loop.stop
950
+ end
951
+
952
+ @loop.work { @deferred.resolve(:foo) }
953
+ @loop.work { deferred2.resolve(:baz) }
954
+ @loop.work { deferred1.resolve(:bar) }
955
+ }
956
+
957
+ @log.should == [:foo, :bar, :baz]
958
+ end
959
+
960
+
961
+ it "should reject the derived promise if at least one of the promises in the array is rejected" do
962
+ @loop.run {
963
+ deferred1 = @loop.defer
964
+ deferred2 = @loop.defer
965
+
966
+ Libuv::Q.all(@loop, @promise, deferred1.promise, deferred2.promise).then(@default_fail, proc {|reason|
967
+ @log << reason
968
+ @loop.stop
969
+ })
970
+
971
+ @loop.work { @deferred.resolve(:foo) }
972
+ @loop.work { deferred2.reject(:baz) }
973
+ }
974
+
975
+ @log.should == [:baz]
976
+ end
977
+
978
+ end
979
+
980
+ end