compsci 0.3.0.1 → 0.3.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,5 @@
1
1
  require 'compsci/node'
2
+ require 'compsci/names'
2
3
  require 'minitest/autorun'
3
4
 
4
5
  include CompSci
@@ -10,14 +11,32 @@ describe Node do
10
11
  @emilio_estevez = Node.new 'emilio'
11
12
  end
12
13
 
14
+ it "must display_line" do
15
+ nodes = [@martin_sheen, @charlie_sheen, @emilio_estevez]
16
+ str = Node.display_line nodes: nodes, width: 80
17
+ # TODO: it was 78 once. Why < 80?
18
+ expect(str.size).must_be :>=, 78 # it might overflow
19
+
20
+ str = Node.display_line nodes: nodes, width: 200
21
+ expect(str.size).must_be :>=, 198 # it won't overflow
22
+ end
23
+
24
+
13
25
  it "must start with no children" do
14
26
  [@martin_sheen, @charlie_sheen, @emilio_estevez].each { |n|
15
- n.children.must_be_empty
27
+ expect(n.children.compact).must_be_empty
16
28
  }
17
29
  end
18
30
 
19
31
  it "must not respond to :parent" do
20
- @martin_sheen.respond_to?(:parent).must_equal false
32
+ expect(@martin_sheen.respond_to?(:parent)).must_equal false
33
+ end
34
+
35
+ it "must create a tree by adding children" do
36
+ @martin_sheen[0] = @charlie_sheen
37
+ @martin_sheen[1] = @emilio_estevez
38
+ expect(@martin_sheen.children).must_include @charlie_sheen
39
+ expect(@martin_sheen.children).must_include @emilio_estevez
21
40
  end
22
41
  end
23
42
 
@@ -30,42 +49,142 @@ describe KeyNode do
30
49
 
31
50
  it "must start with no children" do
32
51
  [@martin_sheen, @charlie_sheen, @emilio_estevez].each { |n|
33
- n.children.must_be_empty
52
+ expect(n.children.compact).must_be_empty
34
53
  }
35
54
  end
36
55
 
37
56
  it "must not respond to :parent" do
38
- @martin_sheen.respond_to?(:parent).must_equal false
57
+ expect(@martin_sheen.respond_to?(:parent)).must_equal false
39
58
  end
40
59
 
41
60
  it "must have a key" do
42
- @martin_sheen.key.must_equal 'marty'
43
- @charlie_sheen.key.must_equal 'charles'
44
- @emilio_estevez.key.must_equal 'emile'
45
- end
46
- end
47
-
48
- describe FlexNode do
49
- before do
50
- @martin_sheen = FlexNode.new 'martin'
51
- @charlie_sheen = FlexNode.new 'charlie'
52
- @emilio_estevez = FlexNode.new 'emilio'
53
- end
54
-
55
- it "must track children" do
56
- @charlie_sheen.add_parent(@martin_sheen)
57
- @martin_sheen.children.must_include @charlie_sheen
58
-
59
- @martin_sheen.children.wont_include @emilio_estevez
60
- @martin_sheen.add_child @emilio_estevez
61
- @martin_sheen.children.must_include @emilio_estevez
62
- end
63
-
64
- it "must create children from scalars" do
65
- @martin_sheen.new_child 'fake_emilio'
66
- @martin_sheen.children.size.must_equal 1
67
- @martin_sheen.children.first.value.must_equal 'fake_emilio'
68
- @martin_sheen.children.wont_include @emilio_estevez
61
+ expect(@martin_sheen.key).must_equal 'marty'
62
+ expect(@charlie_sheen.key).must_equal 'charles'
63
+ expect(@emilio_estevez.key).must_equal 'emile'
64
+ end
65
+
66
+ describe "KeyNode.key_cmp_idx" do
67
+ it "must handle 2 or 3 child_slots" do
68
+ c2 = {
69
+ [1,2] => 0,
70
+ [1,10] => 0,
71
+ [2,2] => :raise,
72
+ [3,2] => 1,
73
+ [10,2] => 1,
74
+ }
75
+ c3 = {
76
+ [1,2] => 0,
77
+ [1,10] => 0,
78
+ [2,2] => 1,
79
+ [3,2] => 2,
80
+ [10,2] => 2,
81
+ }
82
+
83
+ c2.each { |(new_key, key), expected|
84
+ if expected == :raise
85
+ expect(proc {
86
+ KeyNode.key_cmp_idx(new_key, key)
87
+ }).must_raise KeyNode::DuplicateKey
88
+ else
89
+ expect(KeyNode.key_cmp_idx(new_key, key)).must_equal expected
90
+ end
91
+ }
92
+
93
+ c3.each { |(new_key, key), expected|
94
+ expect(KeyNode.key_cmp_idx(new_key, key,
95
+ child_slots: 3)).must_equal expected
96
+ }
97
+ end
98
+ end
99
+
100
+ describe "Binary Search Tree" do
101
+ before do
102
+ @keys = Array.new(4) { |i| Names::WW2[i] }
103
+ @values = Array.new(4) { Names::SOLAR.sample }
104
+ @root = KeyNode.new(@values[0], key: @keys[0], children: 2)
105
+ 1.upto(@keys.size - 1) { |i| @root.insert(@keys[i], @values[i]) }
106
+
107
+ # tree looks like:
108
+ # A:val1
109
+ # B:val2
110
+ # C:val3
111
+ # D:val4
112
+ end
113
+
114
+ it "must link to inserted nodes" do
115
+ expect(@root.children).wont_be_empty
116
+ expect(@root.children[0]).must_be_nil
117
+ c1 = @root.children[1]
118
+ expect(c1).wont_be_nil
119
+ expect(c1.key).must_equal @keys[1]
120
+ expect(c1.children[0]).must_be_nil
121
+ cc1 = c1.children[1]
122
+ expect(cc1).wont_be_nil
123
+ expect(cc1.value).must_equal @values[2]
124
+ expect(cc1.children[0]).must_be_nil
125
+ ccc1 = cc1.children[1]
126
+ expect(ccc1).wont_be_nil
127
+ expect(ccc1.key).must_equal @keys[3]
128
+ expect(ccc1.value).must_equal @values[3]
129
+ end
130
+
131
+ it "must search nodes" do
132
+ node = nil
133
+ new_order = (0..9).to_a.shuffle
134
+ new_order.each { |i|
135
+ k, v = Names::NATO[i], Names::SOLAR.sample
136
+ if node.nil?
137
+ node = KeyNode.new(v, key: k, children: 2)
138
+ else
139
+ node.insert(k, v)
140
+ end
141
+ }
142
+
143
+ 3.times {
144
+ key = Names::NATO[new_order.sample]
145
+ found = node.search key
146
+ expect(found).wont_be_nil
147
+ expect(found.key).must_equal key
148
+ }
149
+
150
+ expect(node.search(Names::SOLAR.sample)).must_be_nil
151
+ end
152
+
153
+ it "must accept or reject duplicates" do
154
+ expect(proc {
155
+ @root.insert(@keys[0], @values.sample)
156
+ }).must_raise KeyNode::DuplicateKey
157
+
158
+ node = KeyNode.new(@values[0], key: @keys[0], duplicates: true)
159
+ child = node.insert(@keys[0], @values[0])
160
+ expect(child).must_be_kind_of KeyNode
161
+ expect(node.children[1]).must_equal child
162
+ expect(node.children[0]).must_be_nil
163
+ end
164
+ end
165
+
166
+ describe "Ternary Search Tree" do
167
+ before do
168
+ @keys = Array.new(4) { |i| Names::NATO[i] }
169
+ @values = Array.new(4) { Names::SOLAR.sample }
170
+ @root = KeyNode.new(@values[0], key: @keys[0], children: 3)
171
+ 1.upto(@keys.size - 1) { |i| @root.insert(@keys[i], @values[i]) }
172
+
173
+ # tree looks like:
174
+ # A:val1
175
+ # B:val2
176
+ # C:val3
177
+ # D:val4
178
+ end
179
+
180
+ it "must insert a duplicate as the middle child" do
181
+ node3 = KeyNode.new(@values[0], key: @keys[0], children: 3)
182
+ child = node3.insert(@keys[0], @values[0])
183
+ expect(child).must_be_kind_of KeyNode
184
+ expect(node3.children[1]).must_equal child
185
+ expect(node3.children[0]).must_be_nil
186
+ expect(node3.children[2]).must_be_nil
187
+ end
69
188
  end
70
189
  end
71
190
 
@@ -78,63 +197,36 @@ describe ChildNode do
78
197
 
79
198
  it "must start with neither parent nor children" do
80
199
  [@martin_sheen, @charlie_sheen, @emilio_estevez].each { |n|
81
- n.parent.nil?.must_equal true
82
- n.children.must_be_empty
200
+ expect(n.parent).must_be_nil
201
+ expect(n.children.compact).must_be_empty
83
202
  }
84
203
  end
85
204
 
86
205
  it "must track parent and children" do
87
- @charlie_sheen.set_parent(0, @martin_sheen)
88
- @charlie_sheen.parent.must_equal @martin_sheen
89
- @martin_sheen.children.must_include @charlie_sheen
90
-
91
- @martin_sheen.children.wont_include @emilio_estevez
92
- @martin_sheen.set_child(0, @emilio_estevez)
93
- @martin_sheen.children.must_include @emilio_estevez
94
- @emilio_estevez.parent.must_equal @martin_sheen
95
- end
96
- end
97
-
98
- describe ChildFlexNode do
99
- before do
100
- @martin_sheen = ChildFlexNode.new 'martin'
101
- @charlie_sheen = ChildFlexNode.new 'charlie'
102
- @emilio_estevez = ChildFlexNode.new 'emilio'
103
- end
104
-
105
- it "must track parent and children" do
106
- @charlie_sheen.add_parent(@martin_sheen)
107
- @charlie_sheen.parent.must_equal @martin_sheen
108
- @martin_sheen.children.must_include @charlie_sheen
109
-
110
- @martin_sheen.children.wont_include @emilio_estevez
111
- @martin_sheen.add_child @emilio_estevez
112
- @martin_sheen.children.must_include @emilio_estevez
113
- @emilio_estevez.parent.must_equal @martin_sheen
114
- end
115
-
116
- it "must determine a node's generation" do
117
- @emilio_estevez.gen.must_equal 0
118
- @martin_sheen.add_child @emilio_estevez
119
- @emilio_estevez.gen.must_equal 1
120
- end
121
-
122
- it "must create children from scalars" do
123
- @martin_sheen.new_child 'fake_emilio'
124
- @martin_sheen.children.size.must_equal 1
125
- @martin_sheen.children.first.value.must_equal 'fake_emilio'
126
- @martin_sheen.children.wont_include @emilio_estevez
127
- end
128
-
129
- it "must recognize siblings" do
130
- @charlie_sheen.add_parent @martin_sheen
131
- @emilio_estevez.add_parent @martin_sheen
132
- @martin_sheen.new_child 'fake_emilio'
133
-
134
- @charlie_sheen.siblings.must_include @emilio_estevez
135
- @charlie_sheen.siblings.wont_include @martin_sheen
136
- @emilio_estevez.siblings.must_include @charlie_sheen
137
- @martin_sheen.siblings.must_be_empty
138
- @emilio_estevez.siblings.find { |n| n.value == 'fake_emilio' }.wont_be_nil
206
+ @martin_sheen[0] = @charlie_sheen
207
+ expect(@charlie_sheen.parent).must_equal @martin_sheen
208
+ expect(@martin_sheen.children).must_include @charlie_sheen
209
+
210
+ expect(@martin_sheen.children).wont_include @emilio_estevez
211
+ @martin_sheen[1] = @emilio_estevez
212
+ expect(@emilio_estevez.parent).must_equal @martin_sheen
213
+ expect(@martin_sheen.children).must_include @emilio_estevez
214
+ expect(@martin_sheen.children).must_include @charlie_sheen
215
+ end
216
+
217
+ it "must track siblings" do
218
+ @martin_sheen[0] = @charlie_sheen
219
+ @martin_sheen[1] = @emilio_estevez
220
+ expect(@charlie_sheen.siblings).must_include @emilio_estevez
221
+ # TODO: should siblings not include self?
222
+ # expect(@charlie_sheen.siblings).wont_include @charlie_sheen
223
+ expect(@charlie_sheen.siblings).must_include @charlie_sheen
224
+ end
225
+
226
+ it "must track generation" do
227
+ @martin_sheen[0] = @charlie_sheen
228
+ expect(@charlie_sheen.gen).must_equal 1
229
+ @charlie_sheen[0] = @emilio_estevez # kinky!
230
+ expect(@emilio_estevez.gen).must_equal 2
139
231
  end
140
232
  end
@@ -12,13 +12,13 @@ describe Simplex::Parse do
12
12
  "99x" => [99.0, :x],
13
13
  "z" => [ 1.0, :z],
14
14
  "-b" => [-1.0, :b] }.each { |valid, expected|
15
- P.term(valid).must_equal expected
15
+ expect(P.term(valid)).must_equal expected
16
16
  }
17
17
  end
18
18
 
19
19
  it "must reject invalid terms" do
20
20
  ["3xy", "24/7x", "x17", "2*x"].each { |invalid|
21
- proc { P.term(invalid) }.must_raise RuntimeError
21
+ expect(proc { P.term(invalid) }).must_raise RuntimeError
22
22
  }
23
23
  end
24
24
  end
@@ -32,7 +32,7 @@ describe Simplex::Parse do
32
32
  "a - -b" => { a: 1.0, b: 1.0 },
33
33
  "a A b" => { a: 1.0, :A => 1.0, b: 1.0 },
34
34
  }.each { |valid, expected|
35
- P.expression(valid).must_equal expected
35
+ expect(P.expression(valid)).must_equal expected
36
36
  }
37
37
  end
38
38
 
@@ -40,18 +40,18 @@ describe Simplex::Parse do
40
40
  ["a2 + b2 = c2",
41
41
  "x + xy",
42
42
  "x * 2"].each { |invalid|
43
- proc { P.expression(invalid) }.must_raise P::Error
43
+ expect(proc { P.expression(invalid) }).must_raise P::Error
44
44
  }
45
45
  end
46
46
  end
47
47
 
48
48
  describe "Parse.tokenize" do
49
49
  it "ignores leading or trailing whitespace" do
50
- P.tokenize(" 5x + 2.9y ").must_equal ["5x", "+", "2.9y"]
50
+ expect(P.tokenize(" 5x + 2.9y ")).must_equal ["5x", "+", "2.9y"]
51
51
  end
52
52
 
53
53
  it "ignores multiple spaces" do
54
- P.tokenize("5x + 2.9y").must_equal ["5x", "+", "2.9y"]
54
+ expect(P.tokenize("5x + 2.9y")).must_equal ["5x", "+", "2.9y"]
55
55
  end
56
56
  end
57
57
 
@@ -61,7 +61,7 @@ describe Simplex::Parse do
61
61
  "0.94a - 22.1b <= -14.67" => [{ a: 0.94, b: -22.1 }, -14.67],
62
62
  "x <= 0" => [{ x: 1.0 }, 0],
63
63
  }.each { |valid, expected|
64
- P.inequality(valid).must_equal expected
64
+ expect(P.inequality(valid)).must_equal expected
65
65
  }
66
66
  end
67
67
 
@@ -70,25 +70,33 @@ describe Simplex::Parse do
70
70
  "0.94a - 22.1b <= -14.67c",
71
71
  "x < 0",
72
72
  ].each { |invalid|
73
- proc { P.inequality(invalid) }.must_raise P::Error
73
+ expect(proc { P.inequality(invalid) }).must_raise P::Error
74
74
  }
75
75
  end
76
76
  end
77
77
  end
78
78
 
79
79
  describe "Simplex.maximize" do
80
- it "must problem stuff" do
80
+ it "must solve a problem" do
81
81
  prob = Simplex.problem(maximize: 'x + y',
82
82
  constraints: ['2x + y <= 4',
83
83
  'x + 2y <= 3'])
84
84
  sol = prob.solution
85
- sol.must_equal [Rational(5, 3), Rational(2, 3)]
85
+ expect(sol).must_equal [Rational(5, 3), Rational(2, 3)]
86
86
  end
87
87
 
88
- it "must maximize stuff" do
89
- Simplex.maximize('x + y',
90
- '2x + y <= 4',
91
- 'x + 2y <= 3').must_equal [Rational(5, 3),
92
- Rational(2, 3)]
88
+ it "must maximize" do
89
+ expect(Simplex.maximize('x + y',
90
+ '2x + y <= 4',
91
+ 'x + 2y <= 3')).must_equal [Rational(5, 3),
92
+ Rational(2, 3)]
93
+ end
94
+
95
+ it "must reject bad expressions" do
96
+ expect(proc { Simplex.maximize(5) }).must_raise ArgumentError
97
+ expect(proc {
98
+ Simplex.maximize('5')
99
+ }).must_raise Simplex::Parse::InvalidTerm
100
+ # proc { Simplex.maximize('5x') }.must_raise Simplex::Parse::InvalidTerm
93
101
  end
94
102
  end
@@ -7,8 +7,8 @@ describe Timer do
7
7
  describe "elapsed" do
8
8
  it "must return the block value and positive number" do
9
9
  answer, elapsed = Timer.elapsed { sleep 0.01; :foo }
10
- answer.must_equal :foo
11
- elapsed.must_be_close_to 0.015, 0.005
10
+ expect(answer).must_equal :foo
11
+ expect(elapsed).must_be_close_to 0.015, 0.01
12
12
  end
13
13
  end
14
14
 
@@ -16,7 +16,7 @@ describe Timer do
16
16
  it "must be positive" do
17
17
  start = Timer.now
18
18
  sleep 0.01
19
- Timer.since(start).must_be_close_to 0.015, 0.005
19
+ expect(Timer.since(start)).must_be_close_to 0.015, 0.01
20
20
  end
21
21
  end
22
22
 
@@ -27,9 +27,9 @@ describe Timer do
27
27
  sleep 0.01
28
28
  :foo
29
29
  }
30
- answer.must_equal :foo
31
- avg_et.must_be_close_to 0.01, 0.005
32
- Timer.since(start).must_be_close_to 0.15, 0.05
30
+ expect(answer).must_equal :foo
31
+ expect(avg_et).must_be_close_to 0.01, 0.005
32
+ expect(Timer.since(start)).must_be_close_to 0.15, 0.05
33
33
  end
34
34
 
35
35
  it "must repeat short loops and stop on time" do
@@ -42,8 +42,8 @@ describe Timer do
42
42
  _answer, avg_et = Timer.loop_avg(count: 5) {
43
43
  sleep 0.01
44
44
  }
45
- avg_et.must_be_close_to 0.015, 0.005
46
- Timer.since(start).must_be_close_to 0.1, 0.05
45
+ expect(avg_et).must_be_close_to 0.015, 0.005
46
+ expect(Timer.since(start)).must_be_close_to 0.1, 0.05
47
47
  end
48
48
 
49
49
  it "must not interrupt long loops" do
@@ -51,8 +51,8 @@ describe Timer do
51
51
  _answer, avg_et = Timer.loop_avg(seconds: 0.01) {
52
52
  sleep 0.1
53
53
  }
54
- Timer.since(start).must_be_close_to avg_et, 0.05
55
- avg_et.must_be_close_to 0.15, 0.05
54
+ expect(Timer.since(start)).must_be_close_to avg_et, 0.05
55
+ expect(avg_et).must_be_close_to 0.15, 0.05
56
56
  end
57
57
  end
58
58
  end