Skip to content

Commit c247bb6

Browse files
committed
Refactor parsing test variations
1 parent ed98b0a commit c247bb6

File tree

3 files changed

+56
-42
lines changed

3 files changed

+56
-42
lines changed

FeatureFlags/Classes/Model/Feature+Codable.swift

Lines changed: 34 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ extension Feature: Codable {
2121
case testVariations = "test-variations"
2222
case labels = "labels"
2323
}
24+
static let defaultTestVariations: [TestVariation] = [.enabled, .disabled]
2425

2526
public init(from decoder: Decoder) throws {
2627
let container = try decoder.container(keyedBy: CodingKeys.self)
@@ -38,76 +39,71 @@ extension Feature: Codable {
3839
}
3940
let testBiases = try container.decodeIfPresent([Percentage].self, forKey: .testBiases)
4041
self.testVariationAssignment = try container.decodeIfPresent(Double.self, forKey: .testVariationAssignment)
41-
?? Double.random(in: 0..<100) // [0.0, 100.0)
42+
?? Double.random(in: 0..<100) // [0.0, 100.0)
4243
let testVariations = try container.decodeIfPresent([String].self, forKey: .testVariations)
43-
let defaultTestVariations = [TestVariation(rawValue: "Enabled"), TestVariation(rawValue: "Disabled")]
4444
self.unlocked = unlocked
45+
let parsedTestVariations: [TestVariation]
4546
if let testVariations = testVariations {
46-
if testVariations.isEmpty {
47+
switch testVariations.count {
48+
case 0:
4749
self.isDevelopment = isDevelopment ?? false
4850
self.enabled = isEnabled ?? false
49-
self.testVariations = defaultTestVariations
5051
self.type = type ?? .featureFlag
5152
self.testVariationAssignment = enabled ? 1.0 : 99.0
52-
} else if testVariations.count == 1, let firstVariation = testVariations.first {
53+
parsedTestVariations = Self.defaultTestVariations
54+
case 1:
5355
self.enabled = isEnabled ?? false
5456
self.isDevelopment = isDevelopment ?? false
55-
self.testVariations = [TestVariation(rawValue: firstVariation),
56-
TestVariation(rawValue: "!\(firstVariation)")]
5757
self.type = type ?? .featureFlag
58-
} else if testVariations.count == 2 {
58+
if let firstVariation = testVariations.first {
59+
parsedTestVariations = [
60+
TestVariation(rawValue: firstVariation),
61+
TestVariation(rawValue: "!\(firstVariation)")
62+
]
63+
} else {
64+
parsedTestVariations = Self.defaultTestVariations
65+
}
66+
case 2:
5967
self.enabled = isEnabled ?? true
6068
self.isDevelopment = isDevelopment ?? false
61-
let testVariations = testVariations.map({ TestVariation(rawValue: $0) })
62-
if Feature.testVariationsContains(variationNames: ["enabled", "disabled"], in: testVariations)
63-
|| Feature.testVariationsContains(variationNames: ["on", "off"], in: testVariations) {
64-
self.type = type ?? .featureTest(.featureFlagAB)
65-
self.testVariations = defaultTestVariations
66-
} else {
67-
self.type = type ?? .featureTest(.ab)
68-
self.testVariations = testVariations
69+
parsedTestVariations = testVariations.map {
70+
TestVariation(rawValue: $0)
6971
}
70-
} else {
72+
self.type = parsedTestVariations.sorted() == Self.defaultTestVariations.sorted()
73+
? .featureTest(.featureFlagAB)
74+
: .featureTest(.ab)
75+
default:
7176
self.enabled = isEnabled ?? true
7277
self.isDevelopment = isDevelopment ?? false
73-
self.testVariations = testVariations.map({ TestVariation(rawValue: $0) })
78+
parsedTestVariations = testVariations.map {
79+
TestVariation(rawValue: $0)
80+
}
7481
self.type = type ?? .featureTest(.mvt)
7582
}
7683
} else {
7784
self.enabled = isEnabled ?? false
7885
self.isDevelopment = isDevelopment ?? false
79-
self.testVariations = defaultTestVariations
8086
self.type = type ?? .featureFlag
8187
self.testVariationAssignment = enabled ? 1.0 : 99.0
88+
parsedTestVariations = Self.defaultTestVariations
8289
}
83-
let variations = self.testVariations // Silences compiler error
90+
self.testVariations = parsedTestVariations
8491
if let testBiases = testBiases,
85-
testBiases.reduce(Percentage.min, { (runningTotal, testBias) -> Percentage in
86-
return runningTotal + testBias
87-
}) == Percentage.max,
88-
testBiases.count == variations.count {
92+
testBiases.reduce(Percentage.min, { (runningTotal, testBias) -> Percentage in
93+
return runningTotal + testBias
94+
}) == Percentage.max,
95+
testBiases.count == parsedTestVariations.count {
8996
self.testBiases = testBiases
9097
} else {
91-
self.testBiases = variations.map({ _ in
92-
return Percentage(rawValue: 100.0 / Double(variations.count))
98+
self.testBiases = parsedTestVariations.map({ _ in
99+
return Percentage(rawValue: 100.0 / Double(parsedTestVariations.count))
93100
})
94101
}
95102
self.labels = try container.decodeIfPresent([String?].self, forKey: .labels)
96-
?? [String?](repeating: nil, count: variations.count)
103+
?? [String?](repeating: nil, count: parsedTestVariations.count)
97104
self.testVariationOverride = nil
98105
}
99106

100-
private static func testVariationsContains(variationNames: [String], in variations: [Test.Variation]) -> Bool {
101-
var variationsFound: Bool = false
102-
for variationName in variationNames {
103-
variationsFound = variations.contains(where: { testVariation in
104-
return testVariation.rawValue.lowercased() == variationName
105-
})
106-
if !variationsFound { break }
107-
}
108-
return variationsFound
109-
}
110-
111107
public func encode(to encoder: Encoder) throws {
112108
var container = encoder.container(keyedBy: CodingKeys.self)
113109
try container.encode(name, forKey: .name)

FeatureFlags/Classes/Model/Feature.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import Foundation
99

1010
public struct Feature {
1111

12-
// MARK: Type defintions
12+
// MARK: Type definitions
1313
public typealias Name = FeatureName
1414

1515
// MARK: State

FeatureFlags/Classes/Model/TestVariation.swift

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,21 +22,39 @@ public struct TestVariation: RawRepresentable {
2222
// Note: A logic error has occurred and a Test.Variation could not be assigned.
2323
public static let unassigned = Test.Variation(rawValue: "Unassigned")
2424

25+
private static let disabledRawValues = ["disabled", "off"]
26+
private static let enabledRawValues = ["enabled", "on"]
2527
private let name: RawValue
2628
public typealias RawValue = String
2729

2830
public init(rawValue: RawValue) {
29-
self.name = rawValue
31+
name = Self.name(from: rawValue)
3032
}
3133

3234
public var rawValue: RawValue {
33-
return self.name
35+
return name
36+
}
37+
38+
static func name(from rawValue: RawValue) -> String {
39+
if disabledRawValues.contains(rawValue) {
40+
return Self.disabled.rawValue
41+
} else if enabledRawValues.contains(rawValue) {
42+
return Self.enabled.rawValue
43+
} else {
44+
return rawValue
45+
}
3446
}
3547
}
3648

3749
extension TestVariation: Equatable {
3850
public static func == (lhs: TestVariation, rhs: TestVariation) -> Bool {
39-
return lhs.rawValue.lowercased() == rhs.rawValue.lowercased()
51+
lhs.rawValue.lowercased() == rhs.rawValue.lowercased()
52+
}
53+
}
54+
55+
extension TestVariation: Comparable {
56+
public static func < (lhs: TestVariation, rhs: TestVariation) -> Bool {
57+
lhs.rawValue.lowercased() < rhs.rawValue.lowercased()
4058
}
4159
}
4260

0 commit comments

Comments
 (0)