From 8ade4fbd1a3489e79bd9bb33c7115d3ccb1d224b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 09:18:27 +0200 Subject: [PATCH 01/27] add a sin expression --- Sources/jsonlogic/Parser.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Sources/jsonlogic/Parser.swift b/Sources/jsonlogic/Parser.swift index 30b514d..3e5d921 100644 --- a/Sources/jsonlogic/Parser.swift +++ b/Sources/jsonlogic/Parser.swift @@ -216,6 +216,23 @@ struct Not: Expression { } } +struct Sin: Expression { + let arg: Expression + + func evalWithData(_ data: JSON?) throws -> JSON { + let jsonValue = try arg.evalWithData(data) + + if case let JSON.Int(number) = jsonValue { + let sinValue = sin(Double(number)) + return JSON.Double(sinValue) + } else if case let JSON.Double(number) = jsonValue { + return JSON.Double(sin(number)) + } else { + return JSON.Null + } + } +} + struct Max: Expression { let arg: Expression From 8d6240dda0a7958d628fdcfe08435f7af5a18b3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 09:19:30 +0200 Subject: [PATCH 02/27] add sin to parser --- Sources/jsonlogic/Parser.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/jsonlogic/Parser.swift b/Sources/jsonlogic/Parser.swift index 3e5d921..a2a79b1 100644 --- a/Sources/jsonlogic/Parser.swift +++ b/Sources/jsonlogic/Parser.swift @@ -693,6 +693,8 @@ class Parser { return Max(arg: try self.parse(json: value)) case "min": return Min(arg: try self.parse(json: value)) + case "sin": + return Sin(arg: try self.parse(json: value)) case "substr": guard let array = try self.parse(json: value) as? ArrayOfExpressions else { throw ParseError.GenericError("\(key) statement be followed by an array") From 35aeb97ef674c37ffdc58727f426ac054948fabf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 09:35:46 +0200 Subject: [PATCH 03/27] add sin tests --- Tests/jsonlogicTests/ArithmeticTests.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Tests/jsonlogicTests/ArithmeticTests.swift b/Tests/jsonlogicTests/ArithmeticTests.swift index e537994..79284b9 100644 --- a/Tests/jsonlogicTests/ArithmeticTests.swift +++ b/Tests/jsonlogicTests/ArithmeticTests.swift @@ -167,4 +167,13 @@ class Arithmetic: XCTestCase { """ XCTAssertEqual(2, try applyRule(rule, to: nil)) } + + func testSin() { + var rule = + """ + { "sin": [1.57079632679] } + """ + + XCTAssertEqual(1, try applyRule(rule, to: nil), accuracy: 0.002) + } } From f7bc8e0dfa2eb71b3c8388d2625e3436091cd185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 09:36:19 +0200 Subject: [PATCH 04/27] add array parsing to sin --- Sources/jsonlogic/Parser.swift | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Sources/jsonlogic/Parser.swift b/Sources/jsonlogic/Parser.swift index a2a79b1..237d104 100644 --- a/Sources/jsonlogic/Parser.swift +++ b/Sources/jsonlogic/Parser.swift @@ -222,7 +222,18 @@ struct Sin: Expression { func evalWithData(_ data: JSON?) throws -> JSON { let jsonValue = try arg.evalWithData(data) - if case let JSON.Int(number) = jsonValue { + if case let JSON.Array(array) = try arg.evalWithData(data) { + guard array.count > 1 else { + return array.first?.double.flatMap(sin).flatMap(JSON.Double) ?? + array.first?.int.flatMap(Double.init).flatMap(sin).flatMap(JSON.Double) ?? + JSON.Null + } + + return JSON.Array(array.compactMap { value in + return value.double.flatMap(sin).flatMap(JSON.Double) ?? + value.int.flatMap(Double.init).flatMap(sin).flatMap(JSON.Double) + }) + } else if case let JSON.Int(number) = jsonValue { let sinValue = sin(Double(number)) return JSON.Double(sinValue) } else if case let JSON.Double(number) = jsonValue { From f0d88a3cea8979a5a58f4ae9d9a28bf175225c0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 09:41:32 +0200 Subject: [PATCH 05/27] add more sin tests --- Tests/jsonlogicTests/ArithmeticTests.swift | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Tests/jsonlogicTests/ArithmeticTests.swift b/Tests/jsonlogicTests/ArithmeticTests.swift index 79284b9..e70e451 100644 --- a/Tests/jsonlogicTests/ArithmeticTests.swift +++ b/Tests/jsonlogicTests/ArithmeticTests.swift @@ -171,9 +171,26 @@ class Arithmetic: XCTestCase { func testSin() { var rule = """ - { "sin": [1.57079632679] } + { "sin": [\(Double.pi / 2)] } """ XCTAssertEqual(1, try applyRule(rule, to: nil), accuracy: 0.002) + + rule = + """ + { "sin": [\(Double.pi / 6)] } + """ + + XCTAssertEqual(0.5, try applyRule(rule, to: nil), accuracy: 0.002) + + rule = + """ + { "sin": [\(Double.pi)] } + """ + + XCTAssertEqual(0, try applyRule(rule, to: nil), accuracy: 0.002) + } + + func testCos() { } } From fc8c89904e3ecf700aefec51e869c8bd374da74f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 09:46:27 +0200 Subject: [PATCH 06/27] add cos tests --- Tests/jsonlogicTests/ArithmeticTests.swift | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Tests/jsonlogicTests/ArithmeticTests.swift b/Tests/jsonlogicTests/ArithmeticTests.swift index e70e451..12a17a3 100644 --- a/Tests/jsonlogicTests/ArithmeticTests.swift +++ b/Tests/jsonlogicTests/ArithmeticTests.swift @@ -192,5 +192,25 @@ class Arithmetic: XCTestCase { } func testCos() { + var rule = + """ + { "cos": [\(Double.pi / 2)] } + """ + + XCTAssertEqual(0, try applyRule(rule, to: nil), accuracy: 0.002) + + rule = + """ + { "cos": [\(Double.pi / 3)] } + """ + + XCTAssertEqual(0.5, try applyRule(rule, to: nil), accuracy: 0.002) + + rule = + """ + { "cos": [\(Double.pi)] } + """ + + XCTAssertEqual(1, try applyRule(rule, to: nil), accuracy: 0.002) } } From 29ad98b868f36cb0d31395269f74d8364a64fafe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 09:47:10 +0200 Subject: [PATCH 07/27] add implementation of cos --- Sources/jsonlogic/Parser.swift | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Sources/jsonlogic/Parser.swift b/Sources/jsonlogic/Parser.swift index 237d104..923997f 100644 --- a/Sources/jsonlogic/Parser.swift +++ b/Sources/jsonlogic/Parser.swift @@ -244,6 +244,35 @@ struct Sin: Expression { } } +struct Cos: Expression { + let arg: Expression + + func evalWithData(_ data: JSON?) throws -> JSON { + let jsonValue = try arg.evalWithData(data) + + if case let JSON.Array(array) = try arg.evalWithData(data) { + guard array.count > 1 else { + return array.first?.double.flatMap(cos).flatMap(JSON.Double) ?? + array.first?.int.flatMap(Double.init).flatMap(cos).flatMap(JSON.Double) ?? + JSON.Null + } + + return JSON.Array(array.compactMap { value in + return value.double.flatMap(cos).flatMap(JSON.Double) ?? + value.int.flatMap(Double.init).flatMap(cos).flatMap(JSON.Double) + }) + } else if case let JSON.Int(number) = jsonValue { + let sinValue = cos(Double(number)) + return JSON.Double(sinValue) + } else if case let JSON.Double(number) = jsonValue { + return JSON.Double(cos(number)) + } else { + return JSON.Null + } + } + +} + struct Max: Expression { let arg: Expression From 6377555ce8bbc395fd69c273a1a308dde6a6c859 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 09:49:46 +0200 Subject: [PATCH 08/27] cos of pi is actually -1, not 1 --- Tests/jsonlogicTests/ArithmeticTests.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Tests/jsonlogicTests/ArithmeticTests.swift b/Tests/jsonlogicTests/ArithmeticTests.swift index 12a17a3..d1fe139 100644 --- a/Tests/jsonlogicTests/ArithmeticTests.swift +++ b/Tests/jsonlogicTests/ArithmeticTests.swift @@ -208,7 +208,7 @@ class Arithmetic: XCTestCase { rule = """ - { "cos": [\(Double.pi)] } + { "cos": [\(2 * Double.pi)] } """ XCTAssertEqual(1, try applyRule(rule, to: nil), accuracy: 0.002) From e6e51a6f45256d00d680665d9fac4b8d44e906e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 09:49:59 +0200 Subject: [PATCH 09/27] add cos to parser --- Sources/jsonlogic/Parser.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/jsonlogic/Parser.swift b/Sources/jsonlogic/Parser.swift index 923997f..b20d37e 100644 --- a/Sources/jsonlogic/Parser.swift +++ b/Sources/jsonlogic/Parser.swift @@ -735,6 +735,8 @@ class Parser { return Min(arg: try self.parse(json: value)) case "sin": return Sin(arg: try self.parse(json: value)) + case "cos": + return Cos(arg: try self.parse(json: value)) case "substr": guard let array = try self.parse(json: value) as? ArrayOfExpressions else { throw ParseError.GenericError("\(key) statement be followed by an array") From c4401d2328b6e5df06f02102c913e1ff62b72b95 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 09:51:06 +0200 Subject: [PATCH 10/27] indent test rule set --- Tests/jsonlogicTests/ArithmeticTests.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Tests/jsonlogicTests/ArithmeticTests.swift b/Tests/jsonlogicTests/ArithmeticTests.swift index d1fe139..d6c97f2 100644 --- a/Tests/jsonlogicTests/ArithmeticTests.swift +++ b/Tests/jsonlogicTests/ArithmeticTests.swift @@ -193,23 +193,23 @@ class Arithmetic: XCTestCase { func testCos() { var rule = - """ - { "cos": [\(Double.pi / 2)] } - """ + """ + { "cos": [\(Double.pi / 2)] } + """ XCTAssertEqual(0, try applyRule(rule, to: nil), accuracy: 0.002) rule = - """ - { "cos": [\(Double.pi / 3)] } - """ + """ + { "cos": [\(Double.pi / 3)] } + """ XCTAssertEqual(0.5, try applyRule(rule, to: nil), accuracy: 0.002) rule = - """ - { "cos": [\(2 * Double.pi)] } - """ + """ + { "cos": [\(2 * Double.pi)] } + """ XCTAssertEqual(1, try applyRule(rule, to: nil), accuracy: 0.002) } From fb092d2e7b2382f1779cc6c922153b30f5969d83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 09:55:17 +0200 Subject: [PATCH 11/27] add tan tests --- Tests/jsonlogicTests/ArithmeticTests.swift | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Tests/jsonlogicTests/ArithmeticTests.swift b/Tests/jsonlogicTests/ArithmeticTests.swift index d6c97f2..4f9a2f1 100644 --- a/Tests/jsonlogicTests/ArithmeticTests.swift +++ b/Tests/jsonlogicTests/ArithmeticTests.swift @@ -213,4 +213,34 @@ class Arithmetic: XCTestCase { XCTAssertEqual(1, try applyRule(rule, to: nil), accuracy: 0.002) } + + func testTan() { + var rule = + """ + { "tan": [0] } + """ + + XCTAssertEqual(0, try applyRule(rule, to: nil), accuracy: 0.002) + + rule = + """ + { "tan": [\(Double.pi / 3)] } + """ + + XCTAssertEqual(sqrt(3), try applyRule(rule, to: nil), accuracy: 0.002) + + rule = + """ + { "tan": [\(Double.pi / 4)] } + """ + + XCTAssertEqual(1, try applyRule(rule, to: nil), accuracy: 0.002) + + rule = + """ + { "tan": [\(Double.pi / 2)] } + """ + + XCTAssertEqual(.nan, try applyRule(rule, to: nil), accuracy: 0.002) + } } From 7ada9c6465619d30b4637b2b6509a91dbb73f38f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 10:01:42 +0200 Subject: [PATCH 12/27] do not assume maths is equal to programming --- Tests/jsonlogicTests/ArithmeticTests.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Tests/jsonlogicTests/ArithmeticTests.swift b/Tests/jsonlogicTests/ArithmeticTests.swift index 4f9a2f1..8273a44 100644 --- a/Tests/jsonlogicTests/ArithmeticTests.swift +++ b/Tests/jsonlogicTests/ArithmeticTests.swift @@ -241,6 +241,8 @@ class Arithmetic: XCTestCase { { "tan": [\(Double.pi / 2)] } """ - XCTAssertEqual(.nan, try applyRule(rule, to: nil), accuracy: 0.002) + // In mathematics, this would be undefined + // In a programming language using IEEE 754, this is "a very large number" + XCTAssertGreaterThan(try applyRule(rule, to: nil), 1.5e16) } } From 8e87bb9241f7ca3531788a71e547f0ce9d303513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 10:01:53 +0200 Subject: [PATCH 13/27] add tan and use it in the parser --- Sources/jsonlogic/Parser.swift | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/Sources/jsonlogic/Parser.swift b/Sources/jsonlogic/Parser.swift index b20d37e..9720ead 100644 --- a/Sources/jsonlogic/Parser.swift +++ b/Sources/jsonlogic/Parser.swift @@ -273,6 +273,35 @@ struct Cos: Expression { } +struct Tan: Expression { + let arg: Expression + + func evalWithData(_ data: JSON?) throws -> JSON { + let jsonValue = try arg.evalWithData(data) + + if case let JSON.Array(array) = try arg.evalWithData(data) { + guard array.count > 1 else { + return array.first?.double.flatMap(tan).flatMap(JSON.Double) ?? + array.first?.int.flatMap(Double.init).flatMap(tan).flatMap(JSON.Double) ?? + JSON.Null + } + + return JSON.Array(array.compactMap { value in + return value.double.flatMap(tan).flatMap(JSON.Double) ?? + value.int.flatMap(Double.init).flatMap(tan).flatMap(JSON.Double) + }) + } else if case let JSON.Int(number) = jsonValue { + let sinValue = tan(Double(number)) + return JSON.Double(sinValue) + } else if case let JSON.Double(number) = jsonValue { + return JSON.Double(tan(number)) + } else { + return JSON.Null + } + } + +} + struct Max: Expression { let arg: Expression @@ -737,6 +766,8 @@ class Parser { return Sin(arg: try self.parse(json: value)) case "cos": return Cos(arg: try self.parse(json: value)) + case "tan": + return Tan(arg: try self.parse(json: value)) case "substr": guard let array = try self.parse(json: value) as? ArrayOfExpressions else { throw ParseError.GenericError("\(key) statement be followed by an array") From 76eea060807daadcf3b8d0edcf112163afdd92a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 10:28:21 +0200 Subject: [PATCH 14/27] add rounding tests --- .../NumericalOperations/RoundingTests.swift | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift diff --git a/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift b/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift new file mode 100644 index 0000000..6a16ead --- /dev/null +++ b/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift @@ -0,0 +1,43 @@ +// +// RoundingTests.swift +// jsonlogicTests +// +// Created by Dino on 22/07/2019. +// + +import XCTest +@testable import jsonlogic + +class RoundingTests: XCTestCase { + + func testRounding_noDecimals() { + var rule = + """ + { "rnd": [1.234, 0] } + """ + + XCTAssertEqual(1, try applyRule(rule, to: nil)) + + rule = + """ + { "rnd": [1.789, 0] } + """ + + XCTAssertEqual(2, try applyRule(rule, to: nil)) + + rule = + """ + { "rnd": [-0.7, 0] } + """ + + XCTAssertEqual(-1, try applyRule(rule, to: nil)) + + rule = + """ + { "rnd": [-0.4, 0] } + """ + + XCTAssertEqual(0, try applyRule(rule, to: nil)) + } + +} From 5a7bea409e4c1eb0df75e58a4c3be3349b02d0b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 10:38:48 +0200 Subject: [PATCH 15/27] add a rounding expression --- Sources/jsonlogic/Parser.swift | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Sources/jsonlogic/Parser.swift b/Sources/jsonlogic/Parser.swift index 9720ead..b28cb48 100644 --- a/Sources/jsonlogic/Parser.swift +++ b/Sources/jsonlogic/Parser.swift @@ -159,6 +159,26 @@ struct Comparison: Expression { } } +struct Round: Expression { + let arg: Expression + + func evalWithData(_ data: JSON?) throws -> JSON { + let result = try arg.evalWithData(data) + switch result { + case let .Array(array) where array.count == 2: + guard let numberToRound = array[0].double, + let numberOfPlaces = array[1].int + else { fallthrough } + + let divisor = pow(10.0, Double(numberOfPlaces)) + let result = (numberToRound * divisor).rounded() / divisor + return .Double(result) + default: + return result.toNumber() + } + } +} + //swiftlint:disable:next type_name struct If: Expression { let arg: ArrayOfExpressions From 9d22c91b9c3c169eebffa0bb786b091c77e7ea7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 10:39:21 +0200 Subject: [PATCH 16/27] add round to parser --- Sources/jsonlogic/Parser.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/jsonlogic/Parser.swift b/Sources/jsonlogic/Parser.swift index b28cb48..ca8d9d0 100644 --- a/Sources/jsonlogic/Parser.swift +++ b/Sources/jsonlogic/Parser.swift @@ -766,6 +766,8 @@ class Parser { return Comparison(arg: try self.parse(json: value), operation: >=) case "<=": return Comparison(arg: try self.parse(json: value), operation: <=) + case "rnd": + return Round(arg: try self.parse(json: value)) case "if", "?:": guard let array = try self.parse(json: value) as? ArrayOfExpressions else { throw ParseError.GenericError("\(key) statement be followed by an array") From 4624b6e2893bb40e8f7ce532be460419df70e388 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 10:42:59 +0200 Subject: [PATCH 17/27] dont expect integers as output of round --- .../NumericalOperations/RoundingTests.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift b/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift index 6a16ead..8209a75 100644 --- a/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift +++ b/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift @@ -16,28 +16,28 @@ class RoundingTests: XCTestCase { { "rnd": [1.234, 0] } """ - XCTAssertEqual(1, try applyRule(rule, to: nil)) + XCTAssertEqual(1.0, try applyRule(rule, to: nil)) rule = """ { "rnd": [1.789, 0] } """ - XCTAssertEqual(2, try applyRule(rule, to: nil)) + XCTAssertEqual(2.0, try applyRule(rule, to: nil)) rule = """ { "rnd": [-0.7, 0] } """ - XCTAssertEqual(-1, try applyRule(rule, to: nil)) + XCTAssertEqual(-1.0, try applyRule(rule, to: nil)) rule = """ { "rnd": [-0.4, 0] } """ - XCTAssertEqual(0, try applyRule(rule, to: nil)) + XCTAssertEqual(0.0, try applyRule(rule, to: nil)) } } From 51a6e64e4ae2799538ab19bf14f3bc6fb6f5ea3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 10:44:26 +0200 Subject: [PATCH 18/27] add more tests --- .../NumericalOperations/RoundingTests.swift | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift b/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift index 8209a75..d37f2e8 100644 --- a/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift +++ b/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift @@ -40,4 +40,33 @@ class RoundingTests: XCTestCase { XCTAssertEqual(0.0, try applyRule(rule, to: nil)) } + func testRounding_oneDecimal() { + var rule = + """ + { "rnd": [1.234, 1] } + """ + + XCTAssertEqual(1.2, try applyRule(rule, to: nil)) + + rule = + """ + { "rnd": [1.789, 1] } + """ + + XCTAssertEqual(1.8, try applyRule(rule, to: nil)) + + rule = + """ + { "rnd": [-0.7, 1] } + """ + + XCTAssertEqual(-0.7, try applyRule(rule, to: nil)) + + rule = + """ + { "rnd": [-0.445, 1] } + """ + + XCTAssertEqual(-0.4, try applyRule(rule, to: nil)) + } } From a971b4a026919beeb2ddb7b0c04e9c705c5b292d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 10:45:31 +0200 Subject: [PATCH 19/27] add even more tests --- .../NumericalOperations/RoundingTests.swift | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift b/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift index d37f2e8..9080346 100644 --- a/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift +++ b/Tests/jsonlogicTests/NumericalOperations/RoundingTests.swift @@ -69,4 +69,34 @@ class RoundingTests: XCTestCase { XCTAssertEqual(-0.4, try applyRule(rule, to: nil)) } + + func testRounding_twoDecimals() { + var rule = + """ + { "rnd": [1.234, 2] } + """ + + XCTAssertEqual(1.23, try applyRule(rule, to: nil)) + + rule = + """ + { "rnd": [1.789, 2] } + """ + + XCTAssertEqual(1.79, try applyRule(rule, to: nil)) + + rule = + """ + { "rnd": [-0.799, 1] } + """ + + XCTAssertEqual(-0.80, try applyRule(rule, to: nil)) + + rule = + """ + { "rnd": [-0.495, 1] } + """ + + XCTAssertEqual(-0.50, try applyRule(rule, to: nil)) + } } From 9816da3a1c355288617f5bd110004c111fce10ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 10:49:24 +0200 Subject: [PATCH 20/27] add tests for casting strings to numbers --- Tests/jsonlogicTests/NumberCastTests.swift | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Tests/jsonlogicTests/NumberCastTests.swift diff --git a/Tests/jsonlogicTests/NumberCastTests.swift b/Tests/jsonlogicTests/NumberCastTests.swift new file mode 100644 index 0000000..38bca39 --- /dev/null +++ b/Tests/jsonlogicTests/NumberCastTests.swift @@ -0,0 +1,36 @@ +// +// NumberCastTests.swift +// jsonlogicTests +// +// Created by Dino on 22/07/2019. +// + +import XCTest +@testable import jsonlogic + +class NumberCastTests: XCTestCase { + + func testCastNumericalString() { + var rule = + """ + { "num": ["0"] } + """ + + XCTAssertEqual(0, try applyRule(rule, to: nil), accuracy: 0.002) + + rule = + """ + { "num": ["0.145"] } + """ + + XCTAssertEqual(0.145, try applyRule(rule, to: nil), accuracy: 0.002) + + rule = + """ + { "num": ["3.14159"] } + """ + + XCTAssertEqual(Double.pi, try applyRule(rule, to: nil), accuracy: 0.002) + } + +} From 6758d04f0224b8ba134b91a005c41e438bdb4738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 10:51:53 +0200 Subject: [PATCH 21/27] add invalid test cases --- Tests/jsonlogicTests/NumberCastTests.swift | 38 ++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/Tests/jsonlogicTests/NumberCastTests.swift b/Tests/jsonlogicTests/NumberCastTests.swift index 38bca39..82c4dc3 100644 --- a/Tests/jsonlogicTests/NumberCastTests.swift +++ b/Tests/jsonlogicTests/NumberCastTests.swift @@ -6,6 +6,7 @@ // import XCTest +import JSON @testable import jsonlogic class NumberCastTests: XCTestCase { @@ -32,5 +33,42 @@ class NumberCastTests: XCTestCase { XCTAssertEqual(Double.pi, try applyRule(rule, to: nil), accuracy: 0.002) } + + func testCastInvalidString() { + var rule = + """ + { "num": ["Hello World"] } + """ + + XCTAssertEqual(JSON.Null, try applyRule(rule, to: nil)) + + rule = + """ + { "num": ["0.14AF"] } + """ + + XCTAssertEqual(JSON.Null, try applyRule(rule, to: nil)) + + rule = + """ + { "num": ["F0.14"] } + """ + + XCTAssertEqual(JSON.Null, try applyRule(rule, to: nil)) + + rule = + """ + { "num": ["0...14"] } + """ + + XCTAssertEqual(JSON.Null, try applyRule(rule, to: nil)) + + rule = + """ + { "num": ["2.1.4"] } + """ + + XCTAssertEqual(JSON.Null, try applyRule(rule, to: nil)) + } } From 94802a3ed64863606fef9710ca26f080a48bdc88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 10:52:05 +0200 Subject: [PATCH 22/27] add one more valid test case --- Tests/jsonlogicTests/NumberCastTests.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Tests/jsonlogicTests/NumberCastTests.swift b/Tests/jsonlogicTests/NumberCastTests.swift index 82c4dc3..9f67ea5 100644 --- a/Tests/jsonlogicTests/NumberCastTests.swift +++ b/Tests/jsonlogicTests/NumberCastTests.swift @@ -25,6 +25,14 @@ class NumberCastTests: XCTestCase { """ XCTAssertEqual(0.145, try applyRule(rule, to: nil), accuracy: 0.002) + + rule = + """ + { "num": [".145"] } + """ + + XCTAssertEqual(0.145, try applyRule(rule, to: nil), accuracy: 0.002) + rule = """ From 912d2dd3076fc08cd498973584357d299472d296 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 11:00:25 +0200 Subject: [PATCH 23/27] implement casting to numbers --- Sources/jsonlogic/Parser.swift | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/Sources/jsonlogic/Parser.swift b/Sources/jsonlogic/Parser.swift index ca8d9d0..91a3450 100644 --- a/Sources/jsonlogic/Parser.swift +++ b/Sources/jsonlogic/Parser.swift @@ -179,6 +179,36 @@ struct Round: Expression { } } +struct CastToNumber: Expression { + let arg: Expression + + func evalWithData(_ data: JSON?) throws -> JSON { + let result = try arg.evalWithData(data) + + switch result { + case let .Array(array): + let stringArray = array.compactMap { element -> String? in + switch element { + case .String(let value): + return value + default: + return nil + } + } + + guard stringArray.isEmpty == false else { return .Null } + + return .Array(stringArray.compactMap(Double.init).map(JSON.Double)) + case let .String(string): + guard let value = Double(string) else { return .Null } + + return .Double(value) + default: + return .Null + } + } +} + //swiftlint:disable:next type_name struct If: Expression { let arg: ArrayOfExpressions From 72f7fcaf866f4acbd6210be514a51f054f658709 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 11:01:05 +0200 Subject: [PATCH 24/27] add casting to parser --- Sources/jsonlogic/Parser.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/jsonlogic/Parser.swift b/Sources/jsonlogic/Parser.swift index 91a3450..463647b 100644 --- a/Sources/jsonlogic/Parser.swift +++ b/Sources/jsonlogic/Parser.swift @@ -798,6 +798,8 @@ class Parser { return Comparison(arg: try self.parse(json: value), operation: <=) case "rnd": return Round(arg: try self.parse(json: value)) + case "num": + return CastToNumber(arg: try self.parse(json: value)) case "if", "?:": guard let array = try self.parse(json: value) as? ArrayOfExpressions else { throw ParseError.GenericError("\(key) statement be followed by an array") From faf04d4154cb1fb19adffd60218149391680ecaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 11:58:50 +0200 Subject: [PATCH 25/27] use correct assert methods --- Tests/jsonlogicTests/NumberCastTests.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Tests/jsonlogicTests/NumberCastTests.swift b/Tests/jsonlogicTests/NumberCastTests.swift index 9f67ea5..a728839 100644 --- a/Tests/jsonlogicTests/NumberCastTests.swift +++ b/Tests/jsonlogicTests/NumberCastTests.swift @@ -48,35 +48,35 @@ class NumberCastTests: XCTestCase { { "num": ["Hello World"] } """ - XCTAssertEqual(JSON.Null, try applyRule(rule, to: nil)) + XCTAssertThrowsError(try applyRule(rule, to: nil) as Optional) rule = """ { "num": ["0.14AF"] } """ - XCTAssertEqual(JSON.Null, try applyRule(rule, to: nil)) + XCTAssertThrowsError(try applyRule(rule, to: nil) as Optional) rule = """ { "num": ["F0.14"] } """ - XCTAssertEqual(JSON.Null, try applyRule(rule, to: nil)) - + XCTAssertThrowsError(try applyRule(rule, to: nil) as Optional) + rule = """ { "num": ["0...14"] } """ - XCTAssertEqual(JSON.Null, try applyRule(rule, to: nil)) - + XCTAssertThrowsError(try applyRule(rule, to: nil) as Optional) + rule = """ { "num": ["2.1.4"] } """ - XCTAssertEqual(JSON.Null, try applyRule(rule, to: nil)) + XCTAssertThrowsError(try applyRule(rule, to: nil) as Optional) } } From df03f8bcaf014b82af0e81da47f96eea47d560fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdoc=CC=8C?= Date: Mon, 22 Jul 2019 11:59:08 +0200 Subject: [PATCH 26/27] [Merge additional-functions] make sure to not return an empty array, but a .null --- Sources/jsonlogic/Parser.swift | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Sources/jsonlogic/Parser.swift b/Sources/jsonlogic/Parser.swift index 463647b..fd2d139 100644 --- a/Sources/jsonlogic/Parser.swift +++ b/Sources/jsonlogic/Parser.swift @@ -198,7 +198,15 @@ struct CastToNumber: Expression { guard stringArray.isEmpty == false else { return .Null } - return .Array(stringArray.compactMap(Double.init).map(JSON.Double)) + let doubleArray = stringArray.compactMap(Double.init).map(JSON.Double) + + guard doubleArray.isEmpty == false else { return .Null } + + if doubleArray.count == 1 { + return doubleArray[0] + } + + return .Array(doubleArray) case let .String(string): guard let value = Double(string) else { return .Null } From dfd7eeda1152d8d64fdcc814b4952721e469d9bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Srdo=C4=8D?= Date: Mon, 22 Jul 2019 12:09:12 +0200 Subject: [PATCH 27/27] bump pod version --- jsonlogic.podspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jsonlogic.podspec b/jsonlogic.podspec index 6f61700..2ea8420 100644 --- a/jsonlogic.podspec +++ b/jsonlogic.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "jsonlogic" - s.version = "1.0.0" + s.version = "1.1.0" s.summary = "A JsonLogic Swift library" s.description = "A JsonLogic implementation in Swift. JsonLogic is a way to write rules that involve computations in JSON format, these can be applied on JSON data with consistent results. So you can share between server and clients rules in a common format." s.homepage = "https://github.com/advantagefse/json-logic-swift"