typed_dag 2.0.1 → 2.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/typed_dag/version.rb +1 -1
  4. metadata +3 -141
  5. data/spec/spec_helper.rb +0 -89
  6. data/spec/support/helpers.rb +0 -47
  7. data/spec/test_app/Rakefile +0 -6
  8. data/spec/test_app/app/assets/config/manifest.js +0 -4
  9. data/spec/test_app/app/assets/javascripts/application.js +0 -13
  10. data/spec/test_app/app/assets/javascripts/cable.js +0 -13
  11. data/spec/test_app/app/assets/stylesheets/application.css +0 -15
  12. data/spec/test_app/app/channels/application_cable/channel.rb +0 -4
  13. data/spec/test_app/app/channels/application_cable/connection.rb +0 -4
  14. data/spec/test_app/app/controllers/application_controller.rb +0 -3
  15. data/spec/test_app/app/helpers/application_helper.rb +0 -2
  16. data/spec/test_app/app/jobs/application_job.rb +0 -2
  17. data/spec/test_app/app/mailers/application_mailer.rb +0 -4
  18. data/spec/test_app/app/models/application_record.rb +0 -3
  19. data/spec/test_app/app/models/message.rb +0 -2
  20. data/spec/test_app/app/models/relation.rb +0 -2
  21. data/spec/test_app/app/views/layouts/application.html.erb +0 -14
  22. data/spec/test_app/app/views/layouts/mailer.html.erb +0 -13
  23. data/spec/test_app/app/views/layouts/mailer.text.erb +0 -1
  24. data/spec/test_app/bin/bundle +0 -3
  25. data/spec/test_app/bin/rails +0 -4
  26. data/spec/test_app/bin/rake +0 -4
  27. data/spec/test_app/bin/setup +0 -38
  28. data/spec/test_app/bin/update +0 -29
  29. data/spec/test_app/bin/yarn +0 -11
  30. data/spec/test_app/config.ru +0 -5
  31. data/spec/test_app/config/application.rb +0 -26
  32. data/spec/test_app/config/boot.rb +0 -5
  33. data/spec/test_app/config/cable.yml +0 -10
  34. data/spec/test_app/config/database.mysql.yml.travis +0 -9
  35. data/spec/test_app/config/database.postgresql.yml.travis +0 -9
  36. data/spec/test_app/config/database.yml +0 -23
  37. data/spec/test_app/config/environment.rb +0 -5
  38. data/spec/test_app/config/environments/development.rb +0 -54
  39. data/spec/test_app/config/environments/production.rb +0 -91
  40. data/spec/test_app/config/environments/test.rb +0 -42
  41. data/spec/test_app/config/initializers/application_controller_renderer.rb +0 -6
  42. data/spec/test_app/config/initializers/assets.rb +0 -14
  43. data/spec/test_app/config/initializers/backtrace_silencers.rb +0 -7
  44. data/spec/test_app/config/initializers/cookies_serializer.rb +0 -5
  45. data/spec/test_app/config/initializers/filter_parameter_logging.rb +0 -4
  46. data/spec/test_app/config/initializers/inflections.rb +0 -16
  47. data/spec/test_app/config/initializers/mime_types.rb +0 -4
  48. data/spec/test_app/config/initializers/typed_dag.rb +0 -12
  49. data/spec/test_app/config/initializers/wrap_parameters.rb +0 -14
  50. data/spec/test_app/config/locales/en.yml +0 -33
  51. data/spec/test_app/config/puma.rb +0 -56
  52. data/spec/test_app/config/routes.rb +0 -3
  53. data/spec/test_app/config/secrets.yml +0 -32
  54. data/spec/test_app/config/spring.rb +0 -6
  55. data/spec/test_app/db/development.sqlite3 +0 -0
  56. data/spec/test_app/db/migrate/20170831093433_create_nodes_and_endges.rb +0 -22
  57. data/spec/test_app/db/schema.rb +0 -35
  58. data/spec/test_app/db/test.sqlite3 +0 -0
  59. data/spec/test_app/log/development.log +0 -101
  60. data/spec/test_app/log/test.log +0 -0
  61. data/spec/test_app/package.json +0 -5
  62. data/spec/test_app/public/404.html +0 -67
  63. data/spec/test_app/public/422.html +0 -67
  64. data/spec/test_app/public/500.html +0 -66
  65. data/spec/test_app/public/apple-touch-icon-precomposed.png +0 -0
  66. data/spec/test_app/public/apple-touch-icon.png +0 -0
  67. data/spec/test_app/public/favicon.ico +0 -0
  68. data/spec/typed_dag/configuration.rb +0 -92
  69. data/spec/typed_dag/edge_spec.rb +0 -578
  70. data/spec/typed_dag/node_spec.rb +0 -2178
  71. data/spec/typed_dag/sql/add_closure_spec.rb +0 -116
  72. data/spec/typed_dag/sql/truncate_closure_spec.rb +0 -112
  73. data/spec/typed_dag_spec.rb +0 -7
@@ -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