construqt-ipaddress 0.8.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.
@@ -0,0 +1,265 @@
1
+ module IPAddress
2
+
3
+ #
4
+ # =NAME
5
+ #
6
+ # IPAddress::Prefix
7
+ #
8
+ # =SYNOPSIS
9
+ #
10
+ # Parent class for Prefix32 and Prefix128
11
+ #
12
+ # =DESCRIPTION
13
+ #
14
+ # IPAddress::Prefix is the parent class for IPAddress::Prefix32
15
+ # and IPAddress::Prefix128, defining some modules in common for
16
+ # both the subclasses.
17
+ #
18
+ # IPAddress::Prefix shouldn't be accesses directly, unless
19
+ # for particular needs.
20
+ #
21
+ class Prefix
22
+
23
+ include Comparable
24
+
25
+ attr_reader :prefix
26
+
27
+ #
28
+ # Creates a new general prefix
29
+ #
30
+ def initialize(num)
31
+ @prefix = num.to_i
32
+ end
33
+
34
+ #
35
+ # Returns a string with the prefix
36
+ #
37
+ def to_s
38
+ "#@prefix"
39
+ end
40
+ alias_method :inspect, :to_s
41
+
42
+ #
43
+ # Returns the prefix
44
+ #
45
+ def to_i
46
+ @prefix
47
+ end
48
+
49
+ #
50
+ # Compare the prefix
51
+ #
52
+ def <=>(oth)
53
+ @prefix <=> oth.to_i
54
+ end
55
+
56
+ #
57
+ # Sums two prefixes or a prefix to a
58
+ # number, returns a Fixnum
59
+ #
60
+ def +(oth)
61
+ if oth.is_a? Fixnum
62
+ self.prefix + oth
63
+ else
64
+ self.prefix + oth.prefix
65
+ end
66
+ end
67
+
68
+ #
69
+ # Returns the difference between two
70
+ # prefixes, or a prefix and a number,
71
+ # as a Fixnum
72
+ #
73
+ def -(oth)
74
+ if oth.is_a? Fixnum
75
+ self.prefix - oth
76
+ else
77
+ (self.prefix - oth.prefix).abs
78
+ end
79
+ end
80
+
81
+ end # class Prefix
82
+
83
+
84
+ class Prefix32 < Prefix
85
+
86
+ IN4MASK = 0xffffffff
87
+
88
+ #
89
+ # Creates a new prefix object for 32 bits IPv4 addresses
90
+ #
91
+ # prefix = IPAddress::Prefix32.new 24
92
+ # #=> 24
93
+ #
94
+ def initialize(num)
95
+ unless (0..32).include? num
96
+ raise ArgumentError, "Prefix must be in range 0..32, got: #{num}"
97
+ end
98
+ super(num)
99
+ end
100
+
101
+ #
102
+ # Returns the length of the host portion
103
+ # of a netmask.
104
+ #
105
+ # prefix = Prefix32.new 24
106
+ #
107
+ # prefix.host_prefix
108
+ # #=> 8
109
+ #
110
+ def host_prefix
111
+ 32 - @prefix
112
+ end
113
+
114
+ #
115
+ # Transforms the prefix into a string of bits
116
+ # representing the netmask
117
+ #
118
+ # prefix = IPAddress::Prefix32.new 24
119
+ #
120
+ # prefix.bits
121
+ # #=> "11111111111111111111111100000000"
122
+ #
123
+ def bits
124
+ "%.32b" % to_u32
125
+ end
126
+
127
+ #
128
+ # Gives the prefix in IPv4 dotted decimal format,
129
+ # i.e. the canonical netmask we're all used to
130
+ #
131
+ # prefix = IPAddress::Prefix32.new 24
132
+ #
133
+ # prefix.to_ip
134
+ # #=> "255.255.255.0"
135
+ #
136
+ def to_ip
137
+ [bits].pack("B*").unpack("CCCC").join(".")
138
+ end
139
+
140
+ #
141
+ # An array of octets of the IPv4 dotted decimal
142
+ # format
143
+ #
144
+ # prefix = IPAddress::Prefix32.new 24
145
+ #
146
+ # prefix.octets
147
+ # #=> [255, 255, 255, 0]
148
+ #
149
+ def octets
150
+ to_ip.split(".").map{|i| i.to_i}
151
+ end
152
+
153
+ #
154
+ # Unsigned 32 bits decimal number representing
155
+ # the prefix
156
+ #
157
+ # prefix = IPAddress::Prefix32.new 24
158
+ #
159
+ # prefix.to_u32
160
+ # #=> 4294967040
161
+ #
162
+ def to_u32
163
+ (IN4MASK >> host_prefix) << host_prefix
164
+ end
165
+
166
+ #
167
+ # Shortcut for the octecs in the dotted decimal
168
+ # representation
169
+ #
170
+ # prefix = IPAddress::Prefix32.new 24
171
+ #
172
+ # prefix[2]
173
+ # #=> 255
174
+ #
175
+ def [](index)
176
+ octets[index]
177
+ end
178
+
179
+ #
180
+ # The hostmask is the contrary of the subnet mask,
181
+ # as it shows the bits that can change within the
182
+ # hosts
183
+ #
184
+ # prefix = IPAddress::Prefix32.new 24
185
+ #
186
+ # prefix.hostmask
187
+ # #=> "0.0.0.255"
188
+ #
189
+ def hostmask
190
+ [~to_u32].pack("N").unpack("CCCC").join(".")
191
+ end
192
+
193
+ #
194
+ # Creates a new prefix by parsing a netmask in
195
+ # dotted decimal form
196
+ #
197
+ # prefix = IPAddress::Prefix32::parse_netmask "255.255.255.0"
198
+ # #=> 24
199
+ #
200
+ def self.parse_netmask(netmask)
201
+ octets = netmask.split(".").map{|i| i.to_i}
202
+ num = octets.pack("C"*octets.size).unpack("B*").first.count "1"
203
+ return self.new(num)
204
+ end
205
+
206
+ end # class Prefix32 < Prefix
207
+
208
+ class Prefix128 < Prefix
209
+
210
+ #
211
+ # Creates a new prefix object for 128 bits IPv6 addresses
212
+ #
213
+ # prefix = IPAddress::Prefix128.new 64
214
+ # #=> 64
215
+ #
216
+ def initialize(num=128)
217
+ unless (0..128).include? num.to_i
218
+ raise ArgumentError, "Prefix must be in range 0..128, got: #{num}"
219
+ end
220
+ super(num.to_i)
221
+ end
222
+
223
+ #
224
+ # Transforms the prefix into a string of bits
225
+ # representing the netmask
226
+ #
227
+ # prefix = IPAddress::Prefix128.new 64
228
+ #
229
+ # prefix.bits
230
+ # #=> "1111111111111111111111111111111111111111111111111111111111111111"
231
+ # "0000000000000000000000000000000000000000000000000000000000000000"
232
+ #
233
+ def bits
234
+ "1" * @prefix + "0" * (128 - @prefix)
235
+ end
236
+
237
+ #
238
+ # Unsigned 128 bits decimal number representing
239
+ # the prefix
240
+ #
241
+ # prefix = IPAddress::Prefix128.new 64
242
+ #
243
+ # prefix.to_u128
244
+ # #=> 340282366920938463444927863358058659840
245
+ #
246
+ def to_u128
247
+ bits.to_i(2)
248
+ end
249
+
250
+ #
251
+ # Returns the length of the host portion
252
+ # of a netmask.
253
+ #
254
+ # prefix = Prefix128.new 96
255
+ #
256
+ # prefix.host_prefix
257
+ # #=> 32
258
+ #
259
+ def host_prefix
260
+ 128 - @prefix
261
+ end
262
+
263
+ end # class Prefix123 < Prefix
264
+
265
+ end # module IPAddress
@@ -0,0 +1,555 @@
1
+ require 'test_helper'
2
+
3
+ class IPv4Test < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @klass = IPAddress::IPv4
7
+
8
+ @valid_ipv4 = {
9
+ "0.0.0.0/0" => ["0.0.0.0", 0],
10
+ "10.0.0.0" => ["10.0.0.0", 32],
11
+ "10.0.0.1" => ["10.0.0.1", 32],
12
+ "10.0.0.1/24" => ["10.0.0.1", 24],
13
+ "10.0.0.1/255.255.255.0" => ["10.0.0.1", 24]}
14
+
15
+ @invalid_ipv4 = ["10.0.0.256",
16
+ "10.0.0.0.0",
17
+ "10.0.0",
18
+ "10.0"]
19
+
20
+ @valid_ipv4_range = ["10.0.0.1-254",
21
+ "10.0.1-254.0",
22
+ "10.1-254.0.0"]
23
+
24
+ @netmask_values = {
25
+ "0.0.0.0/0" => "0.0.0.0",
26
+ "10.0.0.0/8" => "255.0.0.0",
27
+ "172.16.0.0/16" => "255.255.0.0",
28
+ "192.168.0.0/24" => "255.255.255.0",
29
+ "192.168.100.4/30" => "255.255.255.252"}
30
+
31
+ @decimal_values ={
32
+ "0.0.0.0/0" => 0,
33
+ "10.0.0.0/8" => 167772160,
34
+ "172.16.0.0/16" => 2886729728,
35
+ "192.168.0.0/24" => 3232235520,
36
+ "192.168.100.4/30" => 3232261124}
37
+
38
+ @ip = @klass.new("172.16.10.1/24")
39
+ @network = @klass.new("172.16.10.0/24")
40
+
41
+ @broadcast = {
42
+ "10.0.0.0/8" => "10.255.255.255/8",
43
+ "172.16.0.0/16" => "172.16.255.255/16",
44
+ "192.168.0.0/24" => "192.168.0.255/24",
45
+ "192.168.100.4/30" => "192.168.100.7/30"}
46
+
47
+ @networks = {
48
+ "10.5.4.3/8" => "10.0.0.0/8",
49
+ "172.16.5.4/16" => "172.16.0.0/16",
50
+ "192.168.4.3/24" => "192.168.4.0/24",
51
+ "192.168.100.5/30" => "192.168.100.4/30"}
52
+
53
+ @class_a = @klass.new("10.0.0.1/8")
54
+ @class_b = @klass.new("172.16.0.1/16")
55
+ @class_c = @klass.new("192.168.0.1/24")
56
+
57
+ @classful = {
58
+ "10.1.1.1" => 8,
59
+ "150.1.1.1" => 16,
60
+ "200.1.1.1" => 24 }
61
+
62
+ end
63
+
64
+ def test_initialize
65
+ @valid_ipv4.keys.each do |i|
66
+ ip = @klass.new(i)
67
+ assert_instance_of @klass, ip
68
+ end
69
+ assert_instance_of IPAddress::Prefix32, @ip.prefix
70
+ assert_raise (ArgumentError) do
71
+ @klass.new
72
+ end
73
+ assert_nothing_raised do
74
+ @klass.new "10.0.0.0/8"
75
+ end
76
+ end
77
+
78
+ def test_initialize_format_error
79
+ @invalid_ipv4.each do |i|
80
+ assert_raise(ArgumentError) {@klass.new(i)}
81
+ end
82
+ assert_raise (ArgumentError) {@klass.new("10.0.0.0/asd")}
83
+ end
84
+
85
+ def test_initialize_without_prefix
86
+ assert_nothing_raised do
87
+ @klass.new("10.10.0.0")
88
+ end
89
+ ip = @klass.new("10.10.0.0")
90
+ assert_instance_of IPAddress::Prefix32, ip.prefix
91
+ assert_equal 32, ip.prefix.to_i
92
+ end
93
+
94
+ def test_attributes
95
+ @valid_ipv4.each do |arg,attr|
96
+ ip = @klass.new(arg)
97
+ assert_equal attr.first, ip.address
98
+ assert_equal attr.last, ip.prefix.to_i
99
+ end
100
+ end
101
+
102
+ def test_octets
103
+ ip = @klass.new("10.1.2.3/8")
104
+ assert_equal ip.octets, [10,1,2,3]
105
+ end
106
+
107
+ def test_initialize_should_require_ip
108
+ assert_raise(ArgumentError) { @klass.new }
109
+ end
110
+
111
+ def test_method_data
112
+ if RUBY_VERSION < "2.0"
113
+ assert_equal "\254\020\n\001", @ip.data
114
+ else
115
+ assert_equal "\xAC\x10\n\x01".b, @ip.data
116
+ end
117
+ end
118
+
119
+ def test_method_to_string
120
+ @valid_ipv4.each do |arg,attr|
121
+ ip = @klass.new(arg)
122
+ assert_equal attr.join("/"), ip.to_string
123
+ end
124
+ end
125
+
126
+ def test_method_to_s
127
+ @valid_ipv4.each do |arg,attr|
128
+ ip = @klass.new(arg)
129
+ assert_equal attr.first, ip.to_s
130
+ ip = @klass.new(arg)
131
+ assert_equal attr.first, ip.compressed
132
+ end
133
+ end
134
+
135
+ def test_netmask
136
+ @netmask_values.each do |addr,mask|
137
+ ip = @klass.new(addr)
138
+ assert_equal mask, ip.netmask
139
+ end
140
+ end
141
+
142
+ def test_method_to_u32
143
+ @decimal_values.each do |addr,int|
144
+ ip = @klass.new(addr)
145
+ assert_equal int, ip.to_u32
146
+ end
147
+ end
148
+
149
+ def test_method_network?
150
+ assert_equal true, @network.network?
151
+ assert_equal false, @ip.network?
152
+ end
153
+
154
+ def test_one_address_network
155
+ network = @klass.new("172.16.10.1/32")
156
+ assert_equal false, network.network?
157
+ end
158
+
159
+ def test_method_broadcast
160
+ @broadcast.each do |addr,bcast|
161
+ ip = @klass.new(addr)
162
+ assert_instance_of @klass, ip.broadcast
163
+ assert_equal bcast, ip.broadcast.to_string
164
+ end
165
+ end
166
+
167
+ def test_method_network
168
+ @networks.each do |addr,net|
169
+ ip = @klass.new addr
170
+ assert_instance_of @klass, ip.network
171
+ assert_equal net, ip.network.to_string
172
+ end
173
+ end
174
+
175
+ def test_method_bits
176
+ ip = @klass.new("127.0.0.1")
177
+ assert_equal "01111111000000000000000000000001", ip.bits
178
+ end
179
+
180
+ def test_method_first
181
+ ip = @klass.new("192.168.100.0/24")
182
+ assert_instance_of @klass, ip.first
183
+ assert_equal "192.168.100.1", ip.first.to_s
184
+ ip = @klass.new("192.168.100.50/24")
185
+ assert_instance_of @klass, ip.first
186
+ assert_equal "192.168.100.1", ip.first.to_s
187
+ end
188
+
189
+ def test_method_last
190
+ ip = @klass.new("192.168.100.0/24")
191
+ assert_instance_of @klass, ip.last
192
+ assert_equal "192.168.100.254", ip.last.to_s
193
+ ip = @klass.new("192.168.100.50/24")
194
+ assert_instance_of @klass, ip.last
195
+ assert_equal "192.168.100.254", ip.last.to_s
196
+ end
197
+
198
+ def test_method_each_host
199
+ ip = @klass.new("10.0.0.1/29")
200
+ arr = []
201
+ ip.each_host {|i| arr << i.to_s}
202
+ expected = ["10.0.0.1","10.0.0.2","10.0.0.3",
203
+ "10.0.0.4","10.0.0.5","10.0.0.6"]
204
+ assert_equal expected, arr
205
+ end
206
+
207
+ def test_method_each
208
+ ip = @klass.new("10.0.0.1/29")
209
+ arr = []
210
+ ip.each {|i| arr << i.to_s}
211
+ expected = ["10.0.0.0","10.0.0.1","10.0.0.2",
212
+ "10.0.0.3","10.0.0.4","10.0.0.5",
213
+ "10.0.0.6","10.0.0.7"]
214
+ assert_equal expected, arr
215
+ end
216
+
217
+ def test_method_size
218
+ ip = @klass.new("10.0.0.1/29")
219
+ assert_equal 8, ip.size
220
+ end
221
+
222
+ def test_method_hosts
223
+ ip = @klass.new("10.0.0.1/29")
224
+ expected = ["10.0.0.1","10.0.0.2","10.0.0.3",
225
+ "10.0.0.4","10.0.0.5","10.0.0.6"]
226
+ assert_equal expected, ip.hosts.map {|i| i.to_s}
227
+ end
228
+
229
+ def test_method_network_u32
230
+ assert_equal 2886732288, @ip.network_u32
231
+ end
232
+
233
+ def test_method_broadcast_u32
234
+ assert_equal 2886732543, @ip.broadcast_u32
235
+ end
236
+
237
+ def test_method_include?
238
+ ip = @klass.new("192.168.10.100/24")
239
+ addr = @klass.new("192.168.10.102/24")
240
+ assert_equal true, ip.include?(addr)
241
+ assert_equal false, ip.include?(@klass.new("172.16.0.48"))
242
+ ip = @klass.new("10.0.0.0/8")
243
+ assert_equal true, ip.include?(@klass.new("10.0.0.0/9"))
244
+ assert_equal true, ip.include?(@klass.new("10.1.1.1/32"))
245
+ assert_equal true, ip.include?(@klass.new("10.1.1.1/9"))
246
+ assert_equal false, ip.include?(@klass.new("172.16.0.0/16"))
247
+ assert_equal false, ip.include?(@klass.new("10.0.0.0/7"))
248
+ assert_equal false, ip.include?(@klass.new("5.5.5.5/32"))
249
+ assert_equal false, ip.include?(@klass.new("11.0.0.0/8"))
250
+ ip = @klass.new("13.13.0.0/13")
251
+ assert_equal false, ip.include?(@klass.new("13.16.0.0/32"))
252
+ end
253
+
254
+ def test_method_include_all?
255
+ ip = @klass.new("192.168.10.100/24")
256
+ addr1 = @klass.new("192.168.10.102/24")
257
+ addr2 = @klass.new("192.168.10.103/24")
258
+ assert_equal true, ip.include_all?(addr1,addr2)
259
+ assert_equal false, ip.include_all?(addr1, @klass.new("13.16.0.0/32"))
260
+ end
261
+
262
+ def test_method_ipv4?
263
+ assert_equal true, @ip.ipv4?
264
+ end
265
+
266
+ def test_method_ipv6?
267
+ assert_equal false, @ip.ipv6?
268
+ end
269
+
270
+ def test_method_private?
271
+ assert_equal true, @klass.new("192.168.10.50/24").private?
272
+ assert_equal true, @klass.new("192.168.10.50/16").private?
273
+ assert_equal true, @klass.new("172.16.77.40/24").private?
274
+ assert_equal true, @klass.new("172.16.10.50/14").private?
275
+ assert_equal true, @klass.new("10.10.10.10/10").private?
276
+ assert_equal true, @klass.new("10.0.0.0/8").private?
277
+ assert_equal false, @klass.new("192.168.10.50/12").private?
278
+ assert_equal false, @klass.new("3.3.3.3").private?
279
+ assert_equal false, @klass.new("10.0.0.0/7").private?
280
+ assert_equal false, @klass.new("172.32.0.0/12").private?
281
+ assert_equal false, @klass.new("172.16.0.0/11").private?
282
+ assert_equal false, @klass.new("192.0.0.2/24").private?
283
+ end
284
+
285
+ def test_method_octet
286
+ assert_equal 172, @ip[0]
287
+ assert_equal 16, @ip[1]
288
+ assert_equal 10, @ip[2]
289
+ assert_equal 1, @ip[3]
290
+ end
291
+
292
+ def test_method_a?
293
+ assert_equal true, @class_a.a?
294
+ assert_equal false, @class_b.a?
295
+ assert_equal false, @class_c.a?
296
+ end
297
+
298
+ def test_method_b?
299
+ assert_equal true, @class_b.b?
300
+ assert_equal false, @class_a.b?
301
+ assert_equal false, @class_c.b?
302
+ end
303
+
304
+ def test_method_c?
305
+ assert_equal true, @class_c.c?
306
+ assert_equal false, @class_a.c?
307
+ assert_equal false, @class_b.c?
308
+ end
309
+
310
+ def test_method_to_ipv6
311
+ assert_equal "ac10:0a01", @ip.to_ipv6
312
+ end
313
+
314
+ def test_method_reverse
315
+ assert_equal "1.10.16.172.in-addr.arpa", @ip.reverse
316
+ end
317
+
318
+ def test_method_rev_domains
319
+ assert_equal ["4.17.173.in-addr.arpa", "5.17.173.in-addr.arpa"], @klass.new("173.17.5.1/23").rev_domains
320
+ assert_equal ["16.173.in-addr.arpa", "17.173.in-addr.arpa"], @klass.new("173.17.1.1/15").rev_domains
321
+ assert_equal ["172.in-addr.arpa", "173.in-addr.arpa"], @klass.new("173.17.1.1/7").rev_domains
322
+ assert_equal ["1.17.173.in-addr.arpa"], @klass.new("173.17.1.1/29").rev_domains
323
+ assert_equal ["1.17.174.in-addr.arpa"], @klass.new("174.17.1.1/24").rev_domains
324
+ assert_equal ["17.175.in-addr.arpa"], @klass.new("175.17.1.1/16").rev_domains
325
+ assert_equal ["176.in-addr.arpa"], @klass.new("176.17.1.1/8").rev_domains
326
+ assert_equal ["0.in-addr.arpa"], @klass.new("177.17.1.1/0").rev_domains
327
+ assert_equal ["1.17.178.in-addr.arpa"], @klass.new("178.17.1.1/32").rev_domains
328
+ end
329
+
330
+ def test_method_compare
331
+ ip1 = @klass.new("10.1.1.1/8")
332
+ ip2 = @klass.new("10.1.1.1/16")
333
+ ip3 = @klass.new("172.16.1.1/14")
334
+ ip4 = @klass.new("10.1.1.1/8")
335
+
336
+ # ip2 should be greater than ip1
337
+ assert_equal true, ip1 < ip2
338
+ assert_equal false, ip1 > ip2
339
+ assert_equal false, ip2 < ip1
340
+ # ip2 should be less than ip3
341
+ assert_equal true, ip2 < ip3
342
+ assert_equal false, ip2 > ip3
343
+ # ip1 should be less than ip3
344
+ assert_equal true, ip1 < ip3
345
+ assert_equal false, ip1 > ip3
346
+ assert_equal false, ip3 < ip1
347
+ # ip1 should be equal to itself
348
+ assert_equal true, ip1 == ip1
349
+ # ip1 should be equal to ip4
350
+ assert_equal true, ip1 == ip4
351
+ # test sorting
352
+ arr = ["10.1.1.1/8","10.1.1.1/16","172.16.1.1/14"]
353
+ assert_equal arr, [ip1,ip2,ip3].sort.map{|s| s.to_string}
354
+ # test same prefix
355
+ ip1 = @klass.new("10.0.0.0/24")
356
+ ip2 = @klass.new("10.0.0.0/16")
357
+ ip3 = @klass.new("10.0.0.0/8")
358
+ arr = ["10.0.0.0/8","10.0.0.0/16","10.0.0.0/24"]
359
+ assert_equal arr, [ip1,ip2,ip3].sort.map{|s| s.to_string}
360
+ end
361
+
362
+ def test_method_minus
363
+ ip1 = @klass.new("10.1.1.1/8")
364
+ ip2 = @klass.new("10.1.1.10/8")
365
+ assert_equal 9, ip2 - ip1
366
+ assert_equal 9, ip1 - ip2
367
+ end
368
+
369
+ def test_method_plus
370
+ ip1 = @klass.new("172.16.10.1/24")
371
+ ip2 = @klass.new("172.16.11.2/24")
372
+ assert_equal ["172.16.10.0/23"], (ip1+ip2).map{|i| i.to_string}
373
+
374
+ ip2 = @klass.new("172.16.12.2/24")
375
+ assert_equal [ip1.network.to_string, ip2.network.to_string],
376
+ (ip1 + ip2).map{|i| i.to_string}
377
+
378
+ ip1 = @klass.new("10.0.0.0/23")
379
+ ip2 = @klass.new("10.0.2.0/24")
380
+ assert_equal ["10.0.0.0/23","10.0.2.0/24"], (ip1+ip2).map{|i| i.to_string}
381
+
382
+ ip1 = @klass.new("10.0.0.0/23")
383
+ ip2 = @klass.new("10.0.2.0/24")
384
+ assert_equal ["10.0.0.0/23","10.0.2.0/24"], (ip2+ip1).map{|i| i.to_string}
385
+
386
+ ip1 = @klass.new("10.0.0.0/16")
387
+ ip2 = @klass.new("10.0.2.0/24")
388
+ assert_equal ["10.0.0.0/16"], (ip1+ip2).map{|i| i.to_string}
389
+
390
+ ip1 = @klass.new("10.0.0.0/23")
391
+ ip2 = @klass.new("10.1.0.0/24")
392
+ assert_equal ["10.0.0.0/23","10.1.0.0/24"], (ip1+ip2).map{|i| i.to_string}
393
+
394
+ end
395
+
396
+ def test_method_netmask_equal
397
+ ip = @klass.new("10.1.1.1/16")
398
+ assert_equal 16, ip.prefix.to_i
399
+ ip.netmask = "255.255.255.0"
400
+ assert_equal 24, ip.prefix.to_i
401
+ end
402
+
403
+ def test_method_split
404
+ assert_raise(ArgumentError) {@ip.split(0)}
405
+ assert_raise(ArgumentError) {@ip.split(257)}
406
+
407
+ assert_equal @ip.network, @ip.split(1).first
408
+
409
+ arr = ["172.16.10.0/27", "172.16.10.32/27", "172.16.10.64/27",
410
+ "172.16.10.96/27", "172.16.10.128/27", "172.16.10.160/27",
411
+ "172.16.10.192/27", "172.16.10.224/27"]
412
+ assert_equal arr, @network.split(8).map {|s| s.to_string}
413
+ arr = ["172.16.10.0/27", "172.16.10.32/27", "172.16.10.64/27",
414
+ "172.16.10.96/27", "172.16.10.128/27", "172.16.10.160/27",
415
+ "172.16.10.192/26"]
416
+ assert_equal arr, @network.split(7).map {|s| s.to_string}
417
+ arr = ["172.16.10.0/27", "172.16.10.32/27", "172.16.10.64/27",
418
+ "172.16.10.96/27", "172.16.10.128/26", "172.16.10.192/26"]
419
+ assert_equal arr, @network.split(6).map {|s| s.to_string}
420
+ arr = ["172.16.10.0/27", "172.16.10.32/27", "172.16.10.64/27",
421
+ "172.16.10.96/27", "172.16.10.128/25"]
422
+ assert_equal arr, @network.split(5).map {|s| s.to_string}
423
+ arr = ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/26",
424
+ "172.16.10.192/26"]
425
+ assert_equal arr, @network.split(4).map {|s| s.to_string}
426
+ arr = ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/25"]
427
+ assert_equal arr, @network.split(3).map {|s| s.to_string}
428
+ arr = ["172.16.10.0/25", "172.16.10.128/25"]
429
+ assert_equal arr, @network.split(2).map {|s| s.to_string}
430
+ arr = ["172.16.10.0/24"]
431
+ assert_equal arr, @network.split(1).map {|s| s.to_string}
432
+ end
433
+
434
+ def test_method_subnet
435
+ assert_raise(ArgumentError) {@network.subnet(23)}
436
+ assert_raise(ArgumentError) {@network.subnet(33)}
437
+ assert_nothing_raised {@ip.subnet(30)}
438
+ arr = ["172.16.10.0/26", "172.16.10.64/26", "172.16.10.128/26",
439
+ "172.16.10.192/26"]
440
+ assert_equal arr, @network.subnet(26).map {|s| s.to_string}
441
+ arr = ["172.16.10.0/25", "172.16.10.128/25"]
442
+ assert_equal arr, @network.subnet(25).map {|s| s.to_string}
443
+ arr = ["172.16.10.0/24"]
444
+ assert_equal arr, @network.subnet(24).map {|s| s.to_string}
445
+ end
446
+
447
+ def test_method_supernet
448
+ assert_raise(ArgumentError) {@ip.supernet(24)}
449
+ assert_equal "0.0.0.0/0", @ip.supernet(0).to_string
450
+ assert_equal "0.0.0.0/0", @ip.supernet(-2).to_string
451
+ assert_equal "172.16.10.0/23", @ip.supernet(23).to_string
452
+ assert_equal "172.16.8.0/22", @ip.supernet(22).to_string
453
+ end
454
+
455
+ def test_classmethod_parse_u32
456
+ @decimal_values.each do |addr,int|
457
+ ip = @klass.parse_u32(int)
458
+ ip.prefix = addr.split("/").last.to_i
459
+ assert_equal ip.to_string, addr
460
+ end
461
+ end
462
+
463
+ def test_classhmethod_extract
464
+ str = "foobar172.16.10.1barbaz"
465
+ assert_equal "172.16.10.1", @klass.extract(str).to_s
466
+ end
467
+
468
+ def test_classmethod_summarize
469
+
470
+ # Should return self if only one network given
471
+ assert_equal [@ip.network], @klass.summarize(@ip)
472
+
473
+ # Summarize homogeneous networks
474
+ ip1 = @klass.new("172.16.10.1/24")
475
+ ip2 = @klass.new("172.16.11.2/24")
476
+ assert_equal ["172.16.10.0/23"], @klass.summarize(ip1,ip2).map{|i| i.to_string}
477
+
478
+ ip1 = @klass.new("10.0.0.1/24")
479
+ ip2 = @klass.new("10.0.1.1/24")
480
+ ip3 = @klass.new("10.0.2.1/24")
481
+ ip4 = @klass.new("10.0.3.1/24")
482
+ assert_equal ["10.0.0.0/22"], @klass.summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
483
+ assert_equal ["10.0.0.0/22"], @klass.summarize(ip4,ip3,ip2,ip1).map{|i| i.to_string}
484
+
485
+ # Summarize non homogeneous networks
486
+ ip1 = @klass.new("10.0.0.0/23")
487
+ ip2 = @klass.new("10.0.2.0/24")
488
+ assert_equal ["10.0.0.0/23","10.0.2.0/24"], @klass.summarize(ip1,ip2).map{|i| i.to_string}
489
+
490
+ ip1 = @klass.new("10.0.0.0/16")
491
+ ip2 = @klass.new("10.0.2.0/24")
492
+ assert_equal ["10.0.0.0/16"], @klass.summarize(ip1,ip2).map{|i| i.to_string}
493
+
494
+ ip1 = @klass.new("10.0.0.0/23")
495
+ ip2 = @klass.new("10.1.0.0/24")
496
+ assert_equal ["10.0.0.0/23","10.1.0.0/24"], @klass.summarize(ip1,ip2).map{|i| i.to_string}
497
+
498
+ ip1 = @klass.new("10.0.0.0/23")
499
+ ip2 = @klass.new("10.0.2.0/23")
500
+ ip3 = @klass.new("10.0.4.0/24")
501
+ ip4 = @klass.new("10.0.6.0/24")
502
+ assert_equal ["10.0.0.0/22","10.0.4.0/24","10.0.6.0/24"],
503
+ @klass.summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
504
+
505
+ ip1 = @klass.new("10.0.1.1/24")
506
+ ip2 = @klass.new("10.0.2.1/24")
507
+ ip3 = @klass.new("10.0.3.1/24")
508
+ ip4 = @klass.new("10.0.4.1/24")
509
+ result = ["10.0.1.0/24","10.0.2.0/23","10.0.4.0/24"]
510
+ assert_equal result, @klass.summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
511
+ assert_equal result, @klass.summarize(ip4,ip3,ip2,ip1).map{|i| i.to_string}
512
+
513
+ ip1 = @klass.new("10.0.1.1/24")
514
+ ip2 = @klass.new("10.10.2.1/24")
515
+ ip3 = @klass.new("172.16.0.1/24")
516
+ ip4 = @klass.new("172.16.1.1/24")
517
+ result = ["10.0.1.0/24","10.10.2.0/24","172.16.0.0/23"]
518
+ assert_equal result, @klass.summarize(ip1,ip2,ip3,ip4).map{|i| i.to_string}
519
+
520
+ ips = [@klass.new("10.0.0.12/30"),
521
+ @klass.new("10.0.100.0/24")]
522
+ result = ["10.0.0.12/30", "10.0.100.0/24"]
523
+ assert_equal result, @klass.summarize(*ips).map{|i| i.to_string}
524
+
525
+ ips = [@klass.new("172.16.0.0/31"),
526
+ @klass.new("10.10.2.1/32")]
527
+ result = ["10.10.2.1/32", "172.16.0.0/31"]
528
+ assert_equal result, @klass.summarize(*ips).map{|i| i.to_string}
529
+
530
+ ips = [@klass.new("172.16.0.0/32"),
531
+ @klass.new("10.10.2.1/32")]
532
+ result = ["10.10.2.1/32", "172.16.0.0/32"]
533
+ assert_equal result, @klass.summarize(*ips).map{|i| i.to_string}
534
+
535
+ end
536
+
537
+ def test_classmethod_parse_data
538
+ ip = @klass.parse_data "\254\020\n\001"
539
+ assert_instance_of @klass, ip
540
+ assert_equal "172.16.10.1", ip.address
541
+ assert_equal "172.16.10.1/32", ip.to_string
542
+ end
543
+
544
+ def test_classmethod_parse_classful
545
+ @classful.each do |ip,prefix|
546
+ res = @klass.parse_classful(ip)
547
+ assert_equal prefix, res.prefix
548
+ assert_equal "#{ip}/#{prefix}", res.to_string
549
+ end
550
+ assert_raise(ArgumentError){ @klass.parse_classful("192.168.256.257") }
551
+ end
552
+
553
+ end # class IPv4Test
554
+
555
+