blockenspiel 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/tests/tc_basic.rb ADDED
@@ -0,0 +1,135 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Blockenspiel basic tests
4
+ #
5
+ # This file contains tests for the simple use cases.
6
+ #
7
+ # -----------------------------------------------------------------------------
8
+ # Copyright 2008 Daniel Azuma
9
+ #
10
+ # All rights reserved.
11
+ #
12
+ # Redistribution and use in source and binary forms, with or without
13
+ # modification, are permitted provided that the following conditions are met:
14
+ #
15
+ # * Redistributions of source code must retain the above copyright notice,
16
+ # this list of conditions and the following disclaimer.
17
+ # * Redistributions in binary form must reproduce the above copyright notice,
18
+ # this list of conditions and the following disclaimer in the documentation
19
+ # and/or other materials provided with the distribution.
20
+ # * Neither the name of the copyright holder, nor the names of any other
21
+ # contributors to this software, may be used to endorse or promote products
22
+ # derived from this software without specific prior written permission.
23
+ #
24
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34
+ # POSSIBILITY OF SUCH DAMAGE.
35
+ # -----------------------------------------------------------------------------
36
+
37
+
38
+ require File.expand_path("#{File.dirname(__FILE__)}/../lib/blockenspiel.rb")
39
+
40
+
41
+ module Blockenspiel
42
+ module Tests # :nodoc:
43
+
44
+ class TestBasic < Test::Unit::TestCase # :nodoc:
45
+
46
+
47
+ class SimpleTarget < Blockenspiel::Base
48
+
49
+ def initialize
50
+ @hash = Hash.new
51
+ end
52
+
53
+ def set_value(key_, value_)
54
+ @hash[key_] = value_
55
+ end
56
+
57
+ def set_value_by_block(key_)
58
+ @hash[key_] = yield
59
+ end
60
+
61
+ def get_value(key_)
62
+ @hash[key_]
63
+ end
64
+ dsl_method :get_value, false
65
+
66
+ end
67
+
68
+
69
+ # Test basic usage with a parameter object.
70
+ #
71
+ # * Asserts that methods are not mixed in to self.
72
+ # * Asserts that the specified target object does in fact receive the block messages.
73
+
74
+ def test_basic_param
75
+ block_ = proc do |t_|
76
+ t_.set_value(:a, 1)
77
+ t_.set_value_by_block(:b){ 2 }
78
+ assert(!self.respond_to?(:set_value))
79
+ assert(!self.respond_to?(:set_value_by_block))
80
+ end
81
+ target_ = SimpleTarget.new
82
+ Blockenspiel.invoke(block_, target_)
83
+ assert_equal(1, target_.get_value(:a))
84
+ assert_equal(2, target_.get_value(:b))
85
+ end
86
+
87
+
88
+ # Test basic usage with a mixin.
89
+ #
90
+ # * Asserts that methods are mixed in to self.
91
+ # * Asserts that methods are removed from self afterward.
92
+ # * Asserts that the specified target object still receives the messages.
93
+
94
+ def test_basic_mixin
95
+ block_ = proc do
96
+ set_value(:a, 1)
97
+ set_value_by_block(:b){ 2 }
98
+ end
99
+ target_ = SimpleTarget.new
100
+ Blockenspiel.invoke(block_, target_)
101
+ assert(!self.respond_to?(:set_value))
102
+ assert(!self.respond_to?(:set_value_by_block))
103
+ assert_equal(1, target_.get_value(:a))
104
+ assert_equal(2, target_.get_value(:b))
105
+ end
106
+
107
+
108
+ # Test basic usage with a builder.
109
+ #
110
+ # * Asserts that the receivers are called.
111
+ # * Asserts that receivers with blocks are handled properly.
112
+
113
+ def test_basic_builder
114
+ block_ = proc do
115
+ set_value(:a, 1)
116
+ set_value_by_block(:b){ 2 }
117
+ end
118
+ hash_ = Hash.new
119
+ Blockenspiel.invoke(block_) do
120
+ add_method(:set_value) do |key_, value_|
121
+ hash_[key_] = value_
122
+ end
123
+ add_method(:set_value_by_block, :receive_block => true) do |key_, bl_|
124
+ hash_[key_] = bl_.call
125
+ end
126
+ end
127
+ assert_equal(1, hash_[:a])
128
+ assert_equal(2, hash_[:b])
129
+ end
130
+
131
+
132
+ end
133
+
134
+ end
135
+ end
@@ -0,0 +1,283 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Blockenspiel dsl method tests
4
+ #
5
+ # This file contains tests for the dsl method directives.
6
+ #
7
+ # -----------------------------------------------------------------------------
8
+ # Copyright 2008 Daniel Azuma
9
+ #
10
+ # All rights reserved.
11
+ #
12
+ # Redistribution and use in source and binary forms, with or without
13
+ # modification, are permitted provided that the following conditions are met:
14
+ #
15
+ # * Redistributions of source code must retain the above copyright notice,
16
+ # this list of conditions and the following disclaimer.
17
+ # * Redistributions in binary form must reproduce the above copyright notice,
18
+ # this list of conditions and the following disclaimer in the documentation
19
+ # and/or other materials provided with the distribution.
20
+ # * Neither the name of the copyright holder, nor the names of any other
21
+ # contributors to this software, may be used to endorse or promote products
22
+ # derived from this software without specific prior written permission.
23
+ #
24
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
28
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34
+ # POSSIBILITY OF SUCH DAMAGE.
35
+ # -----------------------------------------------------------------------------
36
+
37
+
38
+ require File.expand_path("#{File.dirname(__FILE__)}/../lib/blockenspiel.rb")
39
+
40
+
41
+ module Blockenspiel
42
+ module Tests # :nodoc:
43
+
44
+ class TestDSLMethods < Test::Unit::TestCase # :nodoc:
45
+
46
+
47
+ class Target1 < Blockenspiel::Base
48
+
49
+ def initialize(hash_)
50
+ @hash = hash_
51
+ end
52
+
53
+ def set_value1(key_, value_)
54
+ @hash["#{key_}1"] = value_
55
+ end
56
+
57
+ def set_value2(key_)
58
+ @hash["#{key_}2"] = yield
59
+ end
60
+
61
+ def _set_value3(key_, value_)
62
+ @hash["#{key_}3"] = value_
63
+ end
64
+
65
+ end
66
+
67
+
68
+ class Target2 < Blockenspiel::Base
69
+
70
+ def initialize(hash_)
71
+ @hash = hash_
72
+ end
73
+
74
+ dsl_methods false
75
+
76
+ def set_value1(key_, value_)
77
+ @hash["#{key_}1"] = value_
78
+ end
79
+
80
+ dsl_methods true
81
+
82
+ def set_value2(key_)
83
+ @hash["#{key_}2"] = yield
84
+ end
85
+
86
+ def _set_value3(key_, value_)
87
+ @hash["#{key_}3"] = value_
88
+ end
89
+
90
+ end
91
+
92
+
93
+ class Target3 < Blockenspiel::Base
94
+
95
+ def initialize(hash_)
96
+ @hash = hash_
97
+ end
98
+
99
+ dsl_methods false
100
+
101
+ def set_value1(key_, value_)
102
+ @hash["#{key_}1"] = value_
103
+ end
104
+ dsl_method :set_value1
105
+
106
+ def set_value2(key_)
107
+ @hash["#{key_}2"] = yield
108
+ end
109
+ dsl_method :renamed_set_value2, :set_value2
110
+ dsl_method :another_set_value2, :set_value2
111
+
112
+ end
113
+
114
+
115
+ class Target4 < Blockenspiel::Base
116
+
117
+ def initialize(hash_)
118
+ @hash = hash_
119
+ end
120
+
121
+ def set_value1(key_, value_)
122
+ @hash["#{key_}1"] = value_
123
+ end
124
+ dsl_method :set_value1, false
125
+
126
+ def set_value2(key_)
127
+ @hash["#{key_}2"] = yield
128
+ end
129
+ dsl_method :set_value2, false
130
+ dsl_method :renamed_set_value2, :set_value2
131
+
132
+ end
133
+
134
+
135
+ class Target5a < Blockenspiel::Base
136
+
137
+ def initialize(hash_)
138
+ @hash = hash_
139
+ end
140
+
141
+ def set_value1(key_, value_)
142
+ @hash["#{key_}1"] = value_
143
+ end
144
+
145
+ def set_value2(key_)
146
+ @hash["#{key_}2"] = yield
147
+ end
148
+
149
+ def set_value3(key_, value_)
150
+ @hash["#{key_}3"] = value_
151
+ end
152
+
153
+ def set_value4(key_, value_)
154
+ @hash["#{key_}4"] = value_
155
+ end
156
+ dsl_method :set_value4, false
157
+ dsl_method :renamed_set_value4, :set_value4
158
+
159
+ end
160
+
161
+
162
+ class Target5b < Target5a
163
+
164
+ def set_value1(key_, value_)
165
+ @hash["#{key_}1sub"] = value_
166
+ end
167
+
168
+ dsl_method :set_value3, false
169
+
170
+ def set_value5(key_, value_)
171
+ @hash["#{key_}5"] = value_
172
+ end
173
+
174
+ end
175
+
176
+
177
+ # Test default dsl method setting.
178
+ #
179
+ # * Asserts the right dsl methods are added for the default setting.
180
+
181
+ def test_default_setting
182
+ hash_ = Hash.new
183
+ block_ = proc do
184
+ set_value1('a', 1)
185
+ set_value2('b'){ 2 }
186
+ assert_raise(NoMethodError){ _set_value3('c', 3) }
187
+ end
188
+ Blockenspiel.invoke(block_, Target1.new(hash_))
189
+ assert_equal(1, hash_['a1'])
190
+ assert_equal(2, hash_['b2'])
191
+ assert_nil(hash_['c3'])
192
+ end
193
+
194
+
195
+ # Test dsl_methods true and false switching.
196
+ #
197
+ # * Asserts that dsl_methods false turns off automatic method creation.
198
+ # * Asserts that dsl_methods true turns on automatic method creation.
199
+ # * Asserts that underscore methods are added in dsl_methods true mode.
200
+
201
+ def test_onoff_switching
202
+ hash_ = Hash.new
203
+ block_ = proc do
204
+ assert_raise(NoMethodError){ _set_value1('a', 1) }
205
+ set_value2('b'){ 2 }
206
+ _set_value3('c', 3)
207
+ end
208
+ Blockenspiel.invoke(block_, Target2.new(hash_))
209
+ assert_nil(hash_['a1'])
210
+ assert_equal(2, hash_['b2'])
211
+ assert_equal(3, hash_['c3'])
212
+ end
213
+
214
+
215
+ # Test dsl_methods explicit adding.
216
+ #
217
+ # * Asserts that adding an explicit dsl method works.
218
+ # * Asserts that adding an explicit dsl method with a different name works.
219
+
220
+ def test_explicit_add
221
+ hash_ = Hash.new
222
+ block_ = proc do
223
+ set_value1('a', 1)
224
+ assert_raise(NoMethodError){ set_value2('b'){ 2 } }
225
+ renamed_set_value2('c'){ 3 }
226
+ another_set_value2('d'){ 4 }
227
+ end
228
+ Blockenspiel.invoke(block_, Target3.new(hash_))
229
+ assert_equal(1, hash_['a1'])
230
+ assert_nil(hash_['b2'])
231
+ assert_equal(3, hash_['c2'])
232
+ assert_equal(4, hash_['d2'])
233
+ end
234
+
235
+
236
+ # Test dsl_methods explicit removing.
237
+ #
238
+ # * Asserts that removing a dsl method works.
239
+ # * Asserts that re-adding a removed method with a different name works.
240
+
241
+ def test_explicit_removing
242
+ hash_ = Hash.new
243
+ block_ = proc do
244
+ assert_raise(NoMethodError){ set_value1('a', 1) }
245
+ assert_raise(NoMethodError){ set_value2('b'){ 2 } }
246
+ renamed_set_value2('c'){ 3 }
247
+ end
248
+ Blockenspiel.invoke(block_, Target4.new(hash_))
249
+ assert_nil(hash_['a1'])
250
+ assert_nil(hash_['b2'])
251
+ assert_equal(3, hash_['c2'])
252
+ end
253
+
254
+
255
+ # Test dsl method setting with subclasses
256
+ #
257
+ # * Asserts that modules are properly inherited.
258
+ # * Asserts that method overriding is done correctly.
259
+
260
+ def test_subclassing
261
+ hash_ = Hash.new
262
+ block_ = proc do
263
+ set_value1('a', 1)
264
+ set_value2('b'){ 2 }
265
+ assert_raise(NoMethodError){ set_value3('c', 3) }
266
+ assert_raise(NoMethodError){ set_value4('d', 4) }
267
+ renamed_set_value4('e', 5)
268
+ set_value5('f', 6)
269
+ end
270
+ Blockenspiel.invoke(block_, Target5b.new(hash_))
271
+ assert_equal(1, hash_['a1sub'])
272
+ assert_equal(2, hash_['b2'])
273
+ assert_nil(hash_['c3'])
274
+ assert_nil(hash_['d4'])
275
+ assert_equal(5, hash_['e4'])
276
+ assert_equal(6, hash_['f5'])
277
+ end
278
+
279
+
280
+ end
281
+
282
+ end
283
+ end
@@ -0,0 +1,206 @@
1
+ # -----------------------------------------------------------------------------
2
+ #
3
+ # Blockenspiel mixin tests
4
+ #
5
+ # This file contains tests for various mixin cases,
6
+ # including nested blocks and multithreading.
7
+ #
8
+ # -----------------------------------------------------------------------------
9
+ # Copyright 2008 Daniel Azuma
10
+ #
11
+ # All rights reserved.
12
+ #
13
+ # Redistribution and use in source and binary forms, with or without
14
+ # modification, are permitted provided that the following conditions are met:
15
+ #
16
+ # * Redistributions of source code must retain the above copyright notice,
17
+ # this list of conditions and the following disclaimer.
18
+ # * Redistributions in binary form must reproduce the above copyright notice,
19
+ # this list of conditions and the following disclaimer in the documentation
20
+ # and/or other materials provided with the distribution.
21
+ # * Neither the name of the copyright holder, nor the names of any other
22
+ # contributors to this software, may be used to endorse or promote products
23
+ # derived from this software without specific prior written permission.
24
+ #
25
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
29
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35
+ # POSSIBILITY OF SUCH DAMAGE.
36
+ # -----------------------------------------------------------------------------
37
+
38
+
39
+ require File.expand_path("#{File.dirname(__FILE__)}/../lib/blockenspiel.rb")
40
+
41
+
42
+ module Blockenspiel
43
+ module Tests # :nodoc:
44
+
45
+ class TestMixins < Test::Unit::TestCase # :nodoc:
46
+
47
+
48
+ class Target1 < Blockenspiel::Base
49
+
50
+ def initialize(hash_)
51
+ @hash = hash_
52
+ end
53
+
54
+ def set_value(key_, value_)
55
+ @hash["#{key_}1"] = value_
56
+ end
57
+
58
+ def set_value2(key_)
59
+ @hash["#{key_}1"] = yield
60
+ end
61
+
62
+ end
63
+
64
+
65
+ class Target2 < Blockenspiel::Base
66
+
67
+ dsl_methods false
68
+
69
+ def initialize(hash_=nil)
70
+ @hash = hash_ || Hash.new
71
+ end
72
+
73
+ def set_value(key_, value_)
74
+ @hash["#{key_}2"] = value_
75
+ end
76
+ dsl_method :set_value
77
+
78
+ def set_value2(key_)
79
+ @hash["#{key_}2"] = yield
80
+ end
81
+ dsl_method :set_value2_inmixin, :set_value2
82
+
83
+ end
84
+
85
+
86
+ # Basic test of mixin mechanism.
87
+ #
88
+ # * Asserts that the mixin methods are added and removed for a single mixin.
89
+ # * Asserts that the methods properly delegate to the target object.
90
+ # * Asserts that self doesn't change, and instance variables are preserved.
91
+
92
+ def test_basic_mixin
93
+ hash_ = Hash.new
94
+ saved_object_id_ = self.object_id
95
+ @my_instance_variable_test = :hello
96
+ assert(!self.respond_to?(:set_value))
97
+ assert(!self.respond_to?(:set_value2))
98
+ block_ = proc do
99
+ set_value('a', 1)
100
+ set_value2('b'){ 2 }
101
+ assert_equal(:hello, @my_instance_variable_test)
102
+ assert_equal(saved_object_id_, self.object_id)
103
+ end
104
+ Blockenspiel.invoke(block_, Target1.new(hash_))
105
+ assert(!self.respond_to?(:set_value))
106
+ assert(!self.respond_to?(:set_value2))
107
+ assert_equal(1, hash_['a1'])
108
+ assert_equal(2, hash_['b1'])
109
+ end
110
+
111
+
112
+ # Test renaming of mixin methods.
113
+ #
114
+ # * Asserts that correctly renamed mixin methods are added and removed.
115
+ # * Asserts that the methods properly delegate to the target object.
116
+
117
+ def test_mixin_with_renaming
118
+ hash_ = Hash.new
119
+ assert(!self.respond_to?(:set_value))
120
+ assert(!self.respond_to?(:set_value2))
121
+ assert(!self.respond_to?(:set_value2_inmixin))
122
+ block_ = proc do
123
+ set_value('a', 1)
124
+ set_value2_inmixin('b'){ 2 }
125
+ assert(!self.respond_to?(:set_value2))
126
+ end
127
+ Blockenspiel.invoke(block_, Target2.new(hash_))
128
+ assert(!self.respond_to?(:set_value))
129
+ assert(!self.respond_to?(:set_value2))
130
+ assert(!self.respond_to?(:set_value2_inmixin))
131
+ assert_equal(1, hash_['a2'])
132
+ assert_equal(2, hash_['b2'])
133
+ end
134
+
135
+
136
+ # Test of two different nested mixins.
137
+ #
138
+ # * Asserts that the right methods are added and removed at the right time.
139
+ # * Asserts that the methods delegate to the right target object, even when
140
+ # multiple mixins add the same method name
141
+
142
+ def test_nested_different
143
+ hash_ = Hash.new
144
+ assert(!self.respond_to?(:set_value))
145
+ assert(!self.respond_to?(:set_value2))
146
+ assert(!self.respond_to?(:set_value2_inmixin))
147
+ Blockenspiel.invoke(proc do
148
+ set_value('a', 1)
149
+ set_value2('b'){ 2 }
150
+ assert(!self.respond_to?(:set_value2_inmixin))
151
+ Blockenspiel.invoke(proc do
152
+ set_value('c', 1)
153
+ set_value2_inmixin('d'){ 2 }
154
+ end, Target2.new(hash_))
155
+ assert(!self.respond_to?(:set_value2_inmixin))
156
+ set_value('e', 1)
157
+ set_value2('f'){ 2 }
158
+ end, Target1.new(hash_))
159
+ assert(!self.respond_to?(:set_value))
160
+ assert(!self.respond_to?(:set_value2))
161
+ assert(!self.respond_to?(:set_value2_inmixin))
162
+ assert_equal(1, hash_['a1'])
163
+ assert_equal(2, hash_['b1'])
164
+ assert_equal(1, hash_['c2'])
165
+ assert_equal(2, hash_['d2'])
166
+ assert_equal(1, hash_['e1'])
167
+ assert_equal(2, hash_['f1'])
168
+ end
169
+
170
+
171
+ # Test of the same mixin nested in itself.
172
+ #
173
+ # * Asserts that the methods are added and removed at the right time.
174
+
175
+ def test_nested_same
176
+ hash_ = Hash.new
177
+ assert(!self.respond_to?(:set_value))
178
+ assert(!self.respond_to?(:set_value2))
179
+ assert(!self.respond_to?(:set_value2_inmixin))
180
+ Blockenspiel.invoke(proc do
181
+ set_value('a', 1)
182
+ set_value2_inmixin('b'){ 2 }
183
+ Blockenspiel.invoke(proc do
184
+ set_value('c', 1)
185
+ set_value2_inmixin('d'){ 2 }
186
+ assert(!self.respond_to?(:set_value2))
187
+ end, Target2.new(hash_))
188
+ set_value('e', 1)
189
+ set_value2_inmixin('f'){ 2 }
190
+ end, Target2.new(hash_))
191
+ assert(!self.respond_to?(:set_value))
192
+ assert(!self.respond_to?(:set_value2))
193
+ assert(!self.respond_to?(:set_value2_inmixin))
194
+ assert_equal(1, hash_['a2'])
195
+ assert_equal(2, hash_['b2'])
196
+ assert_equal(1, hash_['c2'])
197
+ assert_equal(2, hash_['d2'])
198
+ assert_equal(1, hash_['e2'])
199
+ assert_equal(2, hash_['f2'])
200
+ end
201
+
202
+
203
+ end
204
+
205
+ end
206
+ end