diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index ff2e3e9..49f21a6 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -23,6 +23,6 @@ jobs: - name: Install Node Dependencies run: npm i - name: Install Flow CLI - run: bash -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/feature/stable-cadence/install.sh)" + run: bash -ci "$(curl -fsSL https://raw.githubusercontent.com/onflow/flow-cli/master/install.sh)" - name: Run tests - run: flow-c1 test --cover --covercode="contracts" test/*_test.cdc + run: flow test --cover --covercode="contracts" test/*_test.cdc diff --git a/contracts/AddressUtils.cdc b/contracts/AddressUtils.cdc index 6b8a839..fd012e2 100644 --- a/contracts/AddressUtils.cdc +++ b/contracts/AddressUtils.cdc @@ -3,7 +3,7 @@ access(all) contract AddressUtils { var address = input // get rid of 0x - if address.length > 1 && address.utf8[1] == 120 { + if address.length > 1 && address[1] == "x" { address = address.slice(from: 2, upTo: address.length) } @@ -11,6 +11,7 @@ access(all) contract AddressUtils { if address.length % 2 == 1 { address = "0".concat(address) } + return address } @@ -49,7 +50,7 @@ access(all) contract AddressUtils { return nil } - access(all) fun isValidAddress(_ input: AnyStruct, forNetwork: String): Bool { + access(all) fun isValidAddress(_ input: AnyStruct, forNetwork network: String): Bool { let address = self.parseUInt64(input) if address == nil { return false @@ -63,25 +64,25 @@ access(all) contract AddressUtils { } let parityCheckMatrixColumns: [UInt64] = [ - 0x00001, 0x00002, 0x00004, 0x00008, 0x00010, 0x00020, 0x00040, 0x00080, - 0x00100, 0x00200, 0x00400, 0x00800, 0x01000, 0x02000, 0x04000, 0x08000, - 0x10000, 0x20000, 0x40000, 0x7328d, 0x6689a, 0x6112f, 0x6084b, 0x433fd, - 0x42aab, 0x41951, 0x233ce, 0x22a81, 0x21948, 0x1ef60, 0x1deca, 0x1c639, - 0x1bdd8, 0x1a535, 0x194ac, 0x18c46, 0x1632b, 0x1529b, 0x14a43, 0x13184, - 0x12942, 0x118c1, 0x0f812, 0x0e027, 0x0d00e, 0x0c83c, 0x0b01d, 0x0a831, - 0x0982b, 0x07034, 0x0682a, 0x05819, 0x03807, 0x007d2, 0x00727, 0x0068e, - 0x0067c, 0x0059d, 0x004eb, 0x003b4, 0x0036a, 0x002d9, 0x001c7, 0x0003f + 0x00001, 0x00002, 0x00004, 0x00008, 0x00010, 0x00020, 0x00040, 0x00080, + 0x00100, 0x00200, 0x00400, 0x00800, 0x01000, 0x02000, 0x04000, 0x08000, + 0x10000, 0x20000, 0x40000, 0x7328d, 0x6689a, 0x6112f, 0x6084b, 0x433fd, + 0x42aab, 0x41951, 0x233ce, 0x22a81, 0x21948, 0x1ef60, 0x1deca, 0x1c639, + 0x1bdd8, 0x1a535, 0x194ac, 0x18c46, 0x1632b, 0x1529b, 0x14a43, 0x13184, + 0x12942, 0x118c1, 0x0f812, 0x0e027, 0x0d00e, 0x0c83c, 0x0b01d, 0x0a831, + 0x0982b, 0x07034, 0x0682a, 0x05819, 0x03807, 0x007d2, 0x00727, 0x0068e, + 0x0067c, 0x0059d, 0x004eb, 0x003b4, 0x0036a, 0x002d9, 0x001c7, 0x0003f ] var parity: UInt64 = 0 - var codeWord: UInt64 = codeWords[forNetwork]! + var codeWord = codeWords[network]! codeWord = codeWord ^ address! if codeWord == 0 { return false } - for column in parityCheckMatrixColumns{ + for column in parityCheckMatrixColumns { if codeWord & 1 == 1 { parity = parity ^ column } @@ -93,7 +94,7 @@ access(all) contract AddressUtils { access(all) fun getNetworkFromAddress(_ input: AnyStruct): String? { for network in ["MAINNET", "TESTNET", "EMULATOR", "PREVIEWNET"] { - if self.isValidAddress(input, forNetwork: network){ + if self.isValidAddress(input, forNetwork: network) { return network } } @@ -101,6 +102,6 @@ access(all) contract AddressUtils { } access(all) fun currentNetwork(): String { - return self.getNetworkFromAddress(self.account.address) ?? panic("unknown network!") + return self.getNetworkFromAddress(self.account.address) ?? panic("unknown network!") } } diff --git a/contracts/ArrayUtils.cdc b/contracts/ArrayUtils.cdc index 7996fdd..5f81e0c 100644 --- a/contracts/ArrayUtils.cdc +++ b/contracts/ArrayUtils.cdc @@ -1,6 +1,7 @@ // Copied from https://github.com/bluesign/flow-utils/blob/dnz/cadence/contracts/ArrayUtils.cdc with minor adjustments access(all) contract ArrayUtils { + access(all) fun rangeFunc(_ start: Int, _ end: Int, _ f: fun (Int): Void) { var current = start while current < end { @@ -18,51 +19,49 @@ access(all) contract ArrayUtils { } access(all) fun reverse(_ array: [Int]): [Int] { - var res: [Int] = [] - var i: Int = array.length - 1 - while i >= 0 { - res.append(array[i]) - i = i - 1 - } - return res + return array.reverse() } - access(all) fun transform(_ array: auth(Mutate) &[AnyStruct], _ f : fun (&AnyStruct, auth(Mutate) &[AnyStruct], Int)){ - for i in self.range(0, array.length){ - f(array[i], array, i) + access(all) fun transform( + _ array: auth(Mutate) &[AnyStruct], + _ f : fun (&AnyStruct, auth(Mutate) &[AnyStruct], Int) + ) { + let length = array.length + if length > 0 { + for i in InclusiveRange(0, length - 1) { + f(array[i], array, i) + } } } - access(all) fun iterate(_ array: [AnyStruct], _ f : fun (AnyStruct): Bool) { - for item in array{ - if !f(item){ + access(all) fun iterate(_ array: [AnyStruct], _ f: fun (AnyStruct): Bool) { + for item in array { + if !f(item) { break } } } - access(all) fun map(_ array: [AnyStruct], _ f : fun (AnyStruct): AnyStruct) : [AnyStruct] { - var res : [AnyStruct] = [] - for item in array{ - res.append(f(item)) - } - return res + access(all) fun map(_ array: [AnyStruct], _ f: fun (AnyStruct): AnyStruct): [AnyStruct] { + return array.map(f) } - access(all) fun mapStrings(_ array: [String], _ f: fun (String) : String) : [String] { - var res : [String] = [] - for item in array{ - res.append(f(item)) - } - return res + access(all) fun mapStrings(_ array: [String], _ f: fun (String): String): [String] { + return array.map(f) } - access(all) fun reduce(_ array: [AnyStruct], _ initial: AnyStruct, _ f : fun (AnyStruct, AnyStruct): AnyStruct) : AnyStruct{ - var res: AnyStruct = f(initial, array[0]) - for i in self.range(1, array.length){ - res = f(res, array[i]) + access(all) fun reduce(_ + array: [AnyStruct], + _ initial: AnyStruct, + _ f: fun (AnyStruct, AnyStruct): AnyStruct + ): AnyStruct { + var res = initial + let length = array.length + if length > 0 { + for i in InclusiveRange(0, length - 1) { + res = f(res, array[i]) + } } return res } - } \ No newline at end of file diff --git a/contracts/StringUtils.cdc b/contracts/StringUtils.cdc index f9f2ba6..3b19c07 100644 --- a/contracts/StringUtils.cdc +++ b/contracts/StringUtils.cdc @@ -2,76 +2,73 @@ import "ArrayUtils" access(all) contract StringUtils { - access(all) fun format(_ s: String, _ args: {String:String}): String{ + access(all) fun format(_ s: String, _ args: {String: String}): String { var formatted = s - for key in args.keys{ + for key in args.keys { formatted = StringUtils.replaceAll(formatted, "{".concat(key).concat("}"), args[key]!) } return formatted } - access(all) fun explode(_ s: String): [String]{ - var chars : [String] = [] - for i in ArrayUtils.range(0, s.length){ - chars.append(s[i].toString()) - } - return chars + access(all) fun explode(_ s: String): [String] { + return s.split(separator: "") } - access(all) fun trimLeft(_ s: String): String{ - for i in ArrayUtils.range(0, s.length){ - if s[i] != " "{ - return s.slice(from: i, upTo: s.length) + access(all) fun trimLeft(_ s: String): String { + let length = s.length + if length > 0 { + for i in InclusiveRange(0, length - 1) { + if s[i] != " " { + return s.slice(from: i, upTo: s.length) + } } } return "" } - access(all) fun trim(_ s: String): String{ + access(all) fun trim(_ s: String): String { return self.trimLeft(s) } - access(all) fun replaceAll(_ s: String, _ search: String, _ replace: String): String{ + access(all) fun replaceAll(_ s: String, _ search: String, _ replace: String): String { return s.replaceAll(of: search, with: replace) } - access(all) fun hasPrefix(_ s: String, _ prefix: String) : Bool{ - return s.length >= prefix.length && s.slice(from:0, upTo: prefix.length)==prefix + access(all) fun hasPrefix(_ s: String, _ prefix: String): Bool { + return s.length >= prefix.length + && s.slice(from:0, upTo: prefix.length) == prefix } - access(all) fun hasSuffix(_ s: String, _ suffix: String) : Bool{ - return s.length >= suffix.length && s.slice(from:s.length-suffix.length, upTo: s.length)==suffix + access(all) fun hasSuffix(_ s: String, _ suffix: String): Bool { + return s.length >= suffix.length + && s.slice(from: s.length - suffix.length, upTo: s.length) == suffix } - access(all) fun index(_ s : String, _ substr : String, _ startIndex: Int): Int?{ - for i in ArrayUtils.range(startIndex,s.length-substr.length+1){ - if s[i]==substr[0] && s.slice(from:i, upTo:i+substr.length) == substr{ - return i - } + access(all) fun index(_ s: String, _ substr: String, _ startIndex: Int): Int? { + var s = s + if startIndex > 0 { + s = s.slice(from: startIndex, upTo: s.length) + } + let index = s.index(of: substr) + if index < 0 { + return nil } - return nil + return index + startIndex } - access(all) fun count(_ s: String, _ substr: String): Int{ - var pos = [self.index(s, substr, 0)] - while pos[0]!=nil { - pos.insert(at:0, self.index(s, substr, pos[0]!+pos.length*substr.length+1)) - } - return pos.length-1 + access(all) fun count(_ s: String, _ substr: String): Int { + return s.count(substr) } access(all) fun contains(_ s: String, _ substr: String): Bool { - if let index = self.index(s, substr, 0) { - return true - } - return false + return s.contains(substr) } - access(all) fun substringUntil(_ s: String, _ until: String, _ startIndex: Int): String{ - if let index = self.index( s, until, startIndex){ - return s.slice(from:startIndex, upTo: index) + access(all) fun substringUntil(_ s: String, _ until: String, _ startIndex: Int): String { + if let index = self.index(s, until, startIndex) { + return s.slice(from: startIndex, upTo: index) } - return s.slice(from:startIndex, upTo:s.length) + return s.slice(from: startIndex, upTo: s.length) } access(all) fun split(_ s: String, _ delimiter: String): [String] { diff --git a/run-tests.sh b/run-tests.sh index ba818f4..c1c35d0 100755 --- a/run-tests.sh +++ b/run-tests.sh @@ -1 +1,2 @@ -flow-c1 test --cover --covercode="contracts" test/*_test.cdc \ No newline at end of file +#!/bin/sh +flow test --cover --covercode="contracts" test/*_test.cdc diff --git a/scripts/address.cdc b/scripts/address.cdc index f191440..5e7e48d 100644 --- a/scripts/address.cdc +++ b/scripts/address.cdc @@ -1,11 +1,10 @@ import "AddressUtils" -access(all) fun main(){ +access(all) fun main() { log(AddressUtils.currentNetwork()) log(AddressUtils.parseAddress("0x1")) log(AddressUtils.parseAddress(1)) log(AddressUtils.parseAddress(0x1)) log(AddressUtils.parseAddress("0xf8d6e0586b0a20c7")) log(AddressUtils.parseAddress(AddressUtils.getType())) - } \ No newline at end of file diff --git a/test/AddressUtils_test.cdc b/test/AddressUtils_test.cdc index b0e6771..455b0f1 100644 --- a/test/AddressUtils_test.cdc +++ b/test/AddressUtils_test.cdc @@ -28,116 +28,139 @@ fun setup() { } access(all) -fun testWithoutPrefix() { +fun testWithoutPrefixEvenLength() { // Act - var address = AddressUtils.withoutPrefix("0xf8d6e0586b0a20c7") + let address = AddressUtils.withoutPrefix("0xf8d6e0586b0a20c7") // Assert Test.assertEqual("f8d6e0586b0a20c7", address) +} + +access(all) +fun testWithoutPrefixOddLength() { // Act - // Odd length - address = AddressUtils.withoutPrefix("8d6e0586b0a20c7") + let address = AddressUtils.withoutPrefix("8d6e0586b0a20c7") // Assert Test.assertEqual("08d6e0586b0a20c7", address) } access(all) -fun testParseUInt64() { +fun testParseUInt64HexString() { // Act var address = AddressUtils.parseUInt64("0xf8d6e0586b0a20c7") // Assert Test.assertEqual(17930765636779778247 as UInt64?, address) +} +access(all) +fun testParseUInt64Address() { // Act - address = AddressUtils.parseUInt64(Address(0xf8d6e0586b0a20c7)) + let address = AddressUtils.parseUInt64(Address(0xf8d6e0586b0a20c7)) // Assert Test.assertEqual(17930765636779778247 as UInt64?, address) +} + +access(all) +fun testParseUInt64Type() { // Act // In the testing framework, the FlowToken address is: // 0x0000000000000003 - address = AddressUtils.parseUInt64(FlowToken.getType()) + let address = AddressUtils.parseUInt64(FlowToken.getType()) // Assert Test.assertEqual(3 as UInt64?, address) +} +access(all) +fun testParseUInt64HexInteger() { // Act - address = AddressUtils.parseUInt64(0x01) + let address = AddressUtils.parseUInt64(0x01) // Assert Test.assertEqual(nil, address) +} + +access(all) +fun testParseUInt64String() { // Act - address = AddressUtils.parseUInt64("hello".getType()) + let address = AddressUtils.parseUInt64("hello".getType()) // Assert Test.assertEqual(nil, address) } access(all) -fun testParseAddress() { +fun testParseAddressValid() { // Act - var address = AddressUtils.parseAddress("0xf8d6e0586b0a20c7") + let address = AddressUtils.parseAddress("0xf8d6e0586b0a20c7") // Assert - Test.assertEqual(Address(0xf8d6e0586b0a20c7), address!) + Test.assertEqual(0xf8d6e0586b0a20c7 as Address?, address) +} +access(all) +fun testParseAddressInvalid() { // Act - address = AddressUtils.parseAddress(1005) + let address = AddressUtils.parseAddress(1005) // Assert Test.assertEqual(nil, address) } access(all) -fun testIsValidAddress() { - // Act - let mainnet = AddressUtils.isValidAddress("0xa340dc0a4ec828ab", forNetwork: "MAINNET") - let testnet = AddressUtils.isValidAddress("0x31ad40c07a2a9788", forNetwork: "TESTNET") - let emulator = AddressUtils.isValidAddress("0xf8d6e0586b0a20c7", forNetwork: "EMULATOR") - - // Assert - Test.assert(mainnet && testnet && emulator) - - // Act - var valid = AddressUtils.isValidAddress(1452, forNetwork: "EMULATOR") - - // Assert - Test.assertEqual(false, valid) +fun testIsValidAddressValid() { + Test.assert(AddressUtils.isValidAddress("0xa340dc0a4ec828ab", forNetwork: "MAINNET")) + Test.assert(AddressUtils.isValidAddress("0x31ad40c07a2a9788", forNetwork: "TESTNET")) + Test.assert(AddressUtils.isValidAddress("0xf8d6e0586b0a20c7", forNetwork: "EMULATOR")) +} - // Act - valid = AddressUtils.isValidAddress("0x6834ba37b3980209", forNetwork: "TESTNET") +access(all) +fun testIsValidAddressInvalidEmulator() { + Test.assert(!AddressUtils.isValidAddress(1452, forNetwork: "EMULATOR")) +} - // Assert - Test.assertEqual(false, valid) +access(all) +fun testIsValidAddressInvalidTestnet() { + Test.assert(!AddressUtils.isValidAddress("0x6834ba37b3980209", forNetwork: "TESTNET")) } access(all) -fun testGetNetworkFromAddress() { +fun testGetNetworkFromAddressInvalid() { // Act var network = AddressUtils.getNetworkFromAddress(1541) // Assert Test.assertEqual(nil, network) +} +access(all) +fun testGetNetworkFromAddressEmulator() { // Act - network = AddressUtils.getNetworkFromAddress("0xf8d6e0586b0a20c7") + let network = AddressUtils.getNetworkFromAddress("0xf8d6e0586b0a20c7") // Assert Test.assertEqual("EMULATOR" as String?, network) +} +access(all) +fun testGetNetworkFromAddressTestnet() { // Act - network = AddressUtils.getNetworkFromAddress("0x31ad40c07a2a9788") + let network = AddressUtils.getNetworkFromAddress("0x31ad40c07a2a9788") // Assert Test.assertEqual("TESTNET" as String?, network) +} +access(all) +fun testGetNetworkFromAddressMainnet() { // Act - network = AddressUtils.getNetworkFromAddress("0xa340dc0a4ec828ab") + let network = AddressUtils.getNetworkFromAddress("0xa340dc0a4ec828ab") // Assert Test.assertEqual("MAINNET" as String?, network) @@ -145,7 +168,10 @@ fun testGetNetworkFromAddress() { access(all) fun testGetCurrentNetwork() { - Test.expectFailure(fun(): Void { - AddressUtils.currentNetwork() - }, errorMessageSubstring: "unknown network!") + Test.expectFailure( + fun() { + let network = AddressUtils.currentNetwork() + }, + errorMessageSubstring: "unknown network!" + ) } diff --git a/test/ArrayUtils_test.cdc b/test/ArrayUtils_test.cdc index cca02fd..c86d717 100644 --- a/test/ArrayUtils_test.cdc +++ b/test/ArrayUtils_test.cdc @@ -36,6 +36,36 @@ fun testRange() { Test.assertEqual(expected, range) } +access(all) +fun testRangeZero() { + // Act + let range = ArrayUtils.range(0, 0) + + // Assert + let expected: [Int] = [] + Test.assertEqual(expected, range) +} + +access(all) +fun testRangeNegative() { + // Act + let range = ArrayUtils.range(-2, 2) + + // Assert + let expected: [Int] = [-2, -1, 0, 1] + Test.assertEqual(expected, range) +} + +access(all) +fun testRangeEndSmaller() { + // Act + let range = ArrayUtils.range(2, -2) + + // Assert + let expected: [Int] = [] + Test.assertEqual(expected, range) +} + access(all) fun testReverseRange() { // Act @@ -46,6 +76,16 @@ fun testReverseRange() { Test.assertEqual(expected, range) } +access(all) +fun testReverseEmpty() { + // Act + let range = ArrayUtils.reverse([]) + + // Assert + let expected: [Int] = [] + Test.assertEqual(expected, range) +} + access(all) fun testTransform() { // Arrange @@ -56,10 +96,13 @@ fun testTransform() { ] // Act - ArrayUtils.transform(&tokens as auth(Mutate) &[Token], fun (t: &AnyStruct, arr: auth(Mutate) &[AnyStruct], index: Int) { - let token = t as! &Token - token.setBalance(token.balance * 2) - }) + ArrayUtils.transform( + &tokens as auth(Mutate) &[Token], + fun (t: &AnyStruct, arr: auth(Mutate) &[AnyStruct], index: Int) { + let token = t as! &Token + token.setBalance(token.balance * 2) + } + ) // Assert let expected = [ @@ -70,6 +113,24 @@ fun testTransform() { Test.assertEqual(expected, tokens) } +access(all) +fun testTransformEmpty() { + // Arrange + let values: [Int] = [] + + // Act + ArrayUtils.transform( + &values as auth(Mutate) &[Int], + fun (t: &AnyStruct, arr: auth(Mutate) &[AnyStruct], index: Int) { + panic("unreachable") + } + ) + + // Assert + let expected: [Int] = [] + Test.assertEqual(expected, values) +} + access(all) fun testIterate() { // Arrange @@ -83,18 +144,42 @@ fun testIterate() { // Act var totalBalance = 0 - ArrayUtils.iterate(tokens, fun (t: AnyStruct): Bool { - var token = t as! Token - if token.id <= 2 { - totalBalance = totalBalance + token.balance - return true + ArrayUtils.iterate( + tokens, + fun (t: AnyStruct): Bool { + let token = t as! Token + if token.id <= 2 { + totalBalance = totalBalance + token.balance + return true + } + return false } - return false - }) + ) + // Assert Test.assertEqual(30, totalBalance) } + +access(all) +fun testIterateEmpty() { + // Arrange + let values: [Int] = [] + + // Act + ArrayUtils.iterate( + values, + fun (t: AnyStruct): Bool { + panic("unreachable") + } + ) + + // Assert + let expected: [Int] = [] + Test.assertEqual(expected, values) +} + + access(all) fun testMap() { // Arrange @@ -105,11 +190,14 @@ fun testMap() { ] // Act - let mapped = ArrayUtils.map(tokens, fun (t: AnyStruct): AnyStruct { - var token = t as! Token - token.setBalance(token.balance - 2) - return token - }) + let mapped = ArrayUtils.map( + tokens, + fun (t: AnyStruct): AnyStruct { + let token = t as! Token + token.setBalance(token.balance - 2) + return token + } + ) // Assert let expected: [AnyStruct] = [ @@ -120,6 +208,24 @@ fun testMap() { Test.assertEqual(expected, mapped) } +access(all) +fun testMapEmpty() { + // Arrange + let values: [Int] = [] + + // Act + let mapped = ArrayUtils.map( + values, + fun (t: AnyStruct): AnyStruct { + panic("unreachable") + } + ) + + // Assert + let expected: [AnyStruct] = [] + Test.assertEqual(expected, mapped) +} + access(all) fun testMapStrings() { // Arrange @@ -139,6 +245,24 @@ fun testMapStrings() { Test.assertEqual(expected, mapped) } +access(all) +fun testMapStringsEmpty() { + // Arrange + let strings: [String] = [] + + // Act + let mapped = ArrayUtils.mapStrings( + strings, + fun (s: String): String { + panic("unreachable") + } + ) + + // Assert + let expected: [String] = [] + Test.assertEqual(expected, mapped) +} + access(all) fun testReduce() { // Arrange @@ -150,13 +274,66 @@ fun testReduce() { let initial = Token(id: 5, balance: 0) // Act - let token = ArrayUtils.reduce(tokens, initial, fun (acc: AnyStruct, t: AnyStruct): AnyStruct { - var token = t as! Token - var accToken = acc as! Token - accToken.setBalance(accToken.balance + token.balance) - return accToken - }) + let token = ArrayUtils.reduce( + tokens, + initial, + fun (acc: AnyStruct, t: AnyStruct): AnyStruct { + let token = t as! Token + let accToken = acc as! Token + accToken.setBalance(accToken.balance + token.balance) + return accToken + } + ) // Assert Test.assertEqual(30, (token as! Token).balance) } + +access(all) +fun testReduceEmpty() { + // Arrange + let initial = 42 + + // Act + let res = ArrayUtils.reduce( + [], + initial, + fun (acc: AnyStruct, t: AnyStruct): AnyStruct { + panic("unreachable") + } + ) + + // Assert + Test.assertEqual(initial, res) +} + +access(all) +fun testReduceOne() { + // Act + let res = ArrayUtils.reduce( + [2], + 1, + fun (acc: AnyStruct, t: AnyStruct): AnyStruct { + return (acc as! Int) + (t as! Int) + } + ) + + // Assert + Test.assertEqual(3, res) +} + + +access(all) +fun testReduceTwo() { + // Act + let res = ArrayUtils.reduce( + [2, 3], + 1, + fun (acc: AnyStruct, t: AnyStruct): AnyStruct { + return (acc as! Int) + (t as! Int) + } + ) + + // Assert + Test.assertEqual(6, res) +} diff --git a/test/StringUtils_test.cdc b/test/StringUtils_test.cdc index d3b2e8a..a632a50 100644 --- a/test/StringUtils_test.cdc +++ b/test/StringUtils_test.cdc @@ -27,6 +27,24 @@ fun testFormat() { Test.assertEqual("Hello, Peter!", str) } +access(all) +fun testFormatMissing() { + // Act + let str = StringUtils.format("Hello, {name}!", {}) + + // Assert + Test.assertEqual("Hello, {name}!", str) +} + +access(all) +fun testFormatExtra() { + // Act + let str = StringUtils.format("Hello, {name}!", {"name": "Peter", "foo": "bar"}) + + // Assert + Test.assertEqual("Hello, Peter!", str) +} + access(all) fun testExplode() { // Act @@ -37,6 +55,16 @@ fun testExplode() { Test.assertEqual(expected, chars) } +access(all) +fun testExplodeEmpty() { + // Act + let chars = StringUtils.explode("") + + // Assert + let expected: [String] = [] + Test.assertEqual(expected, chars) +} + access(all) fun testTrimLeft() { // Act @@ -44,9 +72,23 @@ fun testTrimLeft() { // Assert Test.assertEqual("Hello, World!", str) +} + +access(all) +fun testTrimLeftEmpty() { + + // Act + let str = StringUtils.trimLeft("") + + // Assert + Test.assertEqual("", str) +} + +access(all) +fun testTrimLeftOnlySpaces() { // Act - str = StringUtils.trimLeft("") + let str = StringUtils.trimLeft(" ") // Assert Test.assertEqual("", str) @@ -71,50 +113,131 @@ fun testReplaceAll() { } access(all) -fun testHasPrefix() { +fun testHasPrefixValid() { // Act var hasPrefix = StringUtils.hasPrefix("Hello, World!", "Hell") // Assert Test.assert(hasPrefix) +} +access(all) +fun testHasPrefixInvalid() { // Act - hasPrefix = StringUtils.hasPrefix("Hell", "Hello, World!") + let hasPrefix = StringUtils.hasPrefix("Hell", "Hello, World!") // Assert - Test.assertEqual(false, hasPrefix) + Test.assert(!hasPrefix) } access(all) -fun testHasSuffix() { +fun testHasPrefixEmpty() { + // Act + var hasPrefix = StringUtils.hasPrefix("", "Hell") + + // Assert + Test.assert(!hasPrefix) +} + +access(all) +fun testHasPrefixEmptySuffix() { + // Act + var hasPrefix = StringUtils.hasPrefix("foo", "") + + // Assert + Test.assert(hasPrefix) +} + +access(all) +fun testHasSuffixValid() { // Act var hasSuffix = StringUtils.hasSuffix("Hello, World!", "ld!") // Assert Test.assert(hasSuffix) +} + +access(all) +fun testHasSuffixInvalid() { + // Act + let hasSuffix = StringUtils.hasSuffix("ld!", "Hello, World!") + + // Assert + Test.assert(!hasSuffix) +} + +access(all) +fun testHasSuffixEmpty() { + // Act + let hasSuffix = StringUtils.hasSuffix("", "Hello, World!") + + // Assert + Test.assert(!hasSuffix) +} +access(all) +fun testHasSuffixEmptySuffix() { // Act - hasSuffix = StringUtils.hasSuffix("ld!", "Hello, World!") + let hasSuffix = StringUtils.hasSuffix("foo", "") // Assert - Test.assertEqual(false, hasSuffix) + Test.assert(hasSuffix) } access(all) -fun testIndex() { +fun testIndexValid() { // Act var index = StringUtils.index("Hello, Peter!", "Peter", 0) // Assert Test.assertEqual(7 as Int?, index) +} +access(all) +fun testIndexInvalid() { // Act - index = StringUtils.index("Hello, Peter!", "Mark", 0) + let index = StringUtils.index("Hello, Peter!", "Mark", 0) // Assert Test.assertEqual(nil, index) } +access(all) +fun testIndexValidOffset() { + // Act + var index = StringUtils.index("Peter, Peter!", "Peter", 1) + + // Assert + Test.assertEqual(7 as Int?, index) +} + +access(all) +fun testIndexInvalidOffset() { + // Act + let index = StringUtils.index("Mark, Peter!", "Mark", 1) + + // Assert + Test.assertEqual(nil, index) +} + +access(all) +fun testIndexEmpty() { + // Act + var index = StringUtils.index("", "Peter", 0) + + // Assert + Test.assertEqual(nil, index) +} + +access(all) +fun testIndexEmptySearch() { + // Act + var index = StringUtils.index("foo", "", 0) + + // Assert + Test.assertEqual(0 as Int?, index) +} + access(all) fun testCount() { // Act @@ -125,22 +248,25 @@ fun testCount() { } access(all) -fun testContains() { +fun testContainsValid() { // Act var found = StringUtils.contains("Hello, World!", "orl") // Assert Test.assert(found) +} +access(all) +fun testContainsInvalid() { // Act - found = StringUtils.contains("Hello, World!", "wow") + let found = StringUtils.contains("Hello, World!", "wow") // Assert - Test.assertEqual(false, found) + Test.assert(!found) } access(all) -fun testSubstringUntil() { +fun testSubstringUntilValid() { // Act var substring = StringUtils.substringUntil( "Hello, sir. How are you today?", @@ -151,8 +277,12 @@ fun testSubstringUntil() { // Assert Test.assertEqual("Hello, sir", substring) +} + +access(all) +fun testSubstringUntilInvalid() { // Act - substring = StringUtils.substringUntil("Hello, sir!", ".", 0) + let substring = StringUtils.substringUntil("Hello, sir!", ".", 0) // Assert Test.assertEqual("Hello, sir!", substring) @@ -168,6 +298,26 @@ fun testSplit() { Test.assertEqual(expected, phrases) } +access(all) +fun testSplitEmpty() { + // Act + let phrases = StringUtils.split("", ",") + + // Assert + let expected = [""] + Test.assertEqual(expected, phrases) +} + +access(all) +fun testSplitEmptySeparator() { + // Act + let phrases = StringUtils.split("foo", "") + + // Assert + let expected = ["f", "o", "o"] + Test.assertEqual(expected, phrases) +} + access(all) fun testJoin() { // Act @@ -176,3 +326,12 @@ fun testJoin() { // Assert Test.assertEqual("Hello How Are You Today?", str) } + +access(all) +fun testJoinEmpty() { + // Act + let str = StringUtils.join([], " ") + + // Assert + Test.assertEqual("", str) +}