a-ruby-promise 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,156 @@
1
+ # encoding: UTF-8
2
+ require_relative "../spec_helper"
3
+ require_relative "../promises_aplus"
4
+
5
+ dummy = { dummy: "dummy" } # we fulfill or reject with this when we don't intend to test against it
6
+ sentinel = { sentinel: "sentinel" } # a sentinel fulfillment value to test for with strict equality
7
+
8
+ describe "2.2.2: If `onFulfilled` is a function," do
9
+ include PromisesAplus
10
+
11
+ describe "2.2.2.1: it must be called after `promise` is fulfilled, with `promise`’s fulfillment value as its first argument." do
12
+ PromisesAplus.test_fulfilled(self, sentinel) do |promise, done|
13
+ promise.then ->(value) {
14
+ value.must_equal sentinel
15
+ done.call
16
+ }
17
+ end
18
+ end
19
+
20
+ describe "2.2.2.2: it must not be called before `promise` is fulfilled" do
21
+
22
+ it "fulfilled after a delay" do
23
+ d = deferred
24
+ is_fulfilled = false
25
+ d.promise.then ->(v) {
26
+ assert_equal true, is_fulfilled
27
+ done!
28
+ }
29
+
30
+ Thread.new do
31
+ short_sleep
32
+ # Notice: flipped statements since we don't have delayed execution
33
+ is_fulfilled = true
34
+ d.resolve(dummy)
35
+ end
36
+ end
37
+
38
+ it "never fulfilled" do
39
+ d = deferred
40
+ on_fulfilled_called = false
41
+
42
+ d.promise.then ->(v) {
43
+ on_fulfilled_called = true
44
+ done!
45
+ }
46
+
47
+ done = method(:done!)
48
+ Thread.new do
49
+ 3.times { short_sleep }
50
+ assert_equal false, on_fulfilled_called
51
+ done.call
52
+ end
53
+ end
54
+ end
55
+
56
+ describe "2.2.2.3: it must not be called more than once." do
57
+ it "already-fulfilled" do
58
+ times_called = 0
59
+
60
+ resolved(dummy).then(->(v) {
61
+ (times_called += 1).must_equal 1
62
+ done!
63
+ })
64
+ end
65
+
66
+ it "trying to fulfill a pending promise more than once, immediately" do
67
+ d = deferred
68
+ times_called = 0
69
+
70
+ d.promise.then(->(v) {
71
+ (times_called += 1).must_equal 1
72
+ done!
73
+ })
74
+
75
+ d.resolve(dummy)
76
+ d.resolve(dummy)
77
+ end
78
+
79
+ it "trying to fulfill a pending promise more than once, delayed" do
80
+ d = deferred
81
+ times_called = 0
82
+
83
+ d.promise.then(->(v) {
84
+ assert_equal 1, (times_called += 1)
85
+ done!
86
+ })
87
+
88
+ Thread.new do
89
+ short_sleep
90
+ d.resolve(dummy)
91
+ d.resolve(dummy)
92
+ end
93
+ end
94
+
95
+ it "trying to fulfill a pending promise more than once, immediately then delayed" do
96
+ d = deferred
97
+ times_called = 0
98
+
99
+ d.promise.then(->(v) {
100
+ (times_called += 1).must_equal 1
101
+ done!
102
+ })
103
+
104
+ d.resolve(dummy)
105
+ Thread.new do
106
+ short_sleep
107
+ d.resolve(dummy)
108
+ end
109
+ end
110
+
111
+ it "when multiple `then` calls are made, spaced apart in time" do
112
+ d = deferred
113
+ times_called = [0, 0, 0]
114
+
115
+ d.promise.then(->(v) {
116
+ assert_equal 1, (times_called[0] += 1)
117
+ })
118
+
119
+ Thread.new do
120
+ short_sleep
121
+ d.promise.then(->(v) {
122
+ assert_equal 1, (times_called[1] += 1)
123
+ })
124
+ end
125
+
126
+ Thread.new do
127
+ 2.times { short_sleep }
128
+ d.promise.then(->(v) {
129
+ assert_equal 1, (times_called[2] += 1)
130
+ done!
131
+ })
132
+ end
133
+
134
+ Thread.new do
135
+ 3.times { short_sleep }
136
+ d.resolve(dummy)
137
+ end
138
+ end
139
+
140
+ it "when `then` is interleaved with fulfillment" do
141
+ d = deferred
142
+ times_called = [0, 0]
143
+
144
+ d.promise.then(->(v) {
145
+ (times_called[0] += 1).must_equal 1
146
+ })
147
+
148
+ d.resolve(dummy)
149
+
150
+ d.promise.then(->(v) {
151
+ (times_called[1] += 1).must_equal 1
152
+ done!
153
+ })
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,142 @@
1
+ # encoding: UTF-8
2
+ require_relative "../spec_helper"
3
+ require_relative "../promises_aplus"
4
+
5
+ dummy = { dummy: "dummy" }
6
+ sentinel = { sentinel: "sentinel" }
7
+
8
+ describe "2.2.3: If `onRejected` is a function," do
9
+ include PromisesAplus
10
+
11
+ describe "2.2.3.1: it must be called after `promise` is rejected, with `promise`’s rejection reason as its first argument." do
12
+ PromisesAplus.test_rejected(self, sentinel) do |promise, done|
13
+ promise.then nil, ->(reason) {
14
+ reason.must_equal sentinel
15
+ done.call
16
+ }
17
+ end
18
+ end
19
+
20
+ describe "2.2.3.2: it must not be called before `promise` is rejected" do
21
+
22
+ it "rejected after a delay" do
23
+ d = deferred
24
+ is_rejected = false
25
+ d.promise.then(nil, ->(r) {
26
+ is_rejected.must_equal true
27
+ done!
28
+ })
29
+
30
+ sleep 0.050
31
+ is_rejected = true
32
+ d.reject(dummy)
33
+ end
34
+
35
+ it "never rejected" do
36
+ d = deferred
37
+ on_rejected_called = false
38
+
39
+ d.promise.then(nil, ->(r) {
40
+ on_rejected_called = true
41
+ done!
42
+ })
43
+
44
+ sleep 0.150
45
+ on_rejected_called.must_equal false
46
+ done!
47
+ end
48
+ end
49
+
50
+ describe "2.2.3.3: it must not be called more than once." do
51
+ it "already-rejected" do
52
+ times_called = 0
53
+
54
+ rejected(dummy).then(nil, ->(r) {
55
+ (times_called += 1).must_equal 1
56
+ done!
57
+ })
58
+ end
59
+
60
+ it "trying to reject a pending promise more than once, immediately" do
61
+ d = deferred
62
+ times_called = 0
63
+
64
+ d.promise.then(nil, ->(r) {
65
+ (times_called += 1).must_equal 1
66
+ done!
67
+ })
68
+
69
+ d.reject(dummy)
70
+ d.reject(dummy)
71
+ end
72
+
73
+ it "trying to reject a pending promise more than once, delayed" do
74
+ d = deferred
75
+ times_called = 0
76
+
77
+ d.promise.then(nil, ->(r) {
78
+ (times_called += 1).must_equal 1
79
+ done!
80
+ })
81
+
82
+ sleep 0.050
83
+ d.reject(dummy)
84
+ d.reject(dummy)
85
+ end
86
+
87
+ it "trying to reject a pending promise more than once, immediately then delayed" do
88
+ d = deferred
89
+ times_called = 0
90
+
91
+ d.promise.then(nil, ->(r) {
92
+ (times_called += 1).must_equal 1
93
+ done!
94
+ })
95
+
96
+ d.reject(dummy)
97
+
98
+ sleep 0.050
99
+ d.reject(dummy)
100
+ end
101
+
102
+ it "when multiple `then` calls are made, spaced apart in time" do
103
+ d = deferred
104
+ times_called = [0, 0, 0]
105
+
106
+ d.promise.then(nil, ->(r) {
107
+ (times_called[0] += 1).must_equal 1
108
+ })
109
+
110
+ sleep 0.050
111
+ d.promise.then(nil, ->(r) {
112
+ (times_called[1] += 1).must_equal 1
113
+ })
114
+
115
+ sleep 0.050
116
+ d.promise.then(nil, ->(r) {
117
+ (times_called[2] += 1).must_equal 1
118
+ done!
119
+ })
120
+
121
+ sleep 0.050
122
+ d.reject(dummy)
123
+ end
124
+
125
+ it "when `then` is interleaved with rejection" do
126
+ d = deferred
127
+
128
+ times_called = [0, 0]
129
+
130
+ d.promise.then(nil, ->(r) {
131
+ (times_called[0] += 1).must_equal 1
132
+ })
133
+
134
+ d.reject(dummy)
135
+
136
+ d.promise.then(nil, ->(r) {
137
+ (times_called[1] += 1).must_equal 1
138
+ done!
139
+ })
140
+ end
141
+ end
142
+ end
@@ -0,0 +1,188 @@
1
+ # encoding: UTF-8
2
+ require_relative "../spec_helper"
3
+ require_relative "../promises_aplus"
4
+
5
+ dummy = { dummy: "dummy" }
6
+ sentinel = { sentinel: "sentinel" }
7
+
8
+ describe "2.2.4: `onFulfilled` or `onRejected` must not be called until the execution context stack contains only platform code." do
9
+ include PromisesAplus
10
+
11
+ describe "`then` returns before the promise becomes fulfilled or rejected" do
12
+ before { done! and skip "don't know how to delay execution yet" }
13
+
14
+ PromisesAplus.test_fulfilled(self, sentinel) do |promise, done|
15
+ thenHasReturned = false
16
+
17
+ promise.then ->(v) {
18
+ thenHasReturned.must_equal true
19
+ done.call
20
+ }
21
+
22
+ thenHasReturned = true
23
+ end
24
+
25
+ PromisesAplus.test_rejected(self, dummy) do |promise, done|
26
+ thenHasReturned = false
27
+
28
+ promise.then nil, ->(r) {
29
+ thenHasReturned.must_equal true
30
+ done.call
31
+ }
32
+
33
+ thenHasReturned = true
34
+ end
35
+ end
36
+
37
+ describe "Clean-stack execution ordering tests (fulfillment case)" do
38
+ before { done! and skip "don't know how to delay execution yet" }
39
+
40
+ it "when `onFulfilled` is added immediately before the promise is fulfilled" do
41
+ d = deferred()
42
+ onFulfilledCalled = false
43
+
44
+ d.promise.then ->(v) do
45
+ onFulfilledCalled = true
46
+ end
47
+
48
+ d.resolve(dummy)
49
+
50
+ onFulfilledCalled.must_equal false
51
+ done!
52
+ end
53
+
54
+ it "when `onFulfilled` is added immediately after the promise is fulfilled" do
55
+ d = deferred()
56
+ onFulfilledCalled = false
57
+
58
+ d.resolve(dummy)
59
+
60
+ d.promise.then ->(v) do
61
+ onFulfilledCalled = true
62
+ end
63
+
64
+ onFulfilledCalled.must_equal false
65
+ done!
66
+ end
67
+
68
+ it "when one `onFulfilled` is added inside another `onFulfilled`" do
69
+ promise = resolved()
70
+ firstOnFulfilledFinished = false
71
+
72
+ promise.then ->(v) do
73
+ promise.then ->(v) do
74
+ firstOnFulfilledFinished.must_equal true
75
+ done!
76
+ end
77
+ firstOnFulfilledFinished = true
78
+ end
79
+ end
80
+
81
+ it "when `onFulfilled` is added inside an `onRejected`" do
82
+ promise = rejected()
83
+ promise2 = resolved()
84
+ firstOnRejectedFinished = false
85
+
86
+ promise.then nil, ->(r) do
87
+ promise2.then ->(v) do
88
+ firstOnRejectedFinished.must_equal true
89
+ done!
90
+ end
91
+ firstOnRejectedFinished = true
92
+ end
93
+ end
94
+
95
+ it "when the promise is fulfilled asynchronously" do
96
+ d = deferred()
97
+ firstStackFinished = false
98
+
99
+ f = Fiber.new do
100
+ d.resolve(dummy)
101
+ firstStackFinished = true
102
+ end
103
+
104
+ d.promise.then ->(v) do
105
+ firstStackFinished.must_equal true
106
+ done!
107
+ end
108
+
109
+ f.resume
110
+ end
111
+ end
112
+
113
+ describe "Clean-stack execution ordering tests (rejection case)" do
114
+ before { done! and skip "don't know how to delay execution yet" }
115
+
116
+ it "when `onRejected` is added immediately before the promise is rejected" do
117
+ d = deferred()
118
+ onRejectedCalled = false
119
+
120
+ d.promise.then nil, ->(r) do
121
+ onRejectedCalled = true
122
+ end
123
+
124
+ d.reject(dummy)
125
+
126
+ onRejectedCalled.must_equal false
127
+ done!
128
+ end
129
+
130
+ it "when `onRejected` is added immediately after the promise is rejected" do
131
+ d = deferred()
132
+ onRejectedCalled = false
133
+
134
+ d.reject(dummy)
135
+
136
+ d.promise.then nil, ->(r) do
137
+ onRejectedCalled = true
138
+ end
139
+
140
+ onRejectedCalled.must_equal false
141
+ done!
142
+ end
143
+
144
+ it "when `onRejected` is added inside an `onFulfilled`" do
145
+ promise = resolved()
146
+ promise2 = rejected()
147
+ firstOnFulfilledFinished = false
148
+
149
+ promise.then ->(v) do
150
+ promise2.then nil, ->(r) do
151
+ firstOnFulfilledFinished.must_equal true
152
+ done!
153
+ end
154
+ firstOnFulfilledFinished = true
155
+ end
156
+ end
157
+
158
+ it "when one `onRejected` is added inside another `onRejected`" do
159
+ promise = rejected()
160
+ firstOnRejectedFinished = false
161
+
162
+ promise.then nil, ->(r) do
163
+ promise.then nil, ->(r) do
164
+ firstOnRejectedFinished.must_equal true
165
+ done!
166
+ end
167
+ firstOnRejectedFinished = true
168
+ end
169
+ end
170
+
171
+ it "when the promise is rejected asynchronously" do
172
+ d = deferred()
173
+ firstStackFinished = false
174
+
175
+ f = Fiber.new do
176
+ d.reject(dummy)
177
+ firstStackFinished = true
178
+ end
179
+
180
+ d.promise.then nil, ->(r) do
181
+ firstStackFinished.must_equal true
182
+ done!
183
+ end
184
+
185
+ f.resume
186
+ end
187
+ end
188
+ end