Module:IP/testcases

-- Unit tests for Module:IP. Click talk page to run tests.

-- Unit test module setup local ScribuntoUnit = require('Module:ScribuntoUnit') local suite = ScribuntoUnit:new

-- Target module setup local IP = require('Module:IP') local IPAddress = IP.IPAddress local Subnet = IP.Subnet local IPv4Collection = IP.IPv4Collection local IPv6Collection = IP.IPv6Collection

-- Constants local IP_ADDRESS_CLASS = 'IPAddress' local IP_ADDRESS_OBJECT = 'ipAddress' local SUBNET_CLASS = 'Subnet' local SUBNET_OBJECT = 'subnet' local IPV4COLLECTION_CLASS = 'IPv4Collection' local IPV4COLLECTION_OBJECT = 'ipv4Collection' local IPV6COLLECTION_CLASS = 'IPv6Collection' local IPV6COLLECTION_OBJECT = 'ipv6Collection'

--- -- Helper methods ---

function suite:assertError(message, plain, ...) local success, ret = pcall(...) self:assertFalse(success) self:assertStringContains(message, ret, plain) end

function suite:assertNotError(...) local success = pcall(...) self:assertTrue(success) end

function suite:assertSelfParameterError(class, objName, method, ...) local message = string.format(		'IP: invalid %s object. Did you call %s with a dot instead of a colon, i.e. %s.%s instead of %s:%s?',		class, method, objName, method, objName, method	) self:assertError(message, true, ...) end

function suite:assertTypeError(argIdx, funcName, expected, received, ...) local message = string.format(		"bad argument #%d to '%s' (%s expected, got %s)",		argIdx, funcName, expected, received	) self:assertError(message, true, ...) end

function suite:assertObjectError(argIdx, funcName, className, ...) local message = string.format(		"bad argument #%d to '%s' (not a valid %s object)",		argIdx, funcName, className	) self:assertError(message, true, ...) end

function suite:assertIPStringError(ipStr, ...) local message = string.format("'%s' is an invalid IP address", ipStr) self:assertError(message, true, ...) end

function suite:assertCIDRStringError(cidr, ...) local message = string.format("'%s' is an invalid CIDR string", cidr) self:assertError(message, true, ...) end

function suite:assertMetatableProtected(obj) self:assertError('cannot change a protected metatable', true, function 		setmetatable(obj, {})	end) end

function suite:assertNotMetatable(val) self:assertFalse(type(val) == 'table' and type(val.__eq) == 'function') end

function suite:assertObject(val, ...) self:assertTrue(type(val) == 'table') for i, method in ipairs{...} do		self:assertTrue(type(val[method]) == 'function') end end

function suite:assertIPAddressObject(val) suite:assertObject(val, 'getIP', 'isInSubnet') end

function suite:assertSubnetObject(val) suite:assertObject(val, 'getCIDR', 'containsIP') end

function suite:assertCollectionObject(val) suite:assertObject(val, 'addIP', 'addSubnet') end

function suite:assertIPv4CollectionObject(val) self:assertCollectionObject(val) self:assertEquals('IPv4', val:getVersion) end

function suite:assertIPv6CollectionObject(val) self:assertCollectionObject(val) self:assertEquals('IPv6', val:getVersion) end

function suite:assertRangesEqual(expected, actual) self:assertTrue(#expected == #actual) for i = 1, #expected do		local expectedRange = expected[i] local actualRange = actual[i] self:assertEquals(expectedRange[1], actualRange[1]) self:assertEquals(expectedRange[2], actualRange[2]) end end

--- -- IPAddress tests ---

function suite:testIPConstructor local function assertValidIP(ip) self:assertIPAddressObject(IPAddress.new(ip)) end assertValidIP('1.2.3.4') assertValidIP('0.0.0.0') assertValidIP('255.255.255.255') assertValidIP('::') assertValidIP('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff') assertValidIP('2001::f:1234') end

function suite:testInvalidIPs local function assertInvalidIP(ip) self:assertError(			string.format("'%s' is an invalid IP address", ip),			true,			function 				IPAddress.new(ip)			end		) end assertInvalidIP('') assertInvalidIP('foo') assertInvalidIP('01.02.03.04') assertInvalidIP('256.256.256.256') assertInvalidIP('1.2.3') assertInvalidIP('1.2.3.4.5') assertInvalidIP('-1.2.3.4') assertInvalidIP(':') -- TODO: work out what to do about the following test -- assertInvalidIP(':::') assertInvalidIP('2001::f::1234') assertInvalidIP('2001:g::') end

function suite:testIPConstructorErrors self:assertTypeError(		1, 'IPAddress.new', 'string', 'boolean',		function 			IPAddress.new(true)		end	) self:assertTypeError(		1, 'IPAddress.new', 'string', 'number',		function 			IPAddress.new(7)		end	) self:assertTypeError(		1, 'IPAddress.new', 'string', 'nil',		function 			IPAddress.new		end	) self:assertError(		"'foo' is an invalid IP address",		true,		function 			IPAddress.new('foo')		end	) end

function suite:testIPEquals self:assertTrue(IPAddress.new('1.2.3.4') == IPAddress.new('1.2.3.4')) self:assertFalse(IPAddress.new('1.2.3.5') == IPAddress.new('1.2.3.4')) self:assertTrue(IPAddress.new('2001:a1:b2::') == IPAddress.new('2001:a1:b2::')) self:assertTrue(IPAddress.new('::') == IPAddress.new('0:0:0:0:0:0:0:0')) end

function suite:testIPLessThan self:assertFalse(IPAddress.new('1.2.3.4') < IPAddress.new('1.2.3.4')) self:assertFalse(IPAddress.new('1.2.3.5') < IPAddress.new('1.2.3.4')) self:assertTrue(IPAddress.new('1.2.3.3') < IPAddress.new('1.2.3.4')) self:assertTrue(IPAddress.new('2.0.0.0') < IPAddress.new('10.0.0.0')) self:assertTrue(IPAddress.new('2001:a1:b2::') < IPAddress.new('2001:a1:b2::1')) self:assertTrue(IPAddress.new('2001:b::') < IPAddress.new('2001:10::')) end

function suite:testIPLessThanOrEqualTo self:assertTrue(IPAddress.new('1.2.3.4') <= IPAddress.new('1.2.3.4')) self:assertFalse(IPAddress.new('1.2.3.5') <= IPAddress.new('1.2.3.4')) self:assertTrue(IPAddress.new('1.2.3.3') <= IPAddress.new('1.2.3.4')) end

function suite:testIPToString self:assertEquals('1.2.3.4', tostring(IPAddress.new('1.2.3.4'))) self:assertEquals('2001:a1:b2::', tostring(IPAddress.new('2001:a1:b2:0:0:0:0:0'))) end

function suite:testConcatIP self:assertEquals(		'1.2.3.45.6.7.8',		IPAddress.new('1.2.3.4') .. IPAddress.new('5.6.7.8')	) self:assertEquals('1.2.3.4foo', IPAddress.new('1.2.3.4') .. 'foo') end

function suite:testGetIP self:assertEquals('1.2.3.4', IPAddress.new('1.2.3.4'):getIP) end

function suite:testGetIPErrors self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'getIP',		function 			IPAddress.new('1.2.3.4').getIP		end	) self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'getIP',		function 			IPAddress.new('1.2.3.4').getIP(IPAddress.new('5.6.7.8'))		end	) end

function suite:testGetVersion self:assertEquals('IPv4', IPAddress.new('1.2.3.4'):getVersion) self:assertEquals('IPv6', IPAddress.new('2001:db8::ff00:12:3456'):getVersion) end

function suite:testGetVersionErrors self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'getVersion',		function 			IPAddress.new('1.2.3.4').getVersion		end	) self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'getVersion',		function 			IPAddress.new('1.2.3.4').getVersion(IPAddress.new('5.6.7.8'))		end	) end

function suite:testIsIPv4 self:assertTrue(IPAddress.new('1.2.3.4'):isIPv4) self:assertFalse(IPAddress.new('2001:db8::ff00:12:3456'):isIPv4) end

function suite:testIsIPv4Errors self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'isIPv4',		function 			IPAddress.new('1.2.3.4').isIPv4		end	) self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'isIPv4',		function 			IPAddress.new('1.2.3.4').isIPv4(IPAddress.new('5.6.7.8'))		end	) end

function suite:testIsIPv6 self:assertTrue(IPAddress.new('2001:db8::ff00:12:3456'):isIPv6) self:assertFalse(IPAddress.new('1.2.3.4'):isIPv6) end

function suite:testIsIPv6Errors self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'isIPv6',		function 			IPAddress.new('1.2.3.4').isIPv6		end	) self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'isIPv6',		function 			IPAddress.new('1.2.3.4').isIPv6(IPAddress.new('5.6.7.8'))		end	) end

function suite:testIsInSubnet self:assertTrue(IPAddress.new('1.2.3.4'):isInSubnet(Subnet.new('1.2.3.0/24'))) self:assertFalse(IPAddress.new('1.2.3.4'):isInSubnet(Subnet.new('1.2.4.0/24'))) end

function suite:testIsInSubnetFromString self:assertTrue(IPAddress.new('1.2.3.4'):isInSubnet('1.2.3.0/24')) self:assertFalse(IPAddress.new('1.2.3.4'):isInSubnet('1.2.4.0/24')) end

function suite:testIsInSubnetErrors self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'isInSubnet',		function 			IPAddress.new('1.2.3.4').isInSubnet		end	) self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'isInSubnet',		function 			IPAddress.new('1.2.3.4').isInSubnet(IPAddress.new('5.6.7.8'))		end	) self:assertTypeError(		1, 'isInSubnet', 'string or table', 'boolean',		function 			IPAddress.new('1.2.3.4'):isInSubnet(false)		end	) self:assertTypeError(		1, 'isInSubnet', 'string or table', 'nil',		function 			IPAddress.new('1.2.3.4'):isInSubnet		end	) self:assertCIDRStringError(		'foo',		function 			IPAddress.new('1.2.3.4'):isInSubnet('foo')		end	) self:assertObjectError(		1, 'isInSubnet', 'Subnet',		function 			IPAddress.new('1.2.3.4'):isInSubnet{foo = 'bar'}		end	) end

function suite:testGetSubnet self:assertEquals(		'1.2.3.0/24',		IPAddress.new('1.2.3.4'):getSubnet(24):getCIDR	) self:assertEquals(		'1.2.3.128/25',		IPAddress.new('1.2.3.130'):getSubnet(25):getCIDR	) end

function suite:testGetSubnetErrors self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'getSubnet',		function 			IPAddress.new('1.2.3.4').getSubnet(24)		end	) self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'getSubnet',		function 			IPAddress.new('1.2.3.4').getSubnet(IPAddress.new('5.6.7.8'), 24)		end	) self:assertTypeError(		1, 'getSubnet', 'number', 'boolean',		function 			IPAddress.new('1.2.3.4'):getSubnet(false)		end	) self:assertTypeError(		1, 'getSubnet', 'number', 'nil',		function 			IPAddress.new('1.2.3.4'):getSubnet		end	) end

function suite:testGetSubnetIPv4NumberErrors local message = "bad argument #1 to 'getSubnet' (must be an integer between 0 and 32)" self:assertError(message, true, function 		IPAddress.new('1.2.3.4'):getSubnet(33)	end) self:assertError(message, true, function 		IPAddress.new('1.2.3.4'):getSubnet(-1)	end) self:assertError(message, true, function 		IPAddress.new('1.2.3.4'):getSubnet(24.5)	end) end

function suite:testGetSubnetIPv6NumberErrors local message = "bad argument #1 to 'getSubnet' (must be an integer between 0 and 128)" self:assertError(message, true, function 		IPAddress.new('2001:db8::ff00:12:3456'):getSubnet(129)	end) self:assertError(message, true, function 		IPAddress.new('2001:db8::ff00:12:3456'):getSubnet(-1)	end) self:assertError(message, true, function 		IPAddress.new('2001:db8::ff00:12:3456'):getSubnet(112.5)	end) end

function suite:testGetNextIP self:assertEquals('1.2.3.5', tostring(IPAddress.new('1.2.3.4'):getNextIP)) self:assertEquals(		IPAddress.new('2001:db8::ff00:12:3457'),		IPAddress.new('2001:db8::ff00:12:3456'):getNextIP	) end

function suite:testGetNextIPWraparound self:assertEquals(		IPAddress.new('0.0.0.0'),		IPAddress.new('255.255.255.255'):getNextIP	) self:assertEquals(		'::',		tostring(IPAddress.new('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'):getNextIP)	) end

function suite:testGetNextIPErrors self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'getNextIP',		function 			IPAddress.new('1.2.3.4').getNextIP		end	) self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'getNextIP',		function 			IPAddress.new('1.2.3.4').getNextIP(IPAddress.new('5.6.7.8'))		end	) end

function suite:testGetPreviousIP self:assertEquals(		IPAddress.new('1.2.3.3'),		IPAddress.new('1.2.3.4'):getPreviousIP	) self:assertEquals(		IPAddress.new('2001:db8::ff00:12:3455'),		IPAddress.new('2001:db8::ff00:12:3456'):getPreviousIP	) end

function suite:testGetPreviousIPWraparound self:assertEquals(		IPAddress.new('255.255.255.255'),		IPAddress.new('0.0.0.0'):getPreviousIP	) self:assertEquals(		IPAddress.new('ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff'),		IPAddress.new('::'):getPreviousIP	) end

function suite:testGetPreviousIPErrors self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'getPreviousIP',		function 			IPAddress.new('1.2.3.4').getPreviousIP		end	) self:assertSelfParameterError(		IP_ADDRESS_CLASS, IP_ADDRESS_OBJECT, 'getPreviousIP',		function 			IPAddress.new('1.2.3.4').getPreviousIP(IPAddress.new('5.6.7.8'))		end	) end

function suite:testGetIPMetatable self:assertNotMetatable(getmetatable(IPAddress.new('1.2.3.4'))) end

function suite:testSetIPMetatable self:assertMetatableProtected(IPAddress.new('1.2.3.4')) end

--- -- Subnet tests ---

function suite:testValidCIDRs local function assertValidCIDR(cidr) self:assertTrue(type(Subnet.new(cidr)) == 'table') end assertValidCIDR('1.2.3.0/24') assertValidCIDR(' 1.2.3.0/24 ') assertValidCIDR('0.0.0.0/0') assertValidCIDR('0.0.0.0/32') assertValidCIDR('255.255.255.255/32') assertValidCIDR('2001:db8::ff00:12:0/122') assertValidCIDR('2001:DB8::FF00:12:0/122') assertValidCIDR('::/0') assertValidCIDR('::/128') end

function suite:testInvalidCIDRs local function assertInvalidCIDR(cidr) self:assertError(			string.format("'%s' is an invalid CIDR string", cidr),			true,			function 				Subnet.new(cidr)			end		) end assertInvalidCIDR('foo') assertInvalidCIDR('0/0') assertInvalidCIDR('/24') assertInvalidCIDR('1.2.3/24') assertInvalidCIDR(':/0') assertInvalidCIDR('1.2.3.4') assertInvalidCIDR('0.0.0.0/33') assertInvalidCIDR('0.0.0.0/-1') assertInvalidCIDR('256.0.0.0/24') assertInvalidCIDR('1.2.3.4/24') assertInvalidCIDR('1.2.3.0/16') assertInvalidCIDR('0.0.0.0/01') -- Leading zero in bit length assertInvalidCIDR('2001:db8::ff00:12:3456') assertInvalidCIDR('2001:db8::ff00:12:0/foo') assertInvalidCIDR('::/-1') assertInvalidCIDR('::/129') assertInvalidCIDR('gggg:db8::ff00:12:0/122') assertInvalidCIDR('2001:db8::ff00:12:3456/122') assertInvalidCIDR('2001:db8::ff00:12:0/106') end

function suite:testSubnetConstructorErrors self:assertTypeError(		1, 'Subnet.new', 'string', 'boolean',		function 			Subnet.new(true)		end	) self:assertTypeError(		1, 'Subnet.new', 'string', 'number',		function 			Subnet.new(7)		end	) self:assertTypeError(		1, 'Subnet.new', 'string', 'nil',		function 			Subnet.new		end	) end

function suite:testSubnetEquals self:assertTrue(Subnet.new('1.2.3.0/24') == Subnet.new('1.2.3.0/24')) self:assertFalse(Subnet.new('1.2.3.0/24') == Subnet.new('1.2.0.0/16')) end

function suite:testConcatSubnet self:assertEquals(		'1.2.3.0/244.5.6.0/24',		Subnet.new('1.2.3.0/24') .. Subnet.new('4.5.6.0/24')	) self:assertEquals('1.2.3.0/24foo', Subnet.new('1.2.3.0/24') .. 'foo') self:assertEquals('foo1.2.3.0/24', 'foo' .. Subnet.new('1.2.3.0/24')) end

function suite:testSubnetToString self:assertEquals('1.2.3.0/24', tostring(Subnet.new('1.2.3.0/24'))) self:assertEquals(		'2001:db8::ff00:12:0/122',		tostring(Subnet.new('2001:db8::ff00:12:0/122'))	) end

function suite:testSubnetGetmetatable self:assertNotMetatable(getmetatable(Subnet.new('1.2.3.0/24'))) end

function suite:testSubnetSetmetatable self:assertMetatableProtected(Subnet.new('1.2.3.0/24')) end

function suite:testSubnetGetPrefix self:assertEquals(		IPAddress.new('1.2.3.0'),		Subnet.new('1.2.3.0/24'):getPrefix	) end

function suite:testSubnetGetPrefixErrors self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'getPrefix',		function 			Subnet.new('1.2.3.0/24').getPrefix		end	) self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'getPrefix',		function 			Subnet.new('1.2.3.0/24').getPrefix(Subnet.new('4.5.6.0/24'))		end	) end

function suite:testSubnetGetHighestIP self:assertEquals(		IPAddress.new('1.2.3.255'),		Subnet.new('1.2.3.0/24'):getHighestIP	) end

function suite:testGetHighestIPFromGetSubnet self:assertEquals(		IPAddress.new('1.2.3.255'),		IPAddress.new('1.2.3.4'):getSubnet(24):getHighestIP	) end

function suite:testSubnetGetHighestIPErrors self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'getHighestIP',		function 			Subnet.new('1.2.3.0/24').getHighestIP		end	) self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'getHighestIP',		function 			Subnet.new('1.2.3.0/24').getHighestIP(Subnet.new('4.5.6.0/24'))		end	) end

function suite:testSubnetGetBitLength self:assertEquals(24, Subnet.new('1.2.3.0/24'):getBitLength) end

function suite:testSubnetGetBitLengthErrors self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'getBitLength',		function 			Subnet.new('1.2.3.0/24').getBitLength		end	) end

function suite:testSubnetGetCIDR self:assertEquals('1.2.3.0/24', Subnet.new('1.2.3.0/24'):getCIDR) end

function suite:testGetCIDRErrors self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'getCIDR',		function 			Subnet.new('1.2.3.0/24').getCIDR		end	) self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'getCIDR',		function 			Subnet.new('1.2.3.0/24').getCIDR(Subnet.new('4.5.6.0/24'))		end	) end

function suite:testSubnetGetVersion self:assertEquals('IPv4', Subnet.new('1.2.3.0/24'):getVersion) self:assertEquals('IPv6', Subnet.new('2001:db8::ff00:0:0/96'):getVersion) end

function suite:testSubnetGetVersionErrors self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'getVersion',		function 			Subnet.new('1.2.3.0/24').getVersion		end	) self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'getVersion',		function 			Subnet.new('1.2.3.0/24').getVersion(Subnet.new('4.5.6.0/24'))		end	) end

function suite:testSubnetIsIPv4 self:assertTrue(Subnet.new('1.2.3.0/24'):isIPv4) self:assertFalse(Subnet.new('2001:db8::ff00:0:0/96'):isIPv4) end

function suite:testSubnetIsIPv4Errors self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'isIPv4',		function 			Subnet.new('1.2.3.0/24').isIPv4		end	) self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'isIPv4',		function 			Subnet.new('1.2.3.0/24').isIPv4(Subnet.new('4.5.6.0/24'))		end	) end

function suite:testSubnetIsIPv6 self:assertTrue(Subnet.new('2001:db8::ff00:0:0/96'):isIPv6) self:assertFalse(Subnet.new('1.2.3.0/24'):isIPv6) end

function suite:testSubnetIsIPv6Errors self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'isIPv6',		function 			Subnet.new('1.2.3.0/24').isIPv6		end	) self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'isIPv6',		function 			Subnet.new('1.2.3.0/24').isIPv6(Subnet.new('4.5.6.0/24'))		end	) end

function suite:testSubnetContainsIP self:assertTrue(		Subnet.new('1.2.3.0/24'):containsIP(IPAddress.new('1.2.3.4'))	) self:assertFalse(		Subnet.new('1.2.3.0/24'):containsIP(IPAddress.new('1.2.4.4'))	) end

function suite:testSubnetContainsIPErrors self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'containsIP',		function 			Subnet.new('1.2.3.0/24').containsIP(IPAddress.new('1.2.3.4'))		end	) self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'containsIP',		function 			Subnet.new('1.2.3.0/24').containsIP( Subnet.new('4.5.6.0/24'), IPAddress.new('1.2.3.4') )		end	) self:assertTypeError(		1, 'containsIP', 'string or table', 'boolean',		function 			Subnet.new('1.2.3.0/24'):containsIP(false)		end	) self:assertTypeError(		1, 'containsIP', 'string or table', 'nil',		function 			Subnet.new('1.2.3.0/24'):containsIP		end	) self:assertIPStringError(		'foo',		function 			Subnet.new('1.2.3.0/24'):containsIP('foo')		end	) self:assertObjectError(		1, 'containsIP', 'IPAddress',		function 			Subnet.new('1.2.3.0/24'):containsIP{foo = 'bar'}		end	) end

function suite:testOverlapsSubnet self:assertTrue(		Subnet.new('1.2.0.0/16'):overlapsSubnet(Subnet.new('1.2.3.0/24'))	) self:assertFalse(		Subnet.new('1.2.0.0/16'):overlapsSubnet(Subnet.new('1.3.3.0/24'))	) end

function suite:testOverlapsSubnetErrors self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'overlapsSubnet',		function 			Subnet.new('1.2.3.0/24').overlapsSubnet(Subnet.new('1.2.0.0/16'))		end	) self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'overlapsSubnet',		function 			Subnet.new('1.2.3.0/24').overlapsSubnet( Subnet.new('4.5.6.0/24'), Subnet.new('1.2.0.0/16') )		end	) self:assertTypeError(		1, 'overlapsSubnet', 'string or table', 'boolean',		function 			Subnet.new('1.2.3.0/24'):overlapsSubnet(false)		end	) self:assertTypeError(		1, 'overlapsSubnet', 'string or table', 'nil',		function 			Subnet.new('1.2.3.0/24'):overlapsSubnet		end	) self:assertCIDRStringError(		'foo',		function 			Subnet.new('1.2.3.0/24'):overlapsSubnet('foo')		end	) self:assertObjectError(		1, 'overlapsSubnet', 'Subnet',		function 			Subnet.new('1.2.3.0/24'):overlapsSubnet{foo = 'bar'}		end	) end

function suite:testWalkSubnet do local ips = {} for ip in Subnet.new('1.2.3.0/30'):walk do			ips[#ips + 1] = tostring(ip) end self:assertEquals(			'1.2.3.0 1.2.3.1 1.2.3.2 1.2.3.3',			table.concat(ips, ' ')		) end do local ips = {} for ip in Subnet.new('2001:db8::ff00:0:0/126'):walk do			ips[#ips + 1] = tostring(ip) end self:assertEquals(			'2001:db8::ff00:0:0 2001:db8::ff00:0:1 2001:db8::ff00:0:2 2001:db8::ff00:0:3',			table.concat(ips, ' ')		) end end

function suite:testWalkSubnetErrors self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'walk',		function 			Subnet.new('1.2.3.0/24').walk		end	) self:assertSelfParameterError(		SUBNET_CLASS, SUBNET_OBJECT, 'walk',		function 			Subnet.new('1.2.3.0/24').walk(Subnet.new('4.5.6.0/24'))		end	) end

--- -- IPv4Collection tests ---

function suite:testIPv4CollectionConstructor self:assertIPv4CollectionObject(IPv4Collection.new) end

function suite:testIPv4CollectionGetVersion self:assertEquals('IPv4', IPv4Collection.new:getVersion) end

function suite:testIPv4CollectionAddIP self:assertNotError(function IPv4Collection.new:addIP('1.2.3.4') end) self:assertNotError(function IPv4Collection.new:addIP(IPAddress.new('1.2.3.4')) end) suite:assertIPStringError(		'foo',		function 			IPv4Collection.new:addIP(IPAddress.new('foo'))		end	) suite:assertIPStringError(		'1.2.3.0/24',		function 			IPv4Collection.new:addIP(IPAddress.new('1.2.3.0/24'))		end	) end

function suite:testIPv4CollectionAddIPChaining self:assertNotError(function 		IPv4Collection.new			:addIP('1.2.3.4')			:addIP('5.6.7.8')	end) end

function suite:testIPv4CollectionAddIPErrors self:assertTypeError(		1, 'addIP', 'string or table', 'boolean',		function 			IPv4Collection.new:addIP(false)		end	) self:assertTypeError(		1, 'addIP', 'string or table', 'nil',		function 			IPv4Collection.new:addIP		end	) self:assertIPStringError(		'foo',		function 			IPv4Collection.new:addIP('foo')		end	) self:assertObjectError(		1, 'addIP', 'IPAddress',		function 			IPv4Collection.new:addIP{foo = 'bar'}		end	) end

function suite:testIPv4CollectionAddSubnet self:assertNotError(function IPv4Collection.new:addSubnet('1.2.3.0/24') end) self:assertNotError(function IPv4Collection.new:addSubnet(Subnet.new('1.2.3.0/24')) end) suite:assertCIDRStringError(		'foo',		function 			IPv4Collection.new:addSubnet('foo')		end	) suite:assertCIDRStringError(		'1.2.3.4',		function 			IPv4Collection.new:addSubnet('1.2.3.4')		end	) end

function suite:testIPv4CollectionAddSubnetChaining self:assertNotError(function 		IPv4Collection.new			:addSubnet('1.2.3.0/24')			:addSubnet('5.6.7.0/24')	end) end

function suite:testIPv4CollectionAddSubnetErrors self:assertTypeError(		1, 'addSubnet', 'string or table', 'boolean',		function 			IPv4Collection.new:addSubnet(false)		end	) self:assertTypeError(		1, 'addSubnet', 'string or table', 'nil',		function 			IPv4Collection.new:addSubnet		end	) self:assertCIDRStringError(		'foo',		function 			IPv4Collection.new:addSubnet('foo')		end	) self:assertObjectError(		1, 'addSubnet', 'Subnet',		function 			IPv4Collection.new:addSubnet{foo = 'bar'}		end	) end

function suite:testIPv4CollectionContainsIP local collection = IPv4Collection.new collection:addIP('1.2.3.4') self:assertEquals(true, collection:containsIP('1.2.3.4')) self:assertEquals(true, collection:containsIP(IPAddress.new('1.2.3.4'))) self:assertEquals(false, collection:containsIP('1.2.3.5')) end

function suite:testIPv4CollectionContainsIPErrors self:assertTypeError(		1, 'containsIP', 'string or table', 'boolean',		function 			IPv4Collection.new:containsIP(false)		end	) self:assertTypeError(		1, 'containsIP', 'string or table', 'nil',		function 			IPv4Collection.new:containsIP		end	) self:assertIPStringError(		'foo',		function 			IPv4Collection.new:containsIP('foo')		end	) self:assertObjectError(		1, 'containsIP', 'IPAddress',		function 			IPv4Collection.new:containsIP{foo = 'bar'}		end	) end

function suite:testIPv4CollectionGetRanges local collection = IPv4Collection.new collection:addSubnet('1.2.0.0/24') collection:addSubnet('1.2.1.0/24') self:assertRangesEqual(		,		collection:getRanges	) collection:addSubnet('1.2.10.0/24') self:assertRangesEqual(		{			{IPAddress.new('1.2.0.0'), IPAddress.new('1.2.1.255')},			{IPAddress.new('1.2.10.0'), IPAddress.new('1.2.10.255')},		},		collection:getRanges	) end

function suite:testIPv4CollectionOverlapsSubnet local collection = IPv4Collection.new self:assertEquals(false, collection:overlapsSubnet('1.2.3.0/24')) collection:addIP('1.2.3.4') self:assertEquals(true, collection:overlapsSubnet('1.2.3.0/24')) self:assertEquals(false, collection:overlapsSubnet('5.6.7.0/24')) end

function suite:testIPv4CollectionOverlapsSubnetObjects local collection = IPv4Collection.new self:assertEquals(false, collection:overlapsSubnet(Subnet.new('1.2.3.0/24'))) collection:addIP('1.2.3.4') self:assertEquals(true, collection:overlapsSubnet(Subnet.new('1.2.3.0/24'))) self:assertEquals(false, collection:overlapsSubnet(Subnet.new('5.6.7.0/24'))) end

function suite:testIPv4CollectionOverlapsSubnetErrors self:assertTypeError(		1, 'overlapsSubnet', 'string or table', 'boolean',		function 			IPv4Collection.new:overlapsSubnet(false)		end	) self:assertTypeError(		1, 'overlapsSubnet', 'string or table', 'nil',		function 			IPv4Collection.new:overlapsSubnet		end	) self:assertCIDRStringError(		'foo',		function 			IPv4Collection.new:overlapsSubnet('foo')		end	) self:assertObjectError(		1, 'overlapsSubnet', 'Subnet',		function 			IPv4Collection.new:overlapsSubnet{foo = 'bar'}		end	) end

function suite:testIPv4CollectionAddFromString local collection = IPv4Collection.new collection:addFromString('foo 1.2.3.4 bar 5.6.7.0/24 baz') self:assertTrue(collection:containsIP('1.2.3.4')) self:assertTrue(collection:overlapsSubnet('5.6.7.0/24')) end

function suite:testIPv4CollectionAddFromStringChaining self:assertNotError(function 		IPv4Collection.new			:addFromString('foo 1.2.3.4')			:addFromString('bar 5.6.7.8')	end) end

function suite:testIPv4CollectionAddFromStringErrors self:assertTypeError(		1, 'addFromString', 'string', 'boolean',		function 			IPv4Collection.new:addFromString(false)		end	) self:assertTypeError(		1, 'addFromString', 'string', 'nil',		function 			IPv4Collection.new:addFromString		end	) self:assertTypeError(		1, 'addFromString', 'string', 'table',		function 			IPv4Collection.new:addFromString{}		end	) self:assertTypeError(		1, 'addFromString', 'string', 'number',		function 			IPv4Collection.new:addFromString(7)		end	) end

--- -- IPv6Collection tests ---

function suite:testIPv6CollectionConstructor self:assertIPv6CollectionObject(IPv6Collection.new) end

function suite:testIPv6CollectionGetVersion self:assertEquals('IPv6', IPv6Collection.new:getVersion) end

function suite:testIPv6CollectionAddIP self:assertNotError(function IPv6Collection.new:addIP('2001:db8::ff00:12:3456') end) self:assertNotError(function IPv6Collection.new:addIP(IPAddress.new('2001:db8::ff00:12:3456')) end) suite:assertIPStringError(		'foo',		function 			IPv6Collection.new:addIP(IPAddress.new('foo'))		end	) suite:assertIPStringError(		'2001:db8::ff00:12:0/112',		function 			IPv6Collection.new:addIP(IPAddress.new('2001:db8::ff00:12:0/112'))		end	) end

function suite:testIPv6CollectionAddIPChaining self:assertNotError(function 		IPv6Collection.new			:addIP('2001:db8::ff00:0:1234')			:addIP('2001:db8::ff00:0:5678')	end) end

function suite:testIPv6CollectionAddIPErrors self:assertTypeError(		1, 'addIP', 'string or table', 'boolean',		function 			IPv6Collection.new:addIP(false)		end	) self:assertTypeError(		1, 'addIP', 'string or table', 'nil',		function 			IPv6Collection.new:addIP		end	) self:assertIPStringError(		'foo',		function 			IPv6Collection.new:addIP('foo')		end	) self:assertObjectError(		1, 'addIP', 'IPAddress',		function 			IPv6Collection.new:addIP{foo = 'bar'}		end	) end

function suite:testIPv6CollectionAddSubnet self:assertNotError(function IPv6Collection.new:addSubnet('2001:db8::ff00:12:0/112') end) self:assertNotError(function IPv6Collection.new:addSubnet(Subnet.new('2001:db8::ff00:12:0/112')) end) suite:assertCIDRStringError(		'foo',		function 			IPv6Collection.new:addSubnet('foo')		end	) suite:assertCIDRStringError(		'2001:db8::ff00:12:3456',		function 			IPv6Collection.new:addSubnet('2001:db8::ff00:12:3456')		end	) end

function suite:testIPv6CollectionAddSubnetChaining self:assertNotError(function 		IPv6Collection.new			:addSubnet('2001:db8::ff00:0:0/112')			:addSubnet('2001:db8::ff00:1:0/112')	end) end

function suite:testIPv6CollectionAddSubnetErrors self:assertTypeError(		1, 'addSubnet', 'string or table', 'boolean',		function 			IPv6Collection.new:addSubnet(false)		end	) self:assertTypeError(		1, 'addSubnet', 'string or table', 'nil',		function 			IPv6Collection.new:addSubnet		end	) self:assertCIDRStringError(		'foo',		function 			IPv6Collection.new:addSubnet('foo')		end	) self:assertObjectError(		1, 'addSubnet', 'Subnet',		function 			IPv6Collection.new:addSubnet{foo = 'bar'}		end	) end

function suite:testIPv6CollectionContainsIP local collection = IPv6Collection.new collection:addIP('2001:db8::ff00:12:3456') self:assertEquals(true, collection:containsIP('2001:db8::ff00:12:3456')) self:assertEquals(true, collection:containsIP(IPAddress.new('2001:db8::ff00:12:3456'))) self:assertEquals(false, collection:containsIP('1.2.3.5')) end

function suite:testIPv6CollectionContainsIPErrors self:assertTypeError(		1, 'containsIP', 'string or table', 'boolean',		function 			IPv6Collection.new:containsIP(false)		end	) self:assertTypeError(		1, 'containsIP', 'string or table', 'nil',		function 			IPv6Collection.new:containsIP		end	) self:assertIPStringError(		'foo',		function 			IPv6Collection.new:containsIP('foo')		end	) self:assertObjectError(		1, 'containsIP', 'IPAddress',		function 			IPv6Collection.new:containsIP{foo = 'bar'}		end	) end

function suite:testIPv6CollectionGetRanges local collection = IPv6Collection.new collection:addSubnet('2001:db8::ff00:0:0/112') collection:addSubnet('2001:db8::ff00:1:0/112') self:assertRangesEqual(		,		collection:getRanges	) collection:addSubnet('2001:db8::ff00:10:0/112') self:assertRangesEqual(		{			{IPAddress.new('2001:db8::ff00:0:0'), IPAddress.new('2001:db8::ff00:1:ffff')},			{IPAddress.new('2001:db8::ff00:10:0'), IPAddress.new('2001:db8::ff00:10:ffff')},		},		collection:getRanges	) end

function suite:testIPv6CollectionOverlapsSubnet local collection = IPv6Collection.new self:assertEquals(false, collection:overlapsSubnet('2001:db8::ff00:12:0/112')) collection:addIP('2001:db8::ff00:12:3456') self:assertEquals(true, collection:overlapsSubnet('2001:db8::ff00:12:0/112')) self:assertEquals(false, collection:overlapsSubnet('2001:db8::ff00:34:0/112')) end

function suite:testIPv6CollectionOverlapsSubnetObjects local collection = IPv6Collection.new self:assertEquals(false, collection:overlapsSubnet(Subnet.new('2001:db8::ff00:12:0/112'))) collection:addIP('2001:db8::ff00:12:3456') self:assertEquals(true, collection:overlapsSubnet(Subnet.new('2001:db8::ff00:12:0/112'))) self:assertEquals(false, collection:overlapsSubnet(Subnet.new('2001:db8::ff00:34:0/112'))) end

function suite:testIPv6CollectionOverlapsSubnetErrors self:assertTypeError(		1, 'overlapsSubnet', 'string or table', 'boolean',		function 			IPv6Collection.new:overlapsSubnet(false)		end	) self:assertTypeError(		1, 'overlapsSubnet', 'string or table', 'nil',		function 			IPv6Collection.new:overlapsSubnet		end	) self:assertCIDRStringError(		'foo',		function 			IPv6Collection.new:overlapsSubnet('foo')		end	) self:assertObjectError(		1, 'overlapsSubnet', 'Subnet',		function 			IPv6Collection.new:overlapsSubnet{foo = 'bar'}		end	) end

function suite:testIPv6CollectionAddFromString local collection = IPv6Collection.new collection:addFromString('foo 2001:db8::ff00:12:3456 bar 2001:db8::ff00:34:0/112 baz') self:assertTrue(collection:containsIP('2001:db8::ff00:12:3456')) self:assertTrue(collection:overlapsSubnet('2001:db8::ff00:34:0/112')) end

function suite:testIPv6CollectionAddFromStringStartingColon local collection = IPv6Collection.new collection:addFromString('::12:1234 foo') self:assertTrue(collection:containsIP('::12:1234')) end

function suite:testIPv6CollectionAddFromStringStartingIndent local collection = IPv6Collection.new collection:addFromString('::As I was saying, 2001:db8::ff00:12:3456 should be blocked. ~') self:assertTrue(collection:containsIP('2001:db8::ff00:12:3456')) self:assertFalse(collection:containsIP('::')) end

function suite:testIPv6CollectionAddFromStringChaining self:assertNotError(function 		IPv6Collection.new			:addFromString('foo 2001:db8::ff00:0:1234')			:addFromString('bar 2001:db8::ff00:0:5678')	end) end

function suite:testIPv6CollectionAddFromStringErrors self:assertTypeError(		1, 'addFromString', 'string', 'boolean',		function 			IPv6Collection.new:addFromString(false)		end	) self:assertTypeError(		1, 'addFromString', 'string', 'nil',		function 			IPv6Collection.new:addFromString		end	) self:assertTypeError(		1, 'addFromString', 'string', 'table',		function 			IPv6Collection.new:addFromString{}		end	) self:assertTypeError(		1, 'addFromString', 'string', 'number',		function 			IPv6Collection.new:addFromString(7)		end	) end

return suite