jumoku 0.1.1 → 0.1.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 (85) hide show
  1. data/Gemfile +4 -0
  2. data/lib/jumoku.rb +4 -2
  3. data/lib/jumoku/version.rb +1 -1
  4. data/spec/raw_tree_spec.rb +353 -0
  5. data/spec/spec.opts +4 -0
  6. data/spec/spec_helper.rb +14 -0
  7. data/spec/tree_spec.rb +553 -0
  8. data/vendor/git/graphy/CREDITS.md +31 -0
  9. data/vendor/git/graphy/LICENSE +35 -0
  10. data/vendor/git/graphy/README.md +186 -0
  11. data/vendor/git/graphy/Rakefile +61 -0
  12. data/vendor/git/graphy/TODO.md +20 -0
  13. data/vendor/git/graphy/VERSION +1 -0
  14. data/vendor/git/graphy/examples/graph_self.rb +56 -0
  15. data/vendor/git/graphy/examples/module_graph.jpg +0 -0
  16. data/vendor/git/graphy/examples/module_graph.rb +14 -0
  17. data/vendor/git/graphy/examples/self_graph.jpg +0 -0
  18. data/vendor/git/graphy/examples/visualize.jpg +0 -0
  19. data/vendor/git/graphy/examples/visualize.rb +10 -0
  20. data/vendor/git/graphy/graphy.gemspec +149 -0
  21. data/vendor/git/graphy/lib/graphy.rb +90 -0
  22. data/vendor/git/graphy/lib/graphy/adjacency_graph.rb +224 -0
  23. data/vendor/git/graphy/lib/graphy/arc.rb +65 -0
  24. data/vendor/git/graphy/lib/graphy/arc_number.rb +52 -0
  25. data/vendor/git/graphy/lib/graphy/biconnected.rb +84 -0
  26. data/vendor/git/graphy/lib/graphy/chinese_postman.rb +91 -0
  27. data/vendor/git/graphy/lib/graphy/classes/graph_classes.rb +28 -0
  28. data/vendor/git/graphy/lib/graphy/common.rb +63 -0
  29. data/vendor/git/graphy/lib/graphy/comparability.rb +63 -0
  30. data/vendor/git/graphy/lib/graphy/directed_graph.rb +76 -0
  31. data/vendor/git/graphy/lib/graphy/directed_graph/algorithms.rb +92 -0
  32. data/vendor/git/graphy/lib/graphy/directed_graph/distance.rb +167 -0
  33. data/vendor/git/graphy/lib/graphy/dot.rb +94 -0
  34. data/vendor/git/graphy/lib/graphy/edge.rb +37 -0
  35. data/vendor/git/graphy/lib/graphy/ext.rb +79 -0
  36. data/vendor/git/graphy/lib/graphy/graph.rb +631 -0
  37. data/vendor/git/graphy/lib/graphy/graph_api.rb +35 -0
  38. data/vendor/git/graphy/lib/graphy/labels.rb +113 -0
  39. data/vendor/git/graphy/lib/graphy/maximum_flow.rb +77 -0
  40. data/vendor/git/graphy/lib/graphy/ruby_compatibility.rb +17 -0
  41. data/vendor/git/graphy/lib/graphy/search.rb +511 -0
  42. data/vendor/git/graphy/lib/graphy/strong_components.rb +93 -0
  43. data/vendor/git/graphy/lib/graphy/support/support.rb +9 -0
  44. data/vendor/git/graphy/lib/graphy/undirected_graph.rb +57 -0
  45. data/vendor/git/graphy/lib/graphy/undirected_graph/algorithms.rb +90 -0
  46. data/vendor/git/graphy/spec/biconnected_spec.rb +27 -0
  47. data/vendor/git/graphy/spec/chinese_postman_spec.rb +27 -0
  48. data/vendor/git/graphy/spec/community_spec.rb +44 -0
  49. data/vendor/git/graphy/spec/complement_spec.rb +27 -0
  50. data/vendor/git/graphy/spec/digraph_distance_spec.rb +121 -0
  51. data/vendor/git/graphy/spec/digraph_spec.rb +339 -0
  52. data/vendor/git/graphy/spec/dot_spec.rb +48 -0
  53. data/vendor/git/graphy/spec/edge_spec.rb +159 -0
  54. data/vendor/git/graphy/spec/inspection_spec.rb +40 -0
  55. data/vendor/git/graphy/spec/multi_edge_spec.rb +32 -0
  56. data/vendor/git/graphy/spec/neighborhood_spec.rb +38 -0
  57. data/vendor/git/graphy/spec/properties_spec.rb +146 -0
  58. data/vendor/git/graphy/spec/search_spec.rb +227 -0
  59. data/vendor/git/graphy/spec/spec.opts +4 -0
  60. data/vendor/git/graphy/spec/spec_helper.rb +56 -0
  61. data/vendor/git/graphy/spec/strong_components_spec.rb +61 -0
  62. data/vendor/git/graphy/spec/triangulated_spec.rb +125 -0
  63. data/vendor/git/graphy/spec/undirected_graph_spec.rb +220 -0
  64. data/vendor/git/graphy/vendor/priority-queue/CHANGELOG +33 -0
  65. data/vendor/git/graphy/vendor/priority-queue/Makefile +140 -0
  66. data/vendor/git/graphy/vendor/priority-queue/README +133 -0
  67. data/vendor/git/graphy/vendor/priority-queue/benchmark/dijkstra.rb +171 -0
  68. data/vendor/git/graphy/vendor/priority-queue/compare_comments.rb +49 -0
  69. data/vendor/git/graphy/vendor/priority-queue/doc/c-vs-rb.png +0 -0
  70. data/vendor/git/graphy/vendor/priority-queue/doc/compare_big.gp +14 -0
  71. data/vendor/git/graphy/vendor/priority-queue/doc/compare_big.png +0 -0
  72. data/vendor/git/graphy/vendor/priority-queue/doc/compare_small.gp +15 -0
  73. data/vendor/git/graphy/vendor/priority-queue/doc/compare_small.png +0 -0
  74. data/vendor/git/graphy/vendor/priority-queue/doc/results.csv +37 -0
  75. data/vendor/git/graphy/vendor/priority-queue/ext/priority_queue/CPriorityQueue/extconf.rb +2 -0
  76. data/vendor/git/graphy/vendor/priority-queue/ext/priority_queue/CPriorityQueue/priority_queue.c +947 -0
  77. data/vendor/git/graphy/vendor/priority-queue/lib/priority_queue.rb +14 -0
  78. data/vendor/git/graphy/vendor/priority-queue/lib/priority_queue/c_priority_queue.rb +1 -0
  79. data/vendor/git/graphy/vendor/priority-queue/lib/priority_queue/poor_priority_queue.rb +46 -0
  80. data/vendor/git/graphy/vendor/priority-queue/lib/priority_queue/ruby_priority_queue.rb +526 -0
  81. data/vendor/git/graphy/vendor/priority-queue/priority_queue.so +0 -0
  82. data/vendor/git/graphy/vendor/priority-queue/setup.rb +1551 -0
  83. data/vendor/git/graphy/vendor/priority-queue/test/priority_queue_test.rb +371 -0
  84. data/vendor/git/graphy/vendor/rdot.rb +360 -0
  85. metadata +83 -1
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+ gem 'graphy', :path => 'vendor/git/graphy'
data/lib/jumoku.rb CHANGED
@@ -1,5 +1,7 @@
1
- $:.unshift File.dirname(__FILE__) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
1
+ libpath = File.expand_path(File.dirname(__FILE__))
2
+ $:.unshift File.dirname(__FILE__) unless $:.include?(File.dirname(__FILE__)) || $:.include?(libpath)
3
+ $: << libpath + '/../vendor/git/graphy/lib'
4
+ puts $:.inspect
3
5
 
4
6
  require 'pathname'
5
7
  require 'pp'
@@ -1,6 +1,6 @@
1
1
  module Jumoku
2
2
  MAJOR = 0
3
3
  MINOR = 1
4
- PATCH = 1
4
+ PATCH = 2
5
5
  VERSION = [MAJOR, MINOR, PATCH].join('.')
6
6
  end
@@ -0,0 +1,353 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ # The RawTree builder implements TreeAPI and ensures the tree
4
+ # is a valid tree as far as Graph Theory is concerned:
5
+ # a tree is an undirected, connected, acyclic graph.
6
+ #
7
+ # Note: these tests may make use of the "root"/"children" terminology.
8
+ # Be aware this has got *no* structural meaning as a tree is, by
9
+ # definition, undirected. Those terms are used only to simplify
10
+ # nodes creation within the tests, so I recall who branched who.
11
+ # For tests about rooted tree, see arborescence_spec.rb
12
+ describe "RawTreeBuilder" do
13
+ before :each do
14
+ #class MyTree
15
+ #include RawTreeBuilder
16
+ #end
17
+
18
+ @tree = RawTree.new
19
+ end
20
+
21
+ describe "#new" do
22
+ it "should create a valid tree graph" do
23
+ @tree.should_not be_directed
24
+ @tree.should be_acyclic
25
+ @tree.should be_connected
26
+ # aka @tree.should be_valid, 'll use that from now own
27
+
28
+ @tree.nodes.should be_empty
29
+ end
30
+ end
31
+
32
+ # Testing TreeAPI implementation.
33
+
34
+ describe "#add_node!" do
35
+ describe "an empty tree" do
36
+ it "should grow up as a valid tree when adding its first node" do
37
+ @tree.nodes.size.should == 0
38
+
39
+ @tree.add_node! "root"
40
+ @tree.nodes.size.should == 1
41
+ @tree.nodes.should == ["root"]
42
+ end
43
+ end
44
+
45
+ describe "a tree with only one node" do
46
+ before :each do
47
+ @tree.add_node! "root" # remember, this has no meaning
48
+ end
49
+
50
+ it "should raise an error when trying to add a new (disconnected) node" do
51
+ lambda { @tree.add_node! "child1" }.should raise_error
52
+ end
53
+
54
+ it "should grow up as a valid tree when adding new (connected) nodes" do
55
+ lambda { @tree.add_node! "child1", "root" }.should_not raise_error
56
+
57
+ @tree.add_node! "child2", "root"
58
+ @tree.add_node! "grand-child1", "child2"
59
+ @tree.add_node! Jumoku::Branch.new("grand-child2", "child2")
60
+
61
+ @tree.nodes.size.should == 5
62
+
63
+ the_nodes = ["root", "child1", "child2", "grand-child1", "grand-child2"]
64
+ @tree.nodes.should == the_nodes
65
+ @tree.topsort.should_not == the_nodes
66
+
67
+ @tree.add_node! "grand-grand-child1", "grand-child1"
68
+ @tree.add_node! "child3", "root"
69
+ @tree.add_node! "grand-child3", "child3"
70
+ @tree.add_node! "grand-grand-grand-child", "grand-grand-child1"
71
+ @tree.should_not be_directed
72
+ @tree.should be_acyclic
73
+ @tree.should be_connected
74
+ end
75
+
76
+ it "should raise an error when trying to form a cycle" do
77
+ @tree.add_node! "child1", "root"
78
+ @tree.add_node! "child2", "root"
79
+ @tree.add_node! "grand-child", "child1"
80
+
81
+ lambda { @tree.add_node! "grand-child", "child2" }.should raise_error RawTreeError
82
+
83
+ @tree.add_node! "grand-grand-child", "grand-child"
84
+ lambda { @tree.add_node! "grand-grand-child", "child1" }.should raise_error RawTreeError
85
+ lambda { @tree.add_node! "grand-grand-child", "child2" }.should raise_error RawTreeError
86
+ end
87
+ end
88
+ end
89
+
90
+ describe "#add_branch!" do
91
+ describe "an empty tree" do
92
+ it "should allow for the creation of its first two nodes as a branch" do
93
+ lambda { @tree.add_branch! :first, :branch }.should_not raise_error
94
+ @tree.nodes.should == [:first, :branch]
95
+ @tree.should be_valid
96
+ end
97
+ end
98
+
99
+ describe "a tree that's not empty" do
100
+ before :each do
101
+ @tree.add_node! 1
102
+ end
103
+
104
+ it "should not allow for disconnected branch creation" do
105
+ lambda { @tree.add_branch! 10, 11 }.should raise_error RawTreeError
106
+ end
107
+
108
+ it "should grow up as a valid tree when populated with (connected) branches" do
109
+ @tree.nodes.size.should == 1
110
+
111
+ @tree.add_branch! 1, 2
112
+ @tree.nodes.should_not be_empty
113
+ @tree.nodes.size.should == 2
114
+ @tree.nodes.should == [1, 2]
115
+
116
+ @tree.add_branch! 2, 3
117
+ @tree.nodes.size.should == 3
118
+ @tree.nodes.should == [1, 2, 3]
119
+
120
+ @tree.add_branch! 3, 4
121
+ @tree.add_branch! 2, 5
122
+ lambda { @tree.add_branch! 5, 5 }.should raise_error RawTreeError # cycle (loop)
123
+ @tree.add_branch! 4, 3
124
+ @tree.add_branch! 5, 6
125
+ @tree.nodes.size.should == 6
126
+ @tree.nodes.should == [1, 2, 3, 4, 5, 6]
127
+ @tree.should be_valid
128
+ end
129
+ end
130
+ end
131
+
132
+ describe "#remove_node!" do
133
+ describe "an empty tree" do
134
+ it "should not allow to remove a node since there's none" do
135
+ lambda { @tree.remove_node! "vapornode" }.should raise_error RawTreeError
136
+ end
137
+ end
138
+
139
+ describe "a tree that's a single node" do
140
+ before :each do
141
+ @tree.add_node! :last
142
+ end
143
+
144
+ it "should allow for last node deletion" do
145
+ lambda { @tree.remove_node! :last }.should_not raise_error
146
+ @tree.nodes.should be_empty
147
+ @tree.should be_valid
148
+ end
149
+ end
150
+
151
+ describe "a tree that is one sole branch (two nodes)" do
152
+ before :each do
153
+ @tree1 = RawTree.new
154
+ @tree1.add_node! 1
155
+ @tree1.add_node! 2, 1
156
+ @tree2 = RawTree.new
157
+ @tree2.add_node! 1
158
+ @tree2.add_node! 2, 1
159
+ end
160
+
161
+ it "should allow to remove both nodes in any order" do
162
+ @tree1.remove_node! 1
163
+ @tree1.should be_valid
164
+ @tree1.nodes.should == [2]
165
+ @tree1.should be_valid
166
+
167
+ @tree2.remove_node! 2
168
+ @tree2.should be_valid
169
+ @tree2.nodes.should == [1]
170
+ @tree2.should be_valid
171
+ end
172
+ end
173
+
174
+ describe "a tree with more than two nodes" do
175
+ before :each do
176
+ # TODO: DRY this snippet
177
+ # i stands for internal, t for terminal
178
+ @tree.add_branch! :i1, :i2
179
+ @tree.add_branch! :i2, :i3
180
+ @tree.add_branch! :i3, :i4
181
+ @tree.add_branch! :i3, :i5
182
+ @tree.add_branch! :i4, :t6
183
+ @tree.add_branch! :i5, :t7
184
+ @tree.add_branch! :i1, :t8
185
+ end
186
+
187
+ it "should allow deletion of its terminal nodes but not of its internal nodes" do
188
+ @tree.nodes.size.should == 8
189
+ lambda { @tree.remove_node! :t8 }.should_not raise_error
190
+ @tree.nodes.size.should == 7
191
+ @tree.nodes.should_not include :t8
192
+ lambda { @tree.remove_node! :i3 }.should raise_error RawTreeError
193
+ @tree.should be_valid
194
+ end
195
+
196
+ it "should remain a valid tree after any terminal node was removed" do
197
+ @tree.remove_node! :t6
198
+ @tree.has_branch?(:i4, :t6).should_not be_true
199
+ @tree.should be_valid
200
+ end
201
+ end
202
+ end
203
+
204
+ describe "#remove_branch!" do
205
+ describe "an empty tree" do
206
+ it "should not allow for branch deletion" do
207
+ lambda { @tree.remove_branch! :null, :none }.should raise_error RawTreeError
208
+ end
209
+ end
210
+
211
+ describe "an tree that is only one node" do
212
+ before :each do
213
+ @tree.add_node! 1
214
+ end
215
+
216
+ it "should not allow for branch deletion" do
217
+ lambda { @tree.remove_branch! 1, :none }.should raise_error RawTreeError
218
+ end
219
+ end
220
+
221
+ describe "a tree with more than two nodes" do
222
+ before :each do
223
+ # TODO: DRY this snippet
224
+ # i stands for internal, t for terminal
225
+ @tree.add_branch! :i1, :i2
226
+ @tree.add_branch! :i2, :i3
227
+ @tree.add_branch! :i3, :i4
228
+ @tree.add_branch! :i3, :i5
229
+ @tree.add_branch! :i4, :t6
230
+ @tree.add_branch! :i5, :t7
231
+ @tree.add_branch! :i1, :t8
232
+ end
233
+
234
+ it "should allow for terminal branch deletion (triggers terminal node deletion)" do
235
+ @tree.nodes.size.should == 8
236
+ lambda { @tree.remove_branch! :i1, :i2 }.should raise_error RawTreeError
237
+ @tree.nodes.size.should == 8
238
+ lambda { @tree.remove_branch! :i1, :t8 }.should_not raise_error RawTreeError
239
+ @tree.nodes.should_not include :t8
240
+ @tree.has_branch?(:i1, :t8).should be_false
241
+ @tree.should be_valid
242
+
243
+ @tree.remove_branch! Branch.new(:i5, :t7)
244
+ @tree.has_branch?(:i5, :t7).should be_false
245
+ @tree.should be_valid
246
+ end
247
+ end
248
+ end
249
+
250
+ describe "#nodes" do
251
+ describe "an empty tree" do
252
+ it "should not have any node" do
253
+ @tree.nodes.should be_empty
254
+ end
255
+ end
256
+
257
+ describe "a tree with some node" do
258
+ it "should be aware of its node(s)" do
259
+ @tree.add_node! :solo
260
+ @tree.nodes.should == [:solo]
261
+
262
+ @tree.add_branch! 2, :solo
263
+ @tree.add_branch! 2, 3
264
+ @tree.nodes.should == [:solo, 2, 3]
265
+ @tree.should be_valid
266
+ end
267
+ end
268
+ end
269
+
270
+ describe "#terminal_nodes" do
271
+ describe "an empty tree" do
272
+ it "should have no terminal nodes" do
273
+ @tree.terminal_nodes.should be_empty
274
+ end
275
+ end
276
+
277
+ describe "a tree that's a single node" do
278
+ it "should have one terminal node" do
279
+ @tree.add_node! 1
280
+ @tree.terminal_nodes.should == [1]
281
+ end
282
+ end
283
+
284
+ describe "a populated tree" do
285
+ before :each do
286
+ @tree.add_node! 1
287
+ @tree.add_node! 2, 1
288
+ @tree.add_node! 3, 2
289
+ end
290
+
291
+ it "should have a least two terminal nodes" do
292
+ @tree.terminal_nodes.size.should >= 2
293
+
294
+ @tree.add_node! 4, 3
295
+ @tree.add_node! 5, 3
296
+ @tree.terminal_nodes.should == [1, 4, 5]
297
+ end
298
+ end
299
+ end
300
+
301
+ describe "#branches" do
302
+ describe "an empty tree" do
303
+ it "should not have any branch" do
304
+ @tree.branches.should be_empty
305
+ end
306
+ end
307
+
308
+ describe "a tree that's one node" do
309
+ it "should not have any branch" do
310
+ @tree.add_node! :solo
311
+ @tree.branches.should be_empty
312
+ end
313
+ end
314
+
315
+ describe "a tree that's one branch (two nodes)" do
316
+ it "should have one branch only (undirected)" do
317
+ @tree.add_node! :one
318
+ @tree.add_node! :two, :one
319
+ @tree.branches.size.should == 1
320
+ @tree.branches.first.class.should == Graphy::Edge # the Jumoku::Branch class is just
321
+ # a lazy wrapper of it
322
+ @tree.should be_valid
323
+ end
324
+ end
325
+
326
+ describe "a tree with n nodes" do
327
+ before :each do
328
+ # TODO: DRY this as random_tree(n = 10)
329
+ @n = rand(50) # number of nodes
330
+ @tree.add_node! @n
331
+ @old_node = @n
332
+
333
+ (@n - 1).times do
334
+ begin
335
+ @new_node = rand(100)
336
+ @tree.add_node!(@new_node, @old_node)
337
+ rescue RawTreeError
338
+ retry # cycle detected!
339
+ end
340
+ @old_node = @new_node
341
+ end
342
+ end
343
+
344
+ it "should have n - 1 branches" do
345
+ @tree.nodes.size.should == @n
346
+ @tree.branches.size.should == @n - 1
347
+ @tree.should be_valid
348
+ end
349
+ end
350
+ end
351
+
352
+ # TODO: add a final test which sums it up
353
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,4 @@
1
+ --color
2
+ --format progress
3
+ --loadby mtime
4
+ --reverse
@@ -0,0 +1,14 @@
1
+ require File.expand_path("../../lib/jumoku.rb", __FILE__)
2
+
3
+ require 'jumoku'
4
+ include Jumoku
5
+
6
+ RSpec.configure do |config|
7
+ # Remove this line if you don't want RSpec's should and should_not
8
+ # methods or matchers
9
+ require 'rspec/expectations'
10
+ config.include RSpec::Matchers
11
+
12
+ # == Mock Framework
13
+ config.mock_with :rspec
14
+ end
data/spec/tree_spec.rb ADDED
@@ -0,0 +1,553 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ # The Tree builder extends the core functionalities provided
4
+ # by RawTreeBuilder.
5
+ #
6
+ # Note: these tests may make use of the "root"/"children" terminology.
7
+ # Be aware this has got *no* structural meaning as a tree is, by
8
+ # definition, undirected. Those terms are used only to simplify
9
+ # nodes creation within the tests, so I recall who branched who.
10
+ # For tests about rooted tree, see arborescence_spec.rb
11
+ describe "TreeBuilder" do
12
+ before :each do
13
+ class MyTree
14
+ include TreeBuilder
15
+ end
16
+
17
+ @tree = MyTree.new
18
+ end
19
+
20
+ describe "#new" do
21
+ it "should create a valid tree graph" do
22
+ @tree.should be_valid
23
+ @tree.nodes.should be_empty
24
+ end
25
+ end
26
+
27
+ ## Core API is tested in raw_tree_spec.rb.
28
+ ## The following tests focus on TreeBuilder additional methods.
29
+
30
+ describe "#add_node" do
31
+ describe "an empty tree" do
32
+ it "should create a new, valid tree with a single node when its first node is added" do
33
+ @tree.add_node 1
34
+ @tree.should be_empty
35
+
36
+ new_tree = @tree.add_node 1
37
+ new_tree.nodes.should == [1]
38
+ new_tree.should be_valid
39
+ end
40
+ end
41
+
42
+ describe "a populated tree" do
43
+ before :each do
44
+ @tree.add_branch! 1, 2
45
+ @tree.add_branch! 2, 3
46
+ @tree.add_branch! 3, 4
47
+ end
48
+
49
+ it "should create a new, extended, valid tree when an additionnal node is added" do
50
+ @tree.add_node 5, 4
51
+ @tree.add_node 3, 6
52
+ @tree.nodes.size.should == 4
53
+
54
+ new_tree = @tree.add_node 5, 4
55
+ new_tree.nodes.size.should == @tree.nodes.size + 1
56
+ new_tree.nodes.should == [1, 2, 3, 4, 5]
57
+ new_tree.should be_valid
58
+ end
59
+ end
60
+ end
61
+
62
+ describe "#add_branch" do
63
+ describe "an empty tree" do
64
+ it "should create a new, valid tree with only two nodes when a branch is added" do
65
+ new_tree = @tree.add_branch :one, :two
66
+ @tree.should be_empty
67
+ @tree.should be_valid
68
+ new_tree.nodes.should == [:one, :two]
69
+ new_tree.should be_valid
70
+ end
71
+ end
72
+
73
+ describe "a populate" do
74
+ before :each do
75
+ @tree.add_branch! 1, 2
76
+ @tree.add_branch! 2, 3
77
+ @tree.add_branch! 3, 4
78
+ end
79
+
80
+ it "should create a new, extended, valid tree when a branch is added" do
81
+ @tree.add_branch 5, 4
82
+ @tree.add_branch 3, 6
83
+ @tree.nodes.size.should == 4
84
+
85
+ new_tree = @tree.add_branch 5, 4
86
+ new_tree.nodes.size.should == @tree.nodes.size + 1
87
+ new_tree.nodes.should == [1, 2, 3, 4, 5]
88
+ new_tree.should be_valid
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "#remove_node" do
94
+ describe "an empty tree" do
95
+ it "should raise an error when trying to remove a node" do
96
+ lambda { @tree.remove_node :null }.should raise_error, RawTreeError
97
+ end
98
+ end
99
+
100
+ describe "a tree that's one node only" do
101
+ before :each do
102
+ @tree.add_node! 1
103
+ end
104
+
105
+ it "should create a new, empty, valid tree" do
106
+ new_tree = @tree.remove_node 1
107
+ @tree.nodes.should == [1]
108
+ @tree.should be_valid
109
+ new_tree.should be_empty
110
+ new_tree.should be_valid
111
+ end
112
+ end
113
+ end
114
+
115
+ describe "#remove_branch" do
116
+ describe "an empty tree" do
117
+ it "should not allow for removing a branch (even if forced to)" do
118
+ lambda { @tree.remove_branch 1, 2 }.should raise_error, RawTreeError
119
+ lambda { @tree.remove_branch 1, 2, :force => true }.should raise_error, RawTreeError
120
+ end
121
+ end
122
+
123
+ describe "a tree that's one node" do
124
+ before :each do
125
+ @tree.add_node! 1
126
+ end
127
+
128
+ it "should not allow for removing a branch (even if forced to)" do
129
+ lambda { @tree.remove_branch 1, 2 }.should raise_error, RawTreeError
130
+ lambda { @tree.remove_branch 1, 2, :force => true }.should raise_error, RawTreeError
131
+ end
132
+ end
133
+
134
+ describe "a tree with at least two nodes" do
135
+ before :each do
136
+ @tree.add_branch! 1, 2
137
+ @tree.add_branch! 2, 3
138
+ end
139
+
140
+ it "should allow for removing a branch, creating a new, valid tree" do
141
+ lambda { @tree.remove_branch 1, 2, :force => true }.should_not raise_error
142
+ new_tree = @tree.remove_branch 1, 2, :force => true
143
+ @tree.nodes.should == [1, 2, 3]
144
+ new_tree.nodes.should == [2, 3]
145
+ new_tree.should be_valid
146
+ end
147
+ end
148
+ end
149
+
150
+ describe "#add_nodes!" do
151
+ describe "an empty tree" do
152
+ it "should allow for adding its first nodes, by pairs and branches" do
153
+ @tree.add_nodes! 1,2, 2,3, 3,4
154
+ @tree.nodes.should == [1, 2, 3, 4]
155
+ @tree.should be_valid
156
+
157
+ @tree.add_nodes! Branch.new(5, 2)
158
+ @tree.nodes.should == [1, 2, 3, 4, 5]
159
+ @tree.should be_valid
160
+
161
+ @tree.add_nodes! 3,4, 1,10, Branch.new(10, 11), -1,1
162
+ @tree.nodes.size.should == 8
163
+ @tree.should be_valid
164
+
165
+ lambda { @tree.add_nodes! 10, 11 }.should_not raise_error
166
+ lambda { @tree.add_nodes! 1, 11 }.should raise_error, RawTreeError # cycle
167
+
168
+ @tree = Tree.new
169
+ lambda { @tree.add_nodes! 1,2, 3,4 }.should raise_error, RawTreeError # not connected
170
+ lambda { @tree.add_nodes! 1,2, 2,3, 3,1 }.should raise_error, RawTreeError # cycle
171
+ lambda { @tree.add_nodes! 1, 2, 3 }.should raise_error, RawTreeError # even number of nodes
172
+ end
173
+ end
174
+ end
175
+
176
+ describe "#add_nodes" do
177
+ describe "an empty tree" do
178
+ it "should allow for adding its first nodes, by pairs and branches, creating a new, valid tree" do
179
+ new_tree = @tree.add_nodes 1,2, 2,3, 3,4
180
+ @tree.should be_empty
181
+ new_tree.nodes.should == [1, 2, 3, 4]
182
+ new_tree.should be_valid
183
+
184
+ new_tree = @tree.add_nodes Branch.new(4, 5)
185
+ @tree.should be_empty
186
+ new_tree.nodes.should == [4, 5]
187
+ new_tree.should be_valid
188
+
189
+ new_tree = @tree.add_nodes 3,4, 4,10, Branch.new(10, 11), -1,3
190
+ @tree.should be_empty
191
+ new_tree.nodes.size.should == 5
192
+ new_tree.should be_valid
193
+
194
+ lambda { @tree.add_nodes 10, 11 }.should_not raise_error
195
+
196
+ @tree = Tree.new
197
+ lambda { @tree.add_nodes 1,2, 3,4 }.should raise_error, RawTreeError # not connected
198
+ lambda { @tree.add_nodes 1,2, 2,3, 3,1 }.should raise_error, RawTreeError # cycle
199
+ lambda { @tree.add_nodes 1, 2, 3 }.should raise_error, RawTreeError # even number of nodes
200
+ end
201
+ end
202
+ end
203
+
204
+ describe "#add_branches!" do
205
+ describe "an empty tree" do
206
+ it "should allow for adding its first branches" do
207
+ @tree.add_branches! Branch.new(1, 2), 1,3, 3,4
208
+ @tree.nodes.should == [1, 2, 3, 4]
209
+ @tree.should be_valid
210
+
211
+ branch = Branch.new(1, 4)
212
+ lambda { @tree.add_branches! branch }.should raise_error, RawTreeError
213
+ end
214
+ end
215
+
216
+ describe "a populated tree" do
217
+ before :each do
218
+ @tree.add_nodes! 1, 2
219
+ end
220
+
221
+ it "should allow for adding new branches" do
222
+ @tree.add_branches! 2, 3
223
+ @tree.nodes.should == [1, 2, 3]
224
+ @tree.should be_valid
225
+
226
+ @tree.add_branches! Branch.new(0,1), 3,4, Branch.new(4,5)
227
+ [0..5].all? { |n| @tree.nodes.include? n } and @tree.nodes.size.should == 5
228
+ @tree.should be_valid
229
+
230
+ lambda { @tree.add_branches! Branch.new(2, 5) }.should raise_error, RawTreeError
231
+ end
232
+ end
233
+ end
234
+
235
+ describe "add_branches" do
236
+ describe "an empty tree" do
237
+ it "should create a new, valid tree populated with its first branches" do
238
+ b1, b2, b3 = Branch.new(1, 2), Branch.new(2, 3), Branch.new(3, 4)
239
+ new_tree = @tree.add_branches b1, b2, b3
240
+ @tree.should be_empty
241
+ new_tree.nodes.should == [1, 2, 3, 4]
242
+ new_tree.should be_valid
243
+
244
+ lambda { @tree.add_branches 1,2, 2,3, 3,1 }.should raise_error, RawTreeError
245
+ end
246
+ end
247
+
248
+ describe "a populated tree" do
249
+ before :each do
250
+ @tree.add_nodes! 1,2, 2,3, 3,4
251
+ end
252
+
253
+ it "should create a new, valid tree extended with its new branches" do
254
+ new_tree = @tree.add_branches 4, :five, Branch.new(:five, "six")
255
+ @tree.nodes.should == (1..4).to_a
256
+ new_tree.nodes.should == [1, 2, 3, 4, :five, "six"]
257
+ new_tree.should be_valid
258
+
259
+ lambda { @tree.add_branches 10, 11 }.should raise_error, RawTreeError
260
+ lambda { @tree.add_branches Branch.new 1,4 }.should raise_error, RawTreeError
261
+ end
262
+ end
263
+ end
264
+
265
+ describe "#remove_nodes!" do
266
+ describe "an empty tree" do
267
+ it "should not allow for removing nodes" do
268
+ lambda { @tree.remove_nodes! :foo, :bar }.should raise_error, RawTreeError
269
+ end
270
+ end
271
+
272
+ describe "a tree that's one node" do
273
+ before :each do
274
+ @tree.add_node! :one
275
+ end
276
+
277
+ it "should allow for removing its sole node only (bad semantic)" do
278
+ @tree.remove_nodes! :one
279
+ @tree.nodes.should be_empty
280
+ @tree.should be_valid
281
+
282
+ lambda { @tree.remove_nodes! :foo, :bar }.should raise_error, RawTreeError
283
+ end
284
+ end
285
+
286
+ describe "a populated tree" do
287
+ before :each do
288
+ @tree.add_nodes! 1,2, 2,3, 3,4
289
+ end
290
+
291
+ it "should allow for removing its nodes until it's empty" do
292
+ @tree.remove_nodes! (1..4).to_a
293
+ @tree.should be_empty
294
+ @tree.should be_valid
295
+
296
+ lambda { @tree.remove_nodes! :null }.should raise_error, RawTreeError
297
+ end
298
+ end
299
+ end
300
+
301
+ describe "#remove_nodes" do
302
+ describe "an empty tree" do
303
+ it "should not allow for removing nodes" do
304
+ lambda { @tree.remove_nodes :foo, :bar }.should raise_error, RawTreeError
305
+ end
306
+ end
307
+
308
+ describe "a populated tree" do
309
+ before :each do
310
+ @tree.add_nodes! 1,2, 2,3, 3,4
311
+ end
312
+
313
+ it "should allow for removing nodes, creating a new, valid tree" do
314
+ new_tree = @tree.remove_nodes 1, 2, 3, 4
315
+ @tree.nodes.should == [1, 2, 3, 4]
316
+ new_tree.should be_empty
317
+ new_tree.should be_valid
318
+
319
+ lambda { @tree.remove_nodes! :null }.should raise_error, RawTreeError
320
+ end
321
+ end
322
+ end
323
+
324
+ describe "#remove_branches!" do
325
+ describe "an empty tree" do
326
+ it "should not allow for removing branches" do
327
+ lambda { @tree.remove_branches Branch.new(:foo, :bar), 1,2 }.should raise_error, RawTreeError
328
+ end
329
+ end
330
+
331
+ describe "a tree that's only one node" do
332
+ before :each do
333
+ @tree.add_node! :solo
334
+ end
335
+
336
+ it "should not allow for removing branches" do
337
+ lambda { @tree.remove_branches! :solo, :null }.should raise_error, RawTreeError
338
+ end
339
+ end
340
+
341
+ describe "a populated tree" do
342
+ before :each do
343
+ @tree.add_nodes! 1,2, 2,3, 3,4
344
+ end
345
+
346
+ it "should allow for removing branches until it has no more branches or a sole node" do
347
+ @tree.remove_branches! 1,2, Branch.new(2,3), 3,4
348
+ @tree.should be_empty
349
+ @tree.should be_valid
350
+
351
+ lambda { @tree.remove_branches! Branch.new(:foo, :bar), Branch.new(1, 2) }.should raise_error, RawTreeError
352
+ end
353
+ end
354
+ end
355
+
356
+ describe "#remove_branches" do
357
+ describe "an empty tree" do
358
+ it "should not allow for removing branches" do
359
+ lambda { @tree.remove_branches :foo, :bar, Branch.new(1, 2) }.should raise_error, RawTreeError
360
+ end
361
+ end
362
+
363
+ describe "a tree that's one node" do
364
+ before :each do
365
+ @tree.add_node! :solo
366
+ end
367
+
368
+ it "should not allow for removing branches" do
369
+ lambda { @tree.remove_branches :solo, :null }.should raise_error, RawTreeError
370
+ end
371
+ end
372
+
373
+ describe "a populated tree" do
374
+ before :each do
375
+ @tree.add_nodes! 1,2, 2,3, 3,4
376
+ end
377
+
378
+ it "should allow for removing branches until it has no more branches or a sole node, creating a new, valid tree" do
379
+ new_tree = @tree.remove_branches 1,2, Branch.new(2,3), 3,4
380
+ @tree.nodes.should == [1, 2, 3, 4]
381
+ new_tree.should be_empty
382
+ new_tree.should be_valid
383
+
384
+ lambda { @tree.remove_branches Branch.new(:foo, :bar), Branch.new(1, 2) }.should raise_error, RawTreeError
385
+ end
386
+ end
387
+ end
388
+
389
+ describe "#node?" do
390
+ describe "an empty tree" do
391
+ it "should not report having any node" do
392
+ @tree.node?(:null).should be_false
393
+ end
394
+ end
395
+
396
+ describe "a populated tree" do
397
+ before :each do
398
+ @tree.add_nodes! 1,2, 2,3, 3,4
399
+ end
400
+
401
+ it "should be aware of which nodes belong to itself" do
402
+ @tree.node?(1).should be_true
403
+ @tree.has_node?(:null).should be_false
404
+ end
405
+ end
406
+ end
407
+
408
+ describe "#nodes?" do
409
+ describe "an empty tree" do
410
+ it "should not report having any node" do
411
+ @tree.nodes?(:null, :foo, 0).should be_false
412
+ end
413
+ end
414
+
415
+ describe "a populated tree" do
416
+ before :each do
417
+ @tree.add_nodes! 1,2, 2,3, 3,4
418
+ end
419
+
420
+ it "should be aware of which nodes belong to itself" do
421
+ @tree.nodes?(1, 4).should be_true
422
+ @tree.has_nodes?(:null, 1, 2).should be_false
423
+ end
424
+ end
425
+ end
426
+
427
+ describe "#nodes_among?" do
428
+ describe "an empty tree" do
429
+ it "should not report having any node" do
430
+ @tree.nodes_among?(:null, :foo, 0).should be_false
431
+ end
432
+ end
433
+
434
+ describe "a populated tree" do
435
+ before :each do
436
+ @tree.add_nodes! 1,2, 2,3, 3,4
437
+ end
438
+
439
+ it "should be aware of which nodes belong to itself" do
440
+ @tree.nodes_among?(1, 4).should be_true
441
+ @tree.has_node_among?(:foo, 2, :bar).should be_true
442
+ @tree.has_nodes_among?(:foo, 2, :bar, 3, 4, Array.new).should be_true
443
+ @tree.has_nodes_among?(:null, :foo, :bar).should be_false
444
+ end
445
+ end
446
+ end
447
+
448
+ describe "#branch?" do
449
+ describe "an empty tree" do
450
+ it "should not have any branch" do
451
+ @tree.has_branch?(1,2).should be_false
452
+ end
453
+ end
454
+
455
+ describe "a tree that's one node" do
456
+ before :each do
457
+ @tree.add_node! :solo
458
+ end
459
+
460
+ it "should not have any branch" do
461
+ @tree.has_branch?(1,2).should be_false
462
+ end
463
+ end
464
+
465
+ describe "a populated tree" do
466
+ before :each do
467
+ @tree.add_nodes! 1,2, 2,3, 3,4
468
+ end
469
+
470
+ it "should be aware of which branches belong to itself" do
471
+ @tree.has_branch?(2,3).should be_true
472
+ @tree.has_branch?(1,3).should be_false
473
+ @tree.has_branch?(1,:null).should be_false
474
+ end
475
+ end
476
+ end
477
+
478
+ # TODO: tests for #branches? and #branches_among?
479
+ # (actually, done within the tests for #add_consecutive_nodes!)
480
+
481
+ describe "#num_nodes" do
482
+ describe "an empty tree" do
483
+ it "should report having no node" do
484
+ @tree.number_of_nodes.should == 0
485
+ end
486
+ end
487
+
488
+ describe "a populated tree" do
489
+ before :each do
490
+ @tree.add_nodes! 1,2, 2,3, 3,4
491
+ end
492
+
493
+ it "should report how many nodes belong to it" do
494
+ @tree.number_of_nodes.should == 4
495
+ end
496
+ end
497
+ end
498
+
499
+ describe "#num_branches" do
500
+ describe "an empty tree" do
501
+ it "should report having no branch" do
502
+ @tree.number_of_nodes.should == 0
503
+ end
504
+ end
505
+
506
+ describe "a tree that's one node" do
507
+ before :each do
508
+ @tree.add_node! :solo
509
+ end
510
+
511
+ it "should report having no branch" do
512
+ @tree.number_of_branches.should == 0
513
+ end
514
+ end
515
+
516
+ describe "a populated tree" do
517
+ before :each do
518
+ @tree.add_nodes! 1,2, 2,3, 3,4
519
+ end
520
+
521
+ it "should report how many branches belong to it" do
522
+ @tree.number_of_branches.should == @tree.number_of_nodes - 1
523
+ end
524
+ end
525
+ end
526
+
527
+ describe "#add_consecutive_nodes!" do
528
+ describe "a tree" do
529
+ it "should grow as a valid, populated tree if all specified nodes define a valid tree structure" do
530
+ @tree.add_consecutive_nodes!(1, 2, 3, :four, Branch.new(:foo, "bar"))
531
+ @tree.has_branches?(1,2, 2,3, Branch.new(3, :four), :four,:foo, :foo,"bar").should be_true # each specified branch exist
532
+ @tree.has_branches?(1,2, 2,3, Branch.new(3, :four), :four,:foo).should be_true # each specified branch exist
533
+ @tree.has_branches_among?(1,2, 2,3, Branch.new(3, :four), :four,:foo).should be_false # do not list every existing branch
534
+ @tree.has_branches_among?(1,2, 2,3, Branch.new(3, :four), :four,:foo, :foo,"bar").should be_true # list all existing branches
535
+ @tree.has_branches_among?(1,2, 2,3, Branch.new(3, :four), :four,:foo, :foo,"bar", Array.new, "NIL").should be_true # list all existing branches
536
+ @tree.should be_valid
537
+ end
538
+ end
539
+ end
540
+
541
+ describe "#add_consecutive_nodes" do
542
+ describe "a tree" do
543
+ it "should create a new, valid, populated tree if all specified nodes define a valid tree structure" do
544
+ new_tree = @tree.add_consecutive_nodes(1, 2, 3, :four, Branch.new(:foo, "bar"))
545
+ @tree.should be_empty
546
+ new_tree.has_branches?(1,2, 2,3, Branch.new(3, :four), :four,:foo, :foo,"bar").should be_true
547
+ new_tree.has_branches?(1,2, 2,3, Branch.new(3, :four), :four,:foo).should be_true
548
+ new_tree.should be_valid
549
+ end
550
+ end
551
+ end
552
+ end
553
+