Skip to content

Commit

Permalink
Update name of Swift Test Runner + run swift format auto formatting f…
Browse files Browse the repository at this point in the history
…ixes
  • Loading branch information
polok committed Mar 4, 2024
1 parent c6921c7 commit c214eb2
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 78 deletions.
6 changes: 3 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ let package = Package(
targets: ["FeaturevisorTypes"]
),
.executable(
name: "Featurevisor-swift-test",
name: "FeaturevisorSwiftTestRunner",
targets: ["FeaturevisorTestRunner"]
),
],
dependencies: [
.package(url: "https://github.com/daisuke-t-jp/MurmurHash-Swift.git", from: "1.1.1"),
.package(url: "https://github.com/JohnSundell/Files", from: "4.0.0"),
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.6"),
.package(url: "https://github.com/qiuzhifei/swift-commands", from: "0.6.0")
.package(url: "https://github.com/qiuzhifei/swift-commands", from: "0.6.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
Expand All @@ -47,7 +47,7 @@ let package = Package(
"FeaturevisorTypes",
"Files",
"Yams",
.product(name: "Commands", package: "swift-commands")
.product(name: "Commands", package: "swift-commands"),
],
path: "Sources/FeaturevisorTestRunner"
),
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,7 @@ First you need to install the Swift Test Runner using above steps (until we rele
$ cd path/to/featurevisor-swift-sdk
$ swift build -c release
$ cd .build/release
$ cp -f Featurevisor-swift-test /usr/local/bin/featurevisor-swift-test-runner
$ cp -f FeaturevisorSwiftTestRunner /usr/local/bin/featurevisor-swift-test-runner
```

Now you can usage like below:
Expand Down
125 changes: 71 additions & 54 deletions Sources/FeaturevisorTestRunner/FeaturevisorTestRunner.swift
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import Commands
import FeaturevisorSDK
import FeaturevisorTypes
import Files
import Foundation
import Commands
import Yams

@main
Expand All @@ -17,7 +17,7 @@ struct FeaturevisorTestRunner {
let featuresTestDirectoryPath = CommandLine.arguments[1] // TODO Handle command line parameters better

// Run Featurevisor CLI to build the datafiles
Commands.Task.run("bash -c cd \(featuresTestDirectoryPath) && featurevisor build") // TODO: Handle better
Commands.Task.run("bash -c cd \(featuresTestDirectoryPath) && featurevisor build") // TODO: Handle better

let testSuits = try loadAllFeatureTestSuits(
featuresTestDirectoryPath: featuresTestDirectoryPath
Expand All @@ -34,7 +34,8 @@ struct FeaturevisorTestRunner {
try testSuits.forEach({ testSuit in

// skip features which are not supported by ios, tvos
guard isFeatureSupported(by: [.ios, .tvos], featureKey: testSuit.feature, in: features) else {
guard isFeatureSupported(by: [.ios, .tvos], featureKey: testSuit.feature, in: features)
else {
return
}

Expand All @@ -47,28 +48,29 @@ struct FeaturevisorTestRunner {
var isTestSpecFailing = false

for (index, testCase) in testSuit.assertions.enumerated() {

var sdks: [Feature.Tag: [Environment: FeaturevisorInstance]] = [:]

try [Feature.Tag.ios, Feature.Tag.tvos].forEach({ tag in
let sdkProduction = try SDKProvider.provide(
for: tag,
under: .production,
using: featuresTestDirectoryPath,
assertionAt: testCase.at
)
let sdkStaging = try SDKProvider.provide(
for: tag,
under: .staging,
using: featuresTestDirectoryPath,
assertionAt: testCase.at
)

sdks[tag] = [
.staging: sdkStaging,
.production: sdkProduction
]
})

try [Feature.Tag.ios, Feature.Tag.tvos]
.forEach({ tag in
let sdkProduction = try SDKProvider.provide(
for: tag,
under: .production,
using: featuresTestDirectoryPath,
assertionAt: testCase.at
)
let sdkStaging = try SDKProvider.provide(
for: tag,
under: .staging,
using: featuresTestDirectoryPath,
assertionAt: testCase.at
)

sdks[tag] = [
.staging: sdkStaging,
.production: sdkProduction,
]
})

let isFeatureEnabledResult: Bool

Expand All @@ -88,26 +90,29 @@ struct FeaturevisorTestRunner {
else {
break
}

let tag = firstTagToVerifyAgainst(
tags: [.ios, .tvos],
environment: .staging,
featureKey: testSuit.feature,
in: features)

let tag = firstTagToVerifyAgainst(
tags: [.ios, .tvos],
environment: .staging,
featureKey: testSuit.feature,
in: features
)

isFeatureEnabledResult =
sdks[tag]![.staging]!.isEnabled(
sdks[tag]![.staging]!
.isEnabled(
featureKey: testSuit.feature,
context: testCase.context ?? [:]
) == testCase.expectedToBeEnabled

testCase.expectedVariables?
.forEach({ (variableKey, variableExpectedValue) in
let variable = sdks[tag]![.staging]!.getVariable(
featureKey: testSuit.feature,
variableKey: variableKey,
context: testCase.context ?? [:]
)
let variable = sdks[tag]![.staging]!
.getVariable(
featureKey: testSuit.feature,
variableKey: variableKey,
context: testCase.context ?? [:]
)

if variable != variableExpectedValue {
expectedValuesFalses[variableKey] = (
Expand Down Expand Up @@ -155,26 +160,29 @@ struct FeaturevisorTestRunner {
else {
break
}

let tag = firstTagToVerifyAgainst(
tags: [.ios, .tvos],
environment: .production,
featureKey: testSuit.feature,
in: features)

let tag = firstTagToVerifyAgainst(
tags: [.ios, .tvos],
environment: .production,
featureKey: testSuit.feature,
in: features
)

isFeatureEnabledResult =
sdks[tag]![.production]!.isEnabled(
sdks[tag]![.production]!
.isEnabled(
featureKey: testSuit.feature,
context: testCase.context ?? [:]
) == testCase.expectedToBeEnabled

testCase.expectedVariables?
.forEach({ (variableKey, variableExpectedValue) in
let variable = sdks[tag]![.production]!.getVariable(
featureKey: testSuit.feature,
variableKey: variableKey,
context: testCase.context ?? [:]
)
let variable = sdks[tag]![.production]!
.getVariable(
featureKey: testSuit.feature,
variableKey: variableKey,
context: testCase.context ?? [:]
)

if variable != variableExpectedValue {
expectedValuesFalses[variableKey] = (
Expand Down Expand Up @@ -275,15 +283,24 @@ extension FeaturevisorTestRunner {

return feature.tags.contains(where: tags.contains)
}

// If feature is exposed for iOS or tvOS then it doesn't matter which datafile e.g. ios or tvos we use
func firstTagToVerifyAgainst(
tags: [Feature.Tag],
environment: Environment,
featureKey: String,
in features: [Feature]) -> Feature.Tag {

return tags.first(where: { isFeatureSupported(by: [$0], featureKey: featureKey, in: features) && isFeatureExposed(for: [$0], under: environment.rawValue, featureKey: featureKey, in: features)})! // TODO: Deal with force unwrap, redesign the way how we iterate the test suit
in features: [Feature]
) -> Feature.Tag {

return tags.first(where: {
isFeatureSupported(by: [$0], featureKey: featureKey, in: features)
&& isFeatureExposed(
for: [$0],
under: environment.rawValue,
featureKey: featureKey,
in: features
)
})! // TODO: Deal with force unwrap, redesign the way how we iterate the test suit
}

func isFeatureExposed(
Expand All @@ -296,11 +313,11 @@ extension FeaturevisorTestRunner {
guard let feature = features.first(where: { $0.key == "\(featureKey).yml" }) else { // TODO: We need to cut off the extension
return false
}

let supportedTag = tags.first(where: { tag in
feature.environments[environment]?.isExposed(for: tag) ?? false // TODO: Handle it
})

return supportedTag != nil
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,7 @@ enum ExpectedVariableValue: Codable {
codingPath: decoder.codingPath,
debugDescription: "\(VariableValue.self) unknown"
)

debugPrint("ERROR: \(decoder.codingPath)") // TODO


throw DecodingError.dataCorrupted(context)
}
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/FeaturevisorTestRunner/Models/Feature.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

struct Feature: Decodable {

enum Tag: String, Decodable {
case android
case androidtv
Expand Down
27 changes: 18 additions & 9 deletions Sources/FeaturevisorTestRunner/Models/SDKProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,27 @@ import FeaturevisorTypes
import Foundation

enum SDKProvider {

enum DatafileConfig {
private static let productionDatafilePath = "/dist/production/datafile-tag-${{ tag }}.json"
private static let stagingDatafilePath = "/dist/staging/datafile-tag-${{ tag }}.json"

static func relevantPath(for tag: Feature.Tag, under environment: Environment) -> String {
switch environment {
case .production:
return productionDatafilePath.replacingOccurrences(of: "${{ tag }}", with: tag.rawValue) // TODO: Make replace placeholder prettier
case .staging:
return stagingDatafilePath.replacingOccurrences(of: "${{ tag }}", with: tag.rawValue) // TODO: Make replace placeholder prettier
case .production:
return productionDatafilePath.replacingOccurrences(
of: "${{ tag }}",
with: tag.rawValue
) // TODO: Make replace placeholder prettier
case .staging:
return stagingDatafilePath.replacingOccurrences(
of: "${{ tag }}",
with: tag.rawValue
) // TODO: Make replace placeholder prettier
}
}
}

private static let maxBucketedNumber = 100000.0

static func provide(
Expand All @@ -27,8 +33,11 @@ enum SDKProvider {
assertionAt: Double
) throws -> FeaturevisorInstance {

let datafileJSON = try String(contentsOfFile: path + DatafileConfig.relevantPath(for: tag, under: environment), encoding: .utf8)

let datafileJSON = try String(
contentsOfFile: path + DatafileConfig.relevantPath(for: tag, under: environment),
encoding: .utf8
)

let datafileContent = try JSONDecoder()
.decode(DatafileContent.self, from: datafileJSON.data(using: .utf8)!)

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import Foundation

extension String {

func removeAllWhitespaces() -> String {
return String(self.filter { !$0.isWhitespace })
}
Expand Down
16 changes: 10 additions & 6 deletions Sources/FeaturevisorTypes/Types.swift
Original file line number Diff line number Diff line change
Expand Up @@ -318,14 +318,18 @@ public enum VariableValue: Codable {
self = .integer(integer)
}
// To convert int value defined as string into int e.g. "1"
else if let integerString = try? container.decode(String.self), let integer = Int(integerString) {
else if let integerString = try? container.decode(String.self),
let integer = Int(integerString)
{
self = .integer(integer)
}
else if let double = try? container.decode(Double.self) {
self = .double(double)
}
// To convert double value defined as string into double e.g. "1.0"
else if let doubleString = try? container.decode(String.self), let double = Double(doubleString) {
else if let doubleString = try? container.decode(String.self),
let double = Double(doubleString)
{
self = .double(double)
}
else if let array = try? container.decodeStringified([String].self) {
Expand Down Expand Up @@ -403,15 +407,15 @@ extension VariableValue: Equatable {
case (.boolean(let bLhs), .boolean(let bRhs)):
return bLhs == bRhs
case (.string(let sLhs), .string(let sRhs)):
return sLhs == sRhs
return sLhs == sRhs
case (.double(let dLhs), .double(let dRhs)):
return dLhs == dRhs
case (.integer(let iLhs), .integer(let iRhs)):
return iLhs == iRhs
case (.json(let jLhs), .json(let jRhs)):
guard jLhs != jRhs else {
return true
}
guard jLhs != jRhs else {
return true
}
return jLhs.removeAllWhitespaces() == jRhs.removeAllWhitespaces()
case (.object(let oLhs), .object(let oRhs)):
return oLhs == oRhs
Expand Down

0 comments on commit c214eb2

Please sign in to comment.