Skip to content

Commit

Permalink
refactor: feature assertion output + simple duration execution (#67)
Browse files Browse the repository at this point in the history
  • Loading branch information
polok authored Mar 28, 2024
1 parent b81d4f9 commit db24373
Show file tree
Hide file tree
Showing 4 changed files with 145 additions and 57 deletions.
14 changes: 14 additions & 0 deletions Sources/FeaturevisorTestRunner/Extensions/UInt64+Time.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Foundation

extension UInt64 {

var milliseconds: Double {
let elapsedTimeInMilliSeconds = Double(self) / 1_000_000.0
return Double(elapsedTimeInMilliSeconds)
}

var seconds: Double {
let elapsedTimeInMilliSeconds = Double(self) / 1_000_000_000.0
return Double(elapsedTimeInMilliSeconds)
}
}
51 changes: 0 additions & 51 deletions Sources/FeaturevisorTestRunner/FeaturevisorTestRunner+Print.swift

This file was deleted.

38 changes: 32 additions & 6 deletions Sources/FeaturevisorTestRunner/FeaturevisorTestRunner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ struct FeaturevisorTestRunner: ParsableCommand {

let features = try loadAllFeatures(featuresTestDirectoryPath: featuresTestDirectoryPath)

var totalElapsedDurationInMilliseconds: UInt64 = 0

var totalTestSpecs = 0
var failedTestSpecs = 0

Expand All @@ -46,6 +48,11 @@ struct FeaturevisorTestRunner: ParsableCommand {
return
}

let output = FeatureResultOutputBuilder(
feature: testSuit.feature,
onlyFailures: onlyFailures
)

totalTestSpecs += 1
totalAssertionsCount += testSuit.assertions.count

Expand All @@ -63,6 +70,7 @@ struct FeaturevisorTestRunner: ParsableCommand {
using: featuresTestDirectoryPath,
assertionAt: testCase.at
)

let sdkStaging = try SDKProvider.provide(
for: tag,
under: .staging,
Expand Down Expand Up @@ -102,6 +110,8 @@ struct FeaturevisorTestRunner: ParsableCommand {
in: features
)

let startTime = DispatchTime.now()

isFeatureEnabledResult =
sdks[tag]![.staging]!
.isEnabled(
Expand All @@ -125,21 +135,25 @@ struct FeaturevisorTestRunner: ParsableCommand {
}
})

let endTime = DispatchTime.now()

let finalAssertionResult =
isFeatureEnabledResult && expectedValueFailures.isEmpty

isTestSpecFailing = isTestSpecFailing || !finalAssertionResult
failedAssertionsCount =
finalAssertionResult ? failedAssertionsCount : failedAssertionsCount + 1

printAssertionResult(
let elapsedTime = endTime.uptimeNanoseconds - startTime.uptimeNanoseconds
totalElapsedDurationInMilliseconds += elapsedTime

output.addAssertion(
environment: testCase.environment,
index: index,
feature: testSuit.feature,
assertionResult: finalAssertionResult,
expectedValueFailures: expectedValueFailures,
description: testCase.description,
onlyFailures: onlyFailures
elapsedTime: elapsedTime
)

case .production:
Expand All @@ -162,6 +176,8 @@ struct FeaturevisorTestRunner: ParsableCommand {
in: features
)

let startTime = DispatchTime.now()

isFeatureEnabledResult =
sdks[tag]![.production]!
.isEnabled(
Expand All @@ -185,32 +201,42 @@ struct FeaturevisorTestRunner: ParsableCommand {
}
})

let endTime = DispatchTime.now()

let finalAssertionResult =
isFeatureEnabledResult && expectedValueFailures.isEmpty

isTestSpecFailing = isTestSpecFailing || !finalAssertionResult
failedAssertionsCount =
finalAssertionResult ? failedAssertionsCount : failedAssertionsCount + 1

printAssertionResult(
let elapsedTime = endTime.uptimeNanoseconds - startTime.uptimeNanoseconds
totalElapsedDurationInMilliseconds += elapsedTime

output.addAssertion(
environment: testCase.environment,
index: index,
feature: testSuit.feature,
assertionResult: finalAssertionResult,
expectedValueFailures: expectedValueFailures,
description: testCase.description,
onlyFailures: onlyFailures
elapsedTime: elapsedTime
)
}
}

if let output = output.build() {
print(output)
}

failedTestSpecs = isTestSpecFailing ? failedTestSpecs + 1 : failedTestSpecs
})

print("\nTest specs: \(totalTestSpecs - failedTestSpecs) passed, \(failedTestSpecs) failed")
print(
"Assertions: \(totalAssertionsCount - failedAssertionsCount) passed, \(failedAssertionsCount) failed"
)

print("Assertions execution duration: \(totalElapsedDurationInMilliseconds.milliseconds)ms")
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import FeaturevisorTypes
import Foundation

class FeatureResultOutputBuilder {

enum ResultMark: String {
case success = ""
case failure = ""

init(result: Bool) {
self = result ? .success : .failure
}
}

struct Assertion {
let environment: Environment
let index: Int
let assertionResult: Bool
let expectedValueFailures: [VariableKey: (expected: VariableValue, got: VariableValue?)]
let description: String
let elapsedTime: UInt64
}

private let onlyFailures: Bool
private let feature: String
private var assertions: [Assertion] = []

init(feature: String, onlyFailures: Bool) {
self.onlyFailures = onlyFailures
self.feature = feature
}

@discardableResult func addAssertion(
environment: Environment,
index: Int,
assertionResult: Bool,
expectedValueFailures: [VariableKey: (expected: VariableValue, got: VariableValue?)],
description: String,
elapsedTime: UInt64
) -> Self {
let assertion: Assertion = .init(
environment: environment,
index: index,
assertionResult: assertionResult,
expectedValueFailures: expectedValueFailures,
description: description,
elapsedTime: elapsedTime
)

assertions.append(assertion)
return self
}

func build() -> String? {

let hasFailedAssertions = !assertions.filter({ !$0.assertionResult }).isEmpty

guard onlyFailures && hasFailedAssertions || !onlyFailures else {
return nil
}

let totalElapsedTimeInMilliSeconds = assertions.reduce(
0.0,
{ $0 + $1.elapsedTime.milliseconds }
)
var output: String = ""

output.append("\nTesting: \(feature).feature.yml (\(totalElapsedTimeInMilliSeconds)ms)")
output.append("\n feature \"\(feature)\"")

assertions.forEach({ assertion in

let mark = ResultMark(result: assertion.assertionResult)
let index = assertion.index
let env = assertion.environment.rawValue
let description = assertion.description
let expectedValueFailures = assertion.expectedValueFailures
let elapsedTimeInMilliSeconds = assertion.elapsedTime.milliseconds

output.append(
"\n \(mark.rawValue) Assertion #\(index): \(env) \(description) (\(elapsedTimeInMilliSeconds)ms)"
)

expectedValueFailures.forEach({ (key, value) in
output.append("\n => variable key: \(key)")
output.append("\n => expected: \(value.expected)")

if let got = value.got {
output.append("\n => received: \(got)")
}
else {
output.append("\n => received: nil")
}
})
})

return output
}
}

0 comments on commit db24373

Please sign in to comment.