compsci 0.3.0.1 → 0.3.1.1

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