bitstring 1.0.0
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.
- data/CONTRIBUTORS.txt +5 -0
- data/Changelog.txt +20 -0
- data/LICENCE.txt +202 -0
- data/NOTICE.txt +5 -0
- data/README.txt +63 -0
- data/doc/classes/BitString.html +2479 -0
- data/doc/classes/BitString.src/M000001.html +99 -0
- data/doc/classes/BitString.src/M000002.html +18 -0
- data/doc/classes/BitString.src/M000003.html +20 -0
- data/doc/classes/BitString.src/M000004.html +19 -0
- data/doc/classes/BitString.src/M000005.html +24 -0
- data/doc/classes/BitString.src/M000006.html +44 -0
- data/doc/classes/BitString.src/M000007.html +21 -0
- data/doc/classes/BitString.src/M000008.html +18 -0
- data/doc/classes/BitString.src/M000009.html +18 -0
- data/doc/classes/BitString.src/M000010.html +22 -0
- data/doc/classes/BitString.src/M000011.html +29 -0
- data/doc/classes/BitString.src/M000012.html +22 -0
- data/doc/classes/BitString.src/M000013.html +43 -0
- data/doc/classes/BitString.src/M000014.html +19 -0
- data/doc/classes/BitString.src/M000015.html +40 -0
- data/doc/classes/BitString.src/M000016.html +21 -0
- data/doc/classes/BitString.src/M000017.html +18 -0
- data/doc/classes/BitString.src/M000018.html +18 -0
- data/doc/classes/BitString.src/M000019.html +18 -0
- data/doc/classes/BitString.src/M000020.html +20 -0
- data/doc/classes/BitString.src/M000021.html +24 -0
- data/doc/classes/BitString.src/M000022.html +23 -0
- data/doc/classes/BitString.src/M000023.html +42 -0
- data/doc/classes/BitString.src/M000024.html +61 -0
- data/doc/classes/BitString.src/M000025.html +18 -0
- data/doc/classes/BitString.src/M000026.html +18 -0
- data/doc/classes/BitString.src/M000027.html +20 -0
- data/doc/classes/BitString.src/M000028.html +18 -0
- data/doc/classes/BitString.src/M000029.html +18 -0
- data/doc/classes/BitString.src/M000030.html +18 -0
- data/doc/classes/BitString.src/M000031.html +18 -0
- data/doc/classes/BitString.src/M000032.html +18 -0
- data/doc/created.rid +1 -0
- data/doc/files/lib/bitstring/operators_rb.html +122 -0
- data/doc/files/lib/bitstring_rb.html +153 -0
- data/doc/fr_class_index.html +27 -0
- data/doc/fr_file_index.html +28 -0
- data/doc/fr_method_index.html +60 -0
- data/doc/index.html +24 -0
- data/doc/rdoc-style.css +208 -0
- data/lib/bitstring.rb +1318 -0
- data/lib/bitstring/operators.rb +481 -0
- data/test/Rakefile +21 -0
- data/test/test_basic.rb +848 -0
- data/test/test_data.rb +24 -0
- data/test/test_enum.rb +671 -0
- data/test/test_helper.rb +3 -0
- data/test/test_operators.rb +454 -0
- metadata +121 -0
data/test/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
here = File.dirname(__FILE__) + '/'
|
2
|
+
libdir = File.expand_path(here + '../lib/')
|
3
|
+
$LOAD_PATH.unshift(libdir)
|
4
|
+
|
5
|
+
task :default => [ :test_basic, :test_operators, :test_enum ]
|
6
|
+
|
7
|
+
desc 'Test basic methods (construction, etc.)'
|
8
|
+
task :test_basic do
|
9
|
+
ruby "-I#{libdir} #{here}test_basic.rb"
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'Test operators (special characters, like & and |)'
|
13
|
+
task :test_operators do
|
14
|
+
ruby "-I#{libdir} #{here}test_operators.rb"
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Test methods inherited from Enumerable mixin'
|
18
|
+
task :test_enum do
|
19
|
+
ruby "-I#{libdir} #{here}test_enum.rb"
|
20
|
+
end
|
21
|
+
|
data/test/test_basic.rb
ADDED
@@ -0,0 +1,848 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
3
|
+
require File.dirname(__FILE__) + '/test_data.rb'
|
4
|
+
|
5
|
+
#
|
6
|
+
# Test basic functionality, and non-operator methods we provide.
|
7
|
+
# (Other tests handle operators and the methods inherited from
|
8
|
+
# the Enumerable mixin.)
|
9
|
+
#
|
10
|
+
|
11
|
+
module Tests
|
12
|
+
|
13
|
+
class Test_BitStrings < Test::Unit::TestCase
|
14
|
+
|
15
|
+
#
|
16
|
+
# Just test creating the objects. We'll test whether they're valid
|
17
|
+
# later.
|
18
|
+
#
|
19
|
+
def test_000_construction()
|
20
|
+
TestVals.each do |sVal|
|
21
|
+
lVal = sVal.length
|
22
|
+
#
|
23
|
+
# Turn the binary string into an integer.
|
24
|
+
#
|
25
|
+
iVal = sVal.to_i(2)
|
26
|
+
#
|
27
|
+
# Reverse the string.
|
28
|
+
#
|
29
|
+
sVal_r = sVal.reverse
|
30
|
+
#
|
31
|
+
# Make an array of the digits as strings, and one of the digits as
|
32
|
+
# integers.
|
33
|
+
#
|
34
|
+
iVal_a = (sVal_a = sVal.split(//)).map { |bit| bit.to_i }
|
35
|
+
#
|
36
|
+
# Make reversed copies of those, too.
|
37
|
+
#
|
38
|
+
sVal_a_r = sVal_a.reverse
|
39
|
+
iVal_a_r = iVal_a.reverse
|
40
|
+
|
41
|
+
#
|
42
|
+
# Test making an unbounded string from the integer.
|
43
|
+
#
|
44
|
+
assert_nothing_raised("Test unbounded no exception new(#{iVal})") do
|
45
|
+
bs = BitString.new(iVal)
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# From the string.
|
50
|
+
#
|
51
|
+
assert_nothing_raised("Test unbounded no exception new('#{sVal}')") do
|
52
|
+
bs = BitString.new(sVal)
|
53
|
+
end
|
54
|
+
|
55
|
+
#
|
56
|
+
# From the array of integers.
|
57
|
+
#
|
58
|
+
assert_nothing_raised("Test unbounded no exception new('#{iVal_a.inspect}')") do
|
59
|
+
bs = BitString.new(iVal_a)
|
60
|
+
end
|
61
|
+
|
62
|
+
#
|
63
|
+
# Try bounded now.
|
64
|
+
#
|
65
|
+
assert_nothing_raised("Test bounded no exception new(#{iVal})") do
|
66
|
+
bs = BitString.new(iVal, lVal)
|
67
|
+
end
|
68
|
+
assert_nothing_raised("Test bounded no exception new('#{sVal}')") do
|
69
|
+
bs = BitString.new(sVal, lVal)
|
70
|
+
end
|
71
|
+
assert_nothing_raised("Test bounded no exception new(#{iVal_a.inspect})") do
|
72
|
+
bs = BitString.new(iVal_a, lVal)
|
73
|
+
end
|
74
|
+
|
75
|
+
#
|
76
|
+
# Again, with lengths shorter than the values.
|
77
|
+
#
|
78
|
+
assert_nothing_raised("Test bounded no exception new(#{iVal} short)") do
|
79
|
+
bs = BitString.new(iVal, lVal / 2)
|
80
|
+
end
|
81
|
+
assert_nothing_raised("Test bounded no exception new('#{sVal}' short)") do
|
82
|
+
bs = BitString.new(sVal, lVal / 2)
|
83
|
+
end
|
84
|
+
assert_nothing_raised("Test bounded no exception new(#{iVal_a.inspect} short)") do
|
85
|
+
bs = BitString.new(iVal_a, lVal / 2)
|
86
|
+
end
|
87
|
+
|
88
|
+
#
|
89
|
+
# Now the block (bounded) form.
|
90
|
+
#
|
91
|
+
assert_nothing_raised("Test bounded new() {'#{sVal}'}") do
|
92
|
+
bs = BitString.new(lVal) { |bit| sVal_a_r[bit] }
|
93
|
+
end
|
94
|
+
assert_nothing_raised("Test bounded new() {#{iVal_a.inspect}}") do
|
95
|
+
bs = BitString.new(lVal) { |bit| iVal_a_r[bit] }
|
96
|
+
end
|
97
|
+
|
98
|
+
#
|
99
|
+
# Check that the constructor arguments are vetted.
|
100
|
+
#
|
101
|
+
input = 'a'
|
102
|
+
assert_raise(ArgumentError, "Test unbounded new(#{input.inspect})") do
|
103
|
+
bs = BitString.new(input)
|
104
|
+
end
|
105
|
+
input = iVal_a.collect { |v| v + 2 }
|
106
|
+
assert_raise(ArgumentError, "Test unbounded new(#{input.inspect})") do
|
107
|
+
bs = BitString.new(input)
|
108
|
+
end
|
109
|
+
input = iVal.to_s
|
110
|
+
unless (iVal < 2)
|
111
|
+
assert_raise(ArgumentError, "Test unbounded new(#{input.inspect})") do
|
112
|
+
bs = BitString.new(input)
|
113
|
+
end
|
114
|
+
assert_raise(ArgumentError, "Test bounded new(#{input.inspect})") do
|
115
|
+
bs = BitString.new(input, input.length)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
input = 'a'
|
119
|
+
assert_raise(ArgumentError, "Test bounded new(#{input.inspect})") do
|
120
|
+
bs = BitString.new(input, 1)
|
121
|
+
end
|
122
|
+
assert_raise(ArgumentError, "Test bounded new(0, 'a')") do
|
123
|
+
bs = BitString.new(0, 'a')
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
#
|
129
|
+
# Test that conversion to an integer value works properly, since
|
130
|
+
# we depend on the to_i() method later in the tests.
|
131
|
+
#
|
132
|
+
def test_001_to_i()
|
133
|
+
TestVals.each do |sVal|
|
134
|
+
iVal = sVal.to_i(2)
|
135
|
+
bs = BitString.new(sVal)
|
136
|
+
assert_equal(iVal,
|
137
|
+
bs.to_i,
|
138
|
+
"Test BitString.to_i(#{sVal}) => #{iVal}")
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
#
|
143
|
+
# Test that conversion *from* an integer value works properly.
|
144
|
+
#
|
145
|
+
def test_002_from_i()
|
146
|
+
TestVals.each do |sVal|
|
147
|
+
iVal = sVal.to_i(2)
|
148
|
+
bs = BitString.new(0)
|
149
|
+
bs.from_i(iVal)
|
150
|
+
assert_equal(iVal,
|
151
|
+
bs.to_i,
|
152
|
+
"Test BitString.from_i(#{sVal}) => #{iVal}")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
#
|
157
|
+
# Similarly, consider the to_s() method very early because we depend
|
158
|
+
# on it later.
|
159
|
+
#
|
160
|
+
def test_003_to_s()
|
161
|
+
TestVals.each do |sVal|
|
162
|
+
iVal = sVal.to_i(2)
|
163
|
+
sVal_e = sVal.sub(/^0+(.)/, '\1')
|
164
|
+
bs = BitString.new(sVal)
|
165
|
+
assert_equal(sVal_e,
|
166
|
+
bs.to_s,
|
167
|
+
"Test unbounded '#{sVal}'.to_s => '#{sVal_e}'")
|
168
|
+
bs = BitString.new(sVal, sVal.length)
|
169
|
+
assert_equal(sVal,
|
170
|
+
bs.to_s,
|
171
|
+
"Test bounded '#{sVal}'.to_s => '#{sVal}'")
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
#
|
176
|
+
# The length() method is pretty important, too.
|
177
|
+
#
|
178
|
+
def test_004_length()
|
179
|
+
TestVals.each do |sVal|
|
180
|
+
#
|
181
|
+
# The length() method returns either the size of a bounded
|
182
|
+
# bitstring, or the number of digits from the most significant
|
183
|
+
# 1.
|
184
|
+
#
|
185
|
+
uLength = sVal.sub(/^0+(.)/, '\1').length
|
186
|
+
bLength = sVal.length
|
187
|
+
bs = BitString.new(sVal)
|
188
|
+
assert_equal(uLength,
|
189
|
+
bs.length,
|
190
|
+
"Test unbounded '#{sVal}'.length => #{uLength}")
|
191
|
+
#
|
192
|
+
# Now do the same check for the bounded version.
|
193
|
+
#
|
194
|
+
bs = BitString.new(sVal, sVal.length)
|
195
|
+
bLength = sVal.length
|
196
|
+
assert_equal(bLength,
|
197
|
+
bs.length,
|
198
|
+
"Test bounded '#{sVal}'.length => #{bLength}")
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
#
|
203
|
+
# Test that string are being properly marked as bounded -- or not.
|
204
|
+
#
|
205
|
+
def test_005_bounded?()
|
206
|
+
TestVals.each do |sVal|
|
207
|
+
bs = BitString.new(sVal)
|
208
|
+
assert(! bs.bounded?)
|
209
|
+
bs = BitString.new(sVal, sVal.length)
|
210
|
+
assert(bs.bounded?)
|
211
|
+
bs = BitString.new(sVal.length) { |i| sVal.reverse[i,1].to_i }
|
212
|
+
assert(bs.bounded?)
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
#
|
217
|
+
# Test the clear() and clear!() methods.
|
218
|
+
#
|
219
|
+
def test_006_clear()
|
220
|
+
TestVals.each do |sVal|
|
221
|
+
bs = BitString.new(sVal)
|
222
|
+
tbs = bs.clear
|
223
|
+
assert_equal(sVal.to_i(2),
|
224
|
+
bs.to_i,
|
225
|
+
"Test that '#{sVal}'.clear() leaves original set")
|
226
|
+
assert_equal(0,
|
227
|
+
tbs.to_i,
|
228
|
+
"Test that '#{sVal}'.clear() returns cleared bitstring")
|
229
|
+
bs.clear!
|
230
|
+
assert_equal(0,
|
231
|
+
bs.to_i,
|
232
|
+
"Test that '#{sVal}'.clear!() clears original bitstring")
|
233
|
+
end
|
234
|
+
end # def test_006_clear()
|
235
|
+
|
236
|
+
#
|
237
|
+
# Indexed access is critically important, so we test its permutations
|
238
|
+
# here rather in the 'operators' test set.
|
239
|
+
#
|
240
|
+
|
241
|
+
#
|
242
|
+
# Try simple single-bit accesses through the [] method.
|
243
|
+
#
|
244
|
+
def test_007_indexing()
|
245
|
+
TestVals.each do |sVal|
|
246
|
+
lVal = sVal.length
|
247
|
+
iVal_a_r = sVal.reverse.split(//).map { |bit| bit.to_i }
|
248
|
+
bs = BitString.new(sVal)
|
249
|
+
#
|
250
|
+
# Let's try fetching each bit.
|
251
|
+
#
|
252
|
+
lVal.times do |i|
|
253
|
+
assert_equal(iVal_a_r[i],
|
254
|
+
bs[i],
|
255
|
+
"Test fetching index [#{i}] => #{iVal_a_r[i]}")
|
256
|
+
end
|
257
|
+
|
258
|
+
#
|
259
|
+
# Try setting each bit to its value.
|
260
|
+
#
|
261
|
+
bs = BitString.new(sVal)
|
262
|
+
lVal.times do |i|
|
263
|
+
bs[i] = iVal_a_r[i]
|
264
|
+
assert_equal(iVal_a_r[i],
|
265
|
+
bs[i],
|
266
|
+
"Test setting bit to itself " +
|
267
|
+
"[#{i}] = #{iVal_a_r[i]}; [#{i}] => #{iVal_a_r[i]}")
|
268
|
+
end
|
269
|
+
|
270
|
+
#
|
271
|
+
# Try setting each bit to its complement.
|
272
|
+
#
|
273
|
+
bs = BitString.new(sVal)
|
274
|
+
lVal.times do |i|
|
275
|
+
pre = bs.to_s
|
276
|
+
bs[i] = ~ bs[i]
|
277
|
+
post = bs.to_s
|
278
|
+
assert_not_equal(iVal_a_r[i],
|
279
|
+
bs[i],
|
280
|
+
"Test setting bit to its complement " +
|
281
|
+
"[#{i}] = ~[#{i}] != #{iVal_a_r[i]}\n" +
|
282
|
+
"pre=[#{pre}] post=[#{post}] sVal=[#{sVal}]")
|
283
|
+
end
|
284
|
+
|
285
|
+
#
|
286
|
+
# Try fetching with indices beyond the bounds.
|
287
|
+
#
|
288
|
+
msg = "Test no exception from unbounded '#{sVal}'[#{lVal + 10}]"
|
289
|
+
assert_nothing_raised(msg) do
|
290
|
+
bs[lVal + 10]
|
291
|
+
end
|
292
|
+
msg = "Test IndexError exception from unbounded '#{sVal}'[-1]"
|
293
|
+
assert_raise(IndexError, msg) do
|
294
|
+
bs[-1]
|
295
|
+
end
|
296
|
+
bs = BitString.new(sVal, lVal)
|
297
|
+
msg = "Test IndexError exception from bounded '#{sVal}'[#{lVal + 10}]"
|
298
|
+
assert_raise(IndexError, msg) do
|
299
|
+
bs[lVal + 10]
|
300
|
+
end
|
301
|
+
msg = "Test IndexError exception from bounded '#{sVal}'[-1]"
|
302
|
+
assert_raise(IndexError, msg) do
|
303
|
+
bs[-1]
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
#
|
309
|
+
# Now let's try ranges for indexing. First, use [start..end] syntax.
|
310
|
+
#
|
311
|
+
def test_008_ranges()
|
312
|
+
TestVals.each do |sVal|
|
313
|
+
length = sVal.length
|
314
|
+
(length - 2).times do |width|
|
315
|
+
width += 2
|
316
|
+
bs = BitString.new(sVal)
|
317
|
+
#
|
318
|
+
# Test subranging n bits at a time in a fetch
|
319
|
+
#
|
320
|
+
(length - width + 1).times do |i|
|
321
|
+
excerpt = sVal[length-width-i,width].to_i(2)
|
322
|
+
rng = i..i+width-1
|
323
|
+
assert_equal(excerpt,
|
324
|
+
bs[rng].to_i,
|
325
|
+
'Test fetching bitstring subrange ' +
|
326
|
+
"'#{bs.to_s}'[#{rng}] => '#{excerpt}'\n" +
|
327
|
+
"(sVal='#{sVal}', length=#{length}, " +
|
328
|
+
"width=#{width}, i=#{i})")
|
329
|
+
end
|
330
|
+
#
|
331
|
+
# Now try setting that range to its complement
|
332
|
+
#
|
333
|
+
(length - width + 1).times do |i|
|
334
|
+
bs = BitString.new(sVal)
|
335
|
+
excerpt = (~ sVal[length-width-i,width].to_i(2)) & (2**width - 1)
|
336
|
+
rng = i..i+width-1
|
337
|
+
bs[rng] = excerpt
|
338
|
+
assert_equal(excerpt,
|
339
|
+
bs[rng].to_i,
|
340
|
+
'Test bitstring subrange after set' +
|
341
|
+
"'#{bs.to_s}'[#{rng}] => '#{excerpt}'")
|
342
|
+
end
|
343
|
+
|
344
|
+
#
|
345
|
+
# Now do the same with a bounded bitstring.
|
346
|
+
#
|
347
|
+
bs = BitString.new(sVal, length)
|
348
|
+
#
|
349
|
+
# Test subranging n bits at a time in a fetch
|
350
|
+
#
|
351
|
+
(length - width + 1).times do |i|
|
352
|
+
excerpt = sVal[length-width-i,width].to_i(2)
|
353
|
+
rng = i..i+width-1
|
354
|
+
assert_equal(excerpt,
|
355
|
+
bs[rng].to_i,
|
356
|
+
'Test fetching bitstring subrange ' +
|
357
|
+
"'#{bs.to_s}'[#{rng}] => '#{excerpt}'\n" +
|
358
|
+
"(sVal='#{sVal}', length=#{length}, " +
|
359
|
+
"width=#{width}, i=#{i})")
|
360
|
+
end
|
361
|
+
#
|
362
|
+
# Now try setting that range to its complement
|
363
|
+
#
|
364
|
+
(length - width + 1).times do |i|
|
365
|
+
bs = BitString.new(sVal, length)
|
366
|
+
excerpt = (~ sVal[length-width-i,width].to_i(2)) & (2**width - 1)
|
367
|
+
rng = i..i+width-1
|
368
|
+
bs[rng] = excerpt
|
369
|
+
assert_equal(excerpt,
|
370
|
+
bs[rng].to_i,
|
371
|
+
'Test bitstring subrange after set' +
|
372
|
+
"'#{bs.to_s}'[#{rng}] => '#{excerpt}'")
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
#
|
379
|
+
# Now try the [start,count] format.
|
380
|
+
#
|
381
|
+
def test_009_ranges()
|
382
|
+
TestVals.each do |sVal|
|
383
|
+
bs = BitString.new(sVal)
|
384
|
+
length = sVal.length
|
385
|
+
(length - 2).times do |width|
|
386
|
+
width += 2
|
387
|
+
#
|
388
|
+
# Test subranging n bits at a time
|
389
|
+
#
|
390
|
+
(length - width + 1).times do |i|
|
391
|
+
excerpt = sVal[length-width-i,width].to_i(2)
|
392
|
+
assert_equal(excerpt,
|
393
|
+
bs[i,width].to_i,
|
394
|
+
'Test bitstring subrange ' +
|
395
|
+
"'#{bs.to_s}'[#{i},#{width}] =>'#{excerpt}'")
|
396
|
+
end
|
397
|
+
end
|
398
|
+
end
|
399
|
+
end
|
400
|
+
|
401
|
+
#
|
402
|
+
# Verify that the 'least significant bit' method is returning the
|
403
|
+
# right value.
|
404
|
+
#
|
405
|
+
def test_010_lsb()
|
406
|
+
TestVals.each do |sVal|
|
407
|
+
iVal = sVal.to_i(2)
|
408
|
+
bs = BitString.new(sVal)
|
409
|
+
assert_equal(sVal[-1,1].to_i(2),
|
410
|
+
bs.lsb,
|
411
|
+
"Test lsb(#{sVal}) => #{sVal[-1,1].to_i(2)}")
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
#
|
416
|
+
# Test the msb (most significant bit) method, which only works on
|
417
|
+
# bounded strings.
|
418
|
+
#
|
419
|
+
def test_011_msb()
|
420
|
+
TestVals.each do |sVal|
|
421
|
+
bs = BitString.new(sVal)
|
422
|
+
msg = "Test RuntimeError raised by unbounded msb()"
|
423
|
+
assert_raise(RuntimeError, msg) do
|
424
|
+
bs.msb
|
425
|
+
end
|
426
|
+
bs = BitString.new(sVal, sVal.length)
|
427
|
+
assert_equal(sVal[0,1].to_i,
|
428
|
+
bs.msb,
|
429
|
+
"Test bounded msb(#{sVal}) => #{sVal[0,1].to_i}")
|
430
|
+
end
|
431
|
+
end
|
432
|
+
|
433
|
+
#
|
434
|
+
# Test growing the bit string, in either direction.
|
435
|
+
#
|
436
|
+
def test_012_grow()
|
437
|
+
nBits = 10
|
438
|
+
TestVals.each do |sVal|
|
439
|
+
bs = BitString.new(sVal)
|
440
|
+
msg = "Test IndexError raised for unbounded grow(#{-nBits})"
|
441
|
+
assert_raise(IndexError, msg) do
|
442
|
+
bs.grow(-nBits)
|
443
|
+
end
|
444
|
+
msg = "Test IndexError raised for unbounded grow!(#{-nBits})"
|
445
|
+
assert_raise(IndexError, msg) do
|
446
|
+
bs.grow!(-nBits)
|
447
|
+
end
|
448
|
+
msg = "Test RuntimeError raised for unbounded grow(#{nBits})"
|
449
|
+
assert_raise(RuntimeError, msg) do
|
450
|
+
bs.grow(nBits)
|
451
|
+
end
|
452
|
+
msg = "Test RuntimeError raised for unbounded grow!(#{nBits})"
|
453
|
+
assert_raise(RuntimeError) do
|
454
|
+
bs.grow!(nBits)
|
455
|
+
end
|
456
|
+
|
457
|
+
#
|
458
|
+
# Loop for the default value.
|
459
|
+
#
|
460
|
+
[ nil, 0, 1 ].each do |defval|
|
461
|
+
bcmd = "bs.grow(#{nBits}"
|
462
|
+
bcmd += ", #{defval}" unless (defval.nil?)
|
463
|
+
[ nil, 'BitString::HIGH_END', 'BitString::LOW_END' ].each do |dir|
|
464
|
+
dir = nil if (defval.nil?)
|
465
|
+
cmd = bcmd
|
466
|
+
cmd += ", #{dir}" unless (dir.nil?)
|
467
|
+
cmd += ')'
|
468
|
+
idir = dir
|
469
|
+
eval("idir = #{dir}") unless (dir.nil?)
|
470
|
+
#
|
471
|
+
# Create the base bitstring, and then get the grown copy
|
472
|
+
#
|
473
|
+
bs = BitString.new(sVal, sVal.length)
|
474
|
+
tbs = eval(cmd)
|
475
|
+
cmd2 = cmd.sub(/(grow)\(/, '\1!(')
|
476
|
+
eval(cmd2)
|
477
|
+
cmd.sub!(/^bs/, '')
|
478
|
+
cmd2.sub!(/^bs/, '')
|
479
|
+
assert_equal(sVal.length + nBits,
|
480
|
+
tbs.length,
|
481
|
+
"Test '#{sVal}'#{cmd}.length (#{tbs.to_s})")
|
482
|
+
assert_equal(sVal.length + nBits,
|
483
|
+
bs.length,
|
484
|
+
"Test '#{sVal}'#{cmd2}.length (#{bs.to_s})")
|
485
|
+
if ((defval.nil? && idir.nil?) ||
|
486
|
+
((defval == 0) &&
|
487
|
+
(idir.nil? || (idir == BitString::HIGH_END))))
|
488
|
+
#
|
489
|
+
# grow(nBits)
|
490
|
+
# grow(nBits, 0)
|
491
|
+
# grow(nBits, 0, BitString::HIGH_END)
|
492
|
+
#
|
493
|
+
assert_equal(0,
|
494
|
+
tbs[sVal.length,nBits].to_i,
|
495
|
+
"Test '#{sVal}'#{cmd} fills high 0 (#{tbs.to_s})")
|
496
|
+
assert_equal(0,
|
497
|
+
bs[sVal.length,nBits].to_i,
|
498
|
+
"Test '#{sVal}'#{cmd2} fills high 0 " +
|
499
|
+
"(#{tbs.to_s})")
|
500
|
+
|
501
|
+
assert_equal(0,
|
502
|
+
tbs[sVal.length,nBits].to_i,
|
503
|
+
"Test '#{sVal}'#{cmd} fills high 0 (#{tbs.to_s})")
|
504
|
+
assert_equal(0,
|
505
|
+
bs[sVal.length,nBits].to_i,
|
506
|
+
"Test '#{sVal}'#{cmd2} fills high 0 (#{bs.to_s})")
|
507
|
+
elsif ((defval == 1) &&
|
508
|
+
(idir.nil? || (idir == BitString::HIGH_END)))
|
509
|
+
#
|
510
|
+
# grow(nBits, 1)
|
511
|
+
# grow(nBits, 1, BitString::HIGH_END)
|
512
|
+
#
|
513
|
+
assert_equal(2**nBits - 1,
|
514
|
+
tbs[sVal.length,nBits].to_i,
|
515
|
+
"Test '#{sVal}'#{cmd} fills high 1 (#{tbs.to_s})")
|
516
|
+
assert_equal(2**nBits - 1,
|
517
|
+
bs[sVal.length,nBits].to_i,
|
518
|
+
"Test '#{sVal}'#{cmd2} fills high 1 (#{bs.to_s})")
|
519
|
+
elsif ((defval == 0) && (idir == BitString::LOW_END))
|
520
|
+
#
|
521
|
+
# grow(nBits, 0, BitString::LOW_END)
|
522
|
+
#
|
523
|
+
assert_equal(0,
|
524
|
+
tbs[0,nBits].to_i,
|
525
|
+
"Test '#{sVal}'#{cmd} fills low 0 (#{tbs.to_s})")
|
526
|
+
assert_equal(0,
|
527
|
+
bs[0,nBits].to_i,
|
528
|
+
"Test '#{sVal}'#{cmd2} fills low 0 (#{bs.to_s})")
|
529
|
+
|
530
|
+
assert_equal(sVal.to_i(2),
|
531
|
+
tbs[nBits,sVal.length].to_i,
|
532
|
+
"Test '#{sVal}'#{cmd} properly shifts and " +
|
533
|
+
"low fills 0 (#{tbs.to_s})")
|
534
|
+
assert_equal(sVal.to_i(2),
|
535
|
+
bs[nBits,sVal.length].to_i,
|
536
|
+
"Test '#{sVal}'#{cmd2} properly shifts and " +
|
537
|
+
"low fills 0 (#{bs.to_s})")
|
538
|
+
elsif ((defval == 1) && (idir == BitString::LOW_END))
|
539
|
+
#
|
540
|
+
# grow(nBits, 1, BitString::LOW_END)
|
541
|
+
#
|
542
|
+
assert_equal(2**nBits - 1,
|
543
|
+
tbs[0,nBits].to_i,
|
544
|
+
"Test '#{sVal}'#{cmd} fills low 1 (#{tbs.to_s})")
|
545
|
+
assert_equal(2**nBits - 1,
|
546
|
+
bs[0,nBits].to_i,
|
547
|
+
"Test '#{sVal}'#{cmd2} fills low 1 (#{bs.to_s})")
|
548
|
+
|
549
|
+
assert_equal(sVal.to_i(2),
|
550
|
+
tbs[nBits,sVal.length].to_i,
|
551
|
+
"Test '#{sVal}'#{cmd} properly shifts and " +
|
552
|
+
"low fills 1 (#{tbs.to_s})")
|
553
|
+
assert_equal(sVal.to_i(2),
|
554
|
+
bs[nBits,sVal.length].to_i,
|
555
|
+
"Test '#{sVal}'#{cmd2} properly shifts and " +
|
556
|
+
"low fills 1 (#{bs.to_s})")
|
557
|
+
else
|
558
|
+
assert(false, "Missed case '#{sVal}'#{cmd}\n" +
|
559
|
+
"sVal=#{tbs.to_s}\n" +
|
560
|
+
"defval=#{defval.inspect}\n" +
|
561
|
+
"dir=#{dir.inspect}")
|
562
|
+
end
|
563
|
+
end
|
564
|
+
end
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
#
|
569
|
+
# Test shrinking the bitstring (making it shorter).
|
570
|
+
#
|
571
|
+
def test_013_shrink()
|
572
|
+
TestVals.each do |sVal|
|
573
|
+
nBits = [9, sVal.length].min + 1
|
574
|
+
bs = BitString.new(sVal)
|
575
|
+
assert_raise(IndexError) do
|
576
|
+
bs.shrink(-nBits)
|
577
|
+
end
|
578
|
+
assert_raise(IndexError) do
|
579
|
+
bs.shrink!(-nBits)
|
580
|
+
end
|
581
|
+
assert_raise(RuntimeError) do
|
582
|
+
bs.shrink(nBits)
|
583
|
+
end
|
584
|
+
assert_raise(RuntimeError) do
|
585
|
+
bs.shrink!(nBits)
|
586
|
+
end
|
587
|
+
bs = BitString.new(sVal, sVal.length)
|
588
|
+
assert_raise(RuntimeError) do
|
589
|
+
bs.shrink(sVal.length)
|
590
|
+
end
|
591
|
+
assert_raise(RuntimeError) do
|
592
|
+
bs.shrink!(sVal.length)
|
593
|
+
end
|
594
|
+
|
595
|
+
#
|
596
|
+
# Loop for the default value.
|
597
|
+
#
|
598
|
+
[ nil, 0, 1 ].each do |defval|
|
599
|
+
bcmd = "bs.shrink(#{nBits}"
|
600
|
+
[ nil, 'BitString::HIGH_END', 'BitString::LOW_END' ].each do |dir|
|
601
|
+
cmd = bcmd
|
602
|
+
cmd += ", #{dir}" unless (dir.nil?)
|
603
|
+
cmd += ')'
|
604
|
+
idir = dir
|
605
|
+
eval("idir = #{dir}") unless (dir.nil?)
|
606
|
+
#
|
607
|
+
# Create the base bitstring, and then get the shrunken copy
|
608
|
+
#
|
609
|
+
bs = BitString.new(sVal, sVal.length)
|
610
|
+
tbs = eval(cmd)
|
611
|
+
cmd2 = cmd.sub(/(shrink)\(/, '\1!(')
|
612
|
+
eval(cmd2)
|
613
|
+
cmd.sub!(/^bs/, '')
|
614
|
+
cmd2.sub!(/^bs/, '')
|
615
|
+
assert_equal(sVal.length - nBits,
|
616
|
+
tbs.length,
|
617
|
+
"Test '#{sVal}'#{cmd}.length (#{tbs.to_s})")
|
618
|
+
assert_equal(sVal.length - nBits,
|
619
|
+
bs.length,
|
620
|
+
"Test '#{sVal}'#{cmd2}.length (#{bs.to_s})")
|
621
|
+
newLength = sVal.length - nBits
|
622
|
+
if (idir.nil? || (idir == BitString::HIGH_END))
|
623
|
+
#
|
624
|
+
# shrink(nBits)
|
625
|
+
# shrink(nBits, BitString::HIGH_END)
|
626
|
+
#
|
627
|
+
assert_equal(sVal[nBits,newLength].to_i(2),
|
628
|
+
tbs.to_i,
|
629
|
+
"Test '#{sVal}'#{cmd} properly truncates " +
|
630
|
+
"high (#{tbs.to_s})")
|
631
|
+
assert_equal(sVal[nBits,newLength].to_i(2),
|
632
|
+
bs.to_i,
|
633
|
+
"Test '#{sVal}'#{cmd2} properly truncates " +
|
634
|
+
"high (#{bs.to_s})")
|
635
|
+
|
636
|
+
elsif (idir == BitString::LOW_END)
|
637
|
+
#
|
638
|
+
# shrink(nBits, BitString::LOW_END)
|
639
|
+
#
|
640
|
+
assert_equal(sVal[0,newLength].to_i(2),
|
641
|
+
tbs.to_i,
|
642
|
+
"Test '#{sVal}'#{cmd} properly shifts " +
|
643
|
+
"low (#{tbs.to_s})")
|
644
|
+
assert_equal(sVal[0,newLength].to_i(2),
|
645
|
+
bs.to_i,
|
646
|
+
"Test '#{sVal}'#{cmd2} properly shifts " +
|
647
|
+
"low (#{bs.to_s})")
|
648
|
+
else
|
649
|
+
assert(false, "Missed case '#{sVal}'#{cmd}\n" +
|
650
|
+
"sVal=#{tbs.to_s}\n" +
|
651
|
+
"dir=#{dir.inspect}")
|
652
|
+
end
|
653
|
+
end
|
654
|
+
end
|
655
|
+
end
|
656
|
+
end
|
657
|
+
|
658
|
+
#
|
659
|
+
# Try resizing bitstrings.
|
660
|
+
#
|
661
|
+
def test_014_resize()
|
662
|
+
assert_raise(IndexError, "Test resize(0) raises IndexError") do
|
663
|
+
bs = BitString.new(-1, 12)
|
664
|
+
bs.resize(0)
|
665
|
+
end
|
666
|
+
TestVals.each do |sVal|
|
667
|
+
#
|
668
|
+
# First off, test resizing unbounded bitstrings. The length()
|
669
|
+
# method returns the number of digits from the most significant
|
670
|
+
# 1. We should be able to resize up or down, and the result will
|
671
|
+
# be bounded.
|
672
|
+
#
|
673
|
+
bs = BitString.new(sVal)
|
674
|
+
oLength = bs.length
|
675
|
+
uLength = sVal.sub(/^0+(.)/, '\1').length
|
676
|
+
#
|
677
|
+
# Resize down. Make sure we have at least 1 bit, since resizing
|
678
|
+
# to zero length raises an exception.
|
679
|
+
#
|
680
|
+
nBits = [9, [uLength / 2, 1].max].min
|
681
|
+
tbs = bs.resize(nBits)
|
682
|
+
assert_equal(oLength,
|
683
|
+
bs.length,
|
684
|
+
"Test that resize original stays the same length")
|
685
|
+
assert(tbs.bounded?,
|
686
|
+
"Test that new downsized bitstring is bounded")
|
687
|
+
assert_equal(nBits,
|
688
|
+
tbs.length,
|
689
|
+
"Test '#{sVal}'.resize(#{nBits} => '#{tbs.to_s}'.length")
|
690
|
+
bs.resize!(nBits)
|
691
|
+
assert(bs.bounded?, "Test that downsized bitstring is bounded")
|
692
|
+
assert_equal(nBits,
|
693
|
+
bs.length,
|
694
|
+
"Test '#{sVal}'.resize(#{nBits} => '#{bs.to_s}'.length")
|
695
|
+
|
696
|
+
#
|
697
|
+
# Resize up.
|
698
|
+
#
|
699
|
+
bs = BitString.new(sVal, sVal.length)
|
700
|
+
oLength = bs.length
|
701
|
+
nBits = uLength * 2
|
702
|
+
tbs = bs.resize(nBits)
|
703
|
+
assert_equal(oLength,
|
704
|
+
bs.length,
|
705
|
+
"Test that resize original stays the same length")
|
706
|
+
assert(tbs.bounded?, "Test that new upsized bitstring is bounded")
|
707
|
+
assert_equal(nBits,
|
708
|
+
tbs.length,
|
709
|
+
"Test '#{sVal}'.resize(#{nBits} => '#{tbs.to_s}'.length")
|
710
|
+
bs.resize!(nBits)
|
711
|
+
assert(bs.bounded?, "Test that upsized bitstring is bounded")
|
712
|
+
assert_equal(nBits,
|
713
|
+
bs.length,
|
714
|
+
"Test '#{sVal}'.resize(#{nBits} => '#{bs.to_s}'.length")
|
715
|
+
end
|
716
|
+
end
|
717
|
+
|
718
|
+
#
|
719
|
+
# Test rotating bitstrings (only works for bounded ones).
|
720
|
+
#
|
721
|
+
def test_015_rotate()
|
722
|
+
bs = BitString.new('1001010010101110001101')
|
723
|
+
msg = "Test RuntimeError raised for unbounded rotate(10)"
|
724
|
+
assert_raise(RuntimeError, msg) do
|
725
|
+
tbs = bs.rotate(10)
|
726
|
+
end
|
727
|
+
msg = "Test RuntimeError raised for unbounded rotate!(10)"
|
728
|
+
assert_raise(RuntimeError, msg) do
|
729
|
+
bs.rotate!(10)
|
730
|
+
end
|
731
|
+
TestVals.each do |sVal|
|
732
|
+
lVal = sVal.length
|
733
|
+
100.times do |i|
|
734
|
+
bs = BitString.new(sVal, lVal)
|
735
|
+
tBits = rand(lVal * (rand(5) + 1))
|
736
|
+
nBits = tBits % lVal
|
737
|
+
sign = rand(100) < 50 ? -1 : 1
|
738
|
+
if (sign < 0)
|
739
|
+
#
|
740
|
+
# Rotating left
|
741
|
+
#
|
742
|
+
nsVal = sVal[nBits,lVal-nBits] + sVal[0,nBits]
|
743
|
+
else
|
744
|
+
#
|
745
|
+
# Rotating right.
|
746
|
+
#
|
747
|
+
nsVal = sVal[lVal-nBits,nBits] + sVal[0,lVal-nBits]
|
748
|
+
end
|
749
|
+
tbs = bs.rotate(tBits * sign)
|
750
|
+
assert_equal(sVal,
|
751
|
+
bs.to_s,
|
752
|
+
"Test that rotate(#{tBits * sign}) " +
|
753
|
+
"doesn't alter the source")
|
754
|
+
assert_equal(nsVal,
|
755
|
+
tbs.to_s,
|
756
|
+
"Test '#{sVal}'.rotate(#{tBits * sign}) => '#{nsVal}'")
|
757
|
+
bs.rotate!(tBits * sign)
|
758
|
+
assert_equal(nsVal,
|
759
|
+
bs.to_s,
|
760
|
+
"Test '#{sVal}'.rotate!(#{tBits * sign}) => '#{nsVal}'")
|
761
|
+
end
|
762
|
+
end
|
763
|
+
end
|
764
|
+
|
765
|
+
#
|
766
|
+
# Test the masking.
|
767
|
+
#
|
768
|
+
def test_017_mask()
|
769
|
+
TestVals.each do |sVal|
|
770
|
+
bs = BitString.new(sVal)
|
771
|
+
assert_raise(IndexError, "Test error on too many mask bits") do
|
772
|
+
bs.mask(bs.length + 2)
|
773
|
+
end
|
774
|
+
assert_raise(IndexError, "Test error on too many mask bits") do
|
775
|
+
bs.mask(bs.length + 2)
|
776
|
+
end
|
777
|
+
assert_equal(2**bs.length - 1,
|
778
|
+
bs.mask,
|
779
|
+
"Test unbounded full mask of '#{sVal}'")
|
780
|
+
bs = BitString.new(sVal, sVal.length)
|
781
|
+
assert_equal(2**bs.length - 1,
|
782
|
+
bs.mask,
|
783
|
+
"Test bounded full mask of '#{sVal}'")
|
784
|
+
end
|
785
|
+
end
|
786
|
+
|
787
|
+
#
|
788
|
+
# Test the each() method.
|
789
|
+
#
|
790
|
+
def test_018_each()
|
791
|
+
TestVals.each do |sVal|
|
792
|
+
bs = BitString.new(sVal)
|
793
|
+
pos = 0
|
794
|
+
bs.each do |val|
|
795
|
+
assert_equal(val,
|
796
|
+
bs[pos],
|
797
|
+
"Test unbounded each block(#{val}) (for #{pos})")
|
798
|
+
pos += 1
|
799
|
+
end
|
800
|
+
#
|
801
|
+
# And again for a bounded value.
|
802
|
+
#
|
803
|
+
bs = BitString.new(sVal, sVal.length)
|
804
|
+
pos = 0
|
805
|
+
bs.each do |val|
|
806
|
+
assert_equal(val,
|
807
|
+
bs[pos],
|
808
|
+
"Test bounded each block(#{val}) (for #{pos})")
|
809
|
+
pos += 1
|
810
|
+
end
|
811
|
+
end
|
812
|
+
end
|
813
|
+
|
814
|
+
#
|
815
|
+
# Test the bit-counting method.
|
816
|
+
#
|
817
|
+
def test_020_population()
|
818
|
+
TestVals.each do |sVal|
|
819
|
+
bs = BitString.new(sVal)
|
820
|
+
ones = sVal.gsub(/0/, '').length
|
821
|
+
zeroes = sVal.gsub(/^0+(.)/, '\1').gsub(/1/, '').length
|
822
|
+
assert_raise(ArgumentError, 'Test exception for population("a")') do
|
823
|
+
bs.population('a')
|
824
|
+
end
|
825
|
+
assert_equal(ones,
|
826
|
+
bs.population(1),
|
827
|
+
"Test unbounded '#{sVal}'.population(1)")
|
828
|
+
assert_equal(zeroes,
|
829
|
+
bs.population(0),
|
830
|
+
"Test unbounded '#{sVal}'.population(0)")
|
831
|
+
#
|
832
|
+
# Now bounded.
|
833
|
+
#
|
834
|
+
bs = BitString.new(sVal, sVal.length)
|
835
|
+
ones = sVal.gsub(/0/, '').length
|
836
|
+
zeroes = sVal.gsub(/1/, '').length
|
837
|
+
assert_equal(ones,
|
838
|
+
bs.population(1),
|
839
|
+
"Test bounded '#{sVal}'.population(1)")
|
840
|
+
assert_equal(zeroes,
|
841
|
+
bs.population(0),
|
842
|
+
"Test bounded '#{sVal}'.population(0)")
|
843
|
+
end
|
844
|
+
end
|
845
|
+
|
846
|
+
end
|
847
|
+
|
848
|
+
end # module Tests
|