libuv 0.11.22 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +19 -17
  3. data/.gitmodules +3 -3
  4. data/.rspec +1 -1
  5. data/.travis.yml +16 -16
  6. data/Gemfile +4 -4
  7. data/LICENSE +23 -23
  8. data/README.md +89 -89
  9. data/Rakefile +31 -31
  10. data/lib/libuv.rb +54 -54
  11. data/lib/libuv/async.rb +47 -47
  12. data/lib/libuv/check.rb +55 -55
  13. data/lib/libuv/dns.rb +85 -85
  14. data/lib/libuv/error.rb +78 -74
  15. data/lib/libuv/ext/ext.rb +260 -258
  16. data/lib/libuv/ext/platform/darwin_x64.rb +23 -23
  17. data/lib/libuv/ext/platform/linux.rb +7 -7
  18. data/lib/libuv/ext/platform/unix.rb +29 -29
  19. data/lib/libuv/ext/platform/windows.rb +40 -40
  20. data/lib/libuv/ext/tasks.rb +31 -31
  21. data/lib/libuv/ext/tasks/mac.rb +23 -23
  22. data/lib/libuv/ext/tasks/unix.rb +23 -23
  23. data/lib/libuv/ext/tasks/win.rb +14 -14
  24. data/lib/libuv/ext/types.rb +238 -238
  25. data/lib/libuv/file.rb +281 -269
  26. data/lib/libuv/filesystem.rb +232 -232
  27. data/lib/libuv/fs_event.rb +31 -31
  28. data/lib/libuv/handle.rb +85 -85
  29. data/lib/libuv/idle.rb +56 -56
  30. data/lib/libuv/loop.rb +412 -412
  31. data/lib/libuv/mixins/assertions.rb +23 -23
  32. data/lib/libuv/mixins/fs_checks.rb +60 -58
  33. data/lib/libuv/mixins/listener.rb +34 -34
  34. data/lib/libuv/mixins/net.rb +40 -40
  35. data/lib/libuv/mixins/resource.rb +27 -27
  36. data/lib/libuv/mixins/stream.rb +153 -154
  37. data/lib/libuv/pipe.rb +184 -203
  38. data/lib/libuv/prepare.rb +56 -56
  39. data/lib/libuv/signal.rb +51 -51
  40. data/lib/libuv/tcp.rb +334 -334
  41. data/lib/libuv/timer.rb +85 -85
  42. data/lib/libuv/tty.rb +37 -37
  43. data/lib/libuv/udp.rb +240 -240
  44. data/lib/libuv/version.rb +3 -3
  45. data/lib/libuv/work.rb +75 -75
  46. data/libuv.gemspec +56 -56
  47. data/spec/async_spec.rb +61 -60
  48. data/spec/cpu_spec.rb +10 -10
  49. data/spec/defer_spec.rb +980 -980
  50. data/spec/dns_spec.rb +96 -90
  51. data/spec/filesystem_spec.rb +270 -261
  52. data/spec/idle_spec.rb +56 -56
  53. data/spec/pipe_spec.rb +160 -160
  54. data/spec/tcp_spec.rb +271 -267
  55. metadata +64 -51
data/lib/libuv/version.rb CHANGED
@@ -1,3 +1,3 @@
1
- module Libuv
2
- VERSION = '0.11.22'
3
- end
1
+ module Libuv
2
+ VERSION = '0.12.0'
3
+ end
data/lib/libuv/work.rb CHANGED
@@ -1,76 +1,76 @@
1
- module Libuv
2
- class Work < Q::DeferredPromise
3
- include Resource, Listener
4
-
5
-
6
- attr_reader :error
7
- attr_reader :result
8
-
9
-
10
- # @param loop [::Libuv::Loop] loop this work request will be associated
11
- # @param work [Proc] callback to be called in the thread pool
12
- def initialize(loop, work)
13
- super(loop, loop.defer)
14
-
15
- @work = work
16
- @complete = false
17
- @pointer = ::Libuv::Ext.create_request(:uv_work)
18
- @error = nil # error in callback
19
-
20
- error = check_result ::Libuv::Ext.queue_work(@loop, @pointer, callback(:on_work), callback(:on_complete))
21
- if error
22
- ::Libuv::Ext.free(@pointer)
23
- @complete = true
24
- @defer.reject(error)
25
- end
26
- end
27
-
28
- # Attempt to cancel the pending work. Returns true if the work has completed or was canceled.
29
- #
30
- # @return [true, false]
31
- def cancel
32
- if not @complete
33
- @complete = ::Libuv::Ext.cancel(@pointer) >= 0
34
- end
35
- @complete
36
- end
37
-
38
- # Indicates is the work has completed yet or not.
39
- #
40
- # @return [true, false]
41
- def completed?
42
- return @complete
43
- end
44
-
45
-
46
- private
47
-
48
-
49
- def on_complete(req, status)
50
- @complete = true
51
- ::Libuv::Ext.free(req)
52
-
53
- e = check_result(status)
54
- if e
55
- @defer.reject(e)
56
- else
57
- if @error
58
- @defer.reject(@error)
59
- else
60
- @defer.resolve(@result)
61
- end
62
- end
63
-
64
- # Clean up references
65
- clear_callbacks
66
- end
67
-
68
- def on_work(req)
69
- begin
70
- @result = @work.call
71
- rescue Exception => e
72
- @error = e # Catch errors for promise resolution
73
- end
74
- end
75
- end
1
+ module Libuv
2
+ class Work < Q::DeferredPromise
3
+ include Resource, Listener
4
+
5
+
6
+ attr_reader :error
7
+ attr_reader :result
8
+
9
+
10
+ # @param loop [::Libuv::Loop] loop this work request will be associated
11
+ # @param work [Proc] callback to be called in the thread pool
12
+ def initialize(loop, work)
13
+ super(loop, loop.defer)
14
+
15
+ @work = work
16
+ @complete = false
17
+ @pointer = ::Libuv::Ext.create_request(:uv_work)
18
+ @error = nil # error in callback
19
+
20
+ error = check_result ::Libuv::Ext.queue_work(@loop, @pointer, callback(:on_work), callback(:on_complete))
21
+ if error
22
+ ::Libuv::Ext.free(@pointer)
23
+ @complete = true
24
+ @defer.reject(error)
25
+ end
26
+ end
27
+
28
+ # Attempt to cancel the pending work. Returns true if the work has completed or was canceled.
29
+ #
30
+ # @return [true, false]
31
+ def cancel
32
+ if not @complete
33
+ @complete = ::Libuv::Ext.cancel(@pointer) >= 0
34
+ end
35
+ @complete
36
+ end
37
+
38
+ # Indicates is the work has completed yet or not.
39
+ #
40
+ # @return [true, false]
41
+ def completed?
42
+ return @complete
43
+ end
44
+
45
+
46
+ private
47
+
48
+
49
+ def on_complete(req, status)
50
+ @complete = true
51
+ ::Libuv::Ext.free(req)
52
+
53
+ e = check_result(status)
54
+ if e
55
+ @defer.reject(e)
56
+ else
57
+ if @error
58
+ @defer.reject(@error)
59
+ else
60
+ @defer.resolve(@result)
61
+ end
62
+ end
63
+
64
+ # Clean up references
65
+ clear_callbacks
66
+ end
67
+
68
+ def on_work(req)
69
+ begin
70
+ @result = @work.call
71
+ rescue Exception => e
72
+ @error = e # Catch errors for promise resolution
73
+ end
74
+ end
75
+ end
76
76
  end
data/libuv.gemspec CHANGED
@@ -1,56 +1,56 @@
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_runtime_dependency 'ruby-tls', '>= 1.0.3'
21
-
22
- gem.add_development_dependency 'rspec', '>= 2.14'
23
- gem.add_development_dependency 'rake', '>= 10.1'
24
- gem.add_development_dependency 'yard'
25
-
26
- gem.files = `git ls-files`.split("\n")
27
- gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
28
-
29
- # Add the submodule to the gem
30
- relative_path = File.expand_path("../", __FILE__) + '/'
31
- `git submodule --quiet foreach pwd`.split($\).each do |submodule_path|
32
-
33
- if (ENV['OS'] == 'Windows_NT') && submodule_path[0] == '/'
34
- # Detect if cygwin path is being used by git
35
- submodule_path = submodule_path[1..-1]
36
- submodule_path.insert(1, ':')
37
- end
38
-
39
- # for each submodule, change working directory to that submodule
40
- Dir.chdir(submodule_path) do
41
- # Make the submodule path relative
42
- submodule_path = submodule_path.gsub(/#{relative_path}/i, '')
43
-
44
- # issue git ls-files in submodule's directory
45
- submodule_files = `git ls-files`.split($\)
46
-
47
- # prepend the submodule path to create relative file paths
48
- submodule_files_paths = submodule_files.map do |filename|
49
- File.join(submodule_path, filename)
50
- end
51
-
52
- # add relative paths to gem.files
53
- gem.files += submodule_files_paths
54
- end
55
- end
56
- 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_runtime_dependency 'ruby-tls', '>= 1.0.3'
21
+
22
+ gem.add_development_dependency 'rspec', '>= 2.14'
23
+ gem.add_development_dependency 'rake', '>= 10.1'
24
+ gem.add_development_dependency 'yard'
25
+
26
+ gem.files = `git ls-files`.split("\n")
27
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
28
+
29
+ # Add the submodule to the gem
30
+ relative_path = File.expand_path("../", __FILE__) + '/'
31
+ `git submodule --quiet foreach pwd`.split($\).each do |submodule_path|
32
+
33
+ if (ENV['OS'] == 'Windows_NT') && submodule_path[0] == '/'
34
+ # Detect if cygwin path is being used by git
35
+ submodule_path = submodule_path[1..-1]
36
+ submodule_path.insert(1, ':')
37
+ end
38
+
39
+ # for each submodule, change working directory to that submodule
40
+ Dir.chdir(submodule_path) do
41
+ # Make the submodule path relative
42
+ submodule_path = submodule_path.gsub(/#{relative_path}/i, '')
43
+
44
+ # issue git ls-files in submodule's directory
45
+ submodule_files = `git ls-files`.split($\)
46
+
47
+ # prepend the submodule path to create relative file paths
48
+ submodule_files_paths = submodule_files.map do |filename|
49
+ File.join(submodule_path, filename)
50
+ end
51
+
52
+ # add relative paths to gem.files
53
+ gem.files += submodule_files_paths
54
+ end
55
+ end
56
+ end
data/spec/async_spec.rb CHANGED
@@ -1,60 +1,61 @@
1
- require 'libuv'
2
-
3
-
4
- describe Libuv::Async do
5
- before :each do
6
- @log = []
7
- @general_failure = []
8
-
9
- @loop = Libuv::Loop.default
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
- expect(@general_failure).to eq([])
58
- expect(@count < 7 && @count > 3).to eq(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.default
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
+ @timeout.close
46
+ @loop.stop
47
+ end
48
+ stopper.start(1000)
49
+ end
50
+
51
+ @loop.work(proc {
52
+ callback.call
53
+ }).catch do |err|
54
+ @general_failure << err
55
+ end
56
+ }
57
+
58
+ expect(@general_failure).to eq([])
59
+ expect(@count < 7 && @count > 3).to eq(true)
60
+ end
61
+ end
data/spec/cpu_spec.rb CHANGED
@@ -1,10 +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
- expect(count != nil && count > 0).to eq(true)
9
- end
10
- end
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
+ expect(count != nil && count > 0).to eq(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.default
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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq(['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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([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
- expect(@log).to eq([: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
- expect(@log).to eq([])
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
- expect(@log).to eq([])
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
- expect(@log).to eq([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
- expect(@log).to eq([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
- expect(@log).to eq([])
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
- expect(@log).to eq([: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
- expect(@log).to eq([])
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
- expect(@log).to eq([: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
- expect(@log).to eq([])
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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq([: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
- expect(@log).to eq(['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
- expect(@log).to eq(['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
- expect(@log).to eq([[]])
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
- expect(@log).to eq([: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
- expect(@log).to eq([: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.default
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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq(['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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([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
+ expect(@log).to eq([: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
+ expect(@log).to eq([])
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
+ expect(@log).to eq([])
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
+ expect(@log).to eq([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
+ expect(@log).to eq([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
+ expect(@log).to eq([])
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
+ expect(@log).to eq([: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
+ expect(@log).to eq([])
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
+ expect(@log).to eq([: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
+ expect(@log).to eq([])
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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq([: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
+ expect(@log).to eq(['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
+ expect(@log).to eq(['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
+ expect(@log).to eq([[]])
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
+ expect(@log).to eq([: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
+ expect(@log).to eq([:baz])
976
+ end
977
+
978
+ end
979
+
980
+ end