From 39a84513147281c165f71379b04375c9758471a0 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Tue, 30 Apr 2024 13:42:33 -0400 Subject: [PATCH 01/13] Digital PCT265 story ONEAPP-7249 - CoreLogging protocol for easier logging. --- .../ActionHandling/ActionOpenPageModel.swift | 10 ++++++++ .../MVMCoreLoggingHandler+Extension.swift | 25 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/MVMCore/MVMCore/ActionHandling/ActionOpenPageModel.swift b/MVMCore/MVMCore/ActionHandling/ActionOpenPageModel.swift index c8362a8..ac7ee02 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionOpenPageModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionOpenPageModel.swift @@ -116,3 +116,13 @@ public struct ActionOpenPageModel: ActionModelProtocol, ActionOpenPageProtocol, try container.encodeIfPresent(fallbackResponse, forKey: .fallbackResponse) } } + +extension ActionOpenPageModel: CustomDebugStringConvertible { + public var debugDescription: String { + if let requestURL { + return "\(Self.self) for \(pageType) @ \(requestURL)" + } else { + return "\(Self.self) for \(pageType)" + } + } +} diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler+Extension.swift b/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler+Extension.swift index d74201e..cc80a81 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler+Extension.swift +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler+Extension.swift @@ -13,3 +13,28 @@ import Foundation Swift.print(message) } } + +public protocol CoreLogging { + func debugLog(_ string: String) + + var loggingPrefix: String { get } +} + +public extension CoreLogging { + + var loggingPrefix: String { + return String(describing: self) + } + + static func debugLog(_ string: String) { + #if LOGGING + MVMCoreLoggingHandler.shared()?.handleDebugMessage("\(String(describing: Self.self)) \(string)") + #endif + } + + func debugLog(_ string: String) { + #if LOGGING + MVMCoreLoggingHandler.shared()?.handleDebugMessage("\(loggingPrefix) " + string) + #endif + } +} From 85747b146ea638b31de1ceb3a287679da539ad7d Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Tue, 30 Apr 2024 20:35:30 -0400 Subject: [PATCH 02/13] Digital PCT265 story ONEAPP-7249 - Pipe logs to system logger rather than stdout. Logging updates to categorize logs. --- .../MVMCoreLoggingDelegateProtocol.swift | 9 ++++-- .../MVMCoreLoggingHandler+Extension.swift | 17 +++++------ .../OtherHandlers/MVMCoreLoggingHandler.swift | 30 +++++++++++++++++-- 3 files changed, 41 insertions(+), 15 deletions(-) diff --git a/MVMCore/MVMCore/MainProtocols/MVMCoreLoggingDelegateProtocol.swift b/MVMCore/MVMCore/MainProtocols/MVMCoreLoggingDelegateProtocol.swift index eb6f223..b903a09 100644 --- a/MVMCore/MVMCore/MainProtocols/MVMCoreLoggingDelegateProtocol.swift +++ b/MVMCore/MVMCore/MainProtocols/MVMCoreLoggingDelegateProtocol.swift @@ -8,13 +8,16 @@ public protocol MVMCoreLoggingDelegateProtocol { - // Can be used to log different actions performed by the core. + /// Can be used to log different actions performed by the core. func handleDebugMessage(_ message: String?) + + /// Can be used to log a message under a particular cagetory. + func handleDebugMessage(_ message: String, category: String?) - // Can be used to choose how to log error objects. + /// Can be used to choose how to log error objects. func addError(toLog errorObject: MVMCoreErrorObject) - // Log that the load has finished. + /// Log that the load has finished. func logLoadFinished(_ loadObject: MVMCoreLoadObject?, loadedViewController: MVMCoreViewControllerProtocol?, error: MVMCoreErrorObject?) } diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler+Extension.swift b/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler+Extension.swift index cc80a81..e322f37 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler+Extension.swift +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler+Extension.swift @@ -7,34 +7,31 @@ // import Foundation - -@objc public extension MVMCoreLoggingHandler { - @objc func print(with message: String) { - Swift.print(message) - } -} +import os public protocol CoreLogging { - func debugLog(_ string: String) + static var loggingCategory: String? { get } var loggingPrefix: String { get } } public extension CoreLogging { + static var loggingCategory: String? { return nil } + var loggingPrefix: String { - return String(describing: self) + return "" } static func debugLog(_ string: String) { #if LOGGING - MVMCoreLoggingHandler.shared()?.handleDebugMessage("\(String(describing: Self.self)) \(string)") + MVMCoreLoggingHandler.shared()?.handleDebugMessage(string, category: loggingCategory) #endif } func debugLog(_ string: String) { #if LOGGING - MVMCoreLoggingHandler.shared()?.handleDebugMessage("\(loggingPrefix) " + string) + MVMCoreLoggingHandler.shared()?.handleDebugMessage("\(loggingPrefix)\(string)", category: Self.loggingCategory) #endif } } diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift b/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift index 1732fd5..cb0ee9c 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift @@ -7,9 +7,28 @@ // import Foundation +import os @objc open class MVMCoreLoggingHandler: NSObject, MVMCoreLoggingDelegateProtocol { + public static let standardCategory = "General" + + private let logger = Logger(subsystem: "MVMCoreLogging", category: standardCategory) + private var loggerCache = [String: Logger]() + + open func getLogger(category: String?) -> Logger { + if let category { + if let logger = loggerCache[category] { + return logger + } else { + let logger = Logger(subsystem: Bundle.main.bundleIdentifier!, category: category) + loggerCache[category] = logger + return logger + } + } + return logger + } + @objc(sharedLoggingHandler) public static func shared() -> Self? { return MVMCoreActionUtility.initializerClassCheck(MVMCoreObject.sharedInstance()?.loggingDelegate as? NSObject, classToVerify: self) as? Self @@ -29,8 +48,15 @@ import Foundation // MARK: - logging delegate @objc open func handleDebugMessage(_ message: String?) { #if LOGGING - guard let message = message else { return } - self.print(with: message) + guard let message = message else { return } + logger.debug("\(message, privacy: .public)") // Assume that becaues this is a LOGGING build we want these messages to be unmasked. + // TODO: How do we split the messaging by Library and Subsystem? + #endif + } + + open func handleDebugMessage(_ message: String, category: String?) { + #if LOGGING + getLogger(category: category).debug("\(message, privacy: .public)") // Assume that becaues this is a LOGGING build we want these messages to be unmasked. #endif } From 9ff641060e4966560b1fa5b7ac6b1b73139f7c37 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Tue, 30 Apr 2024 20:36:00 -0400 Subject: [PATCH 03/13] Digital PCT265 story ONEAPP-7249 - Registry signature update. --- MVMCore/MVMCore/Models/Model/ModelRegistry.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift index 65e413d..dbb2afa 100644 --- a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift +++ b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift @@ -50,9 +50,9 @@ public struct ModelRegistry { /// A convenience wrapping function where error handling is managed within the class. /// - Parameter type: Takes an object of ModelProtocol.self which is used to register - public static func register(_ type: M.Type) { + public static func register(_ type: M.Type, allowsReplace: Bool = false) { do { - try throwable_register(type: type) + try throwable_register(type: type, allowsReplace: allowsReplace) } catch { handleError(error) } From a5763d45163a37a537b2fa4ffd72b0659b246f5b Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Thu, 2 May 2024 17:03:03 -0400 Subject: [PATCH 04/13] Digital PCT265 story ONEAPP-7249 - Pipe logs to stdout when the message is too long. --- .../MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift b/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift index cb0ee9c..86047d0 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift @@ -49,6 +49,11 @@ import os @objc open func handleDebugMessage(_ message: String?) { #if LOGGING guard let message = message else { return } + guard message.count < 1024 else { + logger.debug("\(message.prefix(100), privacy: .public)... ") // Send initial log to console. + print(message) // Print the whole on stdout. + return + } logger.debug("\(message, privacy: .public)") // Assume that becaues this is a LOGGING build we want these messages to be unmasked. // TODO: How do we split the messaging by Library and Subsystem? #endif @@ -56,6 +61,11 @@ import os open func handleDebugMessage(_ message: String, category: String?) { #if LOGGING + guard message.count < 1024 else { + getLogger(category: category).debug("\(message.prefix(100), privacy: .public)... ") // Send initial log to console. + print(message) // Print the whole on stdout. + return + } getLogger(category: category).debug("\(message, privacy: .public)") // Assume that becaues this is a LOGGING build we want these messages to be unmasked. #endif } From dde3e565a366214525070e95213c6e36a01d2f82 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Thu, 2 May 2024 17:17:57 -0400 Subject: [PATCH 05/13] Digital PCT265 defect CXTDT-552909 - Client crash prevention on invalid module JSON. --- MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m index f2af3c3..4f90380 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreCache.m @@ -365,6 +365,16 @@ static NSString * const STATIC_CACHE_COMPONENT = @"StaticCache.txt"; - (void)addModulesToCache:(nonnull NSDictionary *)jsonDictionary queue:(nullable NSOperationQueue *)queue waitUntilFinished:(BOOL)waitUntilFinished completionBlock:(nullable void (^)(void))completionBlock { [jsonDictionary enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop) { + if (![obj isKindOfClass:[NSDictionary class]]) { + MVMCoreErrorObject *error = [[MVMCoreErrorObject alloc] + initWithTitle:nil + messageToLog:[NSString stringWithFormat:@"Invalid module format. Cannot cache %@ as it's not an object", key] + code:ErrorCodeJSONNotDictionary + domain:ErrorDomainSystem + location:NSStringFromClass([self class])]; + [MVMCoreLoggingHandler.sharedLoggingHandler addErrorToLog:error]; + return; + } [self addModuleToCache:obj module:key]; }]; __weak typeof(self) weakSelf = self; From e8552b0aa21fbb292bb17b928ec908ec399a874b Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Mon, 6 May 2024 12:53:28 -0400 Subject: [PATCH 06/13] Digital PCT265 story ONEAPP-7249 - More logging cleanups and categorization. --- .../MVMCore/ActionHandling/ActionActionsModel.swift | 7 +++++++ .../ActionHandling/MVMCoreActionHandler.swift | 6 +++--- MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m | 12 ++++++------ .../LoadHandling/MVMCoreLoadRequestOperation.m | 10 +++++----- .../Models/ActionType/ActionModelProtocol.swift | 6 +++++- .../OtherHandlers/MVMCoreLoggingHandler.swift | 6 +++--- .../OtherHandlers/MVMCoreLoggingHandlerHelper.h | 6 +++++- 7 files changed, 34 insertions(+), 19 deletions(-) diff --git a/MVMCore/MVMCore/ActionHandling/ActionActionsModel.swift b/MVMCore/MVMCore/ActionHandling/ActionActionsModel.swift index c7e00fc..ba7fa10 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionActionsModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionActionsModel.swift @@ -65,3 +65,10 @@ public struct ActionActionsModel: ActionModelProtocol { try container.encodeIfPresent(analyticsData, forKey: .analyticsData) } } + +extension ActionActionsModel: CustomDebugStringConvertible { + + public var debugDescription: String { + return "\(Self.self) [\(actions)]" + } +} diff --git a/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift b/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift index ff2378e..8d20194 100644 --- a/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift +++ b/MVMCore/MVMCore/ActionHandling/MVMCoreActionHandler.swift @@ -85,9 +85,9 @@ public protocol MVMCoreJSONActionHandlerProtocol: MVMCoreActionHandlerProtocol { open func handleAction(with model: ActionModelProtocol, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) async throws { try Task.checkCancellation() var (additionalData, uuid) = MVMCoreActionHandler.setUUID(additionalData: additionalData) - MVMCoreActionHandler.log(string: "Begin Action: \(model.actionType)", additionalData: additionalData) + MVMCoreActionHandler.log(string: "Begin Action: \(model)", additionalData: additionalData) defer { - MVMCoreActionHandler.log(string: "End Action: \(model.actionType)", additionalData: additionalData) + MVMCoreActionHandler.log(string: "End Action: \(model)", additionalData: additionalData) } let json = try additionalData.removeValue(forKey: jsonKey) as? [AnyHashable : Any] ?? MVMCoreActionHandler.convertActionToJSON(model) @@ -148,7 +148,7 @@ public protocol MVMCoreJSONActionHandlerProtocol: MVMCoreActionHandlerProtocol { } static public func log(string: String, additionalData: [AnyHashable: Any]?) { - MVMCoreLoggingHandler.logDebugMessage(withDelegate: "ActionHandler: UUID: \(String(describing: getUUID(additionalData: additionalData))), \(string)") + MVMCoreLoggingHandler.shared()?.handleDebugMessage("ActionHandler: UUID: \(getUUID(additionalData: additionalData) ?? "untracked"), \(string)", category: String(describing: Self.self)) } fileprivate func logActionError(_ error: Error, _ actionType: String?, _ additionalData: [AnyHashable: Any]?, _ delegateObject: DelegateObject?) { diff --git a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m index 3446798..a4baf05 100644 --- a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m +++ b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadHandler.m @@ -232,7 +232,7 @@ return; } NSString *jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; - MVMCoreLog(@"Request Parameters for URL %@:\n%@", [url absoluteString], jsonString); + MVMCoreNetworkLog(@"Request Parameters for URL %@:\n%@", [url absoluteString], jsonString); #endif // Standard condensed to send to the server. @@ -309,15 +309,15 @@ return nil; } - MVMCoreLog(@"********************************* Cookie Sent *********************************"); + MVMCoreNetworkLog(@"********************************* Cookie Sent *********************************"); [[[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:request.URL] enumerateObjectsUsingBlock:^(NSHTTPCookie * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { - MVMCoreLog(@"Cookie Name: %@, Cookie Value: %@, Domain: %@", obj.name, obj.value, obj.domain); + MVMCoreNetworkLog(@"Cookie Name: %@, Cookie Value: %@, Domain: %@", obj.name, obj.value, obj.domain); }]; NSTimeInterval startTime = [NSDate timeIntervalSinceReferenceDate]; NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { - MVMCoreLog(@"Request Time %f", [NSDate timeIntervalSinceReferenceDate] - startTime); + MVMCoreNetworkLog(@"Request Time %f", [NSDate timeIntervalSinceReferenceDate] - startTime); NSDate *startTimeDate = [NSDate dateWithTimeIntervalSinceReferenceDate:startTime]; @@ -330,7 +330,7 @@ [trackInfo setObject:error.localizedDescription forKey:@"error"]; } - MVMCoreLog(@"Set-Cookie %@ Value: %@", requestParameters.pageType, [(NSHTTPURLResponse *)response allHeaderFields][@"Set-Cookie"]); + MVMCoreNetworkLog(@"Set-Cookie %@ Value: %@", requestParameters.pageType, [(NSHTTPURLResponse *)response allHeaderFields][@"Set-Cookie"]); id jsonObject = nil; MVMCoreErrorObject *errorObject = nil; @@ -354,7 +354,7 @@ // Log the response pretty. NSData *prettyData = [NSJSONSerialization dataWithJSONObject:jsonObject options:NSJSONWritingPrettyPrinted error:&error]; NSString *responseString = [[NSString alloc] initWithData:prettyData encoding:NSUTF8StringEncoding]; - MVMCoreLog(@"Response for Request Page Type %@:\n%@",requestParameters.pageType, responseString); + MVMCoreNetworkLog(@"Response for Request Page Type %@:\n%@",requestParameters.pageType, responseString); } } else { // Empty response. diff --git a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m index 699df7b..801f2d0 100644 --- a/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m +++ b/MVMCore/MVMCore/LoadHandling/MVMCoreLoadRequestOperation.m @@ -86,7 +86,7 @@ // stop any loading animation we may have started [self stopLoadingAnimationIfNeeded]; - MVMCoreLog(@"Load Operation finished for page type %@, background load %@", self.requestParameters.pageType, @(self.backgroundLoad)); + MVMCoreNetworkLog(@"Load Operation finished for page type %@, background load %@", self.requestParameters.pageType, @(self.backgroundLoad)); [super markAsFinished]; } @@ -107,7 +107,7 @@ } - (void)main { - MVMCoreLog(@"Load Operation begun for page type %@, background load %@, delegate %@", self.requestParameters.pageType, @(self.backgroundLoad),self.delegateObject.loadDelegate); + MVMCoreNetworkLog(@"Load Operation begun for page type %@, background load %@, delegate %@", self.requestParameters.pageType, @(self.backgroundLoad),self.delegateObject.loadDelegate); [self.requestParameters resolveURL:[MVMCoreSessionObject sharedGlobal]]; @@ -139,10 +139,10 @@ // Log if loaded from cache. if (pageFromCache) { - MVMCoreLog(@"loaded from cache page %@",[MVMCoreActionUtility formatDictionaryAsJSONString:pageFromCache]); + MVMCoreNetworkLog(@"loaded from cache page %@",[MVMCoreActionUtility formatDictionaryAsJSONString:pageFromCache]); } if (modulesFromCache) { - MVMCoreLog(@"loaded from cache modules %@",[MVMCoreActionUtility formatDictionaryAsJSONString:modulesFromCache]); + MVMCoreNetworkLog(@"loaded from cache modules %@",[MVMCoreActionUtility formatDictionaryAsJSONString:modulesFromCache]); } // Create a load object from any data we fetched. @@ -822,7 +822,7 @@ return; } - MVMCoreLog(@"Error: %@ %@ %@ %@ %@",[error stringErrorCode], error.domain, error.location,error.messageToDisplay, error.messageToLog); + MVMCoreNetworkLog(@"Error: %@ %@ %@ %@ %@",[error stringErrorCode], error.domain, error.location,error.messageToDisplay, error.messageToLog); if (showAlertForErrorIfApplicable && (!loadObject.operation.backgroundLoad || loadObject.requestParameters.allowAlertsIfBackgroundRequest) && !loadObject.requestParameters.handleErrorsSilently && !error.silentError && !error.errorScreenError) { diff --git a/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift b/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift index 028af05..24f5011 100644 --- a/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift +++ b/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift @@ -7,7 +7,7 @@ // -public protocol ActionModelProtocol: ModelProtocol { +public protocol ActionModelProtocol: ModelProtocol, CustomDebugStringConvertible { var actionType: String { get } var extraParameters: JSONValueDictionary? { get set } @@ -33,4 +33,8 @@ public extension ActionModelProtocol { static var categoryName: String { return "\(ActionModelProtocol.self)" } + + var debugDescription: String { + return actionType + } } diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift b/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift index 86047d0..e562854 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandler.swift @@ -50,7 +50,7 @@ import os #if LOGGING guard let message = message else { return } guard message.count < 1024 else { - logger.debug("\(message.prefix(100), privacy: .public)... ") // Send initial log to console. + logger.debug("\(message.prefix(300), privacy: .public)... ") // Send initial log to console. print(message) // Print the whole on stdout. return } @@ -59,10 +59,10 @@ import os #endif } - open func handleDebugMessage(_ message: String, category: String?) { + @objc open func handleDebugMessage(_ message: String, category: String?) { #if LOGGING guard message.count < 1024 else { - getLogger(category: category).debug("\(message.prefix(100), privacy: .public)... ") // Send initial log to console. + getLogger(category: category).debug("\(message.prefix(300), privacy: .public)... ") // Send initial log to console. print(message) // Print the whole on stdout. return } diff --git a/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandlerHelper.h b/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandlerHelper.h index bb0fe9b..1ba0edf 100644 --- a/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandlerHelper.h +++ b/MVMCore/MVMCore/OtherHandlers/MVMCoreLoggingHandlerHelper.h @@ -8,7 +8,11 @@ #ifndef MVMCoreLoggingHandlerHelper_h #define MVMCoreLoggingHandlerHelper_h + #define MVMCoreLog(fmt, ...) \ [MVMCoreLoggingHandler logDebugMessageWithDelegate:[NSString stringWithFormat:(@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__]]; -#endif +#define MVMCoreNetworkLog(fmt, ...) \ +[MVMCoreLoggingHandler.sharedLoggingHandler handleDebugMessage:[NSString stringWithFormat:(@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__] category: @"Network"]; + +#endif From 62a579931283351de60581f60849c065905617b4 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Tue, 7 May 2024 23:27:31 -0400 Subject: [PATCH 07/13] Digital PCT265 story ONEAPP-7249 - Prevent UI updates when there are no model changes. --- .../ActionHandling/ActionActionsModel.swift | 8 ++++ .../ActionHandling/ActionOpenPageModel.swift | 17 +++++++ .../ActionType/ActionModelProtocol.swift | 7 +++ .../ClientParameterModel.swift | 8 +++- .../ClientParameterModelProtocol.swift | 5 ++ .../MVMCore/Models/Model/ModelProtocol.swift | 46 +++++++++++++++++++ 6 files changed, 90 insertions(+), 1 deletion(-) diff --git a/MVMCore/MVMCore/ActionHandling/ActionActionsModel.swift b/MVMCore/MVMCore/ActionHandling/ActionActionsModel.swift index ba7fa10..b36ae29 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionActionsModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionActionsModel.swift @@ -64,6 +64,14 @@ public struct ActionActionsModel: ActionModelProtocol { try container.encodeIfPresent(extraParameters, forKey: .extraParameters) try container.encodeIfPresent(analyticsData, forKey: .analyticsData) } + + public func isEqual(to model: any ModelProtocol) -> Bool { + guard let model = model as? Self else { return false } + return actions.areEqual(to: model.actions) + && concurrent == model.concurrent + && extraParameters == model.extraParameters + && analyticsData == model.analyticsData + } } extension ActionActionsModel: CustomDebugStringConvertible { diff --git a/MVMCore/MVMCore/ActionHandling/ActionOpenPageModel.swift b/MVMCore/MVMCore/ActionHandling/ActionOpenPageModel.swift index ac7ee02..2da0e0c 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionOpenPageModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionOpenPageModel.swift @@ -115,6 +115,23 @@ public struct ActionOpenPageModel: ActionModelProtocol, ActionOpenPageProtocol, try container.encodeIfPresent(analyticsData, forKey: .analyticsData) try container.encodeIfPresent(fallbackResponse, forKey: .fallbackResponse) } + + public func isEqual(to model: any ModelProtocol) -> Bool { + guard let model = model as? Self else { return false } + return pageType == model.pageType + && baseURL == model.baseURL + && appContext == model.appContext + && requestURL == model.requestURL + && modules == model.modules + && presentationStyle == model.presentationStyle + && tabBarIndex == model.tabBarIndex + && background == model.background + && clientParameters == model.clientParameters + && customTimeoutTime == model.customTimeoutTime + && extraParameters == model.extraParameters + && analyticsData == model.analyticsData + && fallbackResponse == model.fallbackResponse + } } extension ActionOpenPageModel: CustomDebugStringConvertible { diff --git a/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift b/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift index 24f5011..d6cb1c7 100644 --- a/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift +++ b/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift @@ -37,4 +37,11 @@ public extension ActionModelProtocol { var debugDescription: String { return actionType } + + func isEqual(to model: any ModelProtocol) -> Bool { + guard let model = model as? Self else { return false } + return model.actionType == actionType + && model.extraParameters == extraParameters + && model.analyticsData == analyticsData + } } diff --git a/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterModel.swift b/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterModel.swift index 9e63c27..3fae967 100644 --- a/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterModel.swift +++ b/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterModel.swift @@ -8,7 +8,8 @@ import Foundation -public class ClientParameterModel: Codable { +public class ClientParameterModel: Equatable, Codable { + var timeout: Double? var list: [ClientParameterModelProtocol] @@ -33,4 +34,9 @@ public class ClientParameterModel: Codable { try container.encodeIfPresent(timeout, forKey: .timeout) try container.encodeModels(list, forKey: .list) } + + public static func == (lhs: ClientParameterModel, rhs: ClientParameterModel) -> Bool { + return lhs.list.areEqual(to: rhs.list) + && lhs.timeout == rhs.timeout + } } diff --git a/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterModelProtocol.swift b/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterModelProtocol.swift index bbde12c..8ba8950 100644 --- a/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterModelProtocol.swift +++ b/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterModelProtocol.swift @@ -30,4 +30,9 @@ public extension ClientParameterModelProtocol { static var categoryName: String { return "\(ClientParameterModelProtocol.self)" } + + func isEqual(to model: any ModelProtocol) -> Bool { + guard let model = model as? Self else { return false } + return type == model.type + } } diff --git a/MVMCore/MVMCore/Models/Model/ModelProtocol.swift b/MVMCore/MVMCore/Models/Model/ModelProtocol.swift index 960f593..302b91d 100644 --- a/MVMCore/MVMCore/Models/Model/ModelProtocol.swift +++ b/MVMCore/MVMCore/Models/Model/ModelProtocol.swift @@ -30,6 +30,9 @@ public protocol ModelProtocol: Codable { /// Convenience function to encode model using an unkeyed container. func encode(unkeyedContainer: inout UnkeyedEncodingContainer) throws + + /// Deep checks if the curent model is equal to another model. Defaults to false unless implemented otherwise. + func isEqual(to model: ModelProtocol) -> Bool } extension ModelProtocol { @@ -49,4 +52,47 @@ extension ModelProtocol { public func encode(unkeyedContainer: inout UnkeyedEncodingContainer) throws { try unkeyedContainer.encode(self) } + + public func isEqual(to model: ModelProtocol) -> Bool { + return false + } +} + +public extension Optional { + + /// Checks if the curent model is equal to another model. + func isEqual(to model: ModelProtocol?) -> Bool { + guard let self = self as? ModelProtocol else { + return model == nil + } + guard let model = model else { + return false + } + return self.isEqual(to: model) + } +} + + +public extension Array /*where Element == ModelProtocol*/ { + /// Checks if all the models in the given array match another given array of models. + func areEqual(to models: [ModelProtocol]) -> Bool { + guard count == models.count, let self = self as? [ModelProtocol] else { return false } + return models.indices.allSatisfy { index in + self[index].isEqual(to: models[index]) + } + } +} + +public extension Optional where Wrapped: Collection { + + func areEqual(to models: [ModelProtocol]?) -> Bool { + guard let self = self as? [ModelProtocol] else { + return models == nil + } + guard let models = models else { + return false + } + return self.areEqual(to: models) + } + } From 20d4d323e096e8bbed2a6858fbc433c8a9d58971 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Wed, 8 May 2024 20:34:21 -0400 Subject: [PATCH 08/13] Digital PCT265 story ONEAPP-7249 - isVisuallyEquivalent build out to work with stabilizing carousel refreshes. --- .../ActionHandling/ActionActionsModel.swift | 4 +- .../ActionHandling/ActionOpenPageModel.swift | 2 +- .../ClientParameterModel.swift | 2 +- .../MVMCore/Models/Model/ModelProtocol.swift | 39 ++++++++++--------- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/MVMCore/MVMCore/ActionHandling/ActionActionsModel.swift b/MVMCore/MVMCore/ActionHandling/ActionActionsModel.swift index b36ae29..b2c8233 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionActionsModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionActionsModel.swift @@ -65,9 +65,9 @@ public struct ActionActionsModel: ActionModelProtocol { try container.encodeIfPresent(analyticsData, forKey: .analyticsData) } - public func isEqual(to model: any ModelProtocol) -> Bool { + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { guard let model = model as? Self else { return false } - return actions.areEqual(to: model.actions) + return actions.isEqual(to: model.actions) && concurrent == model.concurrent && extraParameters == model.extraParameters && analyticsData == model.analyticsData diff --git a/MVMCore/MVMCore/ActionHandling/ActionOpenPageModel.swift b/MVMCore/MVMCore/ActionHandling/ActionOpenPageModel.swift index 2da0e0c..e899d8c 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionOpenPageModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionOpenPageModel.swift @@ -116,7 +116,7 @@ public struct ActionOpenPageModel: ActionModelProtocol, ActionOpenPageProtocol, try container.encodeIfPresent(fallbackResponse, forKey: .fallbackResponse) } - public func isEqual(to model: any ModelProtocol) -> Bool { + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { guard let model = model as? Self else { return false } return pageType == model.pageType && baseURL == model.baseURL diff --git a/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterModel.swift b/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterModel.swift index 3fae967..ec8cf40 100644 --- a/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterModel.swift +++ b/MVMCore/MVMCore/Models/ActionType/Client Parameters/ClientParameterModel.swift @@ -36,7 +36,7 @@ public class ClientParameterModel: Equatable, Codable { } public static func == (lhs: ClientParameterModel, rhs: ClientParameterModel) -> Bool { - return lhs.list.areEqual(to: rhs.list) + return lhs.list.isEqual(to: rhs.list) && lhs.timeout == rhs.timeout } } diff --git a/MVMCore/MVMCore/Models/Model/ModelProtocol.swift b/MVMCore/MVMCore/Models/Model/ModelProtocol.swift index 302b91d..cdabef2 100644 --- a/MVMCore/MVMCore/Models/Model/ModelProtocol.swift +++ b/MVMCore/MVMCore/Models/Model/ModelProtocol.swift @@ -8,7 +8,7 @@ import Foundation -public protocol ModelProtocol: Codable { +public protocol ModelProtocol: ModelComparisonProtocol, Codable { /// The key name of the molecule static var identifier: String { get } @@ -30,9 +30,6 @@ public protocol ModelProtocol: Codable { /// Convenience function to encode model using an unkeyed container. func encode(unkeyedContainer: inout UnkeyedEncodingContainer) throws - - /// Deep checks if the curent model is equal to another model. Defaults to false unless implemented otherwise. - func isEqual(to model: ModelProtocol) -> Bool } extension ModelProtocol { @@ -52,17 +49,23 @@ extension ModelProtocol { public func encode(unkeyedContainer: inout UnkeyedEncodingContainer) throws { try unkeyedContainer.encode(self) } - - public func isEqual(to model: ModelProtocol) -> Bool { +} + +public protocol ModelComparisonProtocol { + /// Deep checks if the curent model is equal to another model. Defaults to false unless implemented otherwise. + func isEqual(to model: ModelComparisonProtocol) -> Bool +} + +extension ModelComparisonProtocol { + public func isEqual(to model: ModelComparisonProtocol) -> Bool { return false } } public extension Optional { - /// Checks if the curent model is equal to another model. - func isEqual(to model: ModelProtocol?) -> Bool { - guard let self = self as? ModelProtocol else { + func isEqual(to model: ModelComparisonProtocol?) -> Bool { + guard let self = self as? ModelComparisonProtocol else { return model == nil } guard let model = model else { @@ -72,11 +75,10 @@ public extension Optional { } } - -public extension Array /*where Element == ModelProtocol*/ { - /// Checks if all the models in the given array match another given array of models. - func areEqual(to models: [ModelProtocol]) -> Bool { - guard count == models.count, let self = self as? [ModelProtocol] else { return false } +public extension Collection { + /// Checks if all the models in the given collection match another given collection. + func isEqual(to models: [ModelComparisonProtocol]) -> Bool { + guard count == models.count, let self = self as? [ModelComparisonProtocol] else { return false } return models.indices.allSatisfy { index in self[index].isEqual(to: models[index]) } @@ -84,15 +86,14 @@ public extension Array /*where Element == ModelProtocol*/ { } public extension Optional where Wrapped: Collection { - - func areEqual(to models: [ModelProtocol]?) -> Bool { - guard let self = self as? [ModelProtocol] else { + /// Checks if the curent model is equal to another model. + func isEqual(to models: [ModelComparisonProtocol]?) -> Bool { + guard let self = self as? [ModelComparisonProtocol] else { return models == nil } guard let models = models else { return false } - return self.areEqual(to: models) + return self.isEqual(to: models) } - } From 009bb01e1b33c766cfe8eb5af2a3274aa3f2180d Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Mon, 13 May 2024 21:22:57 -0400 Subject: [PATCH 09/13] Digital PCT265 story PCT-135: Code review comments, cleanups and isEquals expansion. --- .../ActionHandling/ActionBackModel.swift | 8 ++++++++ .../ActionHandling/ActionCallModel.swift | 7 +++++++ .../ActionHandling/ActionCancelModel.swift | 8 ++++++++ .../ActionHandling/ActionContactModel.swift | 10 ++++++++++ .../ActionHandling/ActionNoopModel.swift | 9 +++++++++ .../ActionHandling/ActionOpenSMSModel.swift | 9 +++++++++ .../ActionHandling/ActionOpenUrlModel.swift | 9 +++++++++ .../ActionPreviousSubmitModel.swift | 8 ++++++++ .../ActionHandling/ActionRestartModel.swift | 7 +++++++ .../ActionHandling/ActionSettingModel.swift | 6 ++++++ .../ActionHandling/ActionShareModel.swift | 20 +++++++++++++++---- .../ActionHandling/OpenURLOptionsModel.swift | 15 +++++++++++++- .../ActionType/ActionModelProtocol.swift | 2 +- .../ActionType/ActionRunJavaScriptModel.swift | 7 +++++++ 14 files changed, 119 insertions(+), 6 deletions(-) diff --git a/MVMCore/MVMCore/ActionHandling/ActionBackModel.swift b/MVMCore/MVMCore/ActionHandling/ActionBackModel.swift index fea8eea..2ec606c 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionBackModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionBackModel.swift @@ -25,4 +25,12 @@ public struct ActionBackModel: ActionModelProtocol { self.extraParameters = extraParameters self.analyticsData = analyticsData } + + // Default + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return model.actionType == actionType + && model.extraParameters == extraParameters + && model.analyticsData == analyticsData + } } diff --git a/MVMCore/MVMCore/ActionHandling/ActionCallModel.swift b/MVMCore/MVMCore/ActionHandling/ActionCallModel.swift index dc6a32e..78c02f1 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionCallModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionCallModel.swift @@ -28,4 +28,11 @@ public struct ActionCallModel: ActionModelProtocol { self.extraParameters = extraParameters self.analyticsData = analyticsData } + + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return extraParameters == model.extraParameters + && analyticsData == model.analyticsData + && callNumber == model.callNumber + } } diff --git a/MVMCore/MVMCore/ActionHandling/ActionCancelModel.swift b/MVMCore/MVMCore/ActionHandling/ActionCancelModel.swift index 83ae013..b1a7c37 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionCancelModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionCancelModel.swift @@ -25,4 +25,12 @@ public struct ActionCancelModel: ActionModelProtocol { self.extraParameters = extraParameters self.analyticsData = analyticsData } + + // Default + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return model.actionType == actionType + && model.extraParameters == extraParameters + && model.analyticsData == analyticsData + } } diff --git a/MVMCore/MVMCore/ActionHandling/ActionContactModel.swift b/MVMCore/MVMCore/ActionHandling/ActionContactModel.swift index 9b975fc..12e918b 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionContactModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionContactModel.swift @@ -42,4 +42,14 @@ public struct ActionContactModel: ActionModelProtocol { self.extraParameters = extraParameters self.analyticsData = analyticsData } + + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return extraParameters == model.extraParameters + && analyticsData == model.analyticsData + && phoneNumber == model.phoneNumber + && firstName == model.firstName + && lastName == model.lastName + && approach == model.approach + } } diff --git a/MVMCore/MVMCore/ActionHandling/ActionNoopModel.swift b/MVMCore/MVMCore/ActionHandling/ActionNoopModel.swift index 941e80a..c0c075d 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionNoopModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionNoopModel.swift @@ -7,6 +7,7 @@ // public struct ActionNoopModel: ActionModelProtocol { + //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -24,4 +25,12 @@ public struct ActionNoopModel: ActionModelProtocol { self.extraParameters = extraParameters self.analyticsData = analyticsData } + + // Default + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return model.actionType == actionType + && model.extraParameters == extraParameters + && model.analyticsData == analyticsData + } } diff --git a/MVMCore/MVMCore/ActionHandling/ActionOpenSMSModel.swift b/MVMCore/MVMCore/ActionHandling/ActionOpenSMSModel.swift index 88f709d..372c942 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionOpenSMSModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionOpenSMSModel.swift @@ -30,4 +30,13 @@ public struct ActionOpenSMSModel: ActionModelProtocol { self.extraParameters = extraParameters self.analyticsData = analyticsData } + + // Default + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return model.extraParameters == extraParameters + && model.analyticsData == analyticsData + && model.phoneNumber == phoneNumber + && model.message == message + } } diff --git a/MVMCore/MVMCore/ActionHandling/ActionOpenUrlModel.swift b/MVMCore/MVMCore/ActionHandling/ActionOpenUrlModel.swift index c9f6f8a..57daae8 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionOpenUrlModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionOpenUrlModel.swift @@ -60,4 +60,13 @@ open class ActionOpenUrlModel: ActionModelProtocol { try container.encodeIfPresent(extraParameters, forKey: .extraParameters) try container.encodeIfPresent(analyticsData, forKey: .analyticsData) } + + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return extraParameters == model.extraParameters + && analyticsData == model.analyticsData + && browserUrl == model.browserUrl + && appURL == model.appURL + && appURLOptions == model.appURLOptions + } } diff --git a/MVMCore/MVMCore/ActionHandling/ActionPreviousSubmitModel.swift b/MVMCore/MVMCore/ActionHandling/ActionPreviousSubmitModel.swift index 31290dc..489aaf7 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionPreviousSubmitModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionPreviousSubmitModel.swift @@ -25,4 +25,12 @@ public struct ActionPreviousSubmitModel: ActionModelProtocol { self.extraParameters = extraParameters self.analyticsData = analyticsData } + + // Default + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return model.actionType == actionType + && model.extraParameters == extraParameters + && model.analyticsData == analyticsData + } } diff --git a/MVMCore/MVMCore/ActionHandling/ActionRestartModel.swift b/MVMCore/MVMCore/ActionHandling/ActionRestartModel.swift index e64a6d3..635c541 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionRestartModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionRestartModel.swift @@ -32,4 +32,11 @@ public struct ActionRestartModel: ActionModelProtocol { self.extraParameters = extraParameters self.analyticsData = analyticsData } + + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return extraParameters == model.extraParameters + && analyticsData == model.analyticsData + && requestURL == model.requestURL + } } diff --git a/MVMCore/MVMCore/ActionHandling/ActionSettingModel.swift b/MVMCore/MVMCore/ActionHandling/ActionSettingModel.swift index b2fd687..0a87349 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionSettingModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionSettingModel.swift @@ -25,4 +25,10 @@ public struct ActionSettingModel: ActionModelProtocol { self.extraParameters = extraParameters self.analyticsData = analyticsData } + + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return extraParameters == model.extraParameters + && analyticsData == model.analyticsData + } } diff --git a/MVMCore/MVMCore/ActionHandling/ActionShareModel.swift b/MVMCore/MVMCore/ActionHandling/ActionShareModel.swift index ddeb7d8..813dd92 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionShareModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionShareModel.swift @@ -6,7 +6,7 @@ // Copyright © 2020 myverizon. All rights reserved. // -public struct ActionShareItemModel: Codable { +public struct ActionShareItemModel: Codable, Equatable { public enum SharedType: String, Codable { case text @@ -14,14 +14,14 @@ public struct ActionShareItemModel: Codable { } public var type: SharedType - public var value: Any + public var value: AnyHashable // Common Equatable type between String and URL. private enum CodingKeys: String, CodingKey { case type case value } - public init(type: SharedType, value: Any) { + public init(type: SharedType, value: AnyHashable) { self.type = type self.value = value } @@ -47,6 +47,11 @@ public struct ActionShareItemModel: Codable { try container.encode(value as! URL, forKey: .value) } } + + public static func == (lhs: ActionShareItemModel, rhs: ActionShareItemModel) -> Bool { + return lhs.type == rhs.type + && lhs.value == rhs.value + } } public struct ActionShareModel: ActionModelProtocol { @@ -101,7 +106,7 @@ public struct ActionShareModel: ActionModelProtocol { private init(deprecatedFrom decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: DeprecatedCodingKeys.self) let type = try typeContainer.decode(ActionShareItemModel.SharedType.self, forKey: .sharedType) - var value: Any + var value: AnyHashable switch type { case .url: value = try typeContainer.decode(URL.self, forKey: .sharedText) @@ -116,4 +121,11 @@ public struct ActionShareModel: ActionModelProtocol { try container.encode(actionType, forKey: .actionType) try container.encode(items, forKey: .items) } + + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return extraParameters == model.extraParameters + && analyticsData == model.analyticsData + && items == model.items + } } diff --git a/MVMCore/MVMCore/ActionHandling/OpenURLOptionsModel.swift b/MVMCore/MVMCore/ActionHandling/OpenURLOptionsModel.swift index 09911c8..ec4e08a 100644 --- a/MVMCore/MVMCore/ActionHandling/OpenURLOptionsModel.swift +++ b/MVMCore/MVMCore/ActionHandling/OpenURLOptionsModel.swift @@ -9,7 +9,8 @@ import Foundation /// A model for UIApplication.OpenExternalURLOptionsKey -open class OpenUrlOptionsModel: Codable { +open class OpenUrlOptionsModel: Codable, Equatable { + public var options: [UIApplication.OpenExternalURLOptionsKey: Any] //-------------------------------------------------- @@ -42,4 +43,16 @@ open class OpenUrlOptionsModel: Codable { try container.encode(universalLinksValue, forKey: .universalLinksOnly) } } + + public static func == (lhs: OpenUrlOptionsModel, rhs: OpenUrlOptionsModel) -> Bool { + return lhs.options.allSatisfy { pair in + switch(pair.key) { + case .universalLinksOnly: + return rhs.options[pair.key] as? Bool == pair.value as? Bool + default: + return true + } + } + } + } diff --git a/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift b/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift index d6cb1c7..3ff3173 100644 --- a/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift +++ b/MVMCore/MVMCore/Models/ActionType/ActionModelProtocol.swift @@ -38,7 +38,7 @@ public extension ActionModelProtocol { return actionType } - func isEqual(to model: any ModelProtocol) -> Bool { + func isEqual(to model: any ModelComparisonProtocol) -> Bool { guard let model = model as? Self else { return false } return model.actionType == actionType && model.extraParameters == extraParameters diff --git a/MVMCore/MVMCore/Models/ActionType/ActionRunJavaScriptModel.swift b/MVMCore/MVMCore/Models/ActionType/ActionRunJavaScriptModel.swift index d457793..f14ffa2 100644 --- a/MVMCore/MVMCore/Models/ActionType/ActionRunJavaScriptModel.swift +++ b/MVMCore/MVMCore/Models/ActionType/ActionRunJavaScriptModel.swift @@ -29,4 +29,11 @@ public class ActionRunJavaScriptModel: ActionModelProtocol { self.extraParameters = extraParameters self.analyticsData = analyticsData } + + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return jsCallback == model.jsCallback + && extraParameters == model.extraParameters + && analyticsData == model.analyticsData + } } From 71689b957b3f35d210d902c926b59c60bfac6b0e Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Fri, 17 May 2024 21:24:18 -0400 Subject: [PATCH 10/13] Digital PCT265 story PCT-135: Switch to shallow equals with deep compare on parent in order to pinpoint midmatched models. Unit testing setup. --- MVMCore/MVMCore/Models/Model/ModelProtocol.swift | 14 +++++++++++++- MVMCore/MVMCore/Models/Model/ModelRegistry.swift | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/MVMCore/MVMCore/Models/Model/ModelProtocol.swift b/MVMCore/MVMCore/Models/Model/ModelProtocol.swift index cdabef2..ed9f5cf 100644 --- a/MVMCore/MVMCore/Models/Model/ModelProtocol.swift +++ b/MVMCore/MVMCore/Models/Model/ModelProtocol.swift @@ -52,7 +52,7 @@ extension ModelProtocol { } public protocol ModelComparisonProtocol { - /// Deep checks if the curent model is equal to another model. Defaults to false unless implemented otherwise. + /// Shallow checks if the curent model is equal to another model. Defaults to false unless implemented otherwise. func isEqual(to model: ModelComparisonProtocol) -> Bool } @@ -97,3 +97,15 @@ public extension Optional where Wrapped: Collection { return self.isEqual(to: models) } } + +public extension Optional { + /// Checks if + func matchExistence(with anotherOptional: Optional) -> Bool { + switch(self) { + case .none: + return anotherOptional == nil + case .some(_): + return anotherOptional != nil + } + } +} diff --git a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift index dbb2afa..bd9f721 100644 --- a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift +++ b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift @@ -105,7 +105,7 @@ public struct ModelRegistry { MVMCoreLoggingHandler.shared()?.addError(toLog: errorObject) #if DEBUG - triggerCrashInDebug() + //triggerCrashInDebug() #endif } From 220b8530dafdd934a49f7e2e46b01275f04672c1 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Tue, 28 May 2024 16:23:59 -0400 Subject: [PATCH 11/13] Digital PCT265 story PCT-135: 'curent' comment typo. --- MVMCore/MVMCore/Models/Model/ModelProtocol.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MVMCore/MVMCore/Models/Model/ModelProtocol.swift b/MVMCore/MVMCore/Models/Model/ModelProtocol.swift index ed9f5cf..8c85a64 100644 --- a/MVMCore/MVMCore/Models/Model/ModelProtocol.swift +++ b/MVMCore/MVMCore/Models/Model/ModelProtocol.swift @@ -52,7 +52,7 @@ extension ModelProtocol { } public protocol ModelComparisonProtocol { - /// Shallow checks if the curent model is equal to another model. Defaults to false unless implemented otherwise. + /// Shallow checks if the current model is equal to another model. Defaults to false unless implemented otherwise. func isEqual(to model: ModelComparisonProtocol) -> Bool } @@ -63,7 +63,7 @@ extension ModelComparisonProtocol { } public extension Optional { - /// Checks if the curent model is equal to another model. + /// Checks if the current model is equal to another model. func isEqual(to model: ModelComparisonProtocol?) -> Bool { guard let self = self as? ModelComparisonProtocol else { return model == nil @@ -86,7 +86,7 @@ public extension Collection { } public extension Optional where Wrapped: Collection { - /// Checks if the curent model is equal to another model. + /// Checks if the current model is equal to another model. func isEqual(to models: [ModelComparisonProtocol]?) -> Bool { guard let self = self as? [ModelComparisonProtocol] else { return models == nil From 134ce14e5aae08c1d1282ffd1b19383cfdb7f5b2 Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Tue, 28 May 2024 16:25:32 -0400 Subject: [PATCH 12/13] Digital PCT265 story PCT-135: Code review. Missing pageType check in ActionRestartModel. --- MVMCore/MVMCore/ActionHandling/ActionRestartModel.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/MVMCore/MVMCore/ActionHandling/ActionRestartModel.swift b/MVMCore/MVMCore/ActionHandling/ActionRestartModel.swift index 635c541..4cde79c 100644 --- a/MVMCore/MVMCore/ActionHandling/ActionRestartModel.swift +++ b/MVMCore/MVMCore/ActionHandling/ActionRestartModel.swift @@ -38,5 +38,6 @@ public struct ActionRestartModel: ActionModelProtocol { return extraParameters == model.extraParameters && analyticsData == model.analyticsData && requestURL == model.requestURL + && pageType == model.pageType } } From 0104570bc9fd7edb6f48255b0e9401e9400d32bd Mon Sep 17 00:00:00 2001 From: "Hedden, Kyle Matthew" Date: Tue, 28 May 2024 17:43:41 -0400 Subject: [PATCH 13/13] Digital PCT265 story PCT-135: Code reivew. Restore debug crash. --- MVMCore/MVMCore/Models/Model/ModelRegistry.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift index bd9f721..dbb2afa 100644 --- a/MVMCore/MVMCore/Models/Model/ModelRegistry.swift +++ b/MVMCore/MVMCore/Models/Model/ModelRegistry.swift @@ -105,7 +105,7 @@ public struct ModelRegistry { MVMCoreLoggingHandler.shared()?.addError(toLog: errorObject) #if DEBUG - //triggerCrashInDebug() + triggerCrashInDebug() #endif }