Skip to content

Commit

Permalink
Merge pull request adobe#26 from adobe/dev
Browse files Browse the repository at this point in the history
Dev to main
  • Loading branch information
shalehaha authored Oct 12, 2020
2 parents b7e2b7d + 61cf5c9 commit 8815389
Show file tree
Hide file tree
Showing 17 changed files with 321 additions and 114 deletions.
15 changes: 13 additions & 2 deletions .github/workflows/swift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,20 @@ jobs:

- name: Install swiftformat
run: brew install swiftformat

- name: Install SwiftLint
run: brew install swiftlint

- name: Linting
run: swiftformat --lint Sources
run: make lint; make check-format

- name: Build
run: swift build -v

- name: Run tests
run: swift test -v
run: swift test -v --enable-code-coverage

- name: Upload Code Coverage
run: make generate-lcov; bash <(curl -s https://codecov.io/bash)


1 change: 1 addition & 0 deletions .swift-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5.0
20 changes: 19 additions & 1 deletion .swiftlint.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
included: # paths to include during linting. `--path` is ignored if present.
- Sources
- Tests

line_length: 1000
function_body_length: 500
disabled_rules: # rule identifiers to exclude from running
- identifier_name
- force_cast
- todo
- multiple_closures_with_trailing_closure
- cyclomatic_complexity
- file_length
- unused_optional_binding
- implicit_getter
- shorthand_operator
- nesting
- switch_case_alignment
- orphaned_doc_comment
- type_name
- large_tuple
- trailing_comma
15 changes: 15 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
lint-autocorrect:
swiftlint autocorrect

lint:
swiftlint lint

check-format:
swiftformat --lint Sources

format:
swiftformat .

generate-lcov:
xcrun llvm-cov export -format="lcov" .build/debug/AEPRulesEnginePackageTests.xctest/Contents/MacOS/AEPRulesEnginePackageTests -instr-profile .build/debug/codecov/default.profdata > info.lcov

14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,22 @@ let rulesEngine = RulesEngine(evaluator: evaluator)

### Define Rules

Any thing that conforms to the `Rule` protocol can be used as rule. The easiest way is to use the built-in `ConsequenceRule`.
```
Any thing that conforms to the `Rule` protocol can be used as rule.
``` Swift
public class MobileRule: Rule {
init(condition: Evaluable) { self.condition = condition }
var condition: Evaluable
}
let condition = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc")
let rule = ConsequenceRule(id: "sample-rule", condition: condition)
let rule = MobileRule(condition: condition)
rulesEngine.addRules(rules: [rule])
```
However, a rule like this doesn't make much sense, without the ability to dynamically fetch a value it will always be true or false.

```
``` Swift
let mustache = Operand<String>(mustache: "{{company}}")
let condition = ComparisonExpression(lhs: mustache, operationName: "equals", rhs: "adobe")
let rule = ConsequenceRule(id: "sample-rule", condition: condition)
let rule = MobileRule(condition: condition)
rulesEngine.addRules(rules: [rule])
```

Expand Down
5 changes: 0 additions & 5 deletions Sources/AEPRulesEngine/ConditionEvaluator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,6 @@ public extension ConditionEvaluator {
addComparisonOperator(operation: "exists", type: Any?.self, closure: { lhs, _ in
lhs != nil
})

// self.addComparisonOperator(operation: "co", closure: { (lhs:Array<String>, rhs:String) in
// return lhs.contains(rhs)
// })
// self.addComparisonOperator(operation: "eq", type: AnyObject.self, closure: {$0.isEqual($1)})
}

private func addCaseInSensitiveOperators() {
Expand Down
14 changes: 1 addition & 13 deletions Sources/AEPRulesEngine/Expression/Operand.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public enum Operand<T> {
return value
case let .token(token):

if let result = token.resolve(in: args[0]) {
if let result = token.resolve(in: args[0].transformer, data: args[0].data) {
return result as? T
}
return nil
Expand Down Expand Up @@ -57,15 +57,3 @@ extension Operand: CustomStringConvertible {
}
}
}

extension MustacheToken {
public func resolve(in context: Context) -> Any? {
switch self {
case let .function(name, innerToken):
let innerValue = innerToken.resolve(in: context)
return context.transformer.transform(name: name, parameter: innerValue ?? "")
case let .variable(path):
return context.data.get(key: path)
}
}
}
1 change: 0 additions & 1 deletion Sources/AEPRulesEngine/Template/Segment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,4 @@ public struct Segment {
let type: Type
let templateString: String
let range: Range<String.Index>
var templateSubstring: String { String(templateString[range]) }
}
68 changes: 66 additions & 2 deletions Tests/AEPRulesEngineTests/UnitTests/ExpressionTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import XCTest

@testable import AEPRulesEngine
struct CustomOperand: Traversable {
func get(key:String) -> Any? {
func get(key: String) -> Any? {
return key
}
}
Expand Down Expand Up @@ -47,6 +47,50 @@ class ExpressionTests: XCTestCase {
XCTAssertTrue(result.value)
}

func testOrSuccess() {
let evaluator = ConditionEvaluator(options: .defaultOptions)

let a = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc1")
let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc")
let c = LogicalExpression(operationName: "or", operands: a, b)
let result = c.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transform()))
XCTAssertTrue(result.value)
}

func testOrFail() {
let evaluator = ConditionEvaluator(options: .defaultOptions)

let a = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc1")
let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc1")
let c = LogicalExpression(operationName: "or", operands: a, b)
let result = c.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transform()))
XCTAssertTrue(!result.value)
}

func testUnknownOperation() {
let evaluator = ConditionEvaluator(options: .defaultOptions)

let a = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc1")
let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc1")
let c = LogicalExpression(operationName: "unkonwn", operands: a, b)
let result = c.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transform()))
XCTAssertTrue(!result.value)
}

func testUnaryExpression() {
let evaluator = ConditionEvaluator(options: .defaultOptions)
evaluator.addUnaryOperator(operation: "isTrue") { (_: CustomOperand) -> Bool in
true
}

let mustache = Operand<CustomOperand>(mustache: "{{custom}}")
let a = UnaryExpression(lhs: mustache, operationName: "isTrue")
let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc")
let c = LogicalExpression(operationName: "and", operands: a, b)
let result = c.evaluate(in: Context(data: ["custom1": CustomOperand()], evaluator: evaluator, transformer: Transform()))
XCTAssertTrue(!result.value)
}

func testMustache() {
let evaluator = ConditionEvaluator(options: .defaultOptions)
let mustache = Operand<String>(mustache: "{{key}}")
Expand All @@ -57,12 +101,22 @@ class ExpressionTests: XCTestCase {
XCTAssertTrue(result.value)
}

func testMustache_Nil() {
func testMustacheNotFound() {
let evaluator = ConditionEvaluator(options: .defaultOptions)
let mustache = Operand<String>(mustache: "{{key}}")
let a = ComparisonExpression(lhs: mustache, operationName: "equals", rhs: "abc")
let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc")
let c = LogicalExpression(operationName: "and", operands: a, b)
let result = c.evaluate(in: Context(data: ["key1": "abc"], evaluator: evaluator, transformer: Transform()))
XCTAssertTrue(!result.value)
}

func testMustache_Nil() {
let evaluator = ConditionEvaluator(options: .defaultOptions)
let mustache = Operand<String>(mustache: "{{key}}")
let a = ComparisonExpression(lhs: mustache, operationName: "equals", rhs: "abc")
let b = ComparisonExpression(lhs: "abc", operationName: "equals", rhs: "abc")
let c = LogicalExpression(operationName: "and", operands: [a, b])
let result = c.evaluate(in: Context(data: ["someelse": "abc"], evaluator: evaluator, transformer: Transform()))
XCTAssertFalse(result.value)
}
Expand Down Expand Up @@ -102,4 +156,14 @@ class ExpressionTests: XCTestCase {
let result = c.evaluate(in: Context(data: ["custom": CustomOperand()], evaluator: evaluator, transformer: Transform()))
XCTAssertTrue(result.value)
}

func testComparisonExpressionWithDifferentTypes() {
let evaluator = ConditionEvaluator(options: .defaultOptions)
evaluator.addComparisonOperator(operation: "equals") { (_: String, _: Int) -> Bool in
true
}
let a = ComparisonExpression(lhs: "3", operationName: "equals", rhs: 3)
let result = a.evaluate(in: Context(data: [:], evaluator: evaluator, transformer: Transform()))
XCTAssertTrue(result.value)
}
}
39 changes: 39 additions & 0 deletions Tests/AEPRulesEngineTests/UnitTests/OperandTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/

import Foundation
import XCTest

@testable import AEPRulesEngine

class OperandTests: XCTestCase {

func testMustacheNoneValue() {
let mustache = Operand<String>(mustache: "")
XCTAssertEqual("<None>", String(describing: mustache))
}

func testDoubleValue(){
let operand = Operand(floatLiteral: 1.2)
XCTAssertEqual("<Value:1.2>", String(describing: operand))
}

func testBoolValue(){
let operand = Operand(booleanLiteral: true)
XCTAssertEqual("<Value:true>", String(describing: operand))
}

func testNilValue(){
let operand: Operand<String> = nil
XCTAssertEqual("<None>", String(describing: operand))
}
}
6 changes: 6 additions & 0 deletions Tests/AEPRulesEngineTests/UnitTests/ParserTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ class ParserTests: XCTestCase {
let result = template.render(data: ["test": "value"], transformers: Transform())
XCTAssertEqual("sdfdfdvalueaaa", result)
}

func testCustomizedTokenFormat() {
let template = Template(templateString: "sdfdfd[[test]]aaa", tagDelimiterPair: ("[[","]]"))
let result = template.render(data: ["test": "value"], transformers: Transform())
XCTAssertEqual("sdfdfdvalueaaa", result)
}

func testTransform() {
let template = Template(templateString: "sdfdfd{{dash(test)}}aaa")
Expand Down
56 changes: 0 additions & 56 deletions Tests/AEPRulesEngineTests/UnitTests/RulesEngineDebugTests.swift

This file was deleted.

30 changes: 30 additions & 0 deletions Tests/AEPRulesEngineTests/UnitTests/RulesEngineLogLevelTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License.
*/

@testable import AEPRulesEngine
import XCTest

class RulesEngineLogLevelTests: XCTestCase {

func testLogLevelComparison() {
XCTAssertTrue(RulesEngineLogLevel.error < RulesEngineLogLevel.warning)
XCTAssertTrue(RulesEngineLogLevel.warning < RulesEngineLogLevel.debug)
XCTAssertTrue(RulesEngineLogLevel.debug < RulesEngineLogLevel.trace)
}

func testLogLevelToString() {
XCTAssertEqual(RulesEngineLogLevel.error.toString(), "ERROR")
XCTAssertEqual(RulesEngineLogLevel.warning.toString(), "WARNING")
XCTAssertEqual(RulesEngineLogLevel.debug.toString(), "DEBUG")
XCTAssertEqual(RulesEngineLogLevel.trace.toString(), "TRACE")
}
}
Loading

0 comments on commit 8815389

Please sign in to comment.