// // Copyright (c) 2023 Touch Instinct // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the Software), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. // import XCTest import TIFoundationUtils final class MigratingBackingStoreTests: XCTestCase { private let sourceStorage = MockMigratingStorageContainer.defaultContainer.sourceStorage private let targetStorage = MockMigratingStorageContainer.defaultContainer.targetStorage private let encoder = JSONKeyValueEncoder() private let decoder = JSONKeyValueDecoder() @MockMigratingCodableBackingStore(key: .profile, storageContainer: .defaultContainer) var profile: Profile? override func setUp() { profile = nil } // MARK: - Read Tests // Precondition - source: ✅ target: ✅ // PostCondition - source: ❌ target: ✅ func testGetValue() throws { let oldProfile = Profile(name: "old", age: 0) let newProfile = Profile(name: "new", age: 0) let _ = sourceStorage.set(encodableObject: oldProfile, forKey: .profile, encoder: encoder) let _ = targetStorage.set(encodableObject: newProfile, forKey: .profile, encoder: encoder) XCTAssertEqual(profile, newProfile) XCTAssertThrowsError(try sourceStorage.codableObject(forKey: .profile, decoder: decoder).get()) XCTAssertNoThrow(try targetStorage.codableObject(forKey: .profile, decoder: decoder).get()) } // Precondition - source: ❌ target: ✅ // PostCondition - source: ❌ target: ✅ func testGetValueWithNoSource() throws { let newProfile = Profile(name: "new", age: 0) let _ = targetStorage.set(encodableObject: newProfile, forKey: .profile, encoder: encoder) XCTAssertEqual(profile, newProfile) XCTAssertThrowsError(try sourceStorage.codableObject(forKey: .profile, decoder: decoder).get()) XCTAssertNoThrow(try targetStorage.codableObject(forKey: .profile, decoder: decoder).get()) } // Precondition - source: ✅ target: ❌ // PostCondition - source: ❌ target: ✅ func testGetValueWithNoTarget() throws { let oldProfile = Profile(name: "old", age: 0) let _ = sourceStorage.set(encodableObject: oldProfile, forKey: .profile, encoder: encoder) XCTAssertEqual(profile, oldProfile) XCTAssertThrowsError(try sourceStorage.codableObject(forKey: .profile, decoder: decoder).get()) XCTAssertNoThrow(try targetStorage.codableObject(forKey: .profile, decoder: decoder).get()) } // Precondition - source: ❌ target: ❌ // PostCondition - source: ❌ target: ❌ func testGetValueWithNoValues() throws { XCTAssertEqual(profile, nil) XCTAssertThrowsError(try sourceStorage.codableObject(forKey: .profile, decoder: decoder).get()) XCTAssertThrowsError(try targetStorage.codableObject(forKey: .profile, decoder: decoder).get()) } // MARK: - Write Tests // Precondition - source: ✅ target: ✅ // PostCondition - source: ❌ target: ✅ func testStoreValue() throws { let oldProfile = Profile(name: "old", age: 0) let newProfile = Profile(name: "new", age: 0) let currentProfile = Profile(name: "name", age: 0) let _ = sourceStorage.set(encodableObject: oldProfile, forKey: .profile, encoder: encoder) let _ = targetStorage.set(encodableObject: newProfile, forKey: .profile, encoder: encoder) profile = currentProfile XCTAssertEqual(profile, currentProfile) XCTAssertThrowsError(try sourceStorage.codableObject(forKey: .profile, decoder: decoder).get()) XCTAssertEqual(try targetStorage.codableObject(forKey: .profile, decoder: decoder).get(), currentProfile) } // Precondition - source: ❌ target: ✅ // PostCondition - source: ❌ target: ✅ func testStoreValueWithNoSource() throws { let newProfile = Profile(name: "new", age: 0) let currentProfile = Profile(name: "name", age: 0) let _ = targetStorage.set(encodableObject: newProfile, forKey: .profile, encoder: encoder) profile = currentProfile XCTAssertEqual(profile, currentProfile) XCTAssertThrowsError(try sourceStorage.codableObject(forKey: .profile, decoder: decoder).get()) XCTAssertEqual(try targetStorage.codableObject(forKey: .profile, decoder: decoder).get(), currentProfile) } // Precondition - source: ✅ target: ❌ // PostCondition - source: ❌ target: ✅ func testStoreValueWithNoTarget() throws { let oldProfile = Profile(name: "old", age: 0) let currentProfile = Profile(name: "name", age: 0) let _ = sourceStorage.set(encodableObject: oldProfile, forKey: .profile, encoder: encoder) profile = currentProfile XCTAssertEqual(profile, currentProfile) XCTAssertThrowsError(try sourceStorage.codableObject(forKey: .profile, decoder: decoder).get()) XCTAssertEqual(try targetStorage.codableObject(forKey: .profile, decoder: decoder).get(), currentProfile) } // Precondition - source: ❌ target: ❌ // PostCondition - source: ❌ target: ✅ func testStoreValueWithNoValues() throws { let currentProfile = Profile(name: "name", age: 0) profile = currentProfile XCTAssertEqual(profile, currentProfile) XCTAssertThrowsError(try sourceStorage.codableObject(forKey: .profile, decoder: decoder).get()) XCTAssertEqual(try targetStorage.codableObject(forKey: .profile, decoder: decoder).get(), currentProfile) } // MARK: - Delete Tests // Precondition - source: ✅ target: ✅ // PostCondition - source: ❌ target: ❌ func testDeleteValue() throws { let oldProfile = Profile(name: "old", age: 0) let newProfile = Profile(name: "new", age: 0) let _ = sourceStorage.set(encodableObject: oldProfile, forKey: .profile, encoder: encoder) let _ = targetStorage.set(encodableObject: newProfile, forKey: .profile, encoder: encoder) profile = nil XCTAssertEqual(profile, nil) XCTAssertThrowsError(try sourceStorage.codableObject(forKey: .profile, decoder: decoder).get()) XCTAssertThrowsError(try targetStorage.codableObject(forKey: .profile, decoder: decoder).get()) } // Precondition - source: ❌ target: ✅ // PostCondition - source: ❌ target: ❌ func testDeleteValueWithNoSource() throws { let newProfile = Profile(name: "new", age: 0) let _ = targetStorage.set(encodableObject: newProfile, forKey: .profile, encoder: encoder) profile = nil XCTAssertEqual(profile, nil) XCTAssertThrowsError(try sourceStorage.codableObject(forKey: .profile, decoder: decoder).get()) XCTAssertThrowsError(try targetStorage.codableObject(forKey: .profile, decoder: decoder).get()) } // Precondition - source: ✅ target: ❌ // PostCondition - source: ❌ target: ❌ func testDeleteValueWithNoTarget() throws { let oldProfile = Profile(name: "old", age: 0) let _ = sourceStorage.set(encodableObject: oldProfile, forKey: .profile, encoder: encoder) profile = nil XCTAssertEqual(profile, nil) XCTAssertThrowsError(try sourceStorage.codableObject(forKey: .profile, decoder: decoder).get()) XCTAssertThrowsError(try targetStorage.codableObject(forKey: .profile, decoder: decoder).get()) } // Precondition - source: ❌ target: ❌ // PostCondition - source: ❌ target: ❌ func testDeleteValueWithNoValues() throws { profile = nil XCTAssertEqual(profile, nil) XCTAssertThrowsError(try sourceStorage.codableObject(forKey: .profile, decoder: decoder).get()) XCTAssertThrowsError(try targetStorage.codableObject(forKey: .profile, decoder: decoder).get()) } }