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.
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