From 1e16ae114b8abaa9f75bc1b9e6d6acef531c75cf Mon Sep 17 00:00:00 2001 From: morevsavva Date: Fri, 26 Jan 2024 12:58:45 +0300 Subject: [PATCH] enable array, dict expression tests. --- .../Expressions/ExpressionResolver.swift | 14 ++++ .../Expressions/Functions/DictFunctions.swift | 64 +++++++++++++++++++ .../Expressions/ExpressionTests.swift | 39 +++++++++++ .../function_signatures_array.json | 19 ++++++ .../function_signatures_std.json | 18 ++++++ .../expression_test_data/functions_array.json | 37 +++++++++++ .../expression_test_data/functions_dict.json | 57 +++++++++++++++++ 7 files changed, 248 insertions(+) diff --git a/client/ios/DivKit/Expressions/ExpressionResolver.swift b/client/ios/DivKit/Expressions/ExpressionResolver.swift index a570fa792..e8b578ca2 100644 --- a/client/ios/DivKit/Expressions/ExpressionResolver.swift +++ b/client/ios/DivKit/Expressions/ExpressionResolver.swift @@ -131,6 +131,20 @@ public final class ExpressionResolver { } } + func resolveDict( + _ expression: Expression<[String: Any]>? + ) -> [String: Any]? { + switch expression { + case let .value(value): + return value + case let .link(link): + variableTracker(Set(link.variablesNames.map(DivVariableName.init(rawValue:)))) + return evaluateSingleItem(link: link) + case .none: + return nil + } + } + private func resolveEscaping(_ value: T?) -> T? { guard var value = value as? String, value.contains("\\") else { return value diff --git a/client/ios/DivKit/Expressions/Functions/DictFunctions.swift b/client/ios/DivKit/Expressions/Functions/DictFunctions.swift index e261b9321..de29a353f 100644 --- a/client/ios/DivKit/Expressions/Functions/DictFunctions.swift +++ b/client/ios/DivKit/Expressions/Functions/DictFunctions.swift @@ -15,6 +15,10 @@ enum DictFunctions: String, CaseIterable { case getDictOptColor case getDictOptUrl + case getArrayFromDict + case getOptArrayFromDict + case getDictFromDict + case getOptDictFromDict case getStringFromDict case getOptStringFromDict case getIntegerFromDict @@ -99,6 +103,14 @@ enum DictFunctions: String, CaseIterable { FunctionVarTernary(impl: _getOptUrlFromDictWithStringFallback), ] ) + case .getArrayFromDict: + return FunctionVarBinary(impl: _getArrayFromDict) + case .getOptArrayFromDict: + return FunctionVarBinary(impl: _getOptArrayFromDict) + case .getDictFromDict: + return FunctionVarBinary(impl: _getDictFromDict) + case .getOptDictFromDict: + return FunctionVarBinary(impl: _getOptDictFromDict) } } @@ -306,6 +318,38 @@ enum DictFunctions: String, CaseIterable { return url } + private func _getDictFromDict( + dict: [String: AnyHashable], + path: [String] + ) throws -> [String: AnyHashable] { + let expression = makeExpression("getDictFromDict", path) + let result = try getProp( + dict: dict, + path: path, + expression: expression + ) + guard let dict = result as? [String: AnyHashable] else { + throw Error.incorrectValueType(expression, "dict", result.actualType).message + } + return dict + } + + private func _getArrayFromDict( + dict: [String: AnyHashable], + path: [String] + ) throws -> [AnyHashable] { + let expression = makeExpression("getArrayFromDict", path) + let result = try getProp( + dict: dict, + path: path, + expression: expression + ) + guard let dict = result as? [AnyHashable] else { + throw Error.incorrectValueType(expression, "array", result.actualType).message + } + return dict + } + private func _getDictOptString( fallback: String, dict: [String: AnyHashable], @@ -394,6 +438,26 @@ enum DictFunctions: String, CaseIterable { return value } + private func _getOptDictFromDict( + dict: [String: AnyHashable], + path: [String] + ) -> [String: AnyHashable] { + guard let value = try? _getDictFromDict(dict: dict, path: path) else { + return [:] + } + return value + } + + private func _getOptArrayFromDict( + dict: [String: AnyHashable], + path: [String] + ) -> [AnyHashable] { + guard let value = try? _getArrayFromDict(dict: dict, path: path) else { + return [] + } + return value + } + private func _getDictOptColorWithColorFallback( fallback: Color, dict: [String: AnyHashable], diff --git a/client/ios/DivKitTests/Expressions/ExpressionTests.swift b/client/ios/DivKitTests/Expressions/ExpressionTests.swift index 4e53248c1..536e3c4df 100644 --- a/client/ios/DivKitTests/Expressions/ExpressionTests.swift +++ b/client/ios/DivKitTests/Expressions/ExpressionTests.swift @@ -42,6 +42,10 @@ private func runTest(_ testCase: ExpressionTestCase) { XCTAssertEqual(testCase.resolveNumeric(), expectedValue) case let .datetime(expectedValue): XCTAssertEqual(testCase.resolveNumeric(), expectedValue) + case let .array(expectedValue): + XCTAssertEqual(testCase.resolveArray(), expectedValue) + case let .dict(expectedValue): + XCTAssertEqual(testCase.resolveDict(), expectedValue) case let .error(expectedMessage): var errorMessage = "" _ = testCase.resolveValue(errorTracker: { errorMessage = $0.message }) @@ -119,6 +123,27 @@ extension ExpressionTestCase { ) return resolver.resolveNumeric(expression) } + + fileprivate func resolveArray() -> [AnyHashable]? { + let expression: Expression<[Any]>? = try? ExpressionLink<[Any]>(rawValue: expression) + .map { .link($0) } + let resolver = ExpressionResolver( + variables: variables, + persistentValuesStorage: DivPersistentValuesStorage() + ) + return resolver.resolveArray(expression) as? [AnyHashable] + } + + fileprivate func resolveDict() -> [String: AnyHashable]? { + let expression: Expression<[String: Any]>? = + try? ExpressionLink<[String: Any]>(rawValue: expression) + .map { .link($0) } + let resolver = ExpressionResolver( + variables: variables, + persistentValuesStorage: DivPersistentValuesStorage() + ) + return resolver.resolveDict(expression) as? [String: AnyHashable] + } } private enum ExpectedValue: Decodable { @@ -127,6 +152,8 @@ private enum ExpectedValue: Decodable { case integer(Int) case bool(Bool) case datetime(Date) + case array([AnyHashable]) + case dict([String: AnyHashable]) case error(String) public init(from decoder: Decoder) throws { @@ -154,6 +181,18 @@ private enum ExpectedValue: Decodable { case "datetime": let value = try container.decode(String.self, forKey: .value) self = .datetime(value.toDatetime()!) + case "array": + let value = try JSONObject(from: decoder).makeDictionary() + guard let array = value?["value"] as? [AnyHashable] else { + fallthrough + } + self = .array(array) + case "dict": + let value = try JSONObject(from: decoder).makeDictionary() + guard let dict = value?["value"] as? [String: AnyHashable] else { + fallthrough + } + self = .dict(dict) case "error": let value = try container.decode(String.self, forKey: .value) self = .error(value) diff --git a/test_data/expression_test_data/function_signatures_array.json b/test_data/expression_test_data/function_signatures_array.json index 867b5fcf5..6e5616fb3 100644 --- a/test_data/expression_test_data/function_signatures_array.json +++ b/test_data/expression_test_data/function_signatures_array.json @@ -272,6 +272,7 @@ "result_type": "url", "platforms": [ "android", + "ios", "web" ] }, @@ -342,6 +343,7 @@ "result_type": "string", "platforms": [ "android", + "ios", "web" ] }, @@ -362,6 +364,7 @@ "result_type": "number", "platforms": [ "android", + "ios", "web" ] }, @@ -382,6 +385,7 @@ "result_type": "integer", "platforms": [ "android", + "ios", "web" ] }, @@ -402,6 +406,7 @@ "result_type": "boolean", "platforms": [ "android", + "ios", "web" ] }, @@ -422,6 +427,7 @@ "result_type": "color", "platforms": [ "android", + "ios", "web" ] }, @@ -446,6 +452,7 @@ "result_type": "string", "platforms": [ "android", + "ios", "web" ] }, @@ -470,6 +477,7 @@ "result_type": "number", "platforms": [ "android", + "ios", "web" ] }, @@ -494,6 +502,7 @@ "result_type": "integer", "platforms": [ "android", + "ios", "web" ] }, @@ -518,6 +527,7 @@ "result_type": "boolean", "platforms": [ "android", + "ios", "web" ] }, @@ -542,6 +552,7 @@ "result_type": "color", "platforms": [ "android", + "ios", "web" ] }, @@ -566,6 +577,7 @@ "result_type": "color", "platforms": [ "android", + "ios", "web" ] }, @@ -586,6 +598,7 @@ "result_type": "url", "platforms": [ "android", + "ios", "web" ] }, @@ -610,6 +623,7 @@ "result_type": "url", "platforms": [ "android", + "ios", "web" ] }, @@ -634,6 +648,7 @@ "result_type": "url", "platforms": [ "android", + "ios", "web" ] }, @@ -654,6 +669,7 @@ "result_type": "array", "platforms": [ "android", + "ios", "web" ] }, @@ -674,6 +690,7 @@ "result_type": "array", "platforms": [ "android", + "ios", "web" ] }, @@ -694,6 +711,7 @@ "result_type": "dict", "platforms": [ "android", + "ios", "web" ] }, @@ -714,6 +732,7 @@ "result_type": "dict", "platforms": [ "android", + "ios", "web" ] }, diff --git a/test_data/expression_test_data/function_signatures_std.json b/test_data/expression_test_data/function_signatures_std.json index 972c7baf5..cfb8bafdd 100644 --- a/test_data/expression_test_data/function_signatures_std.json +++ b/test_data/expression_test_data/function_signatures_std.json @@ -764,6 +764,7 @@ "result_type": "string", "platforms": [ "android", + "ios", "web" ] }, @@ -785,6 +786,7 @@ "result_type": "number", "platforms": [ "android", + "ios", "web" ] }, @@ -806,6 +808,7 @@ "result_type": "integer", "platforms": [ "android", + "ios", "web" ] }, @@ -827,6 +830,7 @@ "result_type": "boolean", "platforms": [ "android", + "ios", "web" ] }, @@ -848,6 +852,7 @@ "result_type": "color", "platforms": [ "android", + "ios", "web" ] }, @@ -869,6 +874,7 @@ "result_type": "url", "platforms": [ "android", + "ios", "web" ] }, @@ -890,6 +896,7 @@ "result_type": "dict", "platforms": [ "android", + "ios", "web" ] }, @@ -911,6 +918,7 @@ "result_type": "array", "platforms": [ "android", + "ios", "web" ] }, @@ -936,6 +944,7 @@ "result_type": "string", "platforms": [ "android", + "ios", "web" ] }, @@ -961,6 +970,7 @@ "result_type": "number", "platforms": [ "android", + "ios", "web" ] }, @@ -986,6 +996,7 @@ "result_type": "integer", "platforms": [ "android", + "ios", "web" ] }, @@ -1011,6 +1022,7 @@ "result_type": "boolean", "platforms": [ "android", + "ios", "web" ] }, @@ -1036,6 +1048,7 @@ "result_type": "color", "platforms": [ "android", + "ios", "web" ] }, @@ -1061,6 +1074,7 @@ "result_type": "color", "platforms": [ "android", + "ios", "web" ] }, @@ -1086,6 +1100,7 @@ "result_type": "url", "platforms": [ "android", + "ios", "web" ] }, @@ -1111,6 +1126,7 @@ "result_type": "url", "platforms": [ "android", + "ios", "web" ] }, @@ -1132,6 +1148,7 @@ "result_type": "array", "platforms": [ "android", + "ios", "web" ] }, @@ -1153,6 +1170,7 @@ "result_type": "dict", "platforms": [ "android", + "ios", "web" ] }, diff --git a/test_data/expression_test_data/functions_array.json b/test_data/expression_test_data/functions_array.json index 88c037316..f73213155 100644 --- a/test_data/expression_test_data/functions_array.json +++ b/test_data/expression_test_data/functions_array.json @@ -37,6 +37,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -58,6 +59,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -79,6 +81,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -101,6 +104,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -123,6 +127,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -144,6 +149,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -165,6 +171,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -187,6 +194,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -209,6 +217,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -230,6 +239,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -251,6 +261,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -273,6 +284,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -295,6 +307,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -316,6 +329,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -337,6 +351,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -358,6 +373,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -379,6 +395,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -400,6 +417,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -421,6 +439,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -442,6 +461,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -469,6 +489,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -491,6 +512,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -512,6 +534,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -533,6 +556,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -554,6 +578,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -575,6 +600,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -596,6 +622,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -617,6 +644,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -644,6 +672,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -665,6 +694,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -692,6 +722,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -714,6 +745,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -739,6 +771,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -760,6 +793,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -785,6 +819,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -807,6 +842,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -828,6 +864,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, diff --git a/test_data/expression_test_data/functions_dict.json b/test_data/expression_test_data/functions_dict.json index a6d733eed..9cff69ec5 100644 --- a/test_data/expression_test_data/functions_dict.json +++ b/test_data/expression_test_data/functions_dict.json @@ -38,6 +38,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -59,6 +60,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -82,6 +84,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -107,6 +110,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -130,6 +134,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -151,6 +156,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -174,6 +180,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -195,6 +202,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -216,6 +224,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -237,6 +246,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -258,6 +268,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -279,6 +290,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -300,6 +312,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -321,6 +334,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -342,6 +356,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -363,6 +378,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -384,6 +400,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -405,6 +422,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -426,6 +444,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -447,6 +466,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -468,6 +488,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -489,6 +510,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -510,6 +532,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -531,6 +554,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -552,6 +576,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -573,6 +598,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -594,6 +620,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -615,6 +642,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -636,6 +664,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -657,6 +686,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -678,6 +708,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -701,6 +732,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -722,6 +754,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -745,6 +778,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -766,6 +800,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -787,6 +822,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -808,6 +844,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -829,6 +866,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -850,6 +888,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -871,6 +910,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -892,6 +932,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -913,6 +954,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -934,6 +976,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -955,6 +998,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -976,6 +1020,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -997,6 +1042,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -1018,6 +1064,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -1039,6 +1086,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -1060,6 +1108,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -1081,6 +1130,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -1102,6 +1152,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -1123,6 +1174,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -1144,6 +1196,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -1165,6 +1218,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -1186,6 +1240,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -1207,6 +1262,7 @@ ], "platforms": [ "android", + "ios", "web" ] }, @@ -1228,6 +1284,7 @@ ], "platforms": [ "android", + "ios", "web" ] },