mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-10 22:45:59 +05:45
210 lines
7.8 KiB
Swift
210 lines
7.8 KiB
Swift
// Copyright 2021 Google LLC
|
|
//
|
|
// Licensed 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 CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
import FirebaseRemoteConfig
|
|
|
|
import XCTest
|
|
|
|
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
|
|
class CodableTests: APITestBase {
|
|
// MARK: - Test decoding Remote Config JSON values
|
|
|
|
// Contrast this test with the subsequent one to see the value of the Codable API.
|
|
func testFetchAndActivateWithoutCodable() async throws {
|
|
let status = try await config.fetchAndActivate()
|
|
XCTAssertEqual(status, .successFetchedFromRemote)
|
|
let dict = try XCTUnwrap(config[Constants.jsonKey].jsonValue as? [String: AnyHashable])
|
|
XCTAssertEqual(dict["recipeName"], "PB&J")
|
|
XCTAssertEqual(dict["ingredients"], ["bread", "peanut butter", "jelly"])
|
|
XCTAssertEqual(dict["cookTime"], 7)
|
|
XCTAssertEqual(
|
|
config[Constants.jsonKey].jsonValue as! [String: AnyHashable],
|
|
Constants.jsonValue
|
|
)
|
|
}
|
|
|
|
struct Recipe: Decodable {
|
|
var recipeName: String
|
|
var ingredients: [String]
|
|
var cookTime: Int
|
|
}
|
|
|
|
func testFetchAndActivateWithCodable() async throws {
|
|
let status = try await config.fetchAndActivate()
|
|
XCTAssertEqual(status, .successFetchedFromRemote)
|
|
let recipe = try XCTUnwrap(config[Constants.jsonKey].decoded(asType: Recipe.self))
|
|
XCTAssertEqual(recipe.recipeName, "PB&J")
|
|
XCTAssertEqual(recipe.ingredients, ["bread", "peanut butter", "jelly"])
|
|
XCTAssertEqual(recipe.cookTime, 7)
|
|
}
|
|
|
|
func testFetchAndActivateWithCodableAlternativeAPI() async throws {
|
|
let status = try await config.fetchAndActivate()
|
|
XCTAssertEqual(status, .successFetchedFromRemote)
|
|
let recipe: Recipe = try XCTUnwrap(config[Constants.jsonKey].decoded())
|
|
XCTAssertEqual(recipe.recipeName, "PB&J")
|
|
XCTAssertEqual(recipe.ingredients, ["bread", "peanut butter", "jelly"])
|
|
XCTAssertEqual(recipe.cookTime, 7)
|
|
}
|
|
|
|
func testFetchAndActivateWithCodableBadJson() async throws {
|
|
let status = try await config.fetchAndActivate()
|
|
XCTAssertEqual(status, .successFetchedFromRemote)
|
|
do {
|
|
_ = try config[Constants.nonJsonKey].decoded(asType: Recipe.self)
|
|
} catch let DecodingError.typeMismatch(_, context) {
|
|
XCTAssertEqual(context.debugDescription,
|
|
"Expected to decode Dictionary<String, Any> but found " +
|
|
"FirebaseRemoteConfigValueDecoderHelper instead.")
|
|
return
|
|
}
|
|
XCTFail("Failed to catch trying to decode non-JSON key as JSON")
|
|
}
|
|
|
|
// MARK: - Test setting Remote Config defaults via an encodable struct
|
|
|
|
struct DataTestDefaults: Encodable {
|
|
var bool: Bool
|
|
var int: Int32
|
|
var long: Int64
|
|
var string: String
|
|
}
|
|
|
|
func testSetEncodeableDefaults() throws {
|
|
let data = DataTestDefaults(
|
|
bool: true,
|
|
int: 2,
|
|
long: 9_876_543_210,
|
|
string: "four"
|
|
)
|
|
try config.setDefaults(from: data)
|
|
let boolValue = try XCTUnwrap(config.defaultValue(forKey: "bool")).numberValue.boolValue
|
|
XCTAssertTrue(boolValue)
|
|
let intValue = try XCTUnwrap(config.defaultValue(forKey: "int")).numberValue.intValue
|
|
XCTAssertEqual(intValue, 2)
|
|
let longValue = try XCTUnwrap(config.defaultValue(forKey: "long")).numberValue.int64Value
|
|
XCTAssertEqual(longValue, 9_876_543_210)
|
|
let stringValue = try XCTUnwrap(config.defaultValue(forKey: "string")).stringValue
|
|
XCTAssertEqual(stringValue, "four")
|
|
}
|
|
|
|
func testSetEncodeableDefaultsInvalid() throws {
|
|
do {
|
|
_ = try config.setDefaults(from: 7)
|
|
} catch let RemoteConfigCodableError.invalidSetDefaultsInput(message) {
|
|
XCTAssertEqual(message,
|
|
"The setDefaults input: 7, must be a Struct that encodes to a Dictionary")
|
|
return
|
|
}
|
|
XCTFail("Failed to catch trying to encode an invalid input to setDefaults.")
|
|
}
|
|
|
|
// MARK: - Test extracting config to an decodable struct.
|
|
|
|
struct MyConfig: Decodable {
|
|
var Recipe: Recipe
|
|
var notJSON: String
|
|
var myInt: Int
|
|
var myFloat: Float
|
|
var myDecimal: Decimal
|
|
var myTrue: Bool
|
|
var myData: Data
|
|
}
|
|
|
|
func testExtractConfig() async throws {
|
|
let status = try await config.fetchAndActivate()
|
|
XCTAssertEqual(status, .successFetchedFromRemote)
|
|
let myConfig: MyConfig = try config.decoded()
|
|
XCTAssertEqual(myConfig.notJSON, Constants.nonJsonValue)
|
|
XCTAssertEqual(myConfig.myInt, Constants.intValue)
|
|
XCTAssertEqual(myConfig.myTrue, true)
|
|
XCTAssertEqual(myConfig.myFloat, Constants.floatValue)
|
|
XCTAssertEqual(myConfig.myDecimal, Constants.decimalValue)
|
|
XCTAssertEqual(myConfig.myData, Constants.dataValue)
|
|
XCTAssertEqual(myConfig.Recipe.recipeName, "PB&J")
|
|
XCTAssertEqual(myConfig.Recipe.ingredients, ["bread", "peanut butter", "jelly"])
|
|
XCTAssertEqual(myConfig.Recipe.cookTime, 7)
|
|
}
|
|
|
|
// Additional fields in config are ignored.
|
|
func testExtractConfigExtra() async throws {
|
|
guard APITests.useFakeConfig else { return }
|
|
fakeConsole.config["extra"] = "extra Value"
|
|
let status = try await config.fetchAndActivate()
|
|
XCTAssertEqual(status, .successFetchedFromRemote)
|
|
let myConfig: MyConfig = try config.decoded()
|
|
XCTAssertEqual(myConfig.notJSON, Constants.nonJsonValue)
|
|
XCTAssertEqual(myConfig.Recipe.recipeName, "PB&J")
|
|
XCTAssertEqual(myConfig.Recipe.ingredients, ["bread", "peanut butter", "jelly"])
|
|
XCTAssertEqual(myConfig.Recipe.cookTime, 7)
|
|
}
|
|
|
|
// Failure if requested field does not exist.
|
|
func testExtractConfigMissing() async throws {
|
|
struct MyConfig: Decodable {
|
|
var missing: String
|
|
var Recipe: String
|
|
var notJSON: String
|
|
}
|
|
let status = try await config.fetchAndActivate()
|
|
XCTAssertEqual(status, .successFetchedFromRemote)
|
|
do {
|
|
let _: MyConfig = try config.decoded()
|
|
} catch let DecodingError.keyNotFound(codingKey, context) {
|
|
XCTAssertEqual(codingKey.stringValue, "missing")
|
|
print(codingKey, context)
|
|
return
|
|
}
|
|
XCTFail("Failed to throw on missing field")
|
|
}
|
|
|
|
func testCodableAfterPlistDefaults() throws {
|
|
struct Defaults: Codable {
|
|
let format: String
|
|
let isPaidUser: Bool
|
|
let newItem: Double
|
|
let Languages: String
|
|
let dictValue: [String: String]
|
|
let arrayValue: [String]
|
|
let arrayIntValue: [Int]
|
|
}
|
|
// setDefaults(fromPlist:) doesn't work because of dynamic linking.
|
|
// More details in RCNRemoteConfigTest.m
|
|
var findPlist: String?
|
|
#if SWIFT_PACKAGE
|
|
findPlist = Bundle.module.path(forResource: "Defaults-testInfo", ofType: "plist")
|
|
#else
|
|
for b in Bundle.allBundles {
|
|
findPlist = b.path(forResource: "Defaults-testInfo", ofType: "plist")
|
|
if findPlist != nil {
|
|
break
|
|
}
|
|
}
|
|
#endif
|
|
let plistFile = try XCTUnwrap(findPlist)
|
|
let defaults = NSDictionary(contentsOfFile: plistFile)
|
|
config.setDefaults(defaults as? [String: NSObject])
|
|
let readDefaults: Defaults = try config.decoded()
|
|
XCTAssertEqual(readDefaults.format, "key to value.")
|
|
XCTAssertEqual(readDefaults.isPaidUser, true)
|
|
XCTAssertEqual(readDefaults.newItem, 2.4)
|
|
XCTAssertEqual(readDefaults.Languages, "English")
|
|
XCTAssertEqual(readDefaults.dictValue, ["foo": "foo",
|
|
"bar": "bar",
|
|
"baz": "baz"])
|
|
XCTAssertEqual(readDefaults.arrayValue, ["foo", "bar", "baz"])
|
|
XCTAssertEqual(readDefaults.arrayIntValue, [1, 2, 0, 3])
|
|
}
|
|
}
|