Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Ability to shift courses dates if deadlines have been missed #288

Merged
merged 15 commits into from
Mar 1, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
246 changes: 246 additions & 0 deletions Authorization/AuthorizationTests/AuthorizationMock.generated.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2436,3 +2436,249 @@ open class DownloadManagerProtocolMock: DownloadManagerProtocol, Mock {
}
}

// MARK: - WebviewCookiesUpdateProtocol

open class WebviewCookiesUpdateProtocolMock: WebviewCookiesUpdateProtocol, Mock {
public init(sequencing sequencingPolicy: SequencingPolicy = .lastWrittenResolvedFirst, stubbing stubbingPolicy: StubbingPolicy = .wrap, file: StaticString = #file, line: UInt = #line) {
SwiftyMockyTestObserver.setup()
self.sequencingPolicy = sequencingPolicy
self.stubbingPolicy = stubbingPolicy
self.file = file
self.line = line
}

var matcher: Matcher = Matcher.default
var stubbingPolicy: StubbingPolicy = .wrap
var sequencingPolicy: SequencingPolicy = .lastWrittenResolvedFirst

private var queue = DispatchQueue(label: "com.swiftymocky.invocations", qos: .userInteractive)
private var invocations: [MethodType] = []
private var methodReturnValues: [Given] = []
private var methodPerformValues: [Perform] = []
private var file: StaticString?
private var line: UInt?

public typealias PropertyStub = Given
public typealias MethodStub = Given
public typealias SubscriptStub = Given

/// Convenience method - call setupMock() to extend debug information when failure occurs
public func setupMock(file: StaticString = #file, line: UInt = #line) {
self.file = file
self.line = line
}

/// Clear mock internals. You can specify what to reset (invocations aka verify, givens or performs) or leave it empty to clear all mock internals
public func resetMock(_ scopes: MockScope...) {
let scopes: [MockScope] = scopes.isEmpty ? [.invocation, .given, .perform] : scopes
if scopes.contains(.invocation) { invocations = [] }
if scopes.contains(.given) { methodReturnValues = [] }
if scopes.contains(.perform) { methodPerformValues = [] }
}

public var authInteractor: AuthInteractorProtocol {
get { invocations.append(.p_authInteractor_get); return __p_authInteractor ?? givenGetterValue(.p_authInteractor_get, "WebviewCookiesUpdateProtocolMock - stub value for authInteractor was not defined") }
}
private var __p_authInteractor: (AuthInteractorProtocol)?

public var cookiesReady: Bool {
get { invocations.append(.p_cookiesReady_get); return __p_cookiesReady ?? givenGetterValue(.p_cookiesReady_get, "WebviewCookiesUpdateProtocolMock - stub value for cookiesReady was not defined") }
set { invocations.append(.p_cookiesReady_set(.value(newValue))); __p_cookiesReady = newValue }
}
private var __p_cookiesReady: (Bool)?

public var updatingCookies: Bool {
get { invocations.append(.p_updatingCookies_get); return __p_updatingCookies ?? givenGetterValue(.p_updatingCookies_get, "WebviewCookiesUpdateProtocolMock - stub value for updatingCookies was not defined") }
set { invocations.append(.p_updatingCookies_set(.value(newValue))); __p_updatingCookies = newValue }
}
private var __p_updatingCookies: (Bool)?

public var errorMessage: String? {
get { invocations.append(.p_errorMessage_get); return __p_errorMessage ?? optionalGivenGetterValue(.p_errorMessage_get, "WebviewCookiesUpdateProtocolMock - stub value for errorMessage was not defined") }
set { invocations.append(.p_errorMessage_set(.value(newValue))); __p_errorMessage = newValue }
}
private var __p_errorMessage: (String)?





open func updateCookies(force: Bool, retryCount: Int) {
addInvocation(.m_updateCookies__force_forceretryCount_retryCount(Parameter<Bool>.value(`force`), Parameter<Int>.value(`retryCount`)))
let perform = methodPerformValue(.m_updateCookies__force_forceretryCount_retryCount(Parameter<Bool>.value(`force`), Parameter<Int>.value(`retryCount`))) as? (Bool, Int) -> Void
perform?(`force`, `retryCount`)
}


fileprivate enum MethodType {
case m_updateCookies__force_forceretryCount_retryCount(Parameter<Bool>, Parameter<Int>)
case p_authInteractor_get
case p_cookiesReady_get
case p_cookiesReady_set(Parameter<Bool>)
case p_updatingCookies_get
case p_updatingCookies_set(Parameter<Bool>)
case p_errorMessage_get
case p_errorMessage_set(Parameter<String?>)

static func compareParameters(lhs: MethodType, rhs: MethodType, matcher: Matcher) -> Matcher.ComparisonResult {
switch (lhs, rhs) {
case (.m_updateCookies__force_forceretryCount_retryCount(let lhsForce, let lhsRetrycount), .m_updateCookies__force_forceretryCount_retryCount(let rhsForce, let rhsRetrycount)):
var results: [Matcher.ParameterComparisonResult] = []
results.append(Matcher.ParameterComparisonResult(Parameter.compare(lhs: lhsForce, rhs: rhsForce, with: matcher), lhsForce, rhsForce, "force"))
results.append(Matcher.ParameterComparisonResult(Parameter.compare(lhs: lhsRetrycount, rhs: rhsRetrycount, with: matcher), lhsRetrycount, rhsRetrycount, "retryCount"))
return Matcher.ComparisonResult(results)
case (.p_authInteractor_get,.p_authInteractor_get): return Matcher.ComparisonResult.match
case (.p_cookiesReady_get,.p_cookiesReady_get): return Matcher.ComparisonResult.match
case (.p_cookiesReady_set(let left),.p_cookiesReady_set(let right)): return Matcher.ComparisonResult([Matcher.ParameterComparisonResult(Parameter<Bool>.compare(lhs: left, rhs: right, with: matcher), left, right, "newValue")])
case (.p_updatingCookies_get,.p_updatingCookies_get): return Matcher.ComparisonResult.match
case (.p_updatingCookies_set(let left),.p_updatingCookies_set(let right)): return Matcher.ComparisonResult([Matcher.ParameterComparisonResult(Parameter<Bool>.compare(lhs: left, rhs: right, with: matcher), left, right, "newValue")])
case (.p_errorMessage_get,.p_errorMessage_get): return Matcher.ComparisonResult.match
case (.p_errorMessage_set(let left),.p_errorMessage_set(let right)): return Matcher.ComparisonResult([Matcher.ParameterComparisonResult(Parameter<String?>.compare(lhs: left, rhs: right, with: matcher), left, right, "newValue")])
default: return .none
}
}

func intValue() -> Int {
switch self {
case let .m_updateCookies__force_forceretryCount_retryCount(p0, p1): return p0.intValue + p1.intValue
case .p_authInteractor_get: return 0
case .p_cookiesReady_get: return 0
case .p_cookiesReady_set(let newValue): return newValue.intValue
case .p_updatingCookies_get: return 0
case .p_updatingCookies_set(let newValue): return newValue.intValue
case .p_errorMessage_get: return 0
case .p_errorMessage_set(let newValue): return newValue.intValue
}
}
func assertionName() -> String {
switch self {
case .m_updateCookies__force_forceretryCount_retryCount: return ".updateCookies(force:retryCount:)"
case .p_authInteractor_get: return "[get] .authInteractor"
case .p_cookiesReady_get: return "[get] .cookiesReady"
case .p_cookiesReady_set: return "[set] .cookiesReady"
case .p_updatingCookies_get: return "[get] .updatingCookies"
case .p_updatingCookies_set: return "[set] .updatingCookies"
case .p_errorMessage_get: return "[get] .errorMessage"
case .p_errorMessage_set: return "[set] .errorMessage"
}
}
}

open class Given: StubbedMethod {
fileprivate var method: MethodType

private init(method: MethodType, products: [StubProduct]) {
self.method = method
super.init(products)
}

public static func authInteractor(getter defaultValue: AuthInteractorProtocol...) -> PropertyStub {
return Given(method: .p_authInteractor_get, products: defaultValue.map({ StubProduct.return($0 as Any) }))
}
public static func cookiesReady(getter defaultValue: Bool...) -> PropertyStub {
return Given(method: .p_cookiesReady_get, products: defaultValue.map({ StubProduct.return($0 as Any) }))
}
public static func updatingCookies(getter defaultValue: Bool...) -> PropertyStub {
return Given(method: .p_updatingCookies_get, products: defaultValue.map({ StubProduct.return($0 as Any) }))
}
public static func errorMessage(getter defaultValue: String?...) -> PropertyStub {
return Given(method: .p_errorMessage_get, products: defaultValue.map({ StubProduct.return($0 as Any) }))
}

}

public struct Verify {
fileprivate var method: MethodType

public static func updateCookies(force: Parameter<Bool>, retryCount: Parameter<Int>) -> Verify { return Verify(method: .m_updateCookies__force_forceretryCount_retryCount(`force`, `retryCount`))}
public static var authInteractor: Verify { return Verify(method: .p_authInteractor_get) }
public static var cookiesReady: Verify { return Verify(method: .p_cookiesReady_get) }
public static func cookiesReady(set newValue: Parameter<Bool>) -> Verify { return Verify(method: .p_cookiesReady_set(newValue)) }
public static var updatingCookies: Verify { return Verify(method: .p_updatingCookies_get) }
public static func updatingCookies(set newValue: Parameter<Bool>) -> Verify { return Verify(method: .p_updatingCookies_set(newValue)) }
public static var errorMessage: Verify { return Verify(method: .p_errorMessage_get) }
public static func errorMessage(set newValue: Parameter<String?>) -> Verify { return Verify(method: .p_errorMessage_set(newValue)) }
}

public struct Perform {
fileprivate var method: MethodType
var performs: Any

public static func updateCookies(force: Parameter<Bool>, retryCount: Parameter<Int>, perform: @escaping (Bool, Int) -> Void) -> Perform {
return Perform(method: .m_updateCookies__force_forceretryCount_retryCount(`force`, `retryCount`), performs: perform)
}
}

public func given(_ method: Given) {
methodReturnValues.append(method)
}

public func perform(_ method: Perform) {
methodPerformValues.append(method)
methodPerformValues.sort { $0.method.intValue() < $1.method.intValue() }
}

public func verify(_ method: Verify, count: Count = Count.moreOrEqual(to: 1), file: StaticString = #file, line: UInt = #line) {
let fullMatches = matchingCalls(method, file: file, line: line)
let success = count.matches(fullMatches)
let assertionName = method.method.assertionName()
let feedback: String = {
guard !success else { return "" }
return Utils.closestCallsMessage(
for: self.invocations.map { invocation in
matcher.set(file: file, line: line)
defer { matcher.clearFileAndLine() }
return MethodType.compareParameters(lhs: invocation, rhs: method.method, matcher: matcher)
},
name: assertionName
)
}()
MockyAssert(success, "Expected: \(count) invocations of `\(assertionName)`, but was: \(fullMatches).\(feedback)", file: file, line: line)
}

private func addInvocation(_ call: MethodType) {
self.queue.sync { invocations.append(call) }
}
private func methodReturnValue(_ method: MethodType) throws -> StubProduct {
matcher.set(file: self.file, line: self.line)
defer { matcher.clearFileAndLine() }
let candidates = sequencingPolicy.sorted(methodReturnValues, by: { $0.method.intValue() > $1.method.intValue() })
let matched = candidates.first(where: { $0.isValid && MethodType.compareParameters(lhs: $0.method, rhs: method, matcher: matcher).isFullMatch })
guard let product = matched?.getProduct(policy: self.stubbingPolicy) else { throw MockError.notStubed }
return product
}
private func methodPerformValue(_ method: MethodType) -> Any? {
matcher.set(file: self.file, line: self.line)
defer { matcher.clearFileAndLine() }
let matched = methodPerformValues.reversed().first { MethodType.compareParameters(lhs: $0.method, rhs: method, matcher: matcher).isFullMatch }
return matched?.performs
}
private func matchingCalls(_ method: MethodType, file: StaticString?, line: UInt?) -> [MethodType] {
matcher.set(file: file ?? self.file, line: line ?? self.line)
defer { matcher.clearFileAndLine() }
return invocations.filter { MethodType.compareParameters(lhs: $0, rhs: method, matcher: matcher).isFullMatch }
}
private func matchingCalls(_ method: Verify, file: StaticString?, line: UInt?) -> Int {
return matchingCalls(method.method, file: file, line: line).count
}
private func givenGetterValue<T>(_ method: MethodType, _ message: String) -> T {
do {
return try methodReturnValue(method).casted()
} catch {
onFatalFailure(message)
Failure(message)
}
}
private func optionalGivenGetterValue<T>(_ method: MethodType, _ message: String) -> T? {
do {
return try methodReturnValue(method).casted()
} catch {
return nil
}
}
private func onFatalFailure(_ message: String) {
guard let file = self.file, let line = self.line else { return } // Let if fail if cannot handle gratefully
SwiftyMockyTestObserver.handleFatalError(message: message, file: file, line: line)
}
}

4 changes: 4 additions & 0 deletions Core/Core.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@
0770DE6128D0B2CB006D8A5D /* Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0770DE6028D0B2CB006D8A5D /* Assets.swift */; };
07DDFCBD29A780BB00572595 /* UINavigationController+Animation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07DDFCBC29A780BB00572595 /* UINavigationController+Animation.swift */; };
07E0939F2B308D2800F1E4B2 /* Data_Certificate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07E0939E2B308D2800F1E4B2 /* Data_Certificate.swift */; };
97E7DF112B81DE7300A2A09B /* SuccessViewWithButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 97E7DF102B81DE7300A2A09B /* SuccessViewWithButton.swift */; };
141F1D302B7328D4009E81EB /* WebviewCookiesUpdateProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 141F1D2F2B7328D4009E81EB /* WebviewCookiesUpdateProtocol.swift */; };
A53A32352B233DEC005FE38A /* ThemeConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A53A32342B233DEC005FE38A /* ThemeConfig.swift */; };
A595689B2B6173DF00ED4F90 /* BranchConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = A595689A2B6173DF00ED4F90 /* BranchConfig.swift */; };
Expand Down Expand Up @@ -302,6 +303,7 @@
349B90CD6579F7B8D257E515 /* Pods_App_Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_App_Core.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3B74C6685E416657F3C5F5A8 /* Pods-App-Core.releaseprod.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core.releaseprod.xcconfig"; path = "Target Support Files/Pods-App-Core/Pods-App-Core.releaseprod.xcconfig"; sourceTree = "<group>"; };
60153262DBC2F9E660D7E11B /* Pods-App-Core.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core.release.xcconfig"; path = "Target Support Files/Pods-App-Core/Pods-App-Core.release.xcconfig"; sourceTree = "<group>"; };
97E7DF102B81DE7300A2A09B /* SuccessViewWithButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuccessViewWithButton.swift; sourceTree = "<group>"; };
9D5B06CAA99EA5CD49CBE2BB /* Pods-App-Core.debugdev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-App-Core.debugdev.xcconfig"; path = "Target Support Files/Pods-App-Core/Pods-App-Core.debugdev.xcconfig"; sourceTree = "<group>"; };
A53A32342B233DEC005FE38A /* ThemeConfig.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeConfig.swift; sourceTree = "<group>"; };
A595689A2B6173DF00ED4F90 /* BranchConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BranchConfig.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -679,6 +681,7 @@
024FCCFF28EF1CD300232339 /* WebBrowser.swift */,
028CE96829858ECC00B6B1C3 /* FlexibleKeyboardInputView.swift */,
023A4DD3299E66BD006C0E48 /* OfflineSnackBarView.swift */,
97E7DF102B81DE7300A2A09B /* SuccessViewWithButton.swift */,
021D925628DCF12900ACC565 /* AlertView.swift */,
0295C884299B99DD00ABE571 /* RefreshableScrollView.swift */,
02B3F16D2AB489A400DDDD4E /* RefreshableScrollViewCompat.swift */,
Expand Down Expand Up @@ -1102,6 +1105,7 @@
027BD3BD2909478B00392132 /* UIView+EnclosingScrollView.swift in Sources */,
BA8FA6682AD59A5700EA029A /* SocialAuthButton.swift in Sources */,
02D400612B0678190029D168 /* SKStoreReviewControllerExtension.swift in Sources */,
97E7DF112B81DE7300A2A09B /* SuccessViewWithButton.swift in Sources */,
02A4833C29B8C57800D33F33 /* DownloadView.swift in Sources */,
027BD3AD2909475000392132 /* KeyboardScroller.swift in Sources */,
070019A528F6F17900D5FC78 /* Data_Media.swift in Sources */,
Expand Down
1 change: 1 addition & 0 deletions Core/Core/Extensions/Notification.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ public extension Notification.Name {
static let onNewVersionAvaliable = Notification.Name("onNewVersionAvaliable")
static let webviewReloadNotification = Notification.Name("webviewReloadNotification")
static let onBlockCompletion = Notification.Name.init("onBlockCompletion")
static let shiftCourseDates = Notification.Name("shiftCourseDates")
}
Loading
Loading