Skip to content

Commit

Permalink
Merge pull request #99 from unsignedapps/flagvaluedictionary-codable
Browse files Browse the repository at this point in the history
Add `Codable` conformance to `FlagValueDictionary`
  • Loading branch information
bok- authored Dec 9, 2021
2 parents 244a766 + eca51ef commit e11cf66
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 16 deletions.
33 changes: 29 additions & 4 deletions Sources/Vexil/Sources/FlagValueDictionary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ import Foundation
/// A simple dictionary-backed FlagValueSource that can be useful for testing
/// and other purposes.
///
open class FlagValueDictionary: Identifiable, ExpressibleByDictionaryLiteral {
open class FlagValueDictionary: Identifiable, ExpressibleByDictionaryLiteral, Codable {

// MARK: - Properties

/// A Unique Identifier for this FlagValueDictionary
public let id = UUID()
public let id: UUID

/// Our internal dictionary type
public typealias DictionaryType = [String: BoxedFlagValue]
Expand All @@ -33,18 +33,43 @@ open class FlagValueDictionary: Identifiable, ExpressibleByDictionaryLiteral {

// MARK: - Initialisation

/// Private (but for @testable) memeberwise initialiser
init (id: UUID, storage: DictionaryType) {
self.id = id
self.storage = storage
}

/// Initialises a `FlagValueDictionary` with the specified dictionary
///
public init (_ dictionary: DictionaryType = [:]) {
self.storage = dictionary
public convenience init (_ dictionary: DictionaryType = [:]) {
self.init(
id: UUID(),
storage: dictionary
)
}

/// Initialises a `FlagValueDictionary` using a dictionary literal
///
public required init(dictionaryLiteral elements: (String, BoxedFlagValue)...) {
self.id = UUID()
self.storage = elements.reduce(into: [:]) { dict, pair in
dict.updateValue(pair.1, forKey: pair.0)
}
}

// MARK: - Codable Support

enum CodingKeys: String, CodingKey {
case id
case storage
}

}

// MARK: - Equatable Support

extension FlagValueDictionary: Equatable {
public static func == (lhs: FlagValueDictionary, rhs: FlagValueDictionary) -> Bool {
return lhs.id == rhs.id && lhs.storage == rhs.storage
}
}
78 changes: 66 additions & 12 deletions Tests/VexilTests/FlagValueDictionaryTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Created by Rob Amos on 17/8/20.
//

import Foundation
@testable import Vexil
import XCTest

Expand All @@ -25,19 +26,72 @@ final class FlagValueDictionaryTests: XCTestCase {

// MARK: - Writing Values

func testWritesValues () {
AssertNoThrow {
let source = FlagValueDictionary()
let flagPole = FlagPole(hoist: TestFlags.self, sources: [ source ])
func testWritesValues () throws {
let source = FlagValueDictionary()
let flagPole = FlagPole(hoist: TestFlags.self, sources: [ source ])

let snapshot = flagPole.emptySnapshot()
snapshot.topLevelFlag = true
snapshot.oneFlagGroup.secondLevelFlag = false
try flagPole.save(snapshot: snapshot, to: source)

XCTAssertEqual(source.storage["top-level-flag"], .bool(true))
XCTAssertEqual(source.storage["one-flag-group.second-level-flag"], .bool(false))
}

// MARK: - Equatable Tests

func testEquatable() {

let identifier1 = UUID()
let original = FlagValueDictionary(
id: identifier1,
storage: [
"top-level-flag": .bool(true)
]
)

let same = FlagValueDictionary(
id: identifier1,
storage: [
"top-level-flag": .bool(true)
]
)

let differentContent = FlagValueDictionary(
id: identifier1,
storage: [
"top-level-flag": .bool(false)
]
)

let differentIdentifier = FlagValueDictionary(
id: UUID(),
storage: [
"top-level-flag": .bool(true)
]
)

XCTAssertEqual(original, same)
XCTAssertNotEqual(original, differentContent)
XCTAssertNotEqual(original, differentIdentifier)

}

// MARK: - Codable Tests

func testCodable() throws {
// BoxedFlagValue's Codable support is more heavily tested in it's tests
let source: FlagValueDictionary = [
"bool-flag": .bool(true),
"string-flag": .string("alpha"),
"integer-flag": .integer(123)
]

let snapshot = flagPole.emptySnapshot()
snapshot.topLevelFlag = true
snapshot.oneFlagGroup.secondLevelFlag = false
try flagPole.save(snapshot: snapshot, to: source)
let encoded = try JSONEncoder().encode(source)
let decoded = try JSONDecoder().decode(FlagValueDictionary.self, from: encoded)

XCTAssertEqual(source.storage["top-level-flag"], .bool(true))
XCTAssertEqual(source.storage["one-flag-group.second-level-flag"], .bool(false))
}
XCTAssertEqual(source, decoded)
}


Expand Down Expand Up @@ -89,7 +143,7 @@ private struct TestFlags: FlagContainer {
var oneFlagGroup: OneFlags

@Flag(description: "Top level test flag")
var topLevelFlag: Bool = false
var topLevelFlag = false

}

Expand Down

0 comments on commit e11cf66

Please sign in to comment.