Skip to content

Commit f8b3915

Browse files
committed
Return Optional for static functions when the function could fail
Add some tests in static functions and return nil in case of a fail test Rename isValidIP function to validateIPv4 Handle custom Errors for validateIPv4 function
1 parent b1745c4 commit f8b3915

File tree

2 files changed

+143
-69
lines changed

2 files changed

+143
-69
lines changed

IPSubnetcalc.swift

Lines changed: 96 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,15 @@
88
import Foundation
99
import Cocoa
1010

11+
//*********************
12+
//Errors for IP format
13+
//*********************
14+
enum SubnetCalcError: Error {
15+
case invalidIPv4(_ info: String)
16+
case invalidIPv4Mask(_ info: String)
17+
case invalidIPv6(_ info: String)
18+
case invalidIPv6Mask(_ info: String)
19+
}
1120

1221
class IPSubnetCalc: NSObject {
1322
//*********
@@ -97,15 +106,23 @@ class IPSubnetCalc: NSObject {
97106
the binary representation of the given IP address
98107

99108
*/
100-
static func binarize(ipAddress: String, space: Bool = false, dotted: Bool = true) -> String {
109+
static func binarize(ipAddress: String, space: Bool = false, dotted: Bool = true) -> String? {
101110
var ipAddressBin = [String]()
102111
var binStr = String()
103112
var ipDigits = [String]()
104113

105114
ipDigits = ipAddress.components(separatedBy: ".")
106115

116+
if ipDigits.count != 4 {
117+
return nil
118+
}
107119
for index in 0...3 {
108-
ipAddressBin.append(String(Int(ipDigits[index])!, radix: 2))
120+
if let ipDigit = Int(ipDigits[index]) {
121+
ipAddressBin.append(String(ipDigit, radix: 2))
122+
}
123+
else {
124+
return nil
125+
}
109126
while (ipAddressBin[index].count < 8) {
110127
ipAddressBin[index].insert("0", at: ipAddressBin[index].startIndex)
111128
}
@@ -139,7 +156,7 @@ class IPSubnetCalc: NSObject {
139156

140157
*/
141158
func binaryMap(dotted: Bool = true) -> String {
142-
return (IPSubnetCalc.binarize(ipAddress: ipv4Address, space: false, dotted: dotted))
159+
return (IPSubnetCalc.binarize(ipAddress: ipv4Address, space: false, dotted: dotted)!)
143160
}
144161

145162
/**
@@ -153,14 +170,22 @@ class IPSubnetCalc: NSObject {
153170
the hexadecimal representation of the given IP address
154171

155172
*/
156-
static func hexarize(ipAddress: String, dotted: Bool = true) -> String {
173+
static func hexarize(ipAddress: String, dotted: Bool = true) -> String? {
157174
var ipDigits = [String]()
158175
var hexIP = String()
159176
var hex4: String
160177

161178
ipDigits = ipAddress.components(separatedBy: ".")
179+
if ipDigits.count != 4 {
180+
return nil
181+
}
162182
for index in 0...3 {
163-
hex4 = String(format: "%X", Int(ipDigits[index])!)
183+
if let ipDigit = Int(ipDigits[index]) {
184+
hex4 = String(format: "%X", ipDigit)
185+
}
186+
else {
187+
return nil
188+
}
164189
if (hex4.count == 1) {
165190
hex4 = "0" + hex4
166191
}
@@ -184,7 +209,7 @@ class IPSubnetCalc: NSObject {
184209

185210
*/
186211
func hexaMap(dotted: Bool = true) -> String {
187-
return (IPSubnetCalc.hexarize(ipAddress: ipv4Address, dotted: dotted))
212+
return (IPSubnetCalc.hexarize(ipAddress: ipv4Address, dotted: dotted)!)
188213
}
189214

190215
/**
@@ -196,14 +221,22 @@ class IPSubnetCalc: NSObject {
196221
a digital IP address in UInt32 format
197222

198223
*/
199-
static func digitize(ipAddress: String) -> UInt32 {
224+
static func digitize(ipAddress: String) -> UInt32? {
200225
var ipAddressNum: UInt32 = 0
201226
var ipDigits = [String]()
227+
//var ipDigit: Unit32
202228

203229
ipDigits = ipAddress.components(separatedBy: ".")
204-
230+
if ipDigits.count != 4 {
231+
return nil
232+
}
205233
for index in 0...3 {
206-
ipAddressNum += UInt32(ipDigits[index])! << (32 - 8 * (index + 1))
234+
if let ipDigit = UInt32(ipDigits[index]) {
235+
ipAddressNum += ipDigit << (32 - 8 * (index + 1))
236+
}
237+
else {
238+
return nil
239+
}
207240
}
208241
return (ipAddressNum & Constants.addr32Full)
209242
}
@@ -229,8 +262,11 @@ class IPSubnetCalc: NSObject {
229262
a digital subnet mask in UInt32 format
230263

231264
*/
232-
static func digitize(maskbits: Int) -> UInt32 {
233-
return ((Constants.addr32Full << (32 - maskbits)) & Constants.addr32Full)
265+
static func digitize(maskbits: Int) -> UInt32? {
266+
if (maskbits <= Constants.NETWORK_BITS_MAX && maskbits >= Constants.NETWORK_BITS_MIN_CLASSLESS) {
267+
return ((Constants.addr32Full << (32 - maskbits)) & Constants.addr32Full)
268+
}
269+
return nil
234270
}
235271

236272
/**
@@ -260,11 +296,10 @@ class IPSubnetCalc: NSObject {
260296
- mask: Optionnal subnet mask
261297
- classless: enable class less checks of the given IP address/mask
262298

263-
- Returns:
264-
Boolean if the given IP address is valid or not
299+
- Throws: an invalid IP or invalid mask error with a message explaining the reason
265300

266301
*/
267-
static func isValidIP(ipAddress: String, mask: String?, classless: Bool = false) -> Bool {
302+
static func validateIPv4(ipAddress: String, mask: String?, classless: Bool = false) throws {
268303
var ip4Digits = [String]()
269304

270305
ip4Digits = ipAddress.components(separatedBy: ".")
@@ -273,41 +308,47 @@ class IPSubnetCalc: NSObject {
273308
if let digit = Int(item, radix: 10) {
274309
if (digit > 255) {
275310
print("bad IPv4 digit \(digit)")
276-
return false
311+
throw SubnetCalcError.invalidIPv4("IPv4 digit \(digit) is greater than 255")
312+
//return false
277313
}
278314
}
279315
else {
280316
print("not digit: \(item)")
281-
return false
317+
throw SubnetCalcError.invalidIPv4("not digit: \(item)")
318+
//return false
282319
}
283320
}
284321
}
285322
else {
286323
print("bad IPv4 format \(ip4Digits)")
287-
return false
324+
throw SubnetCalcError.invalidIPv4("\(ipAddress) too short or too long")
325+
//return false
288326
}
289327
if mask != nil {
290328
if let maskNum = Int(mask!) {
291329
if (classless == true) {
292330
if (maskNum < Constants.NETWORK_BITS_MIN_CLASSLESS || maskNum > Constants.NETWORK_BITS_MAX) {
293331
print("IPv4 classless mask \(maskNum) invalid")
294-
return false
332+
throw SubnetCalcError.invalidIPv4Mask("IPv4 classless mask \(maskNum) should be between \(Constants.NETWORK_BITS_MIN_CLASSLESS) and \(Constants.NETWORK_BITS_MAX)")
333+
//return false
295334
}
296335
}
297336
else if (maskNum < Constants.NETWORK_BITS_MIN || maskNum > Constants.NETWORK_BITS_MAX) {
298337
print("IPv4 mask \(maskNum) invalid")
299-
return false
338+
throw SubnetCalcError.invalidIPv4Mask("IPv4 mask \(maskNum) should be between \(Constants.NETWORK_BITS_MIN) and \(Constants.NETWORK_BITS_MAX)")
339+
//return false
300340
}
301341
}
302342
else {
303343
print("IPv4 mask \(mask!) is not digit")
304-
return false
344+
throw SubnetCalcError.invalidIPv4Mask("IPv4 mask \(mask!) is not a digit")
345+
//return false
305346
}
306347
}
307348
else {
308349
//print("null mask")
309350
}
310-
return true
351+
//return true
311352
}
312353

313354
/**
@@ -319,8 +360,8 @@ class IPSubnetCalc: NSObject {
319360
*/
320361
func subnetId() -> String {
321362
var subnetId: UInt32 = 0
322-
let ipBits = IPSubnetCalc.digitize(ipAddress: self.ipv4Address)
323-
let maskBits = IPSubnetCalc.digitize(maskbits: self.maskBits)
363+
let ipBits = IPSubnetCalc.digitize(ipAddress: self.ipv4Address)!
364+
let maskBits = IPSubnetCalc.digitize(maskbits: self.maskBits)!
324365

325366
subnetId = ipBits & maskBits
326367
return (IPSubnetCalc.dottedDecimal(ipAddress: subnetId))
@@ -335,8 +376,8 @@ class IPSubnetCalc: NSObject {
335376
*/
336377
func subnetBroadcast() -> String {
337378
var broadcast: UInt32 = 0
338-
let ipBits = IPSubnetCalc.digitize(ipAddress: self.ipv4Address)
339-
let maskBits = IPSubnetCalc.digitize(maskbits: self.maskBits)
379+
let ipBits = IPSubnetCalc.digitize(ipAddress: self.ipv4Address)!
380+
let maskBits = IPSubnetCalc.digitize(maskbits: self.maskBits)!
340381

341382
broadcast = ipBits & maskBits | (Constants.addr32Full >> self.maskBits)
342383
return (IPSubnetCalc.dottedDecimal(ipAddress: broadcast))
@@ -447,12 +488,12 @@ class IPSubnetCalc: NSObject {
447488
var lastIP: UInt32 = 0
448489

449490
if (maskBits == 31 || maskBits == 32) {
450-
firstIP = IPSubnetCalc.digitize(ipAddress: subnetId())
451-
lastIP = IPSubnetCalc.digitize(ipAddress: subnetBroadcast())
491+
firstIP = IPSubnetCalc.digitize(ipAddress: subnetId())!
492+
lastIP = IPSubnetCalc.digitize(ipAddress: subnetBroadcast())!
452493
}
453494
else {
454-
firstIP = IPSubnetCalc.digitize(ipAddress: subnetId()) + 1
455-
lastIP = IPSubnetCalc.digitize(ipAddress: subnetBroadcast()) - 1
495+
firstIP = IPSubnetCalc.digitize(ipAddress: subnetId())! + 1
496+
lastIP = IPSubnetCalc.digitize(ipAddress: subnetBroadcast())! - 1
456497
}
457498
range = IPSubnetCalc.dottedDecimal(ipAddress: firstIP) + " - " + IPSubnetCalc.dottedDecimal(ipAddress: lastIP)
458499
return (range)
@@ -470,8 +511,8 @@ class IPSubnetCalc: NSObject {
470511
var firstIP: UInt32 = 0
471512
var lastIP: UInt32 = 0
472513

473-
firstIP = IPSubnetCalc.digitize(ipAddress: subnetId())
474-
lastIP = IPSubnetCalc.digitize(ipAddress: subnetBroadcast())
514+
firstIP = IPSubnetCalc.digitize(ipAddress: subnetId())!
515+
lastIP = IPSubnetCalc.digitize(ipAddress: subnetBroadcast())!
475516
range = IPSubnetCalc.dottedDecimal(ipAddress: firstIP) + " - " + IPSubnetCalc.dottedDecimal(ipAddress: lastIP)
476517
return (range)
477518
}
@@ -485,8 +526,8 @@ class IPSubnetCalc: NSObject {
485526
Network Class conforming to RFC 790
486527

487528
*/
488-
static func netClass(ipAddress: String) -> String {
489-
let ipNum = IPSubnetCalc.digitize(ipAddress: ipAddress)
529+
static func netClass(ipAddress: String) -> String? {
530+
if let ipNum = IPSubnetCalc.digitize(ipAddress: ipAddress) {
490531
let addr1stByte = (ipNum & Constants.maskClassA) >> 24
491532

492533
if (addr1stByte < 127) {
@@ -502,6 +543,8 @@ class IPSubnetCalc: NSObject {
502543
return ("D")
503544
}
504545
return ("E")
546+
}
547+
return nil
505548
}
506549

507550
/**
@@ -512,7 +555,7 @@ class IPSubnetCalc: NSObject {
512555

513556
*/
514557
func netClass() -> String {
515-
return (IPSubnetCalc.netClass(ipAddress: ipv4Address))
558+
return (IPSubnetCalc.netClass(ipAddress: ipv4Address)!)
516559
}
517560

518561
/**
@@ -603,16 +646,18 @@ class IPSubnetCalc: NSObject {
603646
the number of bits for the given mask
604647

605648
*/
606-
static func maskBits(maskAddr: String) -> Int {
649+
static func maskBits(maskAddr: String) -> Int? {
607650
var bits: Int = 0
608651

609-
var mask:UInt32 = IPSubnetCalc.digitize(ipAddress: maskAddr)
652+
if var mask:UInt32 = IPSubnetCalc.digitize(ipAddress: maskAddr) {
610653
while (mask != 0) {
611654
bits += 1
612655
mask <<= 1
613656
}
614657
//print("maskBits \(maskAddr) bits: \(bits)")
615658
return (bits)
659+
}
660+
return nil
616661
}
617662

618663
/**
@@ -766,8 +811,8 @@ class IPSubnetCalc: NSObject {
766811
print("CIDR Network (Route) : " + self.subnetId())
767812
print("CIDR Net Notation : " + self.subnetId() + "/" + String(self.maskBits))
768813
print("CIDR Address Range : " + self.subnetCIDRRange())
769-
print("IP number in binary : " + String(IPSubnetCalc.digitize(ipAddress: self.ipv4Address), radix: 2))
770-
print("Mask bin : " + String(IPSubnetCalc.digitize(maskbits: self.maskBits), radix: 2))
814+
print("IP number in binary : " + String(IPSubnetCalc.digitize(ipAddress: self.ipv4Address)!, radix: 2))
815+
print("Mask bin : " + String(IPSubnetCalc.digitize(maskbits: self.maskBits)!, radix: 2))
771816
//print("Subnet ID bin : " + String(self.subnetId(), radix: 2))
772817
//print("Broadcast bin : " + String(self.subnetBroadcast(), radix: 2))
773818
}
@@ -856,7 +901,7 @@ class IPSubnetCalc: NSObject {
856901
static func convertIPv4toIPv6(ipAddress: String, _6to4: Bool = false) -> String {
857902
var ipv6str = String()
858903

859-
let addr = digitize(ipAddress: ipAddress)
904+
if let addr = digitize(ipAddress: ipAddress) {
860905
ipv6str.append(String((((Constants.addr32Digit1 | Constants.addr32Digit2) & addr) >> 16), radix: 16))
861906
ipv6str.append(":")
862907
ipv6str.append(String(((Constants.addr32Digit3 | Constants.addr32Digit4) & addr), radix: 16))
@@ -865,6 +910,10 @@ class IPSubnetCalc: NSObject {
865910
return ("2002:" + ipv6str + ":0:0:0:0:0")
866911
}
867912
return ("0:0:0:0:0:ffff:" + ipv6str)
913+
}
914+
else {
915+
return ""
916+
}
868917
}
869918

870919
/**
@@ -1312,13 +1361,15 @@ class IPSubnetCalc: NSObject {
13121361

13131362
*/
13141363
init?(ipAddress: String, maskbits: Int) {
1315-
if (IPSubnetCalc.isValidIP(ipAddress: ipAddress, mask: String(maskbits), classless: true)) {
1364+
do {
1365+
try IPSubnetCalc.validateIPv4(ipAddress: ipAddress, mask: String(maskbits), classless: true)
13161366
self.ipv4Address = ipAddress
13171367
self.maskBits = maskbits
13181368
self.ipv6Address = IPSubnetCalc.convertIPv4toIPv6(ipAddress: ipAddress)
13191369
self.ipv6MaskBits = maskbits + Constants.defaultIPv6to4Mask
13201370
}
1321-
else {
1371+
catch {
1372+
print("Init error: \(error)")
13221373
return nil
13231374
}
13241375
}
@@ -1336,7 +1387,8 @@ class IPSubnetCalc: NSObject {
13361387
convenience init?(_ ipAddress: String) {
13371388
var classbit: Int
13381389

1339-
if (IPSubnetCalc.isValidIP(ipAddress: ipAddress, mask: nil)) {
1390+
do {
1391+
try IPSubnetCalc.validateIPv4(ipAddress: ipAddress, mask: nil)
13401392
switch (IPSubnetCalc.netClass(ipAddress: ipAddress)) {
13411393
case "A":
13421394
classbit = Constants.classAbits
@@ -1349,7 +1401,8 @@ class IPSubnetCalc: NSObject {
13491401
}
13501402
self.init(ipAddress: ipAddress, maskbits: classbit)
13511403
}
1352-
else {
1404+
catch {
1405+
print("Init error: \(error)")
13531406
return nil
13541407
}
13551408
}

0 commit comments

Comments
 (0)