multiset 0.3.0 → 0.4.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.
@@ -1,12 +1,629 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
2
 
3
- # This version is a direct porting from version 0.202 (not for Rubygems).
4
- # Unit test code will be added from the next version.
3
+ # Note: NOT ALL METHODS ARE TESTED!
5
4
 
6
5
  require "multiset"
7
6
 
8
7
  describe Multiset do
8
+ # Generation methods
9
+ describe "being generated" do
10
+ describe "by Multiset.parse(Hash)" do
11
+ it "should regard keys as elements and values as counts" do
12
+ Multiset.parse({:a => 3, :b => 2}).should == Multiset[:a, :a, :a, :b, :b]
13
+ end
14
+ end
15
+
16
+ describe "by Multiset.parse(NonHashEnumerable)" do
17
+ it "should regard each of the elements as an element in the Multiset" do
18
+ Multiset.parse([:a, 3, :b, 2]).should == Multiset[:a, 3, :b, 2]
19
+ end
20
+ end
21
+
22
+ describe "by Multiset.parse(NonEnumerable)" do
23
+ it "should be rejected" do
24
+ lambda{ Multiset.parse(83) }.should raise_error(ArgumentError)
25
+ lambda{ Multiset.parse("hoge\npiyo\n") }.should raise_error(ArgumentError)
26
+ end
27
+ end
28
+
29
+ describe "by Multiset.parse_force(NonEnumerable)" do
30
+ it "should be rejected except for strings" do
31
+ lambda{ Multiset.parse_force(83) }.should raise_error(ArgumentError)
32
+ Multiset.parse_force("hoge\npiyo\n").should == Multiset["hoge\n", "piyo\n"]
33
+ end
34
+ end
35
+
36
+ describe "by Multiset#dup" do
37
+ it "should be the same as the original Multiset" do
38
+ tmp = Multiset.new([:a,:a,:b])
39
+ tmp.should == tmp.dup
40
+
41
+ tmp = Multiset[]
42
+ tmp.should == tmp.dup
43
+ end
44
+ end
45
+ end
46
+
47
+ it "should be replaced by another Multiset by Multiset#replace" do
48
+ tmp = Multiset[]
49
+ tmp.replace(Multiset[:a,:b,:b]).should == Multiset[:a,:b,:b]
50
+ end
51
+
52
+ # Comparatory/merging methods
53
+ describe "of two" do
54
+ before do
55
+ @ms1 = Multiset.new(%w'a a a a b b b c c d')
56
+ @ms2 = Multiset.new(%w'b c c d d d e e e e')
57
+ end
58
+
59
+ it "should judge inclusions correctly" do
60
+ tmp1 = Multiset.new(%w'a a a a b b b c c d d')
61
+ tmp2 = Multiset.new(%w'a a a a b b b c c d')
62
+ tmp3 = Multiset.new(%w'a a a b b b c c d')
63
+
64
+ (@ms1 == @ms2).should be_false
65
+ (@ms1 == tmp1).should be_false
66
+ (@ms1 == tmp2).should be_true
67
+ (@ms1 == tmp3).should be_false
68
+
69
+ (@ms1.subset?(@ms2)).should be_false
70
+ (@ms1.subset?(tmp1)).should be_true
71
+ (@ms1.subset?(tmp2)).should be_true
72
+ (@ms1.subset?(tmp3)).should be_false
73
+ (@ms2.subset?(@ms1)).should be_false
74
+ (tmp1.subset?(@ms1)).should be_false
75
+ (tmp2.subset?(@ms1)).should be_true
76
+ (tmp3.subset?(@ms1)).should be_true
77
+
78
+ (@ms1.proper_subset?(@ms2)).should be_false
79
+ (@ms1.proper_subset?(tmp1)).should be_true
80
+ (@ms1.proper_subset?(tmp2)).should be_false
81
+ (@ms1.proper_subset?(tmp3)).should be_false
82
+ (@ms2.proper_subset?(@ms1)).should be_false
83
+ (tmp1.proper_subset?(@ms1)).should be_false
84
+ (tmp2.proper_subset?(@ms1)).should be_false
85
+ (tmp3.proper_subset?(@ms1)).should be_true
86
+
87
+ (@ms1.superset?(@ms2)).should be_false
88
+ (@ms1.superset?(tmp1)).should be_false
89
+ (@ms1.superset?(tmp2)).should be_true
90
+ (@ms1.superset?(tmp3)).should be_true
91
+ (@ms2.superset?(@ms1)).should be_false
92
+ (tmp1.superset?(@ms1)).should be_true
93
+ (tmp2.superset?(@ms1)).should be_true
94
+ (tmp3.superset?(@ms1)).should be_false
95
+
96
+ (@ms1.proper_superset?(@ms2)).should be_false
97
+ (@ms1.proper_superset?(tmp1)).should be_false
98
+ (@ms1.proper_superset?(tmp2)).should be_false
99
+ (@ms1.proper_superset?(tmp3)).should be_true
100
+ (@ms2.proper_superset?(@ms1)).should be_false
101
+ (tmp1.proper_superset?(@ms1)).should be_true
102
+ (tmp2.proper_superset?(@ms1)).should be_false
103
+ (tmp3.proper_superset?(@ms1)).should be_false
104
+ end
105
+
106
+ it "should compute the intersection correctly" do
107
+ (@ms1 & @ms2).should == Multiset.new(%w'b c c d')
108
+ end
109
+
110
+ it "should compute the union correctly" do
111
+ (@ms1 | @ms2).should == Multiset.new(%w'a a a a b b b c c d d d e e e e')
112
+ end
113
+
114
+ it "should compute the sum correctly" do
115
+ (@ms1 + @ms2).should == Multiset.new(%w'a a a a b b b b c c c c d d d d e e e e')
116
+
117
+ tmp = @ms1.dup
118
+ tmp.merge!(@ms2)
119
+ tmp.should == Multiset.new(%w'a a a a b b b b c c c c d d d d e e e e')
120
+ end
121
+
122
+ it "should compute the difference correctly" do
123
+ (@ms1 - @ms2).should == Multiset.new(%w'a a a a b b')
124
+
125
+ tmp = @ms1.dup
126
+ tmp.subtract!(@ms2)
127
+ tmp.should == Multiset.new(%w'a a a a b b')
128
+ end
129
+ end
130
+
131
+ # Iteration methods
132
+ describe "being iterated for entries" do
133
+ before do
134
+ @ms = Multiset.new(%w'a a b b b b c d d d')
135
+ end
136
+
137
+ it "should have the same result between Multiset\#{all?, any?, none?, one?} and Enumerable\#{all?, any?, none?, one?}" do
138
+ @ms.all?{ |x| x == "a" }.should be_false
139
+ @ms.any?{ |x| x == "a" }.should be_true
140
+ @ms.none?{ |x| x == "a" }.should be_false
141
+ @ms.none?{ |x| x.instance_of?(Integer) }.should be_true
142
+ @ms.one?{ |x| x == "a" }.should be_false
143
+ @ms.one?{ |x| x == "c" }.should be_true
144
+ end
145
+
146
+ it "should have the same result between Multiset#count and Enumerable#count" do
147
+ @ms.count("a").should == 2
148
+ @ms.count("x").should == 0
149
+ @ms.count.should == 10
150
+ @ms.count{ |x| x == "b" }.should == 4
151
+ end
152
+
153
+ it "should find an items by the specified condition with Multiset#find / Multiset#detect" do
154
+ @ms.find{ |item| item =~ /d/ }.should == "d"
155
+ end
156
+
157
+ it "should find an item by the specified condition with Multiset#find_with / Multiset#detect_with" do
158
+ @ms.find_with{ |item, count| count == 2 }.should == "a"
159
+ end
160
+
161
+ it "should find an items by the specified condition with Multiset#find_all / Multiset#select" do
162
+ @ms.find_all{ |item| item =~ /d/ }.should == Multiset.new(%w[d d d])
163
+ end
164
+
165
+ it "should find an items by the specified condition with Multiset#find_all_with / Multiset#select_with" do
166
+ @ms.find_all_with{ |item, count| count <= 2 }.should == Multiset.new(%w[a a c])
167
+ end
168
+
169
+ it "should find an items by the specified condition with Multiset#reject" do
170
+ @ms.reject{ |item| item =~ /d/ }.should == Multiset.new(%w[a a b b b b c])
171
+ end
172
+
173
+ it "should find an items by the specified condition with Multiset#reject!" do
174
+ @ms.reject!{ |item| item =~ /x/ }.should be_nil
175
+ @ms.reject!{ |item| item =~ /d/ }.object_id.should == @ms.object_id
176
+ @ms.should == Multiset.new(%w[a a b b b b c])
177
+ end
178
+
179
+ it "should find an items by the specified condition with Multiset#delete_if" do
180
+ @ms.delete_if{ |item| item =~ /x/ }.object_id.should == @ms.object_id
181
+ @ms.delete_if{ |item| item =~ /d/ }.object_id.should == @ms.object_id
182
+ @ms.should == Multiset.new(%w[a a b b b b c])
183
+ end
184
+
185
+ it "should find an items by the specified condition with Multiset#reject_with" do
186
+ @ms.reject_with{ |item, count| item =~ /d/ || count > 3 }.should == Multiset.new(%w[a a c])
187
+ end
188
+
189
+ it "should find an items by the specified condition with Multiset#grep" do
190
+ @ms.grep(/d/).should == Multiset.new(%w[d d d])
191
+ @ms.grep(/d/){ |item| item + "x" }.should == Multiset.new(%w[dx dx dx])
192
+ end
193
+
194
+ it "should repeat for items by the specified condition with Multiset#inject_with / Multiset#reduce_with" do
195
+ result = @ms.inject_with({ :item_sum => "", :count_sum => 0 }) do |obj, item, count|
196
+ obj[:item_sum] += item
197
+ obj[:count_sum] += count
198
+ obj
199
+ end
200
+ result[:item_sum].each_char.sort.should == %w[a b c d]
201
+ result[:count_sum].should == 10
202
+ end
203
+
204
+ it "should return a new Multiset by the specified condition with Multiset#map / Multiset#collect" do
205
+ @ms.map{ |item| item * 2 }.should == Multiset.new(%w'aa aa bb bb bb bb cc dd dd dd')
206
+ end
207
+
208
+ it "should return a new Multiset by the specified condition with Multiset#map_with / Multiset#collect_with" do
209
+ @ms.map_with{ |item, count| [item * 2, count * 2] }.should == Multiset.new(%w'aa aa aa aa bb bb bb bb bb bb bb bb cc cc dd dd dd dd dd dd')
210
+ end
211
+
212
+ it "should return the maximum/mininum value by max/min/minmax" do
213
+ @ms.max.should == "d"
214
+ @ms.min.should == "a"
215
+ @ms.minmax.should == %w[a d]
216
+ @ms.max{ |a, b| b <=> a }.should == "a"
217
+ @ms.min{ |a, b| b <=> a }.should == "d"
218
+ @ms.minmax{ |a, b| b <=> a }.should == %w[d a]
219
+ end
220
+
221
+ it "should return the maximum/mininum value by max_by/min_by/minmax_by" do
222
+ @ms.max_by{ |item| item }.should == "d"
223
+ @ms.min_by{ |item| item }.should == "a"
224
+ @ms.minmax_by{ |item| item }.should == %w[a d]
225
+ end
226
+
227
+ it "should return the maximum/mininum value by max_with/min_with/minmax_with" do
228
+ @ms.max_with{ |a_item, a_count, b_item, b_count| a_count <=> b_count }.should == "b"
229
+ @ms.max_with{ |a_item, a_count, b_item, b_count| b_count <=> a_count }.should == "c"
230
+ @ms.min_with{ |a_item, a_count, b_item, b_count| a_count <=> b_count }.should == "c"
231
+ @ms.min_with{ |a_item, a_count, b_item, b_count| b_count <=> a_count }.should == "b"
232
+ @ms.minmax_with{ |a_item, a_count, b_item, b_count| a_count <=> b_count }.should == %w[c b]
233
+ end
234
+
235
+ it "should return the maximum/mininum value by max_by_with/min_by_with/minmax_by_with" do
236
+ @ms.max_by_with{ |item, count| count }.should == "b"
237
+ @ms.min_by_with{ |item, count| count }.should == "c"
238
+ @ms.minmax_by_with{ |item, count| count }.should == %w[c b]
239
+ end
240
+
241
+ it "should return sorted array by Multiset#sort / Multiset#sort_with" do
242
+ @ms.sort.should == %w[a a b b b b c d d d]
243
+ @ms.sort{ |a, b| b <=> a }.should == %w[d d d c b b b b a a]
244
+ @ms.sort_with{ |a_item, a_count, b_item, b_count| b_count <=> a_count }.should == %w[b b b b d d d a a c]
245
+ end
246
+
247
+ it "should return sorted array by Multiset#sort_by / Multiset#sort_by_with" do
248
+ @ms.sort_by{ |item| item }.should == %w[a a b b b b c d d d]
249
+ @ms.sort_by_with{ |item, count| count }.should == %w[c a a d d d b b b b]
250
+ end
251
+ end
252
+
253
+ # Updating methods
254
+ describe "being updated" do
255
+ before do
256
+ @ms1 = Multiset.new(%w'a a a a b b b c c d')
257
+ end
258
+
259
+ it "should add an element correctly" do
260
+ tmp = @ms1.dup
261
+ tmp << "a"
262
+ tmp.should == Multiset.new(%w'a a a a a b b b c c d')
263
+ end
264
+
265
+ it "should add multiple element correctly" do
266
+ tmp = @ms1.dup
267
+ tmp.add("e", 3)
268
+ tmp.should == Multiset.new(%w'a a a a b b b c c d e e e')
269
+
270
+ tmp = @ms1.dup
271
+ tmp.add("a", 3)
272
+ tmp.should == Multiset.new(%w'a a a a a a a b b b c c d')
273
+ end
274
+
275
+ it "should remove an element correctly" do
276
+ tmp = @ms1.dup
277
+ tmp.delete("a")
278
+ tmp.should == Multiset.new(%w'a a a b b b c c d')
279
+
280
+ tmp = @ms1.dup
281
+ tmp.delete("e") # nothing deleted because `tmp' does not contain "e"
282
+ tmp.should == @ms1
283
+ end
284
+
285
+ it "should remove multiple element correctly" do
286
+ tmp = @ms1.dup
287
+ tmp.delete("a", 3)
288
+ tmp.should == Multiset.new(%w'a b b b c c d')
289
+
290
+ tmp = @ms1.dup
291
+ tmp.delete("a", 6) # in case `tmp' does not contain "a" less than 6 times
292
+ tmp.should == Multiset.new(%w'b b b c c d')
293
+ end
294
+
295
+ it "should remove all element of specified value correctly" do
296
+ tmp = @ms1.dup
297
+ tmp.delete_all("a")
298
+ tmp.should == Multiset.new(%w'b b b c c d')
299
+
300
+ tmp = @ms1.dup
301
+ tmp.delete_all("e") # nothing deleted because `tmp' does not contain "e"
302
+ tmp.should == @ms1
303
+ end
304
+ end
305
+ end
306
+
307
+ describe Hash, "when converted to a multiset" do
308
+ it "should regard keys as elements and values as counts by Hash#to_multiset" do
309
+ {:a => 2, :b => 1}.to_multiset.should == Multiset[:a,:a,:b]
310
+ {:x => 2, :y => 2, :z => 0}.to_multiset.should == Multiset[:x,:x,:y,:y]
311
+ end
9
312
  end
10
313
 
11
314
  describe Multimap do
315
+ describe "generated by adding items one by one" do
316
+ before do
317
+ @empty_multiset = Multiset.new
318
+ @mm = Multimap.new
319
+ end
320
+
321
+ it "should be empty for any key when generated without parameters" do
322
+ @mm[:a].should == @empty_multiset
323
+ @mm[:b].should == @empty_multiset
324
+ end
325
+
326
+ it "should be a singleton multiset by adding a scalar value" do
327
+ @mm[:a].add "bar"
328
+ @mm[:a].should == Multiset["bar"]
329
+ end
330
+
331
+ it "should not make any unsolicited change" do
332
+ @mm[:a].add "bar"
333
+ @mm[:b].should == @empty_multiset
334
+ end
335
+
336
+ it "should be a multiset constructed by the given array" do
337
+ @mm[:a] = %w[foo foo bar]
338
+ @mm[:a].should == Multiset.new(%w[foo foo bar])
339
+ end
340
+
341
+ it "should be a multiset constructed by the given hash (key: element, value: count)" do
342
+ @mm[:a] = {"foo" => 3, "bar" => 2}
343
+ @mm[:a].should == Multiset["foo", "foo", "bar", "foo", "bar"]
344
+ end
345
+
346
+ it "should not be updated by setting a scalar (other than 'Enumerable' object)" do
347
+ lambda{ @mm[:a] = "foobar" }.should raise_error(ArgumentError)
348
+ lambda{ @mm[:a] = 56 }.should raise_error(ArgumentError)
349
+ end
350
+
351
+ it "should be duplicated by Multimap#dup" do
352
+ @mm.dup.should == @mm
353
+ end
354
+ end
355
+
356
+ describe "being compared" do
357
+ it "should be correctly compared" do
358
+ mm1 = Multimap.new
359
+ mm1[:a] = ["foo", "foo", "bar", "hoge", "hoge", "moe"]
360
+ mm1[:b] = ["foo", "bar", "hoge", "hoge", "bar"]
361
+ mm2 = Multimap.new
362
+ mm2[:a] = ["foo", "foo", "bar", "hoge", "hoge", "moe"]
363
+ mm2[:b] = ["foo", "bar", "hoge", "hoge", "bar"]
364
+ mm3 = Multimap.new
365
+ mm3[:a] = ["foo", "foo", "bar", "hoge", "hoge", "moe"]
366
+ mm3[:b] = ["foo", "bar", "hoge", "hoge", "bar", "buz"]
367
+
368
+ mm1.should == mm2
369
+ mm1.should_not == mm3
370
+
371
+ mm3.dup.should == mm3
372
+ end
373
+
374
+ it "should be correctly decided whether it is empty or not" do
375
+ mm = Multimap.new
376
+
377
+ mm[:a] = []
378
+ mm[:b] = [:a, :b]
379
+ mm.should_not be_empty
380
+
381
+ mm[:a] = []
382
+ mm[:b] = []
383
+ mm.should be_empty
384
+ end
385
+ end
386
+
387
+ describe "being referred" do
388
+ before do
389
+ @mm = Multimap.new
390
+ @mm[:a] = ["foo", "foo", "bar", "hoge", "hoge", "moe"]
391
+ @mm[:b] = ["foo", "bar", "hoge", "hoge", "bar"]
392
+ end
393
+
394
+ it "should be correctly iterated by 'each_pair'" do
395
+ tmp_a = []
396
+ tmp_b = []
397
+ @mm.each_pair do |key, sval|
398
+ case key
399
+ when :a
400
+ tmp_a << sval
401
+ when :b
402
+ tmp_b << sval
403
+ else
404
+ raise
405
+ end
406
+ end
407
+ tmp_a.sort.should == ["foo", "foo", "bar", "hoge", "hoge", "moe"].sort
408
+ tmp_b.sort.should == ["foo", "bar", "hoge", "hoge", "bar"].sort
409
+ end
410
+
411
+ it "should be correctly iterated by 'each_pair_with'" do
412
+ tmp_a = []
413
+ tmp_b = []
414
+ @mm.each_pair_with do |key, val, cnt|
415
+ case key
416
+ when :a
417
+ tmp_a << val
418
+ when :b
419
+ tmp_b << val
420
+ else
421
+ raise
422
+ end
423
+ end
424
+ tmp_a.sort.should == ["foo", "foo", "bar", "hoge", "hoge", "moe"].uniq.sort
425
+ tmp_b.sort.should == ["foo", "bar", "hoge", "hoge", "bar"].uniq.sort
426
+ end
427
+
428
+ it "should be correctly iterated by 'each_pair_list'" do
429
+ flag = 0
430
+ @mm.each_pair_list do |key, vals|
431
+ case key
432
+ when :a
433
+ vals.should == Multiset["foo", "foo", "bar", "hoge", "hoge", "moe"]
434
+ flag += 1
435
+ when :b
436
+ vals.should == Multiset["foo", "bar", "hoge", "hoge", "bar"]
437
+ flag += 1
438
+ else
439
+ raise
440
+ end
441
+ end
442
+ flag.should == 2
443
+ end
444
+
445
+ it "should ignore non-existent key by 'each_key'" do
446
+ @mm[:c] = []
447
+
448
+ ms = Multiset.new
449
+ @mm.each_key{ |key| ms << key }
450
+ ms.should == Multiset[:a, :b]
451
+ end
452
+
453
+ it "should be correctly iterated by 'each_value'" do
454
+ ms = Multiset.new
455
+ @mm.each_value{ |sval| ms << sval }
456
+ ms.should == {"foo" => 3, "bar" => 3, "hoge" => 4, "moe" => 1}.to_multiset
457
+ end
458
+ end
459
+
460
+ describe "being updated" do
461
+ before do
462
+ @mm = Multimap.new
463
+ @mm[:a] = ["foo", "foo", "bar", "hoge", "hoge", "moe"]
464
+ @mm[:b] = ["foo", "bar", "hoge", "hoge", "bar"]
465
+ end
466
+
467
+ it "should release items when 'delete'd" do
468
+ @mm.delete(:a).should == Multiset["foo", "foo", "bar", "hoge", "hoge", "moe"]
469
+ @mm[:a].should == Multiset[]
470
+ @mm[:b].should == Multiset["foo", "bar", "hoge", "hoge", "bar"]
471
+ end
472
+
473
+ it "should not release items when 'reject'ed ('reject'ed from only return value)" do
474
+ mm1 = @mm.reject{ |key, sval| sval =~ /o/ }
475
+
476
+ mm1[:a].should == Multiset["bar"]
477
+ mm1[:b].should == Multiset["bar", "bar"]
478
+ mm1.should_not == @mm
479
+ end
480
+
481
+ it "should equal to 'reject!'ed multimap when 'delete_if' is applied" do
482
+ mm1 = @mm.dup
483
+ mm2 = @mm.dup
484
+
485
+ mm1.delete_if{ |key, sval| sval =~ /o/ }
486
+ mm2.reject!{ |key, sval| sval =~ /o/ }
487
+ mm1.should == mm2
488
+
489
+ mm1.delete_if{ |key, sval| sval =~ /x/ }
490
+ mm2.reject!{ |key, sval| sval =~ /x/ }
491
+ mm1.should == mm2
492
+ end
493
+
494
+ it "should return nil when 'reject!' rejects nothing but 'delete_if' not" do
495
+ mm1 = @mm.dup
496
+ mm2 = @mm.dup
497
+
498
+ mm1.delete_if{ |key, sval| sval =~ /o/ }.should == mm1
499
+ mm2.reject!{ |key, sval| sval =~ /o/ }.should == mm2
500
+
501
+ mm1.delete_if{ |key, sval| sval =~ /x/ }.should == mm1
502
+ mm2.reject!{ |key, sval| sval =~ /x/ }.should == nil
503
+ end
504
+
505
+ it "should not release items when 'reject_with' is applied ('reject'ed from only return value)" do
506
+ # reject_with
507
+ mm1 = @mm.reject_with{ |key, val, cnt| cnt >= 2 }
508
+
509
+ mm1[:a].should == Multiset["bar", "moe"]
510
+ mm1[:b].should == Multiset["foo"]
511
+ mm1.should_not == @mm
512
+ end
513
+
514
+ it "should release items when 'delete_with' is applied" do
515
+ retval = @mm.delete_with{ |key, val, cnt| cnt >= 2 }
516
+ retval.should == @mm
517
+ @mm[:a].should == Multiset["bar", "moe"]
518
+ @mm[:b].should == Multiset["foo"]
519
+ end
520
+
521
+ it "should release items when 'delete_with' is applied (but not deleted anything)" do
522
+ retval = @mm.delete_with{ |key, val, cnt| cnt >= 2 && val.length > 4 }
523
+ retval.should == @mm
524
+ @mm[:a].should == Multiset["foo", "foo", "bar", "hoge", "hoge", "moe"]
525
+ @mm[:b].should == Multiset["foo", "bar", "hoge", "hoge", "bar"]
526
+ end
527
+ end
528
+
529
+ describe "being checked its properties" do
530
+ before do
531
+ @mm_base = Multimap.new
532
+ @mm_base[:a] = ["foo", "foo", "bar", "hoge", "hoge", "moe"]
533
+ @mm_base[:b] = ["foo", "bar", "hoge", "hoge", "bar"]
534
+ end
535
+
536
+ # keys, values
537
+ it "should return existing (nonzero) keys by Multimap#keys" do
538
+ mm = @mm_base.dup
539
+ mm[:c] = []
540
+ mm.keys.should satisfy{ |ks| ks == [:a, :b] || ks == [:b, :a] }
541
+ end
542
+
543
+ it "should return all values by Multimap#values" do
544
+ @mm_base.values.should == {"foo" => 3, "bar" => 3, "hoge" => 4, "moe" => 1}.to_multiset
545
+ end
546
+
547
+ # empty?
548
+ it "should return true by Multimap#empty? if and only if it is empty" do
549
+ mm = @mm_base.dup
550
+ mm[:a] = []
551
+ mm.delete :b
552
+ mm.should be_empty
553
+
554
+ mm[:c] = [:x]
555
+ mm.should_not be_empty
556
+ end
557
+
558
+ # has_key?
559
+ it "should return true by Multimap#has_key? if and only if it has the given key" do
560
+ mm = @mm_base.dup
561
+ mm[:c] = []
562
+ mm[:d] = [:z]
563
+ mm.should have_key(:a)
564
+ mm.should have_key(:b)
565
+ mm.should_not have_key(:c)
566
+ mm.should be_member(:d)
567
+ mm.should_not be_member(:x)
568
+ end
569
+
570
+ # has_value?
571
+ it "should return true by Multimap#has_value? if and only if it has the given value" do
572
+ mm = @mm_base.dup
573
+ mm[:c] = []
574
+ mm[:d] = [:z]
575
+ mm.should have_value("foo")
576
+ mm.should have_value(:z)
577
+ mm.should_not have_value("boo")
578
+ mm.should be_value("hoge")
579
+ mm.should_not be_value(:d)
580
+ end
581
+
582
+ # index
583
+ it "should find a value and return a key by Multimap#index" do
584
+ mm = @mm_base.dup
585
+ mm.index("moe").should == :a
586
+ [:a, :b].should be_member(mm.index("hoge"))
587
+ mm.index("boo").should == nil
588
+ end
589
+
590
+ # values_at
591
+ it "should find a corresponding values as multisets by Multimap#values_at" do
592
+ mm = @mm_base.dup
593
+ mm[:x] = []
594
+
595
+ mm.values_at(:b, :x, :a).should == [
596
+ Multiset["foo", "bar", "hoge", "hoge", "bar"],
597
+ Multiset[],
598
+ Multiset["foo", "foo", "bar", "hoge", "hoge", "moe"],
599
+ ]
600
+
601
+ mm.indexes(:b, :x, :a).should == mm.values_at(:b, :x, :a)
602
+ end
603
+
604
+ # length, size
605
+ it "should return the collect number of entries by Multimap#length/size" do
606
+ mm = @mm_base.dup
607
+ mm.length.should == 11
608
+ mm[:c] = [:y]
609
+ mm.length.should == 12
610
+ mm.length.should == mm.size
611
+ end
612
+ end
613
+ end
614
+
615
+ describe Hash, "when converted to a multimap" do
616
+ it "should regard keys as multimap keys and values as multisets by Hash#to_multimap" do
617
+ # to_multimap / multimap
618
+ mm = {:a => [3, 3], :b => [5, 3]}.to_multimap
619
+ mm[:a].should == Multiset[3, 3]
620
+ mm[:b].should == Multiset[5, 3]
621
+ end
622
+
623
+ it "should regard keys as multimap keys and values as multisets by Hash#multimap" do
624
+ mm = {:a => [3, 3], :b => [5, 3]}.multimap
625
+ mm[:a].should == Multiset[[3, 3]]
626
+ mm[:b].should == Multiset[[5, 3]]
627
+ end
12
628
  end
629
+