structx 0.1.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/.gitignore +19 -0
- data/.simplecov +8 -0
- data/.travis.yml +8 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +61 -0
- data/Rakefile +18 -0
- data/lib/structx.rb +169 -0
- data/lib/structx/version.rb +4 -0
- data/structx.gemspec +29 -0
- data/test/compatibility-test.rb +32 -0
- data/test/ruby/1.9/envutil.rb +212 -0
- data/test/ruby/1.9/test_struct.rb +252 -0
- data/test/ruby/2.0/envutil.rb +362 -0
- data/test/ruby/2.0/test_struct.rb +284 -0
- data/test/run.sh +12 -0
- data/test/spec_structx.rb +193 -0
- metadata +166 -0
@@ -0,0 +1,284 @@
|
|
1
|
+
# -*- coding: us-ascii -*-
|
2
|
+
require 'test/unit'
|
3
|
+
require 'timeout'
|
4
|
+
require_relative 'envutil'
|
5
|
+
|
6
|
+
class TestStruct < Test::Unit::TestCase
|
7
|
+
def test_struct
|
8
|
+
struct_test = Struct.new("Test", :foo, :bar)
|
9
|
+
assert_equal(Struct::Test, struct_test)
|
10
|
+
|
11
|
+
test = struct_test.new(1, 2)
|
12
|
+
assert_equal(1, test.foo)
|
13
|
+
assert_equal(2, test.bar)
|
14
|
+
assert_equal(1, test[0])
|
15
|
+
assert_equal(2, test[1])
|
16
|
+
|
17
|
+
a, b = test.to_a
|
18
|
+
assert_equal(1, a)
|
19
|
+
assert_equal(2, b)
|
20
|
+
|
21
|
+
test[0] = 22
|
22
|
+
assert_equal(22, test.foo)
|
23
|
+
|
24
|
+
test.bar = 47
|
25
|
+
assert_equal(47, test.bar)
|
26
|
+
end
|
27
|
+
|
28
|
+
# [ruby-dev:26247] more than 10 struct members causes segmentation fault
|
29
|
+
def test_morethan10members
|
30
|
+
list = %w( a b c d e f g h i j k l m n o p )
|
31
|
+
until list.empty?
|
32
|
+
c = Struct.new(* list.map {|ch| ch.intern }).new
|
33
|
+
list.each do |ch|
|
34
|
+
c.__send__(ch)
|
35
|
+
end
|
36
|
+
list.pop
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_small_structs
|
41
|
+
names = [:a, :b, :c, :d]
|
42
|
+
1.upto(4) {|n|
|
43
|
+
fields = names[0, n]
|
44
|
+
klass = Struct.new(*fields)
|
45
|
+
o = klass.new(*(0...n).to_a)
|
46
|
+
fields.each_with_index {|name, i|
|
47
|
+
assert_equal(i, o[name])
|
48
|
+
}
|
49
|
+
o = klass.new(*(0...n).to_a.reverse)
|
50
|
+
fields.each_with_index {|name, i|
|
51
|
+
assert_equal(n-i-1, o[name])
|
52
|
+
}
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_inherit
|
57
|
+
klass = Struct.new(:a)
|
58
|
+
klass2 = Class.new(klass)
|
59
|
+
o = klass2.new(1)
|
60
|
+
assert_equal(1, o.a)
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_members
|
64
|
+
klass = Struct.new(:a)
|
65
|
+
o = klass.new(1)
|
66
|
+
assert_equal([:a], klass.members)
|
67
|
+
assert_equal([:a], o.members)
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_ref
|
71
|
+
klass = Struct.new(:a)
|
72
|
+
o = klass.new(1)
|
73
|
+
assert_equal(1, o[:a])
|
74
|
+
assert_raise(NameError) { o[:b] }
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_modify
|
78
|
+
klass = Struct.new(:a)
|
79
|
+
o = klass.new(1)
|
80
|
+
assert_raise(SecurityError) do
|
81
|
+
Thread.new do
|
82
|
+
$SAFE = 4
|
83
|
+
o.a = 2
|
84
|
+
end.value
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_set
|
89
|
+
klass = Struct.new(:a)
|
90
|
+
o = klass.new(1)
|
91
|
+
o[:a] = 2
|
92
|
+
assert_equal(2, o[:a])
|
93
|
+
assert_raise(NameError) { o[:b] = 3 }
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_struct_new
|
97
|
+
assert_raise(NameError) { Struct.new("foo") }
|
98
|
+
assert_nothing_raised { Struct.new("Foo") }
|
99
|
+
Struct.instance_eval { remove_const(:Foo) }
|
100
|
+
assert_nothing_raised { Struct.new(:a) { } }
|
101
|
+
assert_raise(RuntimeError) { Struct.new(:a) { raise } }
|
102
|
+
|
103
|
+
assert_equal([:utime, :stime, :cutime, :cstime], Process.times.members)
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_initialize
|
107
|
+
klass = Struct.new(:a)
|
108
|
+
assert_raise(ArgumentError) { klass.new(1, 2) }
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_each
|
112
|
+
klass = Struct.new(:a, :b)
|
113
|
+
o = klass.new(1, 2)
|
114
|
+
assert_equal([1, 2], o.each.to_a)
|
115
|
+
end
|
116
|
+
|
117
|
+
def test_each_pair
|
118
|
+
klass = Struct.new(:a, :b)
|
119
|
+
o = klass.new(1, 2)
|
120
|
+
assert_equal([[:a, 1], [:b, 2]], o.each_pair.to_a)
|
121
|
+
bug7382 = '[ruby-dev:46533]'
|
122
|
+
a = []
|
123
|
+
o.each_pair {|x| a << x}
|
124
|
+
assert_equal([[:a, 1], [:b, 2]], a, bug7382)
|
125
|
+
end
|
126
|
+
|
127
|
+
def test_inspect
|
128
|
+
klass = Struct.new(:a)
|
129
|
+
o = klass.new(1)
|
130
|
+
assert_equal("#<struct a=1>", o.inspect)
|
131
|
+
o.a = o
|
132
|
+
assert_match(/^#<struct a=#<struct #<.*?>:...>>$/, o.inspect)
|
133
|
+
|
134
|
+
Struct.new("Foo", :a)
|
135
|
+
o = Struct::Foo.new(1)
|
136
|
+
assert_equal("#<struct Struct::Foo a=1>", o.inspect)
|
137
|
+
Struct.instance_eval { remove_const(:Foo) }
|
138
|
+
|
139
|
+
klass = Struct.new(:a, :b)
|
140
|
+
o = klass.new(1, 2)
|
141
|
+
assert_equal("#<struct a=1, b=2>", o.inspect)
|
142
|
+
|
143
|
+
klass = Struct.new(:@a)
|
144
|
+
o = klass.new(1)
|
145
|
+
assert_equal("#<struct :@a=1>", o.inspect)
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_init_copy
|
149
|
+
klass = Struct.new(:a)
|
150
|
+
o = klass.new(1)
|
151
|
+
assert_equal(o, o.dup)
|
152
|
+
end
|
153
|
+
|
154
|
+
def test_aref
|
155
|
+
klass = Struct.new(:a)
|
156
|
+
o = klass.new(1)
|
157
|
+
assert_equal(1, o[0])
|
158
|
+
assert_raise(IndexError) { o[-2] }
|
159
|
+
assert_raise(IndexError) { o[1] }
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_aset
|
163
|
+
klass = Struct.new(:a)
|
164
|
+
o = klass.new(1)
|
165
|
+
o[0] = 2
|
166
|
+
assert_equal(2, o[:a])
|
167
|
+
assert_raise(IndexError) { o[-2] = 3 }
|
168
|
+
assert_raise(IndexError) { o[1] = 3 }
|
169
|
+
end
|
170
|
+
|
171
|
+
def test_values_at
|
172
|
+
klass = Struct.new(:a, :b, :c, :d, :e, :f)
|
173
|
+
o = klass.new(1, 2, 3, 4, 5, 6)
|
174
|
+
assert_equal([2, 4, 6], o.values_at(1, 3, 5))
|
175
|
+
assert_equal([2, 3, 4, 3, 4, 5], o.values_at(1..3, 2...5))
|
176
|
+
end
|
177
|
+
|
178
|
+
def test_select
|
179
|
+
klass = Struct.new(:a, :b, :c, :d, :e, :f)
|
180
|
+
o = klass.new(1, 2, 3, 4, 5, 6)
|
181
|
+
assert_equal([1, 3, 5], o.select {|v| v % 2 != 0 })
|
182
|
+
assert_raise(ArgumentError) { o.select(1) }
|
183
|
+
end
|
184
|
+
|
185
|
+
def test_equal
|
186
|
+
klass1 = Struct.new(:a)
|
187
|
+
klass2 = Struct.new(:a, :b)
|
188
|
+
o1 = klass1.new(1)
|
189
|
+
o2 = klass1.new(1)
|
190
|
+
o3 = klass2.new(1)
|
191
|
+
assert(o1.==(o2))
|
192
|
+
assert(o1 != o3)
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_hash
|
196
|
+
klass = Struct.new(:a)
|
197
|
+
o = klass.new(1)
|
198
|
+
assert(o.hash.is_a?(Fixnum))
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_eql
|
202
|
+
klass1 = Struct.new(:a)
|
203
|
+
klass2 = Struct.new(:a, :b)
|
204
|
+
o1 = klass1.new(1)
|
205
|
+
o2 = klass1.new(1)
|
206
|
+
o3 = klass2.new(1)
|
207
|
+
assert(o1.eql?(o2))
|
208
|
+
assert(!(o1.eql?(o3)))
|
209
|
+
end
|
210
|
+
|
211
|
+
def test_size
|
212
|
+
klass = Struct.new(:a)
|
213
|
+
o = klass.new(1)
|
214
|
+
assert_equal(1, o.size)
|
215
|
+
end
|
216
|
+
|
217
|
+
def test_error
|
218
|
+
assert_raise(TypeError){
|
219
|
+
Struct.new(0)
|
220
|
+
}
|
221
|
+
end
|
222
|
+
|
223
|
+
def test_nonascii
|
224
|
+
struct_test = Struct.new("R\u{e9}sum\u{e9}", :"r\u{e9}sum\u{e9}")
|
225
|
+
assert_equal(Struct.const_get("R\u{e9}sum\u{e9}"), struct_test, '[ruby-core:24849]')
|
226
|
+
a = struct_test.new(42)
|
227
|
+
assert_equal("#<struct Struct::R\u{e9}sum\u{e9} r\u{e9}sum\u{e9}=42>", a.inspect, '[ruby-core:24849]')
|
228
|
+
end
|
229
|
+
|
230
|
+
def test_junk
|
231
|
+
struct_test = Struct.new("Foo", "a\000")
|
232
|
+
o = struct_test.new(1)
|
233
|
+
assert_equal(1, o.send("a\000"))
|
234
|
+
Struct.instance_eval { remove_const(:Foo) }
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_comparison_when_recursive
|
238
|
+
klass1 = Struct.new(:a, :b, :c)
|
239
|
+
|
240
|
+
x = klass1.new(1, 2, nil); x.c = x
|
241
|
+
y = klass1.new(1, 2, nil); y.c = y
|
242
|
+
Timeout.timeout(1) {
|
243
|
+
assert x == y
|
244
|
+
assert x.eql? y
|
245
|
+
}
|
246
|
+
|
247
|
+
z = klass1.new(:something, :other, nil); z.c = z
|
248
|
+
Timeout.timeout(1) {
|
249
|
+
assert x != z
|
250
|
+
assert !x.eql?(z)
|
251
|
+
}
|
252
|
+
|
253
|
+
x.c = y; y.c = x
|
254
|
+
Timeout.timeout(1) {
|
255
|
+
assert x == y
|
256
|
+
assert x.eql?(y)
|
257
|
+
}
|
258
|
+
|
259
|
+
x.c = z; z.c = x
|
260
|
+
Timeout.timeout(1) {
|
261
|
+
assert x != z
|
262
|
+
assert !x.eql?(z)
|
263
|
+
}
|
264
|
+
end
|
265
|
+
|
266
|
+
def test_struct_subclass
|
267
|
+
bug5036 = '[ruby-dev:44122]'
|
268
|
+
st = Class.new(Struct)
|
269
|
+
s = st.new("S", :m).new
|
270
|
+
error = assert_raise(SecurityError) do
|
271
|
+
proc do
|
272
|
+
$SAFE = 4
|
273
|
+
s.m = 1
|
274
|
+
end.call
|
275
|
+
end
|
276
|
+
assert_equal("Insecure: can't modify #{st}::S", error.message, bug5036)
|
277
|
+
end
|
278
|
+
|
279
|
+
def test_to_h
|
280
|
+
klass = Struct.new(:a, :b, :c, :d, :e, :f)
|
281
|
+
o = klass.new(1, 2, 3, 4, 5, 6)
|
282
|
+
assert_equal({a:1, b:2, c:3, d:4, e:5, f:6}, o.to_h)
|
283
|
+
end
|
284
|
+
end
|
data/test/run.sh
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
require "structx"
|
2
|
+
|
3
|
+
class A < StructX
|
4
|
+
member :x
|
5
|
+
member :y, default: 10
|
6
|
+
member :z, type: Integer, default: 100
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "StructX" do
|
10
|
+
describe "StructX.new(:x, :y, :z)" do
|
11
|
+
before do
|
12
|
+
@class = StructX.new(:x, :y, :z)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should have 3 members" do
|
16
|
+
@class.members.size.should == 3
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should create from StructX subclass" do
|
20
|
+
should.not.raise do
|
21
|
+
Class.new(StructX).new(:x).new(1)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should inherit members" do
|
26
|
+
Class.new(@class).members.should == [:x, :y, :z]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should create an instance" do
|
30
|
+
@class.new(1, 2, 3).tap do |obj|
|
31
|
+
obj.x.should == 1
|
32
|
+
obj.y.should == 2
|
33
|
+
obj.z.should == 3
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should create an instance with key" do
|
38
|
+
@class.new(x: 1, y: 2, z: 3).tap do |obj|
|
39
|
+
obj.x.should == 1
|
40
|
+
obj.y.should == 2
|
41
|
+
obj.z.should == 3
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should get members" do
|
46
|
+
@class.members.tap do |m|
|
47
|
+
m.should.include(:x)
|
48
|
+
m.should.include(:y)
|
49
|
+
m.should.include(:z)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should raise ArgumentError when number of values are greater than number of members" do
|
54
|
+
should.raise(ArgumentError) do
|
55
|
+
@class.new(1, 2, 3, 4)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should create an instance with #[]" do
|
60
|
+
@class[1, 2, 3].tap do |obj|
|
61
|
+
obj.x.should == 1
|
62
|
+
obj.y.should == 2
|
63
|
+
obj.z.should == 3
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should equal" do
|
68
|
+
@class.new(1, 2, 3).should == @class.new(1, 2, 3)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should write and get member's value" do
|
72
|
+
@class.new(1, 2, 3).tap do |obj|
|
73
|
+
obj.x = 2
|
74
|
+
obj.y = 3
|
75
|
+
obj.z = 4
|
76
|
+
obj.x.should == 2
|
77
|
+
obj.y.should == 3
|
78
|
+
obj.z.should == 4
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should get member's value with index" do
|
83
|
+
@class.new(1, 2, 3).tap do |x|
|
84
|
+
x[0].should == 1
|
85
|
+
x[1].should == 2
|
86
|
+
x[2].should == 3
|
87
|
+
should.raise(IndexError) { x[-4] }
|
88
|
+
should.raise(IndexError) { x[3] }
|
89
|
+
x[:x].should == 1
|
90
|
+
x[:y].should == 2
|
91
|
+
x[:z].should == 3
|
92
|
+
should.raise(NameError) { x[:a] }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should set member's value with index" do
|
97
|
+
@class.new(1, 2, 3).tap do |x|
|
98
|
+
x[0] = 2
|
99
|
+
x[1] = 3
|
100
|
+
x[2] = 4
|
101
|
+
x[0].should == 2
|
102
|
+
x[1].should == 3
|
103
|
+
x[2].should == 4
|
104
|
+
should.raise(IndexError) { x[-4] = 1 }
|
105
|
+
should.raise(IndexError) { x[3] = 1 }
|
106
|
+
x[:x] = 3
|
107
|
+
x[:y] = 4
|
108
|
+
x[:z] = 5
|
109
|
+
x[:x].should == 3
|
110
|
+
x[:y].should == 4
|
111
|
+
x[:z].should == 5
|
112
|
+
should.raise(NameError) { x[:a] = 1}
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
it "should iterate values" do
|
117
|
+
vals = []
|
118
|
+
@class.new(1, 2, 3).tap{|x| x.each {|val| vals << val}; vals.should == x.values}
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should iterate pairs of key and value" do
|
122
|
+
vals = []
|
123
|
+
@class.new(1, 2, 3).tap{|x| x.each_pair {|k, v| vals << [k, v]}; vals.should == x.to_h.to_a}
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should get size" do
|
127
|
+
@class.new(1, 2, 3).size.should == 3
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should get members as strings" do
|
131
|
+
@class.new.members.should == [:x, :y, :z]
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should select" do
|
135
|
+
@class.new(1, 2, 3).select{|i| i.odd?}.should == [1, 3]
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should get values" do
|
139
|
+
@class.new(1, 2, 3).values.should == [1, 2, 3]
|
140
|
+
end
|
141
|
+
|
142
|
+
it "should get values at" do
|
143
|
+
@class.new(1, 2, 3).values_at(0..1).should == [1, 2]
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
StructX.new("TestName", :x, :y)
|
148
|
+
|
149
|
+
describe 'StructX.new("TestName", :x, :y)' do
|
150
|
+
it "should have 2 members" do
|
151
|
+
StructX::TestName.members.size.should == 2
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should create class" do
|
155
|
+
should.not.raise {StructX::TestName}
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should get values" do
|
159
|
+
StructX::TestName.new(1, 2).tap do |obj|
|
160
|
+
obj.x.should == 1
|
161
|
+
obj.y.should == 2
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe "A < StructX" do
|
167
|
+
it "should have 3 members" do
|
168
|
+
A.members.size.should == 3
|
169
|
+
end
|
170
|
+
|
171
|
+
it "should get members" do
|
172
|
+
A.new(x: 1, y: 2, z: 3).tap do |obj|
|
173
|
+
obj.x.should == 1
|
174
|
+
obj.y.should == 2
|
175
|
+
obj.z.should == 3
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
it "should get default value" do
|
180
|
+
A.new(1).tap do |obj|
|
181
|
+
obj.x.should == 1
|
182
|
+
obj.y.should == 10
|
183
|
+
obj.z.should == 100
|
184
|
+
end
|
185
|
+
A.new.tap do |obj|
|
186
|
+
obj.x.should == nil
|
187
|
+
obj.y.should == 10
|
188
|
+
obj.z.should == 100
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|