Skip to content

Commit

Permalink
Making SecurelyStoredValue mutation functions operate on MainActor
Browse files Browse the repository at this point in the history
  • Loading branch information
mergesort committed Aug 27, 2023
1 parent fa8b035 commit 1a81e89
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 22 deletions.
3 changes: 2 additions & 1 deletion Sources/Boutique/SecurelyStoredValue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ import SwiftUI
/// in front of the the `$storedValue`.
///
/// See: ``set(_:)`` and ``remove()`` docs for a more in depth explanation.
@MainActor
@propertyWrapper
public struct SecurelyStoredValue<Item: Codable> {
private let cancellableBox = CancellableBox()
Expand Down Expand Up @@ -83,6 +82,7 @@ public struct SecurelyStoredValue<Item: Codable> {
/// Within Boutique the @Stored property wrapper works very similarly.
///
/// - Parameter value: The value to set @``SecurelyStoredValue`` to.
@MainActor
public func set(_ value: Item?) throws {
if let value {
if self.wrappedValue == nil {
Expand Down Expand Up @@ -115,6 +115,7 @@ public struct SecurelyStoredValue<Item: Codable> {
/// `@Published var items: [Item]` allows you to use `items` as a regular `[Item]`,
/// but `$items` projects `AnyPublisher<[Item], Never>` so you can subscribe to changes items produces.
/// Within Boutique the @Stored property wrapper works very similarly.
@MainActor
public func remove() throws {
if self.wrappedValue != nil {
try self.removeItem()
Expand Down
1 change: 1 addition & 0 deletions Sources/Boutique/StoredValue+Array.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public extension SecurelyStoredValue {
/// To better match expected uses calling append on a currently nil SecurelyStoredValue
/// will return a single element array of the passed in value,
/// rather than returning nil or throwing an error.
@MainActor
func append<Value>(_ value: Value) throws where Item == [Value] {
var updatedArray = self.wrappedValue ?? []
updatedArray.append(value)
Expand Down
1 change: 1 addition & 0 deletions Sources/Boutique/StoredValue+Binding.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public extension SecurelyStoredValue {
/// A convenient way to create a `Binding` from a `SecurelyStoredValue`.
///
/// - Returns: A `Binding<Item?>` of the `SecurelyStoredValue<Item>` provided.
@MainActor
var binding: Binding<Item?> {
Binding(get: {
self.wrappedValue
Expand Down
1 change: 1 addition & 0 deletions Sources/Boutique/StoredValue+Bool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public extension SecurelyStoredValue where Item == Bool {
/// ```
/// self.appState.$isLoggedIn.toggle()
/// ```
@MainActor
func toggle() throws {
if let wrappedValue {
try self.set(!wrappedValue)
Expand Down
1 change: 1 addition & 0 deletions Sources/Boutique/StoredValue+Dictionary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public extension SecurelyStoredValue {
/// To better match expected uses calling update on a currently nil SecurelyStoredValue
/// will return a single element dictionary of the passed in key/value,
/// rather than returning nil or throwing an error.
@MainActor
func update<Key: Hashable, Value>(key: Key, value: Value?) throws where Item == [Key: Value] {
var updatedDictionary = self.wrappedValue ?? [:]
updatedDictionary[key] = value
Expand Down
55 changes: 34 additions & 21 deletions Tests/BoutiqueTests/SecurelyStoredValueTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ final class SecurelyStoredValueTests: XCTestCase {
@SecurelyStoredValue<String>(key: "Boutique.SecurelyStoredValue.Test")
private var storedExistingValue

@MainActor
override func setUp() async throws {
if self.storedExistingValue == nil {
try self.$storedExistingValue.set("Existence")
}
}

@MainActor
override func tearDown() async throws {
try self.$storedPassword.remove()
try self.$storedBool.remove()
Expand All @@ -47,7 +49,18 @@ final class SecurelyStoredValueTests: XCTestCase {
XCTAssertNotEqual(self.storedExistingValue, nil)
}

func testStoredValue() throws {
func testStoredValue() async throws {
XCTAssertEqual(self.storedPassword, nil)

try await self.$storedPassword.set("p@ssw0rd")
XCTAssertEqual(self.storedPassword, "p@ssw0rd")

try await self.$storedPassword.remove()
XCTAssertEqual(self.storedPassword, nil)
}

@MainActor
func testStoredValueOnMainActor() throws {
XCTAssertEqual(self.storedPassword, nil)

try self.$storedPassword.set("p@ssw0rd")
Expand All @@ -57,66 +70,66 @@ final class SecurelyStoredValueTests: XCTestCase {
XCTAssertEqual(self.storedPassword, nil)
}

func testStoredCustomType() throws {
func testStoredCustomType() async throws {
XCTAssertEqual(self.storedItem, nil)

try self.$storedItem.set(.sweater)
try await self.$storedItem.set(.sweater)
XCTAssertEqual(self.storedItem, .sweater)

try self.$storedItem.set(.belt)
try await self.$storedItem.set(.belt)
XCTAssertEqual(self.storedItem, .belt)

try self.$storedItem.remove()
try await self.$storedItem.remove()
XCTAssertEqual(self.storedItem, nil)
}

func testStoredArray() throws {
// Strings
func testStoredArray() async throws {
XCTAssertEqual(self.storedArray, nil)

try self.$storedArray.set([.belt, .sweater])
try await self.$storedArray.set([.belt, .sweater])
XCTAssertEqual(self.storedArray, [.belt, .sweater])

try self.$storedArray.remove()
try await self.$storedArray.remove()
XCTAssertEqual(self.storedArray, nil)
}

func testStoredBoolean() async throws {
XCTAssertEqual(self.storedBool, nil)

try self.$storedBool.set(true)
try await self.$storedBool.set(true)
XCTAssertEqual(self.storedBool, true)

try self.$storedBool.set(false)
try await self.$storedBool.set(false)
XCTAssertEqual(self.storedBool, false)

try self.$storedBool.toggle()
try await self.$storedBool.toggle()
XCTAssertEqual(self.storedBool, true)
}

func testStoredDictionary() async throws {
XCTAssertEqual(self.storedDictionary, nil)

try self.$storedDictionary.update(key: BoutiqueItem.sweater.merchantID, value: BoutiqueItem.sweater)
try await self.$storedDictionary.update(key: BoutiqueItem.sweater.merchantID, value: BoutiqueItem.sweater)
XCTAssertEqual(self.storedDictionary, [BoutiqueItem.sweater.merchantID : BoutiqueItem.sweater])

try self.$storedDictionary.update(key: BoutiqueItem.belt.merchantID, value: nil)
try await self.$storedDictionary.update(key: BoutiqueItem.belt.merchantID, value: nil)
XCTAssertEqual(self.storedDictionary, [BoutiqueItem.sweater.merchantID : BoutiqueItem.sweater])

try self.$storedDictionary.update(key: BoutiqueItem.sweater.merchantID, value: nil)
try await self.$storedDictionary.update(key: BoutiqueItem.sweater.merchantID, value: nil)
XCTAssertEqual(self.storedDictionary, [:])
}

func testStoredArrayValueAppend() async throws {
XCTAssertEqual(self.storedArray, nil)

try self.$storedArray.append(BoutiqueItem.sweater)
try await self.$storedArray.append(BoutiqueItem.sweater)
XCTAssertEqual(self.storedArray, [BoutiqueItem.sweater])

try self.$storedArray.append(BoutiqueItem.belt)
try await self.$storedArray.append(BoutiqueItem.belt)
XCTAssertEqual(self.storedArray, [BoutiqueItem.sweater, BoutiqueItem.belt])
}

@MainActor
func testStoredBinding() async throws {
XCTAssertEqual(self.storedBinding, nil)

Expand Down Expand Up @@ -145,10 +158,10 @@ final class SecurelyStoredValueTests: XCTestCase {
})
.store(in: &cancellables)

try self.$storedItem.set(BoutiqueItem.coat)
try self.$storedItem.set(BoutiqueItem.purse)
try self.$storedItem.set(BoutiqueItem.sweater)
try self.$storedItem.set(BoutiqueItem.belt)
try await self.$storedItem.set(BoutiqueItem.coat)
try await self.$storedItem.set(BoutiqueItem.purse)
try await self.$storedItem.set(BoutiqueItem.sweater)
try await self.$storedItem.set(BoutiqueItem.belt)

await fulfillment(of: [expectation], timeout: 1)
}
Expand Down

0 comments on commit 1a81e89

Please sign in to comment.