jumoku 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
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
+