-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
# Conflicts: # Ometria.xcodeproj/project.xcworkspace/xcuserdata/cata.xcuserdatad/UserInterfaceState.xcuserstate
- Loading branch information
Showing
21 changed files
with
890 additions
and
136 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
78 changes: 78 additions & 0 deletions
78
Ometria Sample/OmetriaSample.xcodeproj/xcshareddata/xcschemes/OmetriaSample.xcscheme
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<Scheme | ||
LastUpgradeVersion = "1410" | ||
version = "1.3"> | ||
<BuildAction | ||
parallelizeBuildables = "YES" | ||
buildImplicitDependencies = "YES"> | ||
<BuildActionEntries> | ||
<BuildActionEntry | ||
buildForTesting = "YES" | ||
buildForRunning = "YES" | ||
buildForProfiling = "YES" | ||
buildForArchiving = "YES" | ||
buildForAnalyzing = "YES"> | ||
<BuildableReference | ||
BuildableIdentifier = "primary" | ||
BlueprintIdentifier = "4EC94EE724BC52D000B8591C" | ||
BuildableName = "OmetriaSample.app" | ||
BlueprintName = "OmetriaSample" | ||
ReferencedContainer = "container:OmetriaSample.xcodeproj"> | ||
</BuildableReference> | ||
</BuildActionEntry> | ||
</BuildActionEntries> | ||
</BuildAction> | ||
<TestAction | ||
buildConfiguration = "Debug" | ||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | ||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | ||
shouldUseLaunchSchemeArgsEnv = "YES"> | ||
<Testables> | ||
</Testables> | ||
</TestAction> | ||
<LaunchAction | ||
buildConfiguration = "Debug" | ||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | ||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | ||
launchStyle = "0" | ||
useCustomWorkingDirectory = "NO" | ||
ignoresPersistentStateOnLaunch = "NO" | ||
debugDocumentVersioning = "YES" | ||
debugServiceExtension = "internal" | ||
allowLocationSimulation = "YES"> | ||
<BuildableProductRunnable | ||
runnableDebuggingMode = "0"> | ||
<BuildableReference | ||
BuildableIdentifier = "primary" | ||
BlueprintIdentifier = "4EC94EE724BC52D000B8591C" | ||
BuildableName = "OmetriaSample.app" | ||
BlueprintName = "OmetriaSample" | ||
ReferencedContainer = "container:OmetriaSample.xcodeproj"> | ||
</BuildableReference> | ||
</BuildableProductRunnable> | ||
</LaunchAction> | ||
<ProfileAction | ||
buildConfiguration = "Release" | ||
shouldUseLaunchSchemeArgsEnv = "YES" | ||
savedToolIdentifier = "" | ||
useCustomWorkingDirectory = "NO" | ||
debugDocumentVersioning = "YES"> | ||
<BuildableProductRunnable | ||
runnableDebuggingMode = "0"> | ||
<BuildableReference | ||
BuildableIdentifier = "primary" | ||
BlueprintIdentifier = "4EC94EE724BC52D000B8591C" | ||
BuildableName = "OmetriaSample.app" | ||
BlueprintName = "OmetriaSample" | ||
ReferencedContainer = "container:OmetriaSample.xcodeproj"> | ||
</BuildableReference> | ||
</BuildableProductRunnable> | ||
</ProfileAction> | ||
<AnalyzeAction | ||
buildConfiguration = "Debug"> | ||
</AnalyzeAction> | ||
<ArchiveAction | ||
buildConfiguration = "Release" | ||
revealArchiveInOrganizer = "YES"> | ||
</ArchiveAction> | ||
</Scheme> |
53 changes: 53 additions & 0 deletions
53
Ometria Sample/OmetriaSample.xcodeproj/xcshareddata/xcschemes/OmetriaSampleTests.xcscheme
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<Scheme | ||
LastUpgradeVersion = "1410" | ||
version = "1.3"> | ||
<BuildAction | ||
parallelizeBuildables = "YES" | ||
buildImplicitDependencies = "YES"> | ||
</BuildAction> | ||
<TestAction | ||
buildConfiguration = "Debug" | ||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | ||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | ||
shouldUseLaunchSchemeArgsEnv = "YES"> | ||
<Testables> | ||
<TestableReference | ||
skipped = "NO" | ||
parallelizable = "YES"> | ||
<BuildableReference | ||
BuildableIdentifier = "primary" | ||
BlueprintIdentifier = "4E46F65629EE9E5E009E384E" | ||
BuildableName = "OmetriaSampleTests.xctest" | ||
BlueprintName = "OmetriaSampleTests" | ||
ReferencedContainer = "container:OmetriaSample.xcodeproj"> | ||
</BuildableReference> | ||
</TestableReference> | ||
</Testables> | ||
</TestAction> | ||
<LaunchAction | ||
buildConfiguration = "Debug" | ||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" | ||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" | ||
launchStyle = "0" | ||
useCustomWorkingDirectory = "NO" | ||
ignoresPersistentStateOnLaunch = "NO" | ||
debugDocumentVersioning = "YES" | ||
debugServiceExtension = "internal" | ||
allowLocationSimulation = "YES"> | ||
</LaunchAction> | ||
<ProfileAction | ||
buildConfiguration = "Release" | ||
shouldUseLaunchSchemeArgsEnv = "YES" | ||
savedToolIdentifier = "" | ||
useCustomWorkingDirectory = "NO" | ||
debugDocumentVersioning = "YES"> | ||
</ProfileAction> | ||
<AnalyzeAction | ||
buildConfiguration = "Debug"> | ||
</AnalyzeAction> | ||
<ArchiveAction | ||
buildConfiguration = "Release" | ||
revealArchiveInOrganizer = "YES"> | ||
</ArchiveAction> | ||
</Scheme> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// | ||
// EventCache+Mock.swift | ||
// OmetriaSampleTests | ||
// | ||
// Created by Catalin Demian on 18.04.2023. | ||
// Copyright © 2023 Ometria. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
@testable import Ometria | ||
@testable import OmetriaSample | ||
|
||
class MockInMemoryEventCache: EventCaching { | ||
var events: [OmetriaEvent]? | ||
let saveHandler: () -> Void | ||
|
||
init(saveHandler: @escaping () -> Void) { | ||
self.saveHandler = saveHandler | ||
} | ||
|
||
func saveToFile(_ events: [OmetriaEvent]?, async: Bool) { | ||
self.events = events | ||
DispatchQueue.main.async { [weak self] in | ||
self?.saveHandler() | ||
} | ||
} | ||
|
||
func loadFromFile() -> [OmetriaEvent]? { | ||
return events | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
// | ||
// EventService+Mock.swift | ||
// OmetriaSampleTests | ||
// | ||
// Created by Catalin Demian on 18.04.2023. | ||
// Copyright © 2023 Ometria. All rights reserved. | ||
// | ||
|
||
import Foundation | ||
@testable import Ometria | ||
@testable import OmetriaSample | ||
|
||
extension OmetriaEvent: Hashable { | ||
public static func == (lhs: OmetriaEvent, rhs: OmetriaEvent) -> Bool { | ||
return lhs.eventId == rhs.eventId | ||
} | ||
|
||
public func hash(into hasher: inout Hasher) { | ||
hasher.combine(eventId) | ||
} | ||
} | ||
|
||
struct MockSuccessEventService: EventServiceProtocol { | ||
func validateEvents(_ events: [OmetriaEvent], completion: @escaping (Result<Any>) -> ()) { | ||
completion(.success("")) | ||
} | ||
|
||
func flushEvents(_ events: [OmetriaEvent], completion: @escaping (Result<Any>) -> ()) { | ||
completion(.success("")) | ||
} | ||
} | ||
|
||
class MockSuccessAndCountEventService: EventServiceProtocol { | ||
var uniqueFlushedEvents: Set<OmetriaEvent> = [] | ||
|
||
func validateEvents(_ events: [OmetriaEvent], completion: @escaping (Result<Any>) -> ()) { | ||
completion(.success("")) | ||
} | ||
|
||
func flushEvents(_ events: [OmetriaEvent], completion: @escaping (Result<Any>) -> ()) { | ||
Task { | ||
try await Task.sleep(nanoseconds: 1_000_000_000) | ||
await MainActor.run { | ||
uniqueFlushedEvents.formUnion(events) | ||
} | ||
completion(.success("")) | ||
} | ||
} | ||
} | ||
|
||
enum MockEventError: Error { | ||
case failed | ||
} | ||
|
||
struct MockFailureEventService: EventServiceProtocol { | ||
func validateEvents(_ events: [OmetriaEvent], completion: @escaping (Result<Any>) -> ()) { | ||
completion(.failure(MockEventError.failed)) | ||
} | ||
|
||
func flushEvents(_ events: [OmetriaEvent], completion: @escaping (Result<Any>) -> ()) { | ||
completion(.failure(MockEventError.failed)) | ||
} | ||
} | ||
|
158 changes: 158 additions & 0 deletions
158
Ometria Sample/OmetriaSampleTests/OmetriaSampleTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
// | ||
// OmetriaSampleTests.swift | ||
// OmetriaSampleTests | ||
// | ||
// Created by Catalin Demian on 18.04.2023. | ||
// Copyright © 2023 Ometria. All rights reserved. | ||
// | ||
|
||
import XCTest | ||
@testable import Ometria | ||
|
||
final class OmetriaSampleTests: XCTestCase { | ||
|
||
override func setUpWithError() throws { | ||
// Put setup code here. This method is called before the invocation of each test method in the class. | ||
} | ||
|
||
override func tearDownWithError() throws { | ||
// Put teardown code here. This method is called after the invocation of each test method in the class. | ||
} | ||
|
||
func test_ometria_cacheEventSuccess() throws { | ||
//given | ||
let expectation = XCTestExpectation() | ||
expectation.expectedFulfillmentCount = 3 | ||
let cache = MockInMemoryEventCache { | ||
expectation.fulfill() | ||
} | ||
let service = MockSuccessEventService() | ||
let ometria = Ometria.init(apiToken: "token", config: OmetriaConfig(), eventService: service, eventCache: cache) | ||
|
||
//when | ||
ometria.trackAppInstalledEvent() | ||
ometria.trackAppLaunchedEvent() | ||
ometria.trackErrorOccuredEvent(error: .invalidAPIResponse) | ||
|
||
|
||
//then | ||
wait(for: [expectation], timeout: 0.1) | ||
XCTAssertTrue(cache.events?.count == 3, "Expected 3 events in cache, but got \(cache.events?.count ?? 0)") | ||
} | ||
|
||
func test_ometria_successfulFlush_removesEventsFromCache() throws { | ||
//given | ||
let expectation = XCTestExpectation() | ||
expectation.expectedFulfillmentCount = 4 // 3 times for tracking the events, and 1 time for removing them when successfully flushed | ||
let cache = MockInMemoryEventCache { | ||
expectation.fulfill() | ||
} | ||
let service = MockSuccessEventService() | ||
let ometria = Ometria.init(apiToken: "token", config: OmetriaConfig(), eventService: service, eventCache: cache) | ||
|
||
//when | ||
ometria.trackAppInstalledEvent() | ||
ometria.trackAppLaunchedEvent() | ||
ometria.trackErrorOccuredEvent(error: .invalidAPIResponse) | ||
ometria.flush() | ||
|
||
//then | ||
wait(for: [expectation], timeout: 0.1) | ||
XCTAssertTrue(cache.events?.count == 0, "Expected 0 events in cache, but got \(cache.events?.count ?? 0)") | ||
} | ||
|
||
func test_ometria_sharedInitializer_successfullyPassesCacheAndEventService() { | ||
let expectation = XCTestExpectation() | ||
expectation.expectedFulfillmentCount = 1 // 3 times for tracking the events, and 1 time for removing them when successfully flushed | ||
let cache = MockInMemoryEventCache { | ||
expectation.fulfill() | ||
} | ||
let service = MockSuccessEventService() | ||
Ometria.initialize(apiToken: "token", eventCache: cache, eventService: service) | ||
|
||
wait(for: [expectation], timeout: 0.1) | ||
} | ||
|
||
func test_ometria_sharedInitializer_withSwizzlingEnabled_addsSwizzlers() { | ||
let cache = MockInMemoryEventCache { | ||
} | ||
let eventService = MockSuccessEventService() | ||
Ometria.initialize(apiToken: "token", eventCache: cache, eventService: eventService, enableSwizzling: true) | ||
|
||
XCTAssertTrue(Swizzler.swizzles.count > 0, "Expected a positive, non-null number of swizzles, but got none") | ||
} | ||
|
||
func test_ometria_sharedInitializer_withSwizzlingDisabled_doesntAddSwizzles() { | ||
let cache = MockInMemoryEventCache { | ||
} | ||
let eventService = MockSuccessEventService() | ||
Ometria.initialize(apiToken: "token", eventCache: cache, eventService: eventService, enableSwizzling: false) | ||
|
||
XCTAssertTrue(Swizzler.swizzles.count == 0, "Expected no swizzles") | ||
} | ||
|
||
func test_ometria_reinitializationWithoutSwizzling_removesSwizzles() { | ||
let cache = MockInMemoryEventCache { | ||
} | ||
let eventService = MockSuccessEventService() | ||
Ometria.initialize(apiToken: "token", eventCache: cache, eventService: eventService, enableSwizzling: true) | ||
Ometria.initialize(apiToken: "token", eventCache: cache, eventService: eventService, enableSwizzling: false) | ||
|
||
XCTAssertTrue(Swizzler.swizzles.count == 0, "Expected no swizzles") | ||
} | ||
|
||
func test_ometria_reinitializationWithSwizzling_resetsSwizzles() { | ||
let cache = MockInMemoryEventCache { | ||
} | ||
let eventService = MockSuccessEventService() | ||
Ometria.initialize(apiToken: "token", eventCache: cache, eventService: eventService, enableSwizzling: true) | ||
let swizzleCount = Swizzler.swizzles.count | ||
Ometria.initialize(apiToken: "token", eventCache: cache, eventService: eventService, enableSwizzling: true) | ||
|
||
// we cannot compare number of swizzled methods, as that would ignore the number of methods that were given an implementation at runtime during the first swizzling iteration | ||
XCTAssertTrue(Swizzler.swizzles.count >= swizzleCount && Swizzler.swizzles.count <= 2 * swizzleCount, "Expected to have at least \(swizzleCount), and less than (\(2 * swizzleCount) swizzled methods") | ||
} | ||
|
||
func test_ometria_reinitialization_successfullyFlushesAllEvents() { | ||
let eventService1 = MockSuccessAndCountEventService() | ||
let eventService2 = MockSuccessAndCountEventService() | ||
let cache1 = MockInMemoryEventCache { | ||
} | ||
let cache2 = MockInMemoryEventCache { | ||
} | ||
Ometria.initialize(apiToken: "token", eventCache: cache1, eventService: eventService1, enableSwizzling: false) | ||
for _ in 0..<100 { | ||
Ometria.sharedInstance().trackProductViewedEvent(productId: UUID().uuidString) | ||
} | ||
Ometria.initialize(apiToken: "token", eventCache: cache2, eventService: eventService2, enableSwizzling: false) | ||
|
||
let expectation = XCTestExpectation() | ||
DispatchQueue.main.asyncAfter(deadline: .now() + 10, execute: { | ||
expectation.fulfill() | ||
}) | ||
|
||
wait(for: [expectation], timeout: 11) | ||
XCTAssertTrue(eventService1.uniqueFlushedEvents.count >= 100, "Expected to flush more than 100 events, but got only \(eventService1.uniqueFlushedEvents.count)") | ||
} | ||
|
||
func test_ometria_instanceReset_clearsCache() { | ||
let eventService = MockFailureEventService() | ||
let cache1 = EventCache(relativePathComponent: "1") | ||
let cache2 = EventCache(relativePathComponent: "2") | ||
Ometria.initialize(apiToken: "test", eventCache: cache1, eventService: eventService) | ||
for _ in 0..<100 { | ||
Ometria.sharedInstance().trackProductViewedEvent(productId: UUID().uuidString) | ||
} | ||
Ometria.initialize(apiToken: "test2", eventCache: cache2, eventService: eventService) | ||
|
||
|
||
let expectation = XCTestExpectation() | ||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.4, execute: { | ||
expectation.fulfill() | ||
}) | ||
|
||
wait(for: [expectation], timeout: 0.5) | ||
let events = cache1.loadFromFile() | ||
XCTAssertTrue(events == nil || events?.count == 0, "Expected to have 0 items in cache, but found some") | ||
} | ||
} |
Oops, something went wrong.