typed_dag 2.0.1 → 2.0.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.
- checksums.yaml +4 -4
- data/README.md +2 -2
- data/lib/typed_dag/version.rb +1 -1
- metadata +3 -141
- data/spec/spec_helper.rb +0 -89
- data/spec/support/helpers.rb +0 -47
- data/spec/test_app/Rakefile +0 -6
- data/spec/test_app/app/assets/config/manifest.js +0 -4
- data/spec/test_app/app/assets/javascripts/application.js +0 -13
- data/spec/test_app/app/assets/javascripts/cable.js +0 -13
- data/spec/test_app/app/assets/stylesheets/application.css +0 -15
- data/spec/test_app/app/channels/application_cable/channel.rb +0 -4
- data/spec/test_app/app/channels/application_cable/connection.rb +0 -4
- data/spec/test_app/app/controllers/application_controller.rb +0 -3
- data/spec/test_app/app/helpers/application_helper.rb +0 -2
- data/spec/test_app/app/jobs/application_job.rb +0 -2
- data/spec/test_app/app/mailers/application_mailer.rb +0 -4
- data/spec/test_app/app/models/application_record.rb +0 -3
- data/spec/test_app/app/models/message.rb +0 -2
- data/spec/test_app/app/models/relation.rb +0 -2
- data/spec/test_app/app/views/layouts/application.html.erb +0 -14
- data/spec/test_app/app/views/layouts/mailer.html.erb +0 -13
- data/spec/test_app/app/views/layouts/mailer.text.erb +0 -1
- data/spec/test_app/bin/bundle +0 -3
- data/spec/test_app/bin/rails +0 -4
- data/spec/test_app/bin/rake +0 -4
- data/spec/test_app/bin/setup +0 -38
- data/spec/test_app/bin/update +0 -29
- data/spec/test_app/bin/yarn +0 -11
- data/spec/test_app/config.ru +0 -5
- data/spec/test_app/config/application.rb +0 -26
- data/spec/test_app/config/boot.rb +0 -5
- data/spec/test_app/config/cable.yml +0 -10
- data/spec/test_app/config/database.mysql.yml.travis +0 -9
- data/spec/test_app/config/database.postgresql.yml.travis +0 -9
- data/spec/test_app/config/database.yml +0 -23
- data/spec/test_app/config/environment.rb +0 -5
- data/spec/test_app/config/environments/development.rb +0 -54
- data/spec/test_app/config/environments/production.rb +0 -91
- data/spec/test_app/config/environments/test.rb +0 -42
- data/spec/test_app/config/initializers/application_controller_renderer.rb +0 -6
- data/spec/test_app/config/initializers/assets.rb +0 -14
- data/spec/test_app/config/initializers/backtrace_silencers.rb +0 -7
- data/spec/test_app/config/initializers/cookies_serializer.rb +0 -5
- data/spec/test_app/config/initializers/filter_parameter_logging.rb +0 -4
- data/spec/test_app/config/initializers/inflections.rb +0 -16
- data/spec/test_app/config/initializers/mime_types.rb +0 -4
- data/spec/test_app/config/initializers/typed_dag.rb +0 -12
- data/spec/test_app/config/initializers/wrap_parameters.rb +0 -14
- data/spec/test_app/config/locales/en.yml +0 -33
- data/spec/test_app/config/puma.rb +0 -56
- data/spec/test_app/config/routes.rb +0 -3
- data/spec/test_app/config/secrets.yml +0 -32
- data/spec/test_app/config/spring.rb +0 -6
- data/spec/test_app/db/development.sqlite3 +0 -0
- data/spec/test_app/db/migrate/20170831093433_create_nodes_and_endges.rb +0 -22
- data/spec/test_app/db/schema.rb +0 -35
- data/spec/test_app/db/test.sqlite3 +0 -0
- data/spec/test_app/log/development.log +0 -101
- data/spec/test_app/log/test.log +0 -0
- data/spec/test_app/package.json +0 -5
- data/spec/test_app/public/404.html +0 -67
- data/spec/test_app/public/422.html +0 -67
- data/spec/test_app/public/500.html +0 -66
- data/spec/test_app/public/apple-touch-icon-precomposed.png +0 -0
- data/spec/test_app/public/apple-touch-icon.png +0 -0
- data/spec/test_app/public/favicon.ico +0 -0
- data/spec/typed_dag/configuration.rb +0 -92
- data/spec/typed_dag/edge_spec.rb +0 -578
- data/spec/typed_dag/node_spec.rb +0 -2178
- data/spec/typed_dag/sql/add_closure_spec.rb +0 -116
- data/spec/typed_dag/sql/truncate_closure_spec.rb +0 -112
- data/spec/typed_dag_spec.rb +0 -7
data/spec/typed_dag/node_spec.rb
DELETED
@@ -1,2178 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
RSpec.describe TypedDag::Node, 'included in Message' do
|
4
|
-
include TypedDag::Specs::Helpers
|
5
|
-
|
6
|
-
let(:message) { Message.create }
|
7
|
-
let(:other_message) { Message.create }
|
8
|
-
let(:child_message) { Message.create parent: message }
|
9
|
-
let(:grandchild_message) { Message.create parent: child_message }
|
10
|
-
let(:parent_message) do
|
11
|
-
parent = Message.create
|
12
|
-
message.parent = parent
|
13
|
-
parent
|
14
|
-
end
|
15
|
-
let(:grandparent_message) do
|
16
|
-
grandparent = Message.create
|
17
|
-
parent_message.parent = grandparent
|
18
|
-
grandparent
|
19
|
-
end
|
20
|
-
|
21
|
-
describe '#in_closure?' do
|
22
|
-
it 'is false' do
|
23
|
-
expect(message.in_closure?(other_message))
|
24
|
-
.to be_falsey
|
25
|
-
end
|
26
|
-
|
27
|
-
context 'with a grandparent' do
|
28
|
-
before do
|
29
|
-
parent_message
|
30
|
-
grandparent_message
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'is true' do
|
34
|
-
expect(message.in_closure?(grandparent_message))
|
35
|
-
.to be_truthy
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
context 'with a grandchild' do
|
40
|
-
before do
|
41
|
-
child_message
|
42
|
-
grandchild_message
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'is true' do
|
46
|
-
expect(message.in_closure?(grandchild_message))
|
47
|
-
.to be_truthy
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
shared_examples_for 'single typed dag' do |configuration|
|
53
|
-
type = configuration[:type]
|
54
|
-
to = configuration[:to]
|
55
|
-
from = configuration[:from].is_a?(Hash) ? configuration[:from][:name] : configuration[:from]
|
56
|
-
from_limit = configuration[:from].is_a?(Hash) ? configuration[:from][:limit] : nil
|
57
|
-
# defining from and from_limit again here to capture the closure and by that avoid
|
58
|
-
# having to pass them around as params
|
59
|
-
let(:from) do
|
60
|
-
configuration[:from].is_a?(Hash) ? configuration[:from][:name] : configuration[:from]
|
61
|
-
end
|
62
|
-
let(:from_limit) { configuration[:from].is_a?(Hash) ? configuration[:from][:limit] : nil }
|
63
|
-
all_to = configuration[:all_to]
|
64
|
-
all_to_depth = (configuration[:all_to].to_s + '_of_depth').to_sym
|
65
|
-
all_from = configuration[:all_from]
|
66
|
-
all_from_depth = (configuration[:all_from].to_s + '_of_depth').to_sym
|
67
|
-
|
68
|
-
describe "##{type}_root?" do
|
69
|
-
let(:method_name) { "#{type}_root?" }
|
70
|
-
|
71
|
-
description = <<-'WITH'
|
72
|
-
|
73
|
-
DAG:
|
74
|
-
A
|
75
|
-
|
76
|
-
WITH
|
77
|
-
context description do
|
78
|
-
let!(:a) { Message.create text: 'A' }
|
79
|
-
|
80
|
-
it 'is true for A' do
|
81
|
-
expect(a.send(method_name))
|
82
|
-
.to be_truthy
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
description = <<-'WITH'
|
87
|
-
|
88
|
-
DAG:
|
89
|
-
A
|
90
|
-
|
|
91
|
-
|
|
92
|
-
+
|
93
|
-
B
|
94
|
-
|
95
|
-
WITH
|
96
|
-
context description do
|
97
|
-
let!(:a) { Message.create text: 'A' }
|
98
|
-
let!(:b) { message_with_from 'B', a }
|
99
|
-
|
100
|
-
it 'is true for A' do
|
101
|
-
expect(a.send(method_name))
|
102
|
-
.to be_truthy
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'is false for B' do
|
106
|
-
expect(b.send(method_name))
|
107
|
-
.to be_falsy
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
describe ".#{type}_roots" do
|
113
|
-
let(:method_name) { "#{type}_roots" }
|
114
|
-
|
115
|
-
description = <<-'WITH'
|
116
|
-
|
117
|
-
DAG:
|
118
|
-
A
|
119
|
-
|
120
|
-
WITH
|
121
|
-
context description do
|
122
|
-
let!(:a) { Message.create text: 'A' }
|
123
|
-
|
124
|
-
it 'is A' do
|
125
|
-
expect(Message.send(method_name))
|
126
|
-
.to match_array [a]
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
description = <<-'WITH'
|
131
|
-
|
132
|
-
DAG:
|
133
|
-
A
|
134
|
-
|
|
135
|
-
|
|
136
|
-
+
|
137
|
-
B
|
138
|
-
|
139
|
-
WITH
|
140
|
-
context description do
|
141
|
-
let!(:a) { Message.create text: 'A' }
|
142
|
-
let!(:b) { message_with_from 'B', a }
|
143
|
-
|
144
|
-
it 'is A' do
|
145
|
-
expect(Message.send(method_name))
|
146
|
-
.to match_array [a]
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
describe "##{type}_roots" do
|
152
|
-
let(:method_name) { "#{type}_roots" }
|
153
|
-
|
154
|
-
description = <<-'WITH'
|
155
|
-
|
156
|
-
DAG:
|
157
|
-
A
|
158
|
-
|
159
|
-
WITH
|
160
|
-
context description do
|
161
|
-
let!(:a) { Message.create text: 'A' }
|
162
|
-
|
163
|
-
it 'for a is empty' do
|
164
|
-
expect(a.send(method_name))
|
165
|
-
.to be_empty
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
if from_limit && from_limit == 1
|
170
|
-
description = <<-'WITH'
|
171
|
-
|
172
|
-
DAG:
|
173
|
-
A
|
174
|
-
|
|
175
|
-
|
|
176
|
-
+
|
177
|
-
B
|
178
|
-
|
|
179
|
-
|
|
180
|
-
+
|
181
|
-
C
|
182
|
-
|
183
|
-
WITH
|
184
|
-
context description do
|
185
|
-
let!(:a) { Message.create text: 'A' }
|
186
|
-
let!(:b) { message_with_from 'B', a }
|
187
|
-
let!(:c) { message_with_from 'C', b }
|
188
|
-
|
189
|
-
it 'for a is empty' do
|
190
|
-
expect(a.send(method_name))
|
191
|
-
.to be_empty
|
192
|
-
end
|
193
|
-
|
194
|
-
it 'for b is a' do
|
195
|
-
expect(b.send(method_name))
|
196
|
-
.to match_array [a]
|
197
|
-
end
|
198
|
-
|
199
|
-
it 'for c is a' do
|
200
|
-
expect(c.send(method_name))
|
201
|
-
.to match_array [a]
|
202
|
-
end
|
203
|
-
end
|
204
|
-
else
|
205
|
-
description = <<-'WITH'
|
206
|
-
|
207
|
-
DAG:
|
208
|
-
A B
|
209
|
-
\ /
|
210
|
-
\ /
|
211
|
-
+ +
|
212
|
-
C
|
213
|
-
|
|
214
|
-
|
|
215
|
-
+
|
216
|
-
D
|
217
|
-
|
218
|
-
WITH
|
219
|
-
context description do
|
220
|
-
let!(:a) { Message.create text: 'A' }
|
221
|
-
let!(:b) { Message.create text: 'B' }
|
222
|
-
let!(:c) { message_with_from 'C', [a, b] }
|
223
|
-
let!(:d) { message_with_from 'D', c }
|
224
|
-
|
225
|
-
it 'for a is empty' do
|
226
|
-
expect(a.send(method_name))
|
227
|
-
.to be_empty
|
228
|
-
end
|
229
|
-
|
230
|
-
it 'for b is empty' do
|
231
|
-
expect(b.send(method_name))
|
232
|
-
.to be_empty
|
233
|
-
end
|
234
|
-
|
235
|
-
it 'for c is a and b' do
|
236
|
-
expect(c.send(method_name))
|
237
|
-
.to match_array [a, b]
|
238
|
-
end
|
239
|
-
|
240
|
-
it 'for d is a and b' do
|
241
|
-
expect(d.send(method_name))
|
242
|
-
.to match_array [a, b]
|
243
|
-
end
|
244
|
-
end
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
describe "#{type}_leaf?" do
|
249
|
-
let(:method_name) { "#{type}_leaf?" }
|
250
|
-
|
251
|
-
description = <<-'WITH'
|
252
|
-
|
253
|
-
DAG:
|
254
|
-
A
|
255
|
-
|
256
|
-
WITH
|
257
|
-
context description do
|
258
|
-
let!(:a) { Message.create text: 'A' }
|
259
|
-
|
260
|
-
it 'is true for A' do
|
261
|
-
expect(a.send(method_name))
|
262
|
-
.to be_truthy
|
263
|
-
end
|
264
|
-
end
|
265
|
-
|
266
|
-
description = <<-'WITH'
|
267
|
-
|
268
|
-
DAG:
|
269
|
-
A
|
270
|
-
|
|
271
|
-
|
|
272
|
-
+
|
273
|
-
B
|
274
|
-
|
275
|
-
WITH
|
276
|
-
context description do
|
277
|
-
let!(:a) { Message.create text: 'A' }
|
278
|
-
let!(:b) { message_with_from 'B', a }
|
279
|
-
|
280
|
-
it 'is false for A' do
|
281
|
-
expect(a.send(method_name))
|
282
|
-
.to be_falsy
|
283
|
-
end
|
284
|
-
|
285
|
-
it 'is true for B' do
|
286
|
-
expect(b.send(method_name))
|
287
|
-
.to be_truthy
|
288
|
-
end
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
describe "##{type}_leaves" do
|
293
|
-
let(:method_name) { "#{type}_leaves" }
|
294
|
-
|
295
|
-
description = <<-'WITH'
|
296
|
-
|
297
|
-
DAG:
|
298
|
-
A
|
299
|
-
|
300
|
-
WITH
|
301
|
-
context description do
|
302
|
-
let!(:a) { Message.create text: 'A' }
|
303
|
-
|
304
|
-
it 'for a is empty' do
|
305
|
-
expect(a.send(method_name))
|
306
|
-
.to be_empty
|
307
|
-
end
|
308
|
-
end
|
309
|
-
|
310
|
-
description = <<-'WITH'
|
311
|
-
|
312
|
-
DAG:
|
313
|
-
A
|
314
|
-
/ \
|
315
|
-
/ \
|
316
|
-
+ +
|
317
|
-
B F
|
318
|
-
/ \
|
319
|
-
/ \
|
320
|
-
+ +
|
321
|
-
C D
|
322
|
-
|
|
323
|
-
|
|
324
|
-
+
|
325
|
-
E
|
326
|
-
|
327
|
-
WITH
|
328
|
-
context description do
|
329
|
-
let!(:a) { Message.create text: 'A' }
|
330
|
-
let!(:b) { message_with_from 'B', a }
|
331
|
-
let!(:c) { message_with_from 'C', b }
|
332
|
-
let!(:d) { message_with_from 'D', b }
|
333
|
-
let!(:e) { message_with_from 'E', d }
|
334
|
-
let!(:f) { message_with_from 'F', a }
|
335
|
-
|
336
|
-
it 'for A is C, E, F' do
|
337
|
-
expect(a.send(method_name))
|
338
|
-
.to match_array [c, e, f]
|
339
|
-
end
|
340
|
-
end
|
341
|
-
end
|
342
|
-
|
343
|
-
describe ".#{type}_leaves" do
|
344
|
-
let(:method_name) { "#{type}_leaves" }
|
345
|
-
|
346
|
-
description = <<-'WITH'
|
347
|
-
|
348
|
-
DAG:
|
349
|
-
A
|
350
|
-
|
351
|
-
WITH
|
352
|
-
context description do
|
353
|
-
let!(:a) { Message.create text: 'A' }
|
354
|
-
|
355
|
-
it 'is A' do
|
356
|
-
expect(Message.send(method_name))
|
357
|
-
.to match_array [a]
|
358
|
-
end
|
359
|
-
end
|
360
|
-
|
361
|
-
description = <<-'WITH'
|
362
|
-
|
363
|
-
DAG:
|
364
|
-
A
|
365
|
-
/ \
|
366
|
-
/ \
|
367
|
-
+ +
|
368
|
-
B F
|
369
|
-
/ \
|
370
|
-
/ \
|
371
|
-
+ +
|
372
|
-
C D
|
373
|
-
|
|
374
|
-
|
|
375
|
-
+
|
376
|
-
E
|
377
|
-
|
378
|
-
WITH
|
379
|
-
context description do
|
380
|
-
let!(:a) { Message.create text: 'A' }
|
381
|
-
let!(:b) { message_with_from 'B', a }
|
382
|
-
let!(:c) { message_with_from 'C', b }
|
383
|
-
let!(:d) { message_with_from 'D', b }
|
384
|
-
let!(:e) { message_with_from 'E', d }
|
385
|
-
let!(:f) { message_with_from 'F', a }
|
386
|
-
|
387
|
-
it 'is C, E, F' do
|
388
|
-
expect(Message.send(method_name))
|
389
|
-
.to match_array [c, e, f]
|
390
|
-
end
|
391
|
-
end
|
392
|
-
end
|
393
|
-
|
394
|
-
describe "##{to} (directly to)" do
|
395
|
-
description = <<-WITH
|
396
|
-
|
397
|
-
DAG:
|
398
|
-
A
|
399
|
-
WITH
|
400
|
-
context description do
|
401
|
-
let!(:a) { Message.new }
|
402
|
-
|
403
|
-
it 'is empty' do
|
404
|
-
expect(a.send(to))
|
405
|
-
.to be_empty
|
406
|
-
end
|
407
|
-
end
|
408
|
-
|
409
|
-
description = <<-WITH
|
410
|
-
|
411
|
-
DAG:
|
412
|
-
A
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
B
|
417
|
-
WITH
|
418
|
-
context description do
|
419
|
-
let!(:a) { Message.create text: 'A' }
|
420
|
-
let!(:b) { message_with_from('B', a) }
|
421
|
-
|
422
|
-
it 'includes B' do
|
423
|
-
expect(a.send(to))
|
424
|
-
.to match_array([b])
|
425
|
-
end
|
426
|
-
end
|
427
|
-
|
428
|
-
description = <<-WITH
|
429
|
-
|
430
|
-
DAG:
|
431
|
-
A
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
B
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
C
|
440
|
-
WITH
|
441
|
-
context description do
|
442
|
-
let!(:a) { Message.create text: 'A' }
|
443
|
-
let!(:b) { message_with_from 'B', a }
|
444
|
-
let!(:c) { message_with_from 'C', b }
|
445
|
-
|
446
|
-
it 'includes B' do
|
447
|
-
expect(a.send(to))
|
448
|
-
.to match_array([b])
|
449
|
-
end
|
450
|
-
end
|
451
|
-
end
|
452
|
-
|
453
|
-
describe "##{to.to_s.singularize}? (is a directly to)" do
|
454
|
-
let(:method) { :"#{to.to_s.singularize}?" }
|
455
|
-
description = <<-WITH
|
456
|
-
|
457
|
-
DAG:
|
458
|
-
A
|
459
|
-
WITH
|
460
|
-
context description do
|
461
|
-
let!(:a) { Message.new }
|
462
|
-
|
463
|
-
it 'is false for a' do
|
464
|
-
expect(a.send(method))
|
465
|
-
.to be_falsey
|
466
|
-
end
|
467
|
-
end
|
468
|
-
|
469
|
-
description = <<-WITH
|
470
|
-
|
471
|
-
DAG:
|
472
|
-
A
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
B
|
477
|
-
WITH
|
478
|
-
context description do
|
479
|
-
let!(:a) { Message.create text: 'A' }
|
480
|
-
let!(:b) { message_with_from('B', a) }
|
481
|
-
|
482
|
-
it 'is false for a' do
|
483
|
-
expect(a.send(method))
|
484
|
-
.to be_falsey
|
485
|
-
end
|
486
|
-
|
487
|
-
it 'is true for b' do
|
488
|
-
expect(b.send(method))
|
489
|
-
.to be_truthy
|
490
|
-
end
|
491
|
-
end
|
492
|
-
|
493
|
-
description = <<-WITH
|
494
|
-
|
495
|
-
DAG:
|
496
|
-
A
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
B
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
C
|
505
|
-
WITH
|
506
|
-
context description do
|
507
|
-
let!(:a) { Message.create text: 'A' }
|
508
|
-
let!(:b) { message_with_from 'B', a }
|
509
|
-
let!(:c) { message_with_from 'C', b }
|
510
|
-
|
511
|
-
it 'is false for a' do
|
512
|
-
expect(a.send(method))
|
513
|
-
.to be_falsey
|
514
|
-
end
|
515
|
-
|
516
|
-
it 'is true for b' do
|
517
|
-
expect(b.send(method))
|
518
|
-
.to be_truthy
|
519
|
-
end
|
520
|
-
|
521
|
-
it 'is true for c' do
|
522
|
-
expect(c.send(method))
|
523
|
-
.to be_truthy
|
524
|
-
end
|
525
|
-
end
|
526
|
-
end
|
527
|
-
|
528
|
-
describe "##{from.to_s.singularize}? (is a directly from)" do
|
529
|
-
let(:method) { :"#{from.to_s.singularize}?" }
|
530
|
-
description = <<-WITH
|
531
|
-
|
532
|
-
DAG:
|
533
|
-
A
|
534
|
-
WITH
|
535
|
-
context description do
|
536
|
-
let!(:a) { Message.new }
|
537
|
-
|
538
|
-
it 'is false for a' do
|
539
|
-
expect(a.send(method))
|
540
|
-
.to be_falsey
|
541
|
-
end
|
542
|
-
end
|
543
|
-
|
544
|
-
description = <<-WITH
|
545
|
-
|
546
|
-
DAG:
|
547
|
-
A
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
B
|
552
|
-
WITH
|
553
|
-
context description do
|
554
|
-
let!(:a) { Message.create text: 'A' }
|
555
|
-
let!(:b) { message_with_from('B', a) }
|
556
|
-
|
557
|
-
it 'is true for a' do
|
558
|
-
expect(a.send(method))
|
559
|
-
.to be_truthy
|
560
|
-
end
|
561
|
-
|
562
|
-
it 'is false for b' do
|
563
|
-
expect(b.send(method))
|
564
|
-
.to be_falsey
|
565
|
-
end
|
566
|
-
end
|
567
|
-
|
568
|
-
description = <<-WITH
|
569
|
-
|
570
|
-
DAG:
|
571
|
-
A
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
B
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
C
|
580
|
-
WITH
|
581
|
-
context description do
|
582
|
-
let!(:a) { Message.create text: 'A' }
|
583
|
-
let!(:b) { message_with_from 'B', a }
|
584
|
-
let!(:c) { message_with_from 'C', b }
|
585
|
-
|
586
|
-
it 'is true for a' do
|
587
|
-
expect(a.send(method))
|
588
|
-
.to be_truthy
|
589
|
-
end
|
590
|
-
|
591
|
-
it 'is true for b' do
|
592
|
-
expect(b.send(method))
|
593
|
-
.to be_truthy
|
594
|
-
end
|
595
|
-
|
596
|
-
it 'is false for c' do
|
597
|
-
expect(c.send(method))
|
598
|
-
.to be_falsey
|
599
|
-
end
|
600
|
-
end
|
601
|
-
end
|
602
|
-
|
603
|
-
describe "##{all_to} (transitive to)" do
|
604
|
-
description = <<-WITH
|
605
|
-
|
606
|
-
DAG:
|
607
|
-
A
|
608
|
-
WITH
|
609
|
-
|
610
|
-
context description do
|
611
|
-
it 'is empty' do
|
612
|
-
expect(message.send(all_to))
|
613
|
-
.to be_empty
|
614
|
-
end
|
615
|
-
end
|
616
|
-
|
617
|
-
description = <<-WITH
|
618
|
-
|
619
|
-
DAG:
|
620
|
-
A
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
B
|
625
|
-
WITH
|
626
|
-
context description do
|
627
|
-
let!(:a) { Message.create text: 'A' }
|
628
|
-
let!(:b) { message_with_from 'B', a }
|
629
|
-
|
630
|
-
it 'includes B' do
|
631
|
-
expect(a.send(all_to))
|
632
|
-
.to match_array([b])
|
633
|
-
end
|
634
|
-
end
|
635
|
-
|
636
|
-
description = <<-WITH
|
637
|
-
|
638
|
-
DAG:
|
639
|
-
A
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
B
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
C
|
648
|
-
WITH
|
649
|
-
context description do
|
650
|
-
let!(:a) { Message.create text: 'A' }
|
651
|
-
let!(:b) { message_with_from 'B', a }
|
652
|
-
let!(:c) { message_with_from 'C', b }
|
653
|
-
|
654
|
-
it 'includes B and C' do
|
655
|
-
expect(a.send(all_to))
|
656
|
-
.to match_array([b, c])
|
657
|
-
end
|
658
|
-
end
|
659
|
-
|
660
|
-
if !from_limit || from_limit > 1
|
661
|
-
description = <<-'WITH'
|
662
|
-
|
663
|
-
DAG:
|
664
|
-
A
|
665
|
-
/ \
|
666
|
-
/ \
|
667
|
-
/ \
|
668
|
-
B C
|
669
|
-
\ /
|
670
|
-
\ /
|
671
|
-
\ /
|
672
|
-
D
|
673
|
-
WITH
|
674
|
-
context description do
|
675
|
-
let!(:a) { Message.create text: 'A' }
|
676
|
-
let!(:b) { message_with_from 'B', a }
|
677
|
-
let!(:c) { message_with_from 'C', a }
|
678
|
-
let!(:d) { message_with_from 'D', [b, c] }
|
679
|
-
|
680
|
-
it 'is B, C and D for A' do
|
681
|
-
expect(d.send(all_from))
|
682
|
-
.to match_array([b, c, a])
|
683
|
-
end
|
684
|
-
end
|
685
|
-
end
|
686
|
-
end
|
687
|
-
|
688
|
-
describe "##{from} (direct from)" do
|
689
|
-
description = <<-WITH
|
690
|
-
|
691
|
-
DAG:
|
692
|
-
A
|
693
|
-
WITH
|
694
|
-
|
695
|
-
context description do
|
696
|
-
let!(:a) { Message.create text: 'A' }
|
697
|
-
|
698
|
-
if from_limit == 1
|
699
|
-
it 'is nil' do
|
700
|
-
expect(a.send(from))
|
701
|
-
.to be_nil
|
702
|
-
end
|
703
|
-
else
|
704
|
-
it 'is empty' do
|
705
|
-
expect(a.send(from))
|
706
|
-
.to be_empty
|
707
|
-
end
|
708
|
-
end
|
709
|
-
end
|
710
|
-
|
711
|
-
description = <<-WITH
|
712
|
-
|
713
|
-
DAG:
|
714
|
-
B
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
A
|
719
|
-
WITH
|
720
|
-
context description do
|
721
|
-
let!(:b) { Message.create text: 'B' }
|
722
|
-
let!(:a) { message_with_from 'A', b }
|
723
|
-
|
724
|
-
if from_limit && from_limit == 1
|
725
|
-
it 'is B' do
|
726
|
-
expect(a.send(from))
|
727
|
-
.to eql b
|
728
|
-
end
|
729
|
-
else
|
730
|
-
it 'includes B' do
|
731
|
-
expect(a.send(from))
|
732
|
-
.to match_array([b])
|
733
|
-
end
|
734
|
-
end
|
735
|
-
end
|
736
|
-
|
737
|
-
description = <<-WITH
|
738
|
-
|
739
|
-
DAG:
|
740
|
-
C
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
B
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
A
|
749
|
-
WITH
|
750
|
-
context description do
|
751
|
-
let!(:c) { Message.create text: 'C' }
|
752
|
-
let!(:b) { message_with_from 'B', c }
|
753
|
-
let!(:a) { message_with_from 'A', b }
|
754
|
-
|
755
|
-
if from_limit == 1
|
756
|
-
it 'is B' do
|
757
|
-
expect(a.send(from))
|
758
|
-
.to eql b
|
759
|
-
end
|
760
|
-
else
|
761
|
-
it 'includes B' do
|
762
|
-
expect(a.send(from))
|
763
|
-
.to match_array([b])
|
764
|
-
end
|
765
|
-
end
|
766
|
-
end
|
767
|
-
end
|
768
|
-
|
769
|
-
describe "##{all_from} (transitive from)" do
|
770
|
-
description = <<-WITH
|
771
|
-
|
772
|
-
DAG:
|
773
|
-
A
|
774
|
-
WITH
|
775
|
-
context description do
|
776
|
-
let!(:a) { Message.create text: 'A' }
|
777
|
-
|
778
|
-
it 'is empty' do
|
779
|
-
expect(a.send(all_from))
|
780
|
-
.to be_empty
|
781
|
-
end
|
782
|
-
end
|
783
|
-
|
784
|
-
description = <<-WITH
|
785
|
-
|
786
|
-
DAG:
|
787
|
-
C
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
B
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
A
|
796
|
-
WITH
|
797
|
-
context description do
|
798
|
-
let!(:c) { Message.create text: 'C' }
|
799
|
-
let!(:b) { message_with_from 'B', c }
|
800
|
-
let!(:a) { message_with_from 'A', b }
|
801
|
-
|
802
|
-
it 'includes B and C' do
|
803
|
-
expect(a.send(all_from))
|
804
|
-
.to match_array([b, c])
|
805
|
-
end
|
806
|
-
end
|
807
|
-
|
808
|
-
if !from_limit || from_limit > 1
|
809
|
-
description = <<-'WITH'
|
810
|
-
|
811
|
-
DAG:
|
812
|
-
A
|
813
|
-
/ \
|
814
|
-
/ \
|
815
|
-
/ \
|
816
|
-
B C
|
817
|
-
\ /
|
818
|
-
\ /
|
819
|
-
\ /
|
820
|
-
D
|
821
|
-
WITH
|
822
|
-
context description do
|
823
|
-
let!(:a) { Message.create text: 'A' }
|
824
|
-
let!(:b) { message_with_from 'B', a }
|
825
|
-
let!(:c) { message_with_from 'C', a }
|
826
|
-
let!(:d) { message_with_from 'D', [b, c] }
|
827
|
-
|
828
|
-
it 'is B, C and A for D' do
|
829
|
-
expect(d.send(all_from))
|
830
|
-
.to match_array([b, c, a])
|
831
|
-
end
|
832
|
-
end
|
833
|
-
end
|
834
|
-
end
|
835
|
-
|
836
|
-
describe "#self_and_#{all_from} (self and transitive from)" do
|
837
|
-
description = <<-WITH
|
838
|
-
|
839
|
-
DAG:
|
840
|
-
A
|
841
|
-
WITH
|
842
|
-
context description do
|
843
|
-
let!(:a) { Message.create text: 'A' }
|
844
|
-
|
845
|
-
it 'is A' do
|
846
|
-
expect(a.send(:"self_and_#{all_from}"))
|
847
|
-
.to match_array [a]
|
848
|
-
end
|
849
|
-
end
|
850
|
-
|
851
|
-
description = <<-WITH
|
852
|
-
|
853
|
-
DAG:
|
854
|
-
C
|
855
|
-
|
|
856
|
-
|
|
857
|
-
+
|
858
|
-
B
|
859
|
-
|
|
860
|
-
|
|
861
|
-
+
|
862
|
-
A
|
863
|
-
WITH
|
864
|
-
context description do
|
865
|
-
let!(:c) { Message.create text: 'C' }
|
866
|
-
let!(:b) { message_with_from 'B', c }
|
867
|
-
let!(:a) { message_with_from 'A', b }
|
868
|
-
|
869
|
-
it 'for A is A, B and C' do
|
870
|
-
expect(a.send(:"self_and_#{all_from}"))
|
871
|
-
.to match_array([a, b, c])
|
872
|
-
end
|
873
|
-
end
|
874
|
-
end
|
875
|
-
|
876
|
-
describe "#self_and_#{all_to} (self and transitive to)" do
|
877
|
-
description = <<-WITH
|
878
|
-
|
879
|
-
DAG:
|
880
|
-
A
|
881
|
-
WITH
|
882
|
-
context description do
|
883
|
-
let!(:a) { Message.create text: 'A' }
|
884
|
-
|
885
|
-
it 'is A' do
|
886
|
-
expect(a.send(:"self_and_#{all_to}"))
|
887
|
-
.to match_array [a]
|
888
|
-
end
|
889
|
-
end
|
890
|
-
|
891
|
-
description = <<-WITH
|
892
|
-
|
893
|
-
DAG:
|
894
|
-
C
|
895
|
-
|
|
896
|
-
|
|
897
|
-
+
|
898
|
-
B
|
899
|
-
|
|
900
|
-
|
|
901
|
-
+
|
902
|
-
A
|
903
|
-
WITH
|
904
|
-
context description do
|
905
|
-
let!(:c) { Message.create text: 'C' }
|
906
|
-
let!(:b) { message_with_from 'B', c }
|
907
|
-
let!(:a) { message_with_from 'A', b }
|
908
|
-
|
909
|
-
it 'for C is A, B and C' do
|
910
|
-
expect(c.send(:"self_and_#{all_to}"))
|
911
|
-
.to match_array([a, b, c])
|
912
|
-
end
|
913
|
-
end
|
914
|
-
end
|
915
|
-
|
916
|
-
describe "##{from}= (directly from)" do
|
917
|
-
description = <<-WITH
|
918
|
-
|
919
|
-
DAG before:
|
920
|
-
A B
|
921
|
-
|
922
|
-
DAG after:
|
923
|
-
B
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
A
|
928
|
-
|
929
|
-
via:
|
930
|
-
assigning via method
|
931
|
-
WITH
|
932
|
-
context description do
|
933
|
-
let!(:a) { Message.create text: 'A' }
|
934
|
-
let!(:b) { Message.create text: 'B' }
|
935
|
-
|
936
|
-
before do
|
937
|
-
a.send("#{from}=", from_one_or_array(b))
|
938
|
-
end
|
939
|
-
|
940
|
-
if from_limit == 1
|
941
|
-
it 'is B' do
|
942
|
-
expect(a.send(from))
|
943
|
-
.to eql b
|
944
|
-
end
|
945
|
-
else
|
946
|
-
it 'includes B' do
|
947
|
-
expect(a.send(from))
|
948
|
-
.to match_array([b])
|
949
|
-
end
|
950
|
-
end
|
951
|
-
end
|
952
|
-
|
953
|
-
description = <<-WITH
|
954
|
-
|
955
|
-
DAG before:
|
956
|
-
A B
|
957
|
-
|
958
|
-
DAG after:
|
959
|
-
B
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
A
|
964
|
-
|
965
|
-
via:
|
966
|
-
assigning to attributes as part of a hash
|
967
|
-
WITH
|
968
|
-
context description do
|
969
|
-
let!(:a) { Message.create text: 'A' }
|
970
|
-
let!(:b) { Message.create text: 'B' }
|
971
|
-
|
972
|
-
before do
|
973
|
-
a.attributes = { from => from_one_or_array(b) }
|
974
|
-
end
|
975
|
-
|
976
|
-
if from_limit == 1
|
977
|
-
it 'is B' do
|
978
|
-
expect(a.send(from))
|
979
|
-
.to eql b
|
980
|
-
end
|
981
|
-
else
|
982
|
-
it 'includes B' do
|
983
|
-
expect(a.send(from))
|
984
|
-
.to match_array([b])
|
985
|
-
end
|
986
|
-
end
|
987
|
-
end
|
988
|
-
|
989
|
-
description = <<-WITH
|
990
|
-
|
991
|
-
DAG before:
|
992
|
-
B
|
993
|
-
|
994
|
-
DAG after:
|
995
|
-
B
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
A
|
1000
|
-
|
1001
|
-
via:
|
1002
|
-
on creation
|
1003
|
-
WITH
|
1004
|
-
context description do
|
1005
|
-
let!(:b) { Message.create text: 'B' }
|
1006
|
-
let(:a) do
|
1007
|
-
Message.create from => from_one_or_array(b)
|
1008
|
-
end
|
1009
|
-
|
1010
|
-
before do
|
1011
|
-
a
|
1012
|
-
end
|
1013
|
-
|
1014
|
-
if from_limit == 1
|
1015
|
-
it 'is B' do
|
1016
|
-
expect(a.send(from))
|
1017
|
-
.to eql b
|
1018
|
-
end
|
1019
|
-
else
|
1020
|
-
it 'includes B' do
|
1021
|
-
expect(a.send(from))
|
1022
|
-
.to match_array([b])
|
1023
|
-
end
|
1024
|
-
end
|
1025
|
-
end
|
1026
|
-
|
1027
|
-
description = <<-WITH
|
1028
|
-
|
1029
|
-
DAG before:
|
1030
|
-
A B C
|
1031
|
-
|
1032
|
-
DAG after:
|
1033
|
-
C
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
B
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
A
|
1042
|
-
|
1043
|
-
Assigning top down
|
1044
|
-
WITH
|
1045
|
-
context description do
|
1046
|
-
let!(:a) { Message.create text: 'A' }
|
1047
|
-
let!(:b) { Message.create text: 'B' }
|
1048
|
-
let!(:c) { Message.create text: 'C' }
|
1049
|
-
|
1050
|
-
before do
|
1051
|
-
b.send("#{from}=", from_one_or_array(c))
|
1052
|
-
a.send("#{from}=", from_one_or_array(b))
|
1053
|
-
end
|
1054
|
-
|
1055
|
-
it 'builds the complete hierarchy' do
|
1056
|
-
expect(a.send(all_from))
|
1057
|
-
.to match_array([b, c])
|
1058
|
-
end
|
1059
|
-
end
|
1060
|
-
|
1061
|
-
description = <<-WITH
|
1062
|
-
|
1063
|
-
DAG before:
|
1064
|
-
A B C
|
1065
|
-
|
1066
|
-
DAG after:
|
1067
|
-
A
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
B
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
C
|
1076
|
-
|
1077
|
-
Assigning top down
|
1078
|
-
WITH
|
1079
|
-
context description do
|
1080
|
-
let!(:a) { Message.create text: 'A' }
|
1081
|
-
let!(:b) { Message.create text: 'B' }
|
1082
|
-
let!(:c) { Message.create text: 'C' }
|
1083
|
-
|
1084
|
-
before do
|
1085
|
-
b.send("#{from}=", from_one_or_array(a))
|
1086
|
-
c.send("#{from}=", from_one_or_array(b))
|
1087
|
-
end
|
1088
|
-
|
1089
|
-
it 'builds the complete hierarchy' do
|
1090
|
-
expect(a.send(all_to))
|
1091
|
-
.to match_array([b, c])
|
1092
|
-
end
|
1093
|
-
end
|
1094
|
-
|
1095
|
-
description = <<-'WITH'
|
1096
|
-
|
1097
|
-
DAG before:
|
1098
|
-
A B C D
|
1099
|
-
|
1100
|
-
DAG after:
|
1101
|
-
A
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
B
|
1106
|
-
/ \
|
1107
|
-
/ \
|
1108
|
-
/ \
|
1109
|
-
C D
|
1110
|
-
|
1111
|
-
Assigning depth first
|
1112
|
-
WITH
|
1113
|
-
context description do
|
1114
|
-
let!(:a) { Message.create text: 'A' }
|
1115
|
-
let!(:b) { Message.create text: 'B' }
|
1116
|
-
let!(:c) { Message.create text: 'C' }
|
1117
|
-
let!(:d) { Message.create text: 'D' }
|
1118
|
-
|
1119
|
-
before do
|
1120
|
-
b.send("#{from}=", from_one_or_array(a))
|
1121
|
-
c.send("#{from}=", from_one_or_array(b))
|
1122
|
-
d.send("#{from}=", from_one_or_array(b))
|
1123
|
-
end
|
1124
|
-
|
1125
|
-
it 'builds the complete hierarchy' do
|
1126
|
-
expect(a.send(all_to))
|
1127
|
-
.to match_array([b, c, d])
|
1128
|
-
end
|
1129
|
-
end
|
1130
|
-
|
1131
|
-
description = <<-WITH
|
1132
|
-
|
1133
|
-
DAG before:
|
1134
|
-
A C
|
1135
|
-
| |
|
1136
|
-
| |
|
1137
|
-
| |
|
1138
|
-
B D
|
1139
|
-
|
1140
|
-
DAG after:
|
1141
|
-
A
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
B
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
C
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
D
|
1154
|
-
WITH
|
1155
|
-
context description do
|
1156
|
-
let!(:a) { Message.create text: 'A' }
|
1157
|
-
let!(:b) { message_with_from 'B', a }
|
1158
|
-
let!(:c) { Message.create text: 'C' }
|
1159
|
-
let!(:d) { message_with_from 'D', c }
|
1160
|
-
|
1161
|
-
before do
|
1162
|
-
c.send("#{from}=", from_one_or_array(b))
|
1163
|
-
end
|
1164
|
-
|
1165
|
-
it 'builds the complete transitive to for A' do
|
1166
|
-
expect(a.send(all_to))
|
1167
|
-
.to match_array([b, c, d])
|
1168
|
-
end
|
1169
|
-
|
1170
|
-
it 'build the correct second generation to for A' do
|
1171
|
-
expect(a.send(all_to_depth, 2))
|
1172
|
-
.to match_array([c])
|
1173
|
-
end
|
1174
|
-
|
1175
|
-
it 'build the correct third generation to for A' do
|
1176
|
-
expect(a.send(all_to_depth, 3))
|
1177
|
-
.to match_array([d])
|
1178
|
-
end
|
1179
|
-
|
1180
|
-
it 'builds the complete transitive to for B' do
|
1181
|
-
expect(b.send(all_to))
|
1182
|
-
.to match_array([c, d])
|
1183
|
-
end
|
1184
|
-
|
1185
|
-
it 'builds the complete transitive from for D' do
|
1186
|
-
expect(d.send(all_from))
|
1187
|
-
.to match_array([c, b, a])
|
1188
|
-
end
|
1189
|
-
|
1190
|
-
it 'builds the complete transitive from for C' do
|
1191
|
-
expect(c.send(all_from))
|
1192
|
-
.to match_array([b, a])
|
1193
|
-
end
|
1194
|
-
end
|
1195
|
-
|
1196
|
-
description = <<-WITH
|
1197
|
-
|
1198
|
-
DAG before:
|
1199
|
-
A
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
B
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
C
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
D
|
1212
|
-
|
1213
|
-
|
1214
|
-
DAG after:
|
1215
|
-
A C
|
1216
|
-
| |
|
1217
|
-
| |
|
1218
|
-
| |
|
1219
|
-
B D
|
1220
|
-
|
1221
|
-
via:
|
1222
|
-
assigning nil/empty to C's from method
|
1223
|
-
WITH
|
1224
|
-
|
1225
|
-
context description do
|
1226
|
-
let!(:a) { Message.create text: 'A' }
|
1227
|
-
let!(:b) { message_with_from 'B', a }
|
1228
|
-
let!(:c) { message_with_from 'C', b }
|
1229
|
-
let!(:d) { message_with_from 'D', c }
|
1230
|
-
|
1231
|
-
before do
|
1232
|
-
if from_limit == 1
|
1233
|
-
c.send("#{from}=", nil)
|
1234
|
-
else
|
1235
|
-
c.send("#{from}=", [])
|
1236
|
-
end
|
1237
|
-
end
|
1238
|
-
|
1239
|
-
it 'empties transitive to for A except B' do
|
1240
|
-
expect(a.send(all_to))
|
1241
|
-
.to match_array [b]
|
1242
|
-
end
|
1243
|
-
|
1244
|
-
it 'empties transitive to for B' do
|
1245
|
-
expect(b.send(all_to))
|
1246
|
-
.to be_empty
|
1247
|
-
end
|
1248
|
-
|
1249
|
-
it 'empties to for B' do
|
1250
|
-
expect(b.send(to))
|
1251
|
-
.to be_empty
|
1252
|
-
end
|
1253
|
-
|
1254
|
-
it 'empties transitive from for D except C' do
|
1255
|
-
expect(d.send(all_from))
|
1256
|
-
.to match_array([c])
|
1257
|
-
end
|
1258
|
-
|
1259
|
-
it 'empties transitive from for C' do
|
1260
|
-
expect(c.send(all_from))
|
1261
|
-
.to be_empty
|
1262
|
-
end
|
1263
|
-
end
|
1264
|
-
|
1265
|
-
description = <<-WITH
|
1266
|
-
|
1267
|
-
DAG before:
|
1268
|
-
A
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
B
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
C
|
1277
|
-
|
1278
|
-
|
1279
|
-
DAG after:
|
1280
|
-
A B
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
C
|
1285
|
-
|
1286
|
-
via:
|
1287
|
-
assigning nil/empty to B's from method
|
1288
|
-
WITH
|
1289
|
-
|
1290
|
-
context description do
|
1291
|
-
let!(:a) { Message.create text: 'A' }
|
1292
|
-
let!(:b) { message_with_from 'B', a }
|
1293
|
-
let!(:c) { message_with_from 'C', b }
|
1294
|
-
|
1295
|
-
before do
|
1296
|
-
if from_limit == 1
|
1297
|
-
b.send("#{from}=", nil)
|
1298
|
-
else
|
1299
|
-
b.send("#{from}=", [])
|
1300
|
-
end
|
1301
|
-
end
|
1302
|
-
|
1303
|
-
it 'empties transitive to for A' do
|
1304
|
-
expect(a.send(all_to))
|
1305
|
-
.to be_empty
|
1306
|
-
end
|
1307
|
-
|
1308
|
-
it 'transitive to for B is C' do
|
1309
|
-
expect(b.send(all_to))
|
1310
|
-
.to match_array [c]
|
1311
|
-
end
|
1312
|
-
|
1313
|
-
it 'empties to for A' do
|
1314
|
-
expect(a.send(to))
|
1315
|
-
.to be_empty
|
1316
|
-
end
|
1317
|
-
|
1318
|
-
it 'empties transitive from for B' do
|
1319
|
-
expect(b.send(all_from))
|
1320
|
-
.to be_empty
|
1321
|
-
end
|
1322
|
-
end
|
1323
|
-
|
1324
|
-
description = <<-WITH
|
1325
|
-
|
1326
|
-
DAG before (unpersisted):
|
1327
|
-
B
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
A
|
1332
|
-
|
1333
|
-
assigning nil afterwards
|
1334
|
-
WITH
|
1335
|
-
context description do
|
1336
|
-
let!(:a) { Message.new text: 'A' }
|
1337
|
-
let!(:b) { Message.create text: 'B' }
|
1338
|
-
|
1339
|
-
before do
|
1340
|
-
a.send("#{from}=", from_one_or_array(b))
|
1341
|
-
|
1342
|
-
a.send("#{from}=", from_one_or_array(nil))
|
1343
|
-
end
|
1344
|
-
|
1345
|
-
if from_limit == 1
|
1346
|
-
it 'is nil' do
|
1347
|
-
expect(a.send(from))
|
1348
|
-
.to be_nil
|
1349
|
-
end
|
1350
|
-
else
|
1351
|
-
it 'is empty' do
|
1352
|
-
expect(a.send(from))
|
1353
|
-
.to be_empty
|
1354
|
-
end
|
1355
|
-
end
|
1356
|
-
end
|
1357
|
-
end
|
1358
|
-
|
1359
|
-
describe "#{all_to_depth} (all to of depth X)" do
|
1360
|
-
description = <<-'WITH'
|
1361
|
-
|
1362
|
-
DAG before:
|
1363
|
-
A
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
B
|
1368
|
-
/ \
|
1369
|
-
/ \
|
1370
|
-
/ \
|
1371
|
-
C D
|
1372
|
-
WITH
|
1373
|
-
context description do
|
1374
|
-
let!(:a) { Message.create text: 'A' }
|
1375
|
-
let!(:b) { message_with_from 'B', a }
|
1376
|
-
let!(:c) { message_with_from 'C', b }
|
1377
|
-
let!(:d) { message_with_from 'D', b }
|
1378
|
-
|
1379
|
-
it 'is B for A with depth 1' do
|
1380
|
-
expect(a.send(all_to_depth, 1))
|
1381
|
-
.to match_array [b]
|
1382
|
-
end
|
1383
|
-
|
1384
|
-
it 'is C and D for A with depth 2' do
|
1385
|
-
expect(a.send(all_to_depth, 2))
|
1386
|
-
.to match_array [c, d]
|
1387
|
-
end
|
1388
|
-
end
|
1389
|
-
end
|
1390
|
-
|
1391
|
-
describe "#{all_from_depth} (all from of depth X)" do
|
1392
|
-
description = <<-'WITH'
|
1393
|
-
|
1394
|
-
DAG before:
|
1395
|
-
A
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
B
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
C
|
1404
|
-
WITH
|
1405
|
-
context description do
|
1406
|
-
let!(:a) { Message.create text: 'A' }
|
1407
|
-
let!(:b) { message_with_from 'B', a }
|
1408
|
-
let!(:c) { message_with_from 'C', b }
|
1409
|
-
|
1410
|
-
it 'is B for C with depth 1' do
|
1411
|
-
expect(c.send(all_from_depth, 1))
|
1412
|
-
.to match_array [b]
|
1413
|
-
end
|
1414
|
-
|
1415
|
-
it 'is C and D for A with depth 2' do
|
1416
|
-
expect(c.send(all_from_depth, 2))
|
1417
|
-
.to match_array [a]
|
1418
|
-
end
|
1419
|
-
end
|
1420
|
-
|
1421
|
-
if !from_limit || from_limit > 1
|
1422
|
-
description = <<-'WITH'
|
1423
|
-
|
1424
|
-
DAG before:
|
1425
|
-
A B
|
1426
|
-
\ /
|
1427
|
-
\ /
|
1428
|
-
\ /
|
1429
|
-
C
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
D
|
1434
|
-
WITH
|
1435
|
-
context description do
|
1436
|
-
let!(:a) { Message.create text: 'A' }
|
1437
|
-
let!(:b) { Message.create text: 'B' }
|
1438
|
-
let!(:c) do
|
1439
|
-
message = Message.create text: 'C'
|
1440
|
-
message.send("#{from}=", [a, b])
|
1441
|
-
message
|
1442
|
-
end
|
1443
|
-
let!(:d) { message_with_from 'd', c }
|
1444
|
-
|
1445
|
-
it 'is C for D with depth 1' do
|
1446
|
-
expect(d.send(all_from_depth, 1))
|
1447
|
-
.to match_array [c]
|
1448
|
-
end
|
1449
|
-
|
1450
|
-
it 'is A and B for D with depth 2' do
|
1451
|
-
expect(d.send(all_from_depth, 2))
|
1452
|
-
.to match_array [a, b]
|
1453
|
-
end
|
1454
|
-
end
|
1455
|
-
end
|
1456
|
-
end
|
1457
|
-
|
1458
|
-
describe '#destroy' do
|
1459
|
-
description = <<-WITH
|
1460
|
-
|
1461
|
-
DAG before:
|
1462
|
-
A
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
B
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
C
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
D
|
1475
|
-
|
1476
|
-
|
1477
|
-
DAG after:
|
1478
|
-
A D
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
B
|
1483
|
-
|
1484
|
-
via:
|
1485
|
-
remove C
|
1486
|
-
WITH
|
1487
|
-
|
1488
|
-
context description do
|
1489
|
-
let!(:a) { Message.create text: 'A' }
|
1490
|
-
let!(:b) { message_with_from 'B', a }
|
1491
|
-
let!(:c) { message_with_from 'C', b }
|
1492
|
-
let!(:d) { message_with_from 'D', c }
|
1493
|
-
|
1494
|
-
before do
|
1495
|
-
c.destroy
|
1496
|
-
end
|
1497
|
-
|
1498
|
-
it 'empties transitive to for A except B' do
|
1499
|
-
expect(a.send(all_to))
|
1500
|
-
.to match_array [b]
|
1501
|
-
end
|
1502
|
-
|
1503
|
-
it 'empties transitive to for B' do
|
1504
|
-
expect(b.send(all_to))
|
1505
|
-
.to be_empty
|
1506
|
-
end
|
1507
|
-
|
1508
|
-
it 'empties to for B' do
|
1509
|
-
expect(b.send(to))
|
1510
|
-
.to be_empty
|
1511
|
-
end
|
1512
|
-
|
1513
|
-
it 'empties transitive from for D' do
|
1514
|
-
expect(d.send(all_from))
|
1515
|
-
.to be_empty
|
1516
|
-
end
|
1517
|
-
|
1518
|
-
if from_limit == 1
|
1519
|
-
it "assigns nil to D's from" do
|
1520
|
-
d.reload
|
1521
|
-
expect(d.send(from))
|
1522
|
-
.to be_nil
|
1523
|
-
end
|
1524
|
-
else
|
1525
|
-
it 'empties from for D' do
|
1526
|
-
expect(d.send(all_from))
|
1527
|
-
.to be_empty
|
1528
|
-
end
|
1529
|
-
end
|
1530
|
-
end
|
1531
|
-
end
|
1532
|
-
|
1533
|
-
describe '#destroy on a relation' do
|
1534
|
-
if !from_limit || from_limit > 1
|
1535
|
-
description = <<-'WITH'
|
1536
|
-
|
1537
|
-
DAG before:
|
1538
|
-
A
|
1539
|
-
/|\
|
1540
|
-
/ | \
|
1541
|
-
+ + +
|
1542
|
-
B--+C+--D
|
1543
|
-
| |
|
1544
|
-
| |
|
1545
|
-
+ |
|
1546
|
-
E |
|
1547
|
-
\ |
|
1548
|
-
\ |
|
1549
|
-
++
|
1550
|
-
F
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
G
|
1555
|
-
|
1556
|
-
|
1557
|
-
DAG after:
|
1558
|
-
A
|
1559
|
-
/|\
|
1560
|
-
/ | \
|
1561
|
-
+ + +
|
1562
|
-
B--+C+--D
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
+
|
1566
|
-
E
|
1567
|
-
\
|
1568
|
-
\
|
1569
|
-
+
|
1570
|
-
F
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
+
|
1574
|
-
G
|
1575
|
-
|
1576
|
-
via:
|
1577
|
-
remove edge between C and F
|
1578
|
-
WITH
|
1579
|
-
context description do
|
1580
|
-
let!(:a) { Message.create text: 'A' }
|
1581
|
-
let!(:b) { message_with_from 'B', a }
|
1582
|
-
let!(:d) { message_with_from 'D', a }
|
1583
|
-
let!(:c) { message_with_from 'C', [a, b, d] }
|
1584
|
-
let!(:e) { message_with_from 'E', b }
|
1585
|
-
let!(:f) { message_with_from 'F', [e, c] }
|
1586
|
-
let!(:g) { message_with_from 'G', f }
|
1587
|
-
|
1588
|
-
before do
|
1589
|
-
Relation.where(from: c, to: f).destroy_all
|
1590
|
-
end
|
1591
|
-
|
1592
|
-
it "#{all_to} (transitive to) of A is B, C, D, E, F, G" do
|
1593
|
-
expect(a.send(all_to))
|
1594
|
-
.to match_array([b, c, d, e, f, g])
|
1595
|
-
end
|
1596
|
-
|
1597
|
-
it "#{all_to} (transitive to) of B is C, E, F, G" do
|
1598
|
-
expect(b.send(all_to))
|
1599
|
-
.to match_array([c, e, f, g])
|
1600
|
-
end
|
1601
|
-
|
1602
|
-
it "#{all_to} (transitive to) of C is empty" do
|
1603
|
-
expect(c.send(all_to))
|
1604
|
-
.to be_empty
|
1605
|
-
end
|
1606
|
-
|
1607
|
-
it "#{all_to} (transitive to) of D is C" do
|
1608
|
-
expect(d.send(all_to))
|
1609
|
-
.to match_array([c])
|
1610
|
-
end
|
1611
|
-
|
1612
|
-
it "#{all_from} (transitive from) of F is E, B, A" do
|
1613
|
-
expect(f.send(all_from))
|
1614
|
-
.to match_array([e, b, a])
|
1615
|
-
end
|
1616
|
-
|
1617
|
-
it "#{all_to_depth} (transitive to of depth) of A with depth 4 is G" do
|
1618
|
-
expect(a.send(all_to_depth, 4))
|
1619
|
-
.to match_array([g])
|
1620
|
-
end
|
1621
|
-
|
1622
|
-
it "#{all_to_depth} (transitive to of depth) of A with depth 3 is F" do
|
1623
|
-
expect(a.send(all_to_depth, 3))
|
1624
|
-
.to match_array([f])
|
1625
|
-
end
|
1626
|
-
end
|
1627
|
-
end
|
1628
|
-
end
|
1629
|
-
end
|
1630
|
-
|
1631
|
-
context 'hierarchy relations' do
|
1632
|
-
it_behaves_like 'single typed dag',
|
1633
|
-
type: :hierarchy,
|
1634
|
-
to: :children,
|
1635
|
-
from: { name: :parent, limit: 1 },
|
1636
|
-
all_to: :descendants,
|
1637
|
-
all_from: :ancestors
|
1638
|
-
end
|
1639
|
-
|
1640
|
-
context 'invalidate relations' do
|
1641
|
-
it_behaves_like 'single typed dag',
|
1642
|
-
type: :invalidate,
|
1643
|
-
to: :invalidates,
|
1644
|
-
from: :invalidated_by,
|
1645
|
-
all_to: :all_invalidates,
|
1646
|
-
all_from: :all_invalidated_by
|
1647
|
-
end
|
1648
|
-
|
1649
|
-
context 'relations of various types' do
|
1650
|
-
describe 'directly to' do
|
1651
|
-
description = <<-'WITH'
|
1652
|
-
|
1653
|
-
DAG:
|
1654
|
-
------- A -------
|
1655
|
-
/ \
|
1656
|
-
invalidate hierarchy
|
1657
|
-
/ \
|
1658
|
-
B C
|
1659
|
-
/ \ / \
|
1660
|
-
invalidate hierarchy invalidate hierarchy
|
1661
|
-
/ \ / \
|
1662
|
-
D E F G
|
1663
|
-
WITH
|
1664
|
-
context description do
|
1665
|
-
let!(:a) { Message.create text: 'A' }
|
1666
|
-
let!(:b) { create_message_with_invalidated_by('B', a) }
|
1667
|
-
let!(:d) { create_message_with_invalidated_by('D', b) }
|
1668
|
-
let!(:e) { Message.create text: 'E', parent: b }
|
1669
|
-
let!(:c) { Message.create text: 'C', parent: a }
|
1670
|
-
let!(:f) { create_message_with_invalidated_by('F', c) }
|
1671
|
-
let!(:g) { Message.create text: 'G', parent: c }
|
1672
|
-
|
1673
|
-
it '#invalidates for A includes B' do
|
1674
|
-
expect(a.invalidates)
|
1675
|
-
.to match_array([b])
|
1676
|
-
end
|
1677
|
-
|
1678
|
-
it '#invalidates for B includes D' do
|
1679
|
-
expect(b.invalidates)
|
1680
|
-
.to match_array([d])
|
1681
|
-
end
|
1682
|
-
|
1683
|
-
it '#children for A includes C' do
|
1684
|
-
expect(a.children)
|
1685
|
-
.to match_array([c])
|
1686
|
-
end
|
1687
|
-
|
1688
|
-
it '#children for C includes G' do
|
1689
|
-
expect(c.children)
|
1690
|
-
.to match_array([g])
|
1691
|
-
end
|
1692
|
-
end
|
1693
|
-
end
|
1694
|
-
|
1695
|
-
describe 'transitive to' do
|
1696
|
-
description = <<-'WITH'
|
1697
|
-
|
1698
|
-
DAG:
|
1699
|
-
------- A -------
|
1700
|
-
/ \
|
1701
|
-
invalidate hierarchy
|
1702
|
-
/ \
|
1703
|
-
B C
|
1704
|
-
/ \ / \
|
1705
|
-
invalidate hierarchy invalidate hierarchy
|
1706
|
-
/ \ / \
|
1707
|
-
D E F G
|
1708
|
-
WITH
|
1709
|
-
context description do
|
1710
|
-
let!(:a) { Message.create text: 'A' }
|
1711
|
-
let!(:b) { create_message_with_invalidated_by('B', a) }
|
1712
|
-
let!(:d) { create_message_with_invalidated_by('D', b) }
|
1713
|
-
let!(:e) { Message.create text: 'E', parent: b }
|
1714
|
-
let!(:c) { Message.create text: 'C', parent: a }
|
1715
|
-
let!(:f) { create_message_with_invalidated_by('F', c) }
|
1716
|
-
let!(:g) { Message.create text: 'G', parent: c }
|
1717
|
-
|
1718
|
-
it '#all_invalidates for A are B and D' do
|
1719
|
-
expect(a.all_invalidates)
|
1720
|
-
.to match_array([b, d])
|
1721
|
-
end
|
1722
|
-
|
1723
|
-
it '#descendants for A are C and G' do
|
1724
|
-
expect(a.descendants)
|
1725
|
-
.to match_array([c, g])
|
1726
|
-
end
|
1727
|
-
end
|
1728
|
-
end
|
1729
|
-
|
1730
|
-
describe 'transitive from' do
|
1731
|
-
description = <<-'WITH'
|
1732
|
-
|
1733
|
-
DAG:
|
1734
|
-
------- A -------
|
1735
|
-
/ \
|
1736
|
-
invalidate hierarchy
|
1737
|
-
/ \
|
1738
|
-
B C
|
1739
|
-
/ \ / \
|
1740
|
-
invalidate hierarchy invalidate hierarchy
|
1741
|
-
/ \ / \
|
1742
|
-
D E F G
|
1743
|
-
WITH
|
1744
|
-
context description do
|
1745
|
-
let!(:a) { Message.create text: 'A' }
|
1746
|
-
let!(:b) { create_message_with_invalidated_by('B', a) }
|
1747
|
-
let!(:d) { create_message_with_invalidated_by('D', b) }
|
1748
|
-
let!(:e) { Message.create text: 'E', parent: b }
|
1749
|
-
let!(:c) { Message.create text: 'C', parent: a }
|
1750
|
-
let!(:f) { create_message_with_invalidated_by('F', c) }
|
1751
|
-
let!(:g) { Message.create text: 'G', parent: c }
|
1752
|
-
|
1753
|
-
it '#all_invalidated_by for D are B and A' do
|
1754
|
-
expect(d.all_invalidated_by)
|
1755
|
-
.to match_array([b, a])
|
1756
|
-
end
|
1757
|
-
|
1758
|
-
it '#all_invalidated_by for F is C' do
|
1759
|
-
expect(f.all_invalidated_by)
|
1760
|
-
.to match_array([c])
|
1761
|
-
end
|
1762
|
-
|
1763
|
-
it '#all_invalidated_by for G is empty' do
|
1764
|
-
expect(g.all_invalidated_by)
|
1765
|
-
.to be_empty
|
1766
|
-
end
|
1767
|
-
|
1768
|
-
it '#ancestors for G are C and A' do
|
1769
|
-
expect(g.ancestors)
|
1770
|
-
.to match_array([c, a])
|
1771
|
-
end
|
1772
|
-
|
1773
|
-
it '#ancestors for C is A' do
|
1774
|
-
expect(c.ancestors)
|
1775
|
-
.to match_array([a])
|
1776
|
-
end
|
1777
|
-
|
1778
|
-
it '#ancestors for D is empty' do
|
1779
|
-
expect(d.ancestors)
|
1780
|
-
.to be_empty
|
1781
|
-
end
|
1782
|
-
end
|
1783
|
-
|
1784
|
-
description = <<-'WITH'
|
1785
|
-
|
1786
|
-
DAG:
|
1787
|
-
A
|
1788
|
-
/ \
|
1789
|
-
invalidate hierarchy
|
1790
|
-
/ \
|
1791
|
-
B C
|
1792
|
-
\ /
|
1793
|
-
invalidate hierarchy
|
1794
|
-
\ /
|
1795
|
-
D
|
1796
|
-
WITH
|
1797
|
-
context description do
|
1798
|
-
let!(:a) { Message.create text: 'A' }
|
1799
|
-
let!(:b) { create_message_with_invalidated_by('B', a) }
|
1800
|
-
let!(:c) { Message.create text: 'C', parent: a }
|
1801
|
-
let!(:d) do
|
1802
|
-
message = Message.create text: 'D', parent: c
|
1803
|
-
message.invalidated_by = [b]
|
1804
|
-
message
|
1805
|
-
end
|
1806
|
-
|
1807
|
-
it '#all_invalidates for A are B and D' do
|
1808
|
-
expect(a.all_invalidates)
|
1809
|
-
.to match_array([b, d])
|
1810
|
-
end
|
1811
|
-
|
1812
|
-
it '#descendants for A are C and D' do
|
1813
|
-
expect(a.descendants)
|
1814
|
-
.to match_array([c, d])
|
1815
|
-
end
|
1816
|
-
|
1817
|
-
it '#all_invalidated_by for D are B and A' do
|
1818
|
-
expect(d.all_invalidated_by)
|
1819
|
-
.to match_array([b, a])
|
1820
|
-
end
|
1821
|
-
|
1822
|
-
it '#ancestors for D are C and A' do
|
1823
|
-
expect(d.ancestors)
|
1824
|
-
.to match_array([c, a])
|
1825
|
-
end
|
1826
|
-
end
|
1827
|
-
end
|
1828
|
-
|
1829
|
-
describe '#destroy' do
|
1830
|
-
description = <<-'WITH'
|
1831
|
-
|
1832
|
-
DAG before:
|
1833
|
-
------- A -------
|
1834
|
-
/ \
|
1835
|
-
invalidate hierarchy
|
1836
|
-
/ \
|
1837
|
-
B C
|
1838
|
-
/ \ / \
|
1839
|
-
invalidate hierarchy invalidate hierarchy
|
1840
|
-
/ \ / \
|
1841
|
-
D E F G
|
1842
|
-
WITH
|
1843
|
-
context description do
|
1844
|
-
let!(:a) { Message.create text: 'A' }
|
1845
|
-
let!(:b) { create_message_with_invalidated_by('B', a) }
|
1846
|
-
let!(:d) { create_message_with_invalidated_by('D', b) }
|
1847
|
-
let!(:e) { Message.create text: 'E', parent: b }
|
1848
|
-
let!(:c) { Message.create text: 'C', parent: a }
|
1849
|
-
let!(:f) { create_message_with_invalidated_by('F', c) }
|
1850
|
-
let!(:g) { Message.create text: 'G', parent: c }
|
1851
|
-
|
1852
|
-
description = <<-'WITH'
|
1853
|
-
|
1854
|
-
DAG after (A deleted):
|
1855
|
-
B C
|
1856
|
-
/ \ / \
|
1857
|
-
invalidate hierarchy invalidate hierarchy
|
1858
|
-
/ \ / \
|
1859
|
-
D E F G
|
1860
|
-
WITH
|
1861
|
-
|
1862
|
-
context description do
|
1863
|
-
before do
|
1864
|
-
a.destroy
|
1865
|
-
end
|
1866
|
-
|
1867
|
-
it '#all_invalidated_by for D is B' do
|
1868
|
-
expect(d.all_invalidated_by)
|
1869
|
-
.to match_array([b])
|
1870
|
-
end
|
1871
|
-
|
1872
|
-
it '#all_invalidated_by for F is C' do
|
1873
|
-
expect(f.all_invalidated_by)
|
1874
|
-
.to match_array([c])
|
1875
|
-
end
|
1876
|
-
|
1877
|
-
it '#all_invalidated_by for G is empty' do
|
1878
|
-
expect(g.all_invalidated_by)
|
1879
|
-
.to be_empty
|
1880
|
-
end
|
1881
|
-
|
1882
|
-
it '#ancestors for G is C' do
|
1883
|
-
expect(g.ancestors)
|
1884
|
-
.to match_array([c])
|
1885
|
-
end
|
1886
|
-
|
1887
|
-
it '#ancestors for C is empty' do
|
1888
|
-
expect(c.ancestors)
|
1889
|
-
.to be_empty
|
1890
|
-
end
|
1891
|
-
|
1892
|
-
it '#ancestors for D is empty' do
|
1893
|
-
expect(d.ancestors)
|
1894
|
-
.to be_empty
|
1895
|
-
end
|
1896
|
-
end
|
1897
|
-
|
1898
|
-
description = <<-'WITH'
|
1899
|
-
|
1900
|
-
DAG after (C deleted):
|
1901
|
-
A F G
|
1902
|
-
|
|
1903
|
-
invalidate
|
1904
|
-
|
|
1905
|
-
B
|
1906
|
-
/ \
|
1907
|
-
invalidate hierarchy
|
1908
|
-
/ \
|
1909
|
-
D E
|
1910
|
-
WITH
|
1911
|
-
|
1912
|
-
context description do
|
1913
|
-
before do
|
1914
|
-
c.destroy
|
1915
|
-
end
|
1916
|
-
|
1917
|
-
it '#descendants for A is empty' do
|
1918
|
-
expect(a.descendants)
|
1919
|
-
.to be_empty
|
1920
|
-
end
|
1921
|
-
|
1922
|
-
it '#all_invalidates for A are B and D' do
|
1923
|
-
expect(a.all_invalidates)
|
1924
|
-
.to match_array([b, d])
|
1925
|
-
end
|
1926
|
-
|
1927
|
-
it '#all_invalidated_by for D is B and A' do
|
1928
|
-
expect(d.all_invalidated_by)
|
1929
|
-
.to match_array([b, a])
|
1930
|
-
end
|
1931
|
-
|
1932
|
-
it '#all_invalidated_by for F is empty' do
|
1933
|
-
expect(f.all_invalidated_by)
|
1934
|
-
.to be_empty
|
1935
|
-
end
|
1936
|
-
|
1937
|
-
it '#all_invalidated_by for G is empty' do
|
1938
|
-
expect(g.all_invalidated_by)
|
1939
|
-
.to be_empty
|
1940
|
-
end
|
1941
|
-
|
1942
|
-
it '#ancestors for G is empty' do
|
1943
|
-
expect(g.ancestors)
|
1944
|
-
.to be_empty
|
1945
|
-
end
|
1946
|
-
|
1947
|
-
it '#ancestors for D is empty' do
|
1948
|
-
expect(d.ancestors)
|
1949
|
-
.to be_empty
|
1950
|
-
end
|
1951
|
-
end
|
1952
|
-
end
|
1953
|
-
end
|
1954
|
-
|
1955
|
-
describe '#rebuild_dag!' do
|
1956
|
-
|
1957
|
-
description = <<-'WITH'
|
1958
|
-
|
1959
|
-
DAG (messed up transitive closures):
|
1960
|
-
A ------
|
1961
|
-
/|\ |
|
1962
|
-
i i i h
|
1963
|
-
+ + + +
|
1964
|
-
B-i+C+i-D H
|
1965
|
-
| | |
|
1966
|
-
i | h
|
1967
|
-
+ i +
|
1968
|
-
E | I
|
1969
|
-
\ | /
|
1970
|
-
i | /
|
1971
|
-
++ /
|
1972
|
-
F /
|
1973
|
-
| /
|
1974
|
-
i h
|
1975
|
-
++
|
1976
|
-
G
|
1977
|
-
|
1978
|
-
WITH
|
1979
|
-
context description do
|
1980
|
-
let!(:a) { Message.create text: 'A' }
|
1981
|
-
let!(:b) { create_message_with_invalidated_by('B', a) }
|
1982
|
-
let!(:d) { create_message_with_invalidated_by('D', a) }
|
1983
|
-
let!(:c) { create_message_with_invalidated_by('C', [a, b, d]) }
|
1984
|
-
let!(:e) { create_message_with_invalidated_by('E', b) }
|
1985
|
-
let!(:f) { create_message_with_invalidated_by('F', [e, c]) }
|
1986
|
-
let!(:h) { Message.create text: 'H', parent: a }
|
1987
|
-
let!(:i) { Message.create text: 'I', parent: h }
|
1988
|
-
let!(:g) do
|
1989
|
-
msg = Message.create text: 'G', parent: i
|
1990
|
-
msg.invalidated_by = [f]
|
1991
|
-
msg
|
1992
|
-
end
|
1993
|
-
|
1994
|
-
before do
|
1995
|
-
Relation
|
1996
|
-
.where('hierarchy + invalidate > 1')
|
1997
|
-
.update_all('hierarchy = hierarchy + 10, invalidate = invalidate + 10')
|
1998
|
-
|
1999
|
-
Message.rebuild_dag!
|
2000
|
-
end
|
2001
|
-
|
2002
|
-
it 'rebuilds the closure for A correctly' do
|
2003
|
-
attribute_array = to_attribute_array a.relations_to
|
2004
|
-
expect(attribute_array)
|
2005
|
-
.to match_array([['A', 'A', 0, 0, 1],
|
2006
|
-
['A', 'B', 0, 1, 1],
|
2007
|
-
['A', 'C', 0, 1, 1],
|
2008
|
-
['A', 'C', 0, 2, 2],
|
2009
|
-
['A', 'D', 0, 1, 1],
|
2010
|
-
['A', 'E', 0, 2, 1],
|
2011
|
-
['A', 'F', 0, 2, 1],
|
2012
|
-
['A', 'F', 0, 3, 3],
|
2013
|
-
['A', 'G', 0, 3, 1],
|
2014
|
-
['A', 'G', 0, 4, 3],
|
2015
|
-
['A', 'G', 3, 0, 1],
|
2016
|
-
['A', 'H', 1, 0, 1],
|
2017
|
-
['A', 'I', 2, 0, 1]])
|
2018
|
-
end
|
2019
|
-
|
2020
|
-
it 'rebuilds the closure for B correctly' do
|
2021
|
-
attribute_array = to_attribute_array b.relations_to
|
2022
|
-
expect(attribute_array)
|
2023
|
-
.to match_array([['B', 'B', 0, 0, 1],
|
2024
|
-
['B', 'C', 0, 1, 1],
|
2025
|
-
['B', 'E', 0, 1, 1],
|
2026
|
-
['B', 'F', 0, 2, 2],
|
2027
|
-
['B', 'G', 0, 3, 2]])
|
2028
|
-
end
|
2029
|
-
|
2030
|
-
it 'rebuilds all reflexive relations' do
|
2031
|
-
expect(Relation.where(hierarchy: 0, invalidate: 0).count)
|
2032
|
-
.to eql 9
|
2033
|
-
end
|
2034
|
-
end
|
2035
|
-
|
2036
|
-
description = <<-'WITH'
|
2037
|
-
|
2038
|
-
DAG (invalid) before:
|
2039
|
-
A
|
2040
|
-
+ \
|
2041
|
-
i h
|
2042
|
-
/ +
|
2043
|
-
C+--h---B
|
2044
|
-
|
2045
|
-
DAG after:
|
2046
|
-
A
|
2047
|
-
\
|
2048
|
-
h
|
2049
|
-
+
|
2050
|
-
C+--h---B
|
2051
|
-
WITH
|
2052
|
-
|
2053
|
-
context description do
|
2054
|
-
let!(:a) { Message.create text: 'A' }
|
2055
|
-
let!(:b) { Message.create text: 'B', parent: a }
|
2056
|
-
let!(:c) { Message.create text: 'C', parent: b }
|
2057
|
-
let!(:invalid_relation) do
|
2058
|
-
Relation
|
2059
|
-
.new(from: c,
|
2060
|
-
to: a,
|
2061
|
-
invalidate: 1)
|
2062
|
-
.save(validate: false)
|
2063
|
-
end
|
2064
|
-
|
2065
|
-
before do
|
2066
|
-
Message.rebuild_dag!
|
2067
|
-
end
|
2068
|
-
|
2069
|
-
it '#descendants_of_depth(1) for A is B' do
|
2070
|
-
expect(a.descendants_of_depth(1))
|
2071
|
-
.to match_array([b])
|
2072
|
-
end
|
2073
|
-
|
2074
|
-
it '#descendants_of_depth(2) for A is C' do
|
2075
|
-
expect(a.descendants_of_depth(2))
|
2076
|
-
.to match_array([c])
|
2077
|
-
end
|
2078
|
-
|
2079
|
-
it '#all_invalidates_of_depth(1) for C is empty' do
|
2080
|
-
expect(c.all_invalidates_of_depth(1))
|
2081
|
-
.to be_empty
|
2082
|
-
end
|
2083
|
-
end
|
2084
|
-
|
2085
|
-
description = <<-'WITH'
|
2086
|
-
|
2087
|
-
DAG (invalid) before:
|
2088
|
-
C+-h--B
|
2089
|
-
|+ +
|
2090
|
-
| \ |
|
2091
|
-
h i h
|
2092
|
-
| \ |
|
2093
|
-
+ \|
|
2094
|
-
D--h-+A
|
2095
|
-
WITH
|
2096
|
-
|
2097
|
-
context description do
|
2098
|
-
let!(:a) { Message.create text: 'A' }
|
2099
|
-
let!(:b) { Message.create text: 'B', parent: a }
|
2100
|
-
let!(:c) { Message.create text: 'C', parent: b }
|
2101
|
-
let!(:d) { Message.create text: 'D', parent: c }
|
2102
|
-
let!(:invalid_relation1) do
|
2103
|
-
Relation
|
2104
|
-
.new(from: a,
|
2105
|
-
to: c,
|
2106
|
-
invalidate: 1)
|
2107
|
-
.save(validate: false)
|
2108
|
-
end
|
2109
|
-
let!(:invalid_relation2) do
|
2110
|
-
Relation
|
2111
|
-
.new(from: d,
|
2112
|
-
to: a,
|
2113
|
-
hierarchy: 1)
|
2114
|
-
.save(validate: false)
|
2115
|
-
end
|
2116
|
-
|
2117
|
-
it 'throws an error if more attempts than specified are made' do
|
2118
|
-
expect { Message.rebuild_dag!(1) }
|
2119
|
-
.to raise_error(TypedDag::RebuildDag::AttemptsExceededError)
|
2120
|
-
end
|
2121
|
-
end
|
2122
|
-
end
|
2123
|
-
|
2124
|
-
describe '*_leaf?' do
|
2125
|
-
description = <<-'WITH'
|
2126
|
-
|
2127
|
-
DAG:
|
2128
|
-
------- A -------
|
2129
|
-
/ \
|
2130
|
-
invalidate hierarchy
|
2131
|
-
/ \
|
2132
|
-
B C
|
2133
|
-
| |
|
2134
|
-
hierarchy invalidate
|
2135
|
-
| |
|
2136
|
-
D E
|
2137
|
-
|
2138
|
-
WITH
|
2139
|
-
context description do
|
2140
|
-
let!(:a) { Message.create text: 'A' }
|
2141
|
-
let!(:b) { create_message_with_invalidated_by('B', a) }
|
2142
|
-
let!(:c) { Message.create text: 'C', parent: a }
|
2143
|
-
let!(:d) { Message.create text: 'D', parent: b }
|
2144
|
-
let!(:e) { create_message_with_invalidated_by('E', c) }
|
2145
|
-
|
2146
|
-
it '#invalidate_leaf? for A is false' do
|
2147
|
-
expect(a)
|
2148
|
-
.not_to be_invalidate_leaf
|
2149
|
-
end
|
2150
|
-
|
2151
|
-
it '#hierarchy_leaf? for A is false' do
|
2152
|
-
expect(a)
|
2153
|
-
.not_to be_hierarchy_leaf
|
2154
|
-
end
|
2155
|
-
|
2156
|
-
it '#invalidate_leaf? for B is true' do
|
2157
|
-
expect(b)
|
2158
|
-
.to be_invalidate_leaf
|
2159
|
-
end
|
2160
|
-
|
2161
|
-
it '#hierarchy_leaf? for B is false' do
|
2162
|
-
expect(b)
|
2163
|
-
.not_to be_hierarchy_leaf
|
2164
|
-
end
|
2165
|
-
|
2166
|
-
it '#invalidate_leaf? for C is false' do
|
2167
|
-
expect(c)
|
2168
|
-
.not_to be_invalidate_leaf
|
2169
|
-
end
|
2170
|
-
|
2171
|
-
it '#hierarchy_leaf? for C is true' do
|
2172
|
-
expect(c)
|
2173
|
-
.to be_hierarchy_leaf
|
2174
|
-
end
|
2175
|
-
end
|
2176
|
-
end
|
2177
|
-
end
|
2178
|
-
end
|