taxonomite 0.1.0 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/lib/taxonomite/exceptions.rb +42 -3
  3. data/lib/taxonomite/node.rb +104 -108
  4. data/lib/taxonomite/taxonomite_configuration.rb +57 -4
  5. data/lib/taxonomite/taxonomy.rb +144 -0
  6. data/lib/taxonomite/tree.rb +67 -27
  7. data/lib/taxonomite/version.rb +1 -1
  8. data/spec/dummy/app/assets/stylesheets/application.css +2 -2
  9. data/spec/dummy/app/controllers/taxonomite_controller.rb +3 -3
  10. data/spec/dummy/app/views/layouts/application.html.erb +2 -2
  11. data/spec/dummy/app/views/taxonomite/_node.html.erb +1 -1
  12. data/spec/dummy/app/views/taxonomite/edit.html.erb +5 -10
  13. data/spec/dummy/app/views/taxonomite/index.html.erb +1 -1
  14. data/spec/dummy/app/views/taxonomite/new.html.erb +0 -4
  15. data/spec/dummy/app/views/taxonomite/show.html.erb +4 -5
  16. data/spec/dummy/config/application.rb +0 -3
  17. data/spec/dummy/config/routes.rb +3 -3
  18. data/spec/dummy/log/development.log +4003 -0
  19. data/spec/dummy/log/test.log +9906 -0
  20. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/4vdQYQIAhYwrL0QVMvfa54lhQG6llPr5uoxQk1ouaM8.cache +1 -0
  21. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/7ucWh-CcCYtuzX4nESCM8wP6Oo-dugQ9oWvKpJBfGXc.cache +0 -0
  22. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/8QLYXmTDdck6lEnExFXVUgVd0VmTjBqiwgkBUaI0mfI.cache +1 -0
  23. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/DHPriyPTqAKI-VE0nnqxYbNlqmqdd3RgpylNEg22ZEU.cache +0 -0
  24. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/DmmfrCpXtt74Hr6NO54lxyOCDv6klnDyBqeDFR7oDU8.cache +2 -0
  25. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/H6fMQ0CH2SZoDE1LEjfMDSDeMVjPnKKABOQsu-cwfTA.cache +1 -0
  26. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/H_sT8XqVfJtCW-AC1MLG9rXc7bZgFDHNDRNIyiHQN80.cache +2 -0
  27. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/HcyLAwu9aQkSXaKmo86TjBGj5kCqEEqEe0PnSGBuHFA.cache +2 -0
  28. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/JuGo9fAopWqzVuLTjAj8tdAP316MxbMVXhPB88frxSE.cache +2 -0
  29. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/OhXYCvG-a_22n0rNMEUgOaqjiz2CPC5MA9Zo-ElvVr0.cache +1 -0
  30. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/PzDdhgDidlsbrgnnvqY64gLSrP2kaVIqwUFPnd-h-q0.cache +1 -0
  31. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/SAk_VBRi2O1BhT-LTDYCY4zy6rntLx1RDoCXZmA9dqA.cache +0 -0
  32. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/WmFpKlhm7tR4kHRsyBRQqupfX_VtT46yYZo6ysyujVA.cache +1 -0
  33. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/XjFN6x13TIQd-Y0w5iv5yiUaeTXVFTUJZ8fi3-Zf9nY.cache +1 -0
  34. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/YR7u7z93aL2h6rPUUFI6nZXzmR57bMMQ0GfS0NAwnTo.cache +0 -0
  35. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/a2YAOseOUMHfaabIoOQHYrg_L8Zr-Dmf2GsQnMkW-Os.cache +0 -0
  36. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/aCaKUaA2zFHYb85d3HsEaLzqqcySgu1RNprCoAsVud0.cache +1 -0
  37. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/asZJOwOxXbTo1DcWgp7Bepytus9KbEtoyjSk5ZGRpCg.cache +1 -0
  38. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/ekIbgUIaZdrL5rxYSxMCKZcTjHANQi6KjM56x166Q2U.cache +2 -0
  39. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/gVc7mlhXRPZKcR593Z7dQrsKdJCjbg3FuDacsK6KC3Q.cache +0 -0
  40. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/hZi1k6tpxxCGYxRe7zY74ItcOI8gZrREOpGuA8JSpGg.cache +3 -0
  41. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/nJmf-nKlKYmmb_4KPWVHI6UtkeXBMYHiMt4fHuhL3NI.cache +1 -0
  42. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/oktKvwt0h2v1ixmHfahaBJKnWt_3nTIpuilb35Nk5IU.cache +1 -0
  43. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/pEhaat2KBd5SrT7szC_8R1_6hK17FTpvoRFkmCRSD3M.cache +2 -0
  44. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/tJb-RVxVPbizlMUsIVfCaQ-Ly2e8fNxjJMxUXCyqO2c.cache +0 -0
  45. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/xhy8Vy-n9RUeqeVICYHCfPXkDfYOtv_dXeuIJEwK_8k.cache +0 -0
  46. data/spec/dummy/tmp/cache/assets/development/sprockets/v3.0/zTELlyyx2TMwFIUjf_8PuaPdHIH7k6AKMjaUTaV7VwY.cache +1 -0
  47. data/spec/factories/taxonomy_taxon.rb +25 -14
  48. data/spec/models/taxonomite/hierarchy_spec.rb +113 -20
  49. data/spec/models/taxonomite/model_spec.rb +0 -5
  50. data/spec/models/taxonomite/tree_spec.rb +120 -10
  51. data/spec/models/taxonomite/zoology.rb +14 -13
  52. data/spec/spec_helper.rb +0 -5
  53. metadata +88 -32
@@ -0,0 +1 @@
1
+ I"}app/assets/stylesheets/application.css?type=text/css&id=9e7650176706ddb2760a74f747181459f8f843e60096f5bcdc31935ed2a0143d:ET
@@ -0,0 +1 @@
1
+ I"}app/assets/stylesheets/application.css?type=text/css&id=c3aa4f676aa8fa75a7fdcfc385da6c6d8698687290155e5aa41711a3909f442e:ET
@@ -0,0 +1,2 @@
1
+ [o:Set:
2
+ @hash{ I"environment-version:ETTI"environment-paths;TTI">processors:type=text/css&file_type=text/css&pipeline=self;TTI"_file-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/stylesheets/scaffold.css;TT
@@ -0,0 +1 @@
1
+ "%����NWS�R�aj��zl��i�����B����[�
@@ -0,0 +1,2 @@
1
+ [o:Set:
2
+ @hash{ I"environment-version:ETTI"environment-paths;TTI">processors:type=text/css&file_type=text/css&pipeline=self;TTI"bfile-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/stylesheets/application.css;TTI"Rfile-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/stylesheets;TTI"_file-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/stylesheets/scaffold.css;TT
@@ -0,0 +1,2 @@
1
+ [o:Set:
2
+ @hash{ I"environment-version:ETTI"environment-paths;TTI"0processors:type=text/css&file_type=text/css;TTI"bfile-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/stylesheets/application.css;TTI">processors:type=text/css&file_type=text/css&pipeline=self;TTI"_file-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/stylesheets/scaffold.css;TTI"Rfile-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/stylesheets;TT
@@ -0,0 +1,2 @@
1
+ [o:Set:
2
+ @hash{ I"environment-version:ETTI"environment-paths;TTI"0processors:type=text/css&file_type=text/css;TTI"bfile-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/stylesheets/application.css;TTI">processors:type=text/css&file_type=text/css&pipeline=self;TTI"_file-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/stylesheets/scaffold.css;TTI"Rfile-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/stylesheets;TT
@@ -0,0 +1 @@
1
+ "%*,�� ΄�;Q������ m���a�!
@@ -0,0 +1 @@
1
+ "%�W\�yho9S���ƫ˥��)|�~���(���
@@ -0,0 +1 @@
1
+ "%���[�RH!Cܥ4ihvd�xA�o��N(� �
@@ -0,0 +1 @@
1
+ I"�app/assets/stylesheets/application.css?type=text/css&pipeline=self&id=12c697dfae49156ee66ec33fffd3cc9021d20a0dd9c26bdd65070ede1c510d09:ET
@@ -0,0 +1 @@
1
+ I"�app/assets/stylesheets/scaffold.css?type=text/css&pipeline=self&id=df3794360df764723a12aad0fa75f26baab65924c04b20ed76487c5bc049a091:ET
@@ -0,0 +1 @@
1
+ I"�app/assets/javascripts/application.js?type=application/javascript&pipeline=self&id=1d4a7f8c94203303609882a8967270c472835b3ce84ff3b76f685f4a94c56f74:ET
@@ -0,0 +1,2 @@
1
+ [o:Set:
2
+ @hash{ I"environment-version:ETTI"environment-paths;TTI">processors:type=text/css&file_type=text/css&pipeline=self;TTI"bfile-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/stylesheets/application.css;TTI"Rfile-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/stylesheets;TTI"_file-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/stylesheets/scaffold.css;TT
@@ -0,0 +1,3 @@
1
+ [o:Set:
2
+ @hash{
3
+ I"environment-version:ETTI"environment-paths;TTI"Zprocessors:type=application/javascript&file_type=application/javascript&pipeline=self;TTI"afile-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/javascripts/application.js;TTI"Rfile-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/javascripts;TT
@@ -0,0 +1 @@
1
+ "%��A�I8���߅�u7�!��H���j���\��|x
@@ -0,0 +1 @@
1
+ I"�app/assets/stylesheets/application.css?type=text/css&pipeline=self&id=7ecdb18055e5b00f327ea5526255fb5292146e7b39700faca7a685f511735146:ET
@@ -0,0 +1,2 @@
1
+ [o:Set:
2
+ @hash{ I"environment-version:ETTI"environment-paths;TTI"Lprocessors:type=application/javascript&file_type=application/javascript;TTI"afile-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/javascripts/application.js;TTI"Zprocessors:type=application/javascript&file_type=application/javascript&pipeline=self;TTI"Rfile-digest:///home/hgillesp/dev/taxonomite/spec/dummy/app/assets/javascripts;TT
@@ -0,0 +1 @@
1
+ I"�app/assets/javascripts/application.js?type=application/javascript&id=60ea9b55c3b2e4f671f3a81e9c413633dce914b0a5dc2b519539ab97c67b678d:ET
@@ -1,45 +1,56 @@
1
1
 
2
+ require 'factory_girl_rails'
2
3
  require 'faker'
3
4
 
4
5
  FactoryGirl.define do
5
6
  factory :taxonomite_node, :class => 'Taxonomite::Node' do
6
7
  name { Faker::Lorem.word.capitalize }
7
- description { Faker::Lorem.paragraph }
8
8
  end
9
9
 
10
10
  factory :taxonomite_species, :class => 'Taxonomite::Species' do
11
11
  name { "#{Faker::Lorem.word.capitalize} #{Faker::Lorem.word}" }
12
- description { Faker::Lorem.paragraph }
13
12
  end
14
13
 
15
14
  factory :taxonomite_genus, :class => 'Taxonomite::Genus' do
16
- name { "#{Faker::Lorem.word.capitalize} #{Faker::Lorem.word}" }
17
- description { Faker::Lorem.paragraph }
15
+ name { "#{Faker::Lorem.word.capitalize}" }
18
16
  end
19
17
 
20
18
  factory :taxonomite_family, :class => 'Taxonomite::Family' do
21
- name { "#{Faker::Lorem.word.capitalize} #{Faker::Lorem.word}" }
22
- description { Faker::Lorem.paragraph }
19
+ name { "#{Faker::Lorem.word.capitalize}" }
23
20
  end
24
21
 
25
22
  factory :taxonomite_order, :class => 'Taxonomite::Order' do
26
- name { "#{Faker::Lorem.word.capitalize} #{Faker::Lorem.word}" }
27
- description { Faker::Lorem.paragraph }
23
+ name { "#{Faker::Lorem.word.capitalize}" }
28
24
  end
29
25
 
30
26
  factory :taxonomite_class, :class => 'Taxonomite::Class' do
31
- name { "#{Faker::Lorem.word.capitalize} #{Faker::Lorem.word}" }
32
- description { Faker::Lorem.paragraph }
27
+ name { "#{Faker::Lorem.word.capitalize}" }
33
28
  end
34
29
 
35
30
  factory :taxonomite_phylum, :class => 'Taxonomite::Phylum' do
36
- name { "#{Faker::Lorem.word.capitalize} #{Faker::Lorem.word}" }
37
- description { Faker::Lorem.paragraph }
31
+ name { "#{Faker::Lorem.word.capitalize}" }
38
32
  end
39
33
 
40
34
  factory :taxonomite_kingdom, :class => 'Taxonomite::Kingdom' do
41
- name { "#{Faker::Lorem.word.capitalize} #{Faker::Lorem.word}" }
42
- description { Faker::Lorem.paragraph }
35
+ name { "#{Faker::Lorem.word.capitalize}" }
36
+ end
37
+
38
+ factory :taxonomite_down_taxonomy, :class => 'Taxonomite::Taxonomy' do
39
+ down_taxonomy { { 'kingdom' => 'phylum', 'phylum' => 'class', 'class' => 'order',
40
+ 'order' => 'family', 'family' => 'genus', 'genus' => 'species' } }
43
41
  end
44
42
 
43
+ factory :taxonomite_up_taxonomy, :class => 'Taxonomite::Taxonomy' do
44
+ up_taxonomy { { 'kingdom' => 'phylum', 'phylum' => 'class', 'class' => 'order',
45
+ 'order' => 'family', 'family' => 'genus', 'genus' => 'species' }.invert }
46
+ end
47
+
48
+ factory :taxonomite_empty_taxonomy, :class => 'Taxonomite::Taxonomy' do
49
+ end
50
+
51
+ factory :taxonomite_single_wildcard_taxonomy, :class => 'Taxonomite::Taxonomy' do
52
+ down_taxonomy { { 'kingdom' => '*', 'phylum' => 'class' } }
53
+ end
54
+
55
+
45
56
  end
@@ -3,32 +3,125 @@ require 'models/taxonomite/zoology'
3
3
 
4
4
  module Taxonomite
5
5
  RSpec.describe Tree, type: :model do
6
+ describe 'enforce hierarchy' do
7
+ context 'without Taxonomy object' do
8
+ before(:each) do
9
+ @family = FactoryGirl.build(:taxonomite_family)
10
+ @genus = FactoryGirl.build(:taxonomite_genus)
11
+ @species = FactoryGirl.build(:taxonomite_species)
12
+ end
6
13
 
7
- context 'sample hierarchy enforcement' do
8
- before(:each) do
9
- @family = FactoryGirl.build(:taxonomite_family)
10
- @genus = FactoryGirl.build(:taxonomite_genus)
11
- @species = FactoryGirl.build(:taxonomite_species)
12
- end
14
+ it 'to allow species in genus when no taxonomy present' do
15
+ expect { @genus.add_child(@species) }.not_to raise_error
16
+ end
13
17
 
14
- it 'to allow species in genus' do
15
- expect { @genus.children << @species }.not_to raise_error
16
- end
18
+ it 'to allow genus in family when no taxonomy present' do
19
+ expect { @family.add_child(@genus) }.not_to raise_error
20
+ end
17
21
 
18
- it 'to allow genus in family' do
19
- expect { @family.children << @genus }.not_to raise_error
20
- end
22
+ it 'to allow genus in species when no taxonomy present' do
23
+ expect { @species.add_child(@genus) }.not_to raise_error
24
+ end
21
25
 
22
- it 'not to allow genus in species' do
23
- expect { @species.children << @genus }.to raise_error
24
- end
26
+ it 'to allow species in family when no taxonomy present' do
27
+ expect { @family.add_child(@species) }.not_to raise_error
28
+ end
29
+ end
25
30
 
26
- it 'not to allow species in family' do
27
- expect { @family.children << @species }.to raise_error
28
- end
31
+ context 'specific taxonomy rejections, with wildcard' do
32
+ before(:each) do
33
+ @taxonomy = FactoryGirl.build(:taxonomite_single_wildcard_taxonomy)
34
+ @kingdom = FactoryGirl.build(:taxonomite_kingdom)
35
+ @phylum = FactoryGirl.build(:taxonomite_phylum)
36
+ @class = FactoryGirl.build(:taxonomite_class)
37
+ @species = FactoryGirl.build(:taxonomite_species)
38
+ end
29
39
 
30
- end
40
+ it 'to allow anything in kingdom (under "*")' do
41
+ expect { @taxonomy.add(@kingdom, @phylum) }.not_to raise_error
42
+ expect { @taxonomy.add(@kingdom, @class) }.not_to raise_error
43
+ expect { @taxonomy.add(@kingdom, @species) }.not_to raise_error
44
+ end
31
45
 
32
- end
46
+ it 'to allow only class under phylum' do
47
+ expect { @taxonomy.add(@phylum, @class) }.not_to raise_error
48
+ expect { @taxonomy.add(@phylum, @species) }.to raise_error
49
+ expect { @taxonomy.add(@phylum, @kingdom) }.to raise_error
50
+ end
51
+
52
+ it 'to allow only nothing under class (empty)' do
53
+ expect { @taxonomy.add(@class, @phylum) }.to raise_error
54
+ expect { @taxonomy.add(@class, @species) }.to raise_error
55
+ expect { @taxonomy.add(@class, @kingdom) }.to raise_error
56
+ end
57
+ end
58
+
59
+ context 'empty Taxonomy object' do
60
+ before(:each) do
61
+ @taxonomy = FactoryGirl.build(:taxonomite_empty_taxonomy)
62
+ @family = FactoryGirl.build(:taxonomite_family)
63
+ @genus = FactoryGirl.build(:taxonomite_genus)
64
+ @species = FactoryGirl.build(:taxonomite_species)
65
+ end
66
+
67
+ it 'to allow anything anywhere' do
68
+ expect { @taxonomy.add(@genus, @species) }.not_to raise_error
69
+ expect { @taxonomy.add(@family, @genus) }.not_to raise_error
70
+ expect { @taxonomy.add(@species, @genus) }.to raise_error # circular reference
71
+ expect { @taxonomy.add(@family, @species) }.not_to raise_error
72
+ end
73
+ end
74
+
75
+ context 'with down-looking Taxonomy object' do
76
+ before(:each) do
77
+ @taxonomy = FactoryGirl.build(:taxonomite_down_taxonomy)
78
+ @family = FactoryGirl.build(:taxonomite_family)
79
+ @genus = FactoryGirl.build(:taxonomite_genus)
80
+ @species = FactoryGirl.build(:taxonomite_species)
81
+ end
82
+
83
+ it 'to allow species in genus with taxonomy present' do
84
+ expect { @taxonomy.add(@genus, @species) }.not_to raise_error
85
+ end
86
+
87
+ it 'to allow genus in family with taxonomy present' do
88
+ expect { @taxonomy.add(@family, @genus) }.not_to raise_error
89
+ end
90
+
91
+ it 'not to allow genus in species with taxonomy present' do
92
+ expect { @taxonomy.add(@species, @genus) }.to raise_error
93
+ end
33
94
 
95
+ it 'not to allow species in family with taxonomy present' do
96
+ expect { @taxonomy.add(@family, @species) }.to raise_error
97
+ end
98
+ end
99
+
100
+ context 'with up-looking Taxonomy object' do
101
+ before(:each) do
102
+ @taxonomy = FactoryGirl.build(:taxonomite_up_taxonomy)
103
+ @family = FactoryGirl.build(:taxonomite_family)
104
+ @genus = FactoryGirl.build(:taxonomite_genus)
105
+ @species = FactoryGirl.build(:taxonomite_species)
106
+ end
107
+
108
+ it 'to allow species in genus with taxonomy present' do
109
+ expect { @taxonomy.add(@genus, @species) }.not_to raise_error
110
+ end
111
+
112
+ it 'to allow genus in family with taxonomy present' do
113
+ expect { @taxonomy.add(@family, @genus) }.not_to raise_error
114
+ end
115
+
116
+ it 'not to allow genus in species with taxonomy present' do
117
+ expect { @taxonomy.add(@species, @genus) }.to raise_error
118
+ end
119
+
120
+ it 'not to allow species in family with taxonomy present' do
121
+ expect { @taxonomy.add(@family, @species) }.to raise_error
122
+ end
123
+ end
124
+
125
+ end
126
+ end
34
127
  end
@@ -20,11 +20,6 @@ module Taxonomite
20
20
  expect(node.name).to eq("new_name")
21
21
  end
22
22
 
23
- it 'sets the description' do
24
- node.description = "new_description"
25
- expect(node.description).to eq("new_description")
26
- end
27
-
28
23
  it 'allow access to children' do
29
24
  expect { node.children }.not_to raise_error
30
25
  end
@@ -7,30 +7,52 @@ module Taxonomite
7
7
  context 'tree creation' do
8
8
  let!(:nodes) { Array.new(3){ |index| build(:taxonomite_node)} }
9
9
 
10
+ it 'allows addition of children' do
11
+ expect { nodes[0].add_child(nodes[1]) }.not_to raise_error
12
+ end
13
+
14
+ it 'allows addition of parent' do
15
+ expect { nodes[0].add_parent(nodes[1]) }.not_to raise_error
16
+ end
17
+
10
18
  it 'to disallow direct circular reference' do
11
- # rephrase to check validity
12
- expect { nodes[0].children << nodes[0] }.to raise_error
19
+ expect { nodes[0].add_child(nodes[0]) }.to raise_error
13
20
  end
14
21
 
15
22
  it 'to disallow circular reference (one deep)' do
16
- nodes[0].children << nodes[1]
17
- expect { nodes[1].children << nodes[0] }.to raise_error
23
+ nodes[0].add_child(nodes[1])
24
+ expect { nodes[1].add_child(nodes[0]) }.to raise_error
18
25
  end
26
+
27
+ it 'remove parent works as expected, parents child becomes nil' do
28
+ nodes[0].add_child(nodes[1])
29
+ expect { nodes[1].remove_parent }.not_to raise_error
30
+ expect(nodes[0].children.size).to eq(0)
31
+ end
32
+
33
+ it 'remove child works as expected, child parent becomes nil' do
34
+ nodes[0].add_child(nodes[1])
35
+ expect { nodes[0].remove_child(nodes[1]) }.not_to raise_error
36
+ expect(nodes[0].children.size).to eq(0)
37
+ expect(nodes[1].parent).nil?
38
+ end
39
+
19
40
  end
20
41
 
21
42
  context 'tree structure' do
22
43
  before(:each) do
23
- @nodes = Array.new(3) { build(:taxonomite_node) }
24
- @nodes[0].children << @nodes[1]
25
- @nodes[1].children << @nodes[2]
44
+ @nodes = Array.new(4) { build(:taxonomite_node) }
45
+ @nodes[0].add_child(@nodes[1])
46
+ @nodes[1].add_child(@nodes[2])
47
+ @nodes[0].add_child(@nodes[3])
26
48
  end
27
49
 
28
- it 'has appropriate children' do
29
- expect(@nodes[0].children.size).to eq(1)
50
+ it 'has appropriate number of children' do
51
+ expect(@nodes[0].children.size).to eq(2)
30
52
  end
31
53
 
32
54
  it 'to disallow circular reference (two deep)' do
33
- expect { @nodes[2].children << @nodes[0] }.to raise_error
55
+ expect { @nodes[2].add_child(@nodes[0]) }.to raise_error
34
56
  end
35
57
 
36
58
  it 'to iterate children' do
@@ -48,6 +70,94 @@ module Taxonomite
48
70
  expect { @nodes[0].destroy }.not_to raise_error
49
71
  expect(@nodes[1].parent).to eq(nil)
50
72
  expect(@nodes[2].parent).not_to eq(nil)
73
+ expect(@nodes[3].parent).to eq(nil)
74
+ end
75
+
76
+ it 'successfully finds leaves of the tree' do
77
+ expect(@nodes[0].leaves.size).to eq(2)
78
+ expect(@nodes[0].leaves.find(@nodes[3])).not_to eq(nil)
79
+ end
80
+
81
+ it 'successfully finds the root of the tree' do
82
+ expect(@nodes[2].root).to eq(@nodes[0])
83
+ expect(@nodes[3].root).to eq(@nodes[0])
84
+ end
85
+
86
+ it 'successfully identifies anscestor' do
87
+ expect(@nodes[2].descendant_of?(@nodes[0])).to eq(true)
88
+ expect(@nodes[0].descendant_of?(@nodes[2])).to eq(false)
89
+ end
90
+
91
+ it 'successfully identifies descendant' do
92
+ expect(@nodes[2].ancestor_of?(@nodes[0])).to eq(false)
93
+ expect(@nodes[0].ancestor_of?(@nodes[2])).to eq(true)
94
+ end
95
+
96
+ it 'can aggregate ancestors' do
97
+ expect { @nodes[0].ancestors.map { |n| n.evaluate('name') } }.not_to raise_error
98
+ end
99
+
100
+ it 'accurately aggregates self and ancestors' do
101
+ a = @nodes[2].self_and_ancestors.map { |n| n.evaluate ('name') }
102
+ expect(a.size).to eq(3)
103
+ expect(a.include?(@nodes[3].name)).not_to eq(true)
104
+ expect(a.include?(@nodes[2].name)).to eq(true)
105
+ expect(a.include?(@nodes[1].name)).to eq(true)
106
+ expect(a.include?(@nodes[0].name)).to eq(true)
107
+ end
108
+
109
+ it 'accurately aggregates ancestors without self' do
110
+ a = @nodes[2].ancestors.map { |n| n.evaluate ('name') }
111
+ expect(a.size).to eq(2)
112
+ expect(a.include?(@nodes[3].name)).not_to eq(true)
113
+ expect(a.include?(@nodes[2].name)).not_to eq(true)
114
+ expect(a.include?(@nodes[1].name)).to eq(true)
115
+ expect(a.include?(@nodes[0].name)).to eq(true)
116
+ end
117
+
118
+ it 'can aggregate self and descendants' do
119
+ expect { @nodes[0].self_and_descendants.map { |n| n.evaluate('name') } }.not_to raise_error
120
+ end
121
+
122
+ it 'accurately aggregates self and descendants' do
123
+ a = @nodes[0].self_and_descendants.map { |n| n.evaluate ('name') }
124
+ expect(a.size).to eq(4)
125
+ expect(a.include?(@nodes[3].name)).to eq(true)
126
+ expect(a.include?(@nodes[2].name)).to eq(true)
127
+ expect(a.include?(@nodes[1].name)).to eq(true)
128
+ expect(a.include?(@nodes[0].name)).to eq(true)
129
+ end
130
+
131
+ it 'accurately aggregates descendants without self' do
132
+ a = @nodes[0].descendants.map { |n| n.evaluate ('name') }
133
+ expect(a.size).to eq(3)
134
+ expect(a.include?(@nodes[3].name)).to eq(true)
135
+ expect(a.include?(@nodes[2].name)).to eq(true)
136
+ expect(a.include?(@nodes[1].name)).to eq(true)
137
+ expect(a.include?(@nodes[0].name)).not_to eq(true)
138
+ end
139
+
140
+ it 'aggregates leaf values without causing exception' do
141
+ expect { @nodes[0].leaves.map { |n| n.evaluate('name') } }.not_to raise_error
142
+ end
143
+
144
+ it 'accurately aggregates leaf values' do
145
+ a = @nodes[0].leaves.map { |n| n.evaluate('name') }
146
+
147
+ # i = 0
148
+ # @nodes.each do |n|
149
+ # print "Node[#{i}]: #{n.name} children: ["; n.children.each { |c| print " #{c.name}" }; puts " ]"
150
+ # puts "\t aggregated value: #{a.find_index(n.name)}"
151
+ # i += 1
152
+ # end
153
+ # puts "nodes: #{@nodes[0].aggregate('name')}"
154
+ # print "leaves: ["; @nodes[0].leaves.each { |l| print " #{l.name}" }; puts " ]"
155
+ # puts "aggregated leaves: #{a}"
156
+
157
+ expect(a.include?(@nodes[3].name)).to eq(true)
158
+ expect(a.include?(@nodes[2].name)).to eq(true)
159
+ expect(a.include?(@nodes[1].name)).not_to eq(true)
160
+ expect(a.include?(@nodes[0].name)).not_to eq(true)
51
161
  end
52
162
 
53
163
  end