From f6bbe435ba41a549e7ea589402a25c3844b5c3aa Mon Sep 17 00:00:00 2001 From: Tomas Strba Date: Fri, 18 Oct 2024 11:44:24 +0200 Subject: [PATCH 1/3] Changes to suggestions for adding a removal button --- Sources/History/HistoryCoordinator.swift | 15 +++++++++++++++ Sources/Suggestions/Suggestion.swift | 12 +++++++++--- Sources/Suggestions/SuggestionResult.swift | 6 +++--- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/Sources/History/HistoryCoordinator.swift b/Sources/History/HistoryCoordinator.swift index e49280670..9017f1db8 100644 --- a/Sources/History/HistoryCoordinator.swift +++ b/Sources/History/HistoryCoordinator.swift @@ -44,6 +44,7 @@ public protocol HistoryCoordinating: AnyObject { func burnDomains(_ baseDomains: Set, tld: TLD, completion: @escaping (Set) -> Void) func burnVisits(_ visits: [Visit], completion: @escaping () -> Void) + func removeUrlEntry(_ url: URL, completion: ((Error?) -> Void)?) } /// Coordinates access to History. Uses its own queue with high qos for all operations. @@ -191,6 +192,20 @@ final public class HistoryCoordinator: HistoryCoordinating { } } + public enum EntryRemovalError: Error { + case notAvailable + } + + public func removeUrlEntry(_ url: URL, completion: ((Error?) -> Void)? = nil) { + guard let historyDictionary = historyDictionary else { return } + guard let entry = historyDictionary[url] else { + completion?(EntryRemovalError.notAvailable) + return + } + + removeEntries([entry], completionHandler: completion) + } + var cleaningDate: Date { .monthAgo } @objc private func cleanOld() { diff --git a/Sources/Suggestions/Suggestion.swift b/Sources/Suggestions/Suggestion.swift index 3a50fdc33..d96cea05e 100644 --- a/Sources/Suggestions/Suggestion.swift +++ b/Sources/Suggestions/Suggestion.swift @@ -28,7 +28,7 @@ public enum Suggestion: Equatable { case openTab(title: String, url: URL) case unknown(value: String) - var url: URL? { + public var url: URL? { switch self { case .website(url: let url), .historyEntry(title: _, url: let url, allowedInTopHits: _), @@ -67,20 +67,26 @@ public enum Suggestion: Equatable { } } - var isOpenTab: Bool { + public var isOpenTab: Bool { if case .openTab = self { return true } return false } - var isBookmark: Bool { + public var isBookmark: Bool { if case .bookmark = self { return true } return false } + public var isHistoryEntry: Bool { + if case .historyEntry = self { + return true + } + return false + } } extension Suggestion { diff --git a/Sources/Suggestions/SuggestionResult.swift b/Sources/Suggestions/SuggestionResult.swift index af0997dea..880cf83c3 100644 --- a/Sources/Suggestions/SuggestionResult.swift +++ b/Sources/Suggestions/SuggestionResult.swift @@ -24,9 +24,9 @@ public struct SuggestionResult: Equatable { SuggestionResult(topHits: [], duckduckgoSuggestions: [], localSuggestions: []) } - private(set) public var topHits: [Suggestion] - private(set) public var duckduckgoSuggestions: [Suggestion] - private(set) public var localSuggestions: [Suggestion] + public var topHits: [Suggestion] + public var duckduckgoSuggestions: [Suggestion] + public var localSuggestions: [Suggestion] public init(topHits: [Suggestion], duckduckgoSuggestions: [Suggestion], From 9847842c048d7a7f2bf779bc6f347e4491b63a10 Mon Sep 17 00:00:00 2001 From: Tomas Strba Date: Wed, 30 Oct 2024 10:05:02 +0100 Subject: [PATCH 2/3] Unit tests --- .../HistoryCoordinatorTests.swift | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/Tests/HistoryTests/HistoryCoordinatorTests.swift b/Tests/HistoryTests/HistoryCoordinatorTests.swift index 98811e65d..c84622e00 100644 --- a/Tests/HistoryTests/HistoryCoordinatorTests.swift +++ b/Tests/HistoryTests/HistoryCoordinatorTests.swift @@ -316,6 +316,43 @@ class HistoryCoordinatorTests: XCTestCase { return bookmarksDatabase } + func testWhenRemoveUrlEntryCalledWithExistingUrl_ThenEntryIsRemovedAndNoError() { + let (historyStoringMock, historyCoordinator) = HistoryCoordinator.aHistoryCoordinator + + let url = URL(string: "https://duckduckgo.com")! + historyCoordinator.addVisit(of: url) + + XCTAssertTrue(historyCoordinator.history!.contains(where: { $0.url == url })) + + let removalExpectation = expectation(description: "Entry removed without error") + historyCoordinator.removeUrlEntry(url) { error in + XCTAssertNil(error, "Expected no error when removing an existing URL entry") + removalExpectation.fulfill() + } + + waitForExpectations(timeout: 1.0) + + XCTAssertFalse(historyCoordinator.history!.contains(where: { $0.url == url })) + XCTAssertTrue(historyStoringMock.removeEntriesCalled, "Expected removeEntries to be called") + XCTAssertEqual(historyStoringMock.removeEntriesArray.count, 1) + XCTAssertEqual(historyStoringMock.removeEntriesArray.first?.url, url) + } + + func testWhenRemoveUrlEntryCalledWithNonExistingUrl_ThenEntryRemovalFailsWithNotAvailableError() { + let (_, historyCoordinator) = HistoryCoordinator.aHistoryCoordinator + + let nonExistentUrl = URL(string: "https://nonexistent.com")! + + let removalExpectation = expectation(description: "Entry removal fails with notAvailable error") + historyCoordinator.removeUrlEntry(nonExistentUrl) { error in + XCTAssertNotNil(error, "Expected an error when removing a non-existent URL entry") + XCTAssertEqual(error as? HistoryCoordinator.EntryRemovalError, .notAvailable, "Expected notAvailable error") + removalExpectation.fulfill() + } + + waitForExpectations(timeout: 1.0) + } + } fileprivate extension HistoryCoordinator { From c8102e7afa2b06f4afaffaf6f50e4d251c9e7395 Mon Sep 17 00:00:00 2001 From: Tomas Strba Date: Fri, 1 Nov 2024 14:08:04 +0100 Subject: [PATCH 3/3] Making SuggestionResult immutable --- Sources/Suggestions/SuggestionResult.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/Suggestions/SuggestionResult.swift b/Sources/Suggestions/SuggestionResult.swift index 880cf83c3..1576ed48c 100644 --- a/Sources/Suggestions/SuggestionResult.swift +++ b/Sources/Suggestions/SuggestionResult.swift @@ -24,9 +24,9 @@ public struct SuggestionResult: Equatable { SuggestionResult(topHits: [], duckduckgoSuggestions: [], localSuggestions: []) } - public var topHits: [Suggestion] - public var duckduckgoSuggestions: [Suggestion] - public var localSuggestions: [Suggestion] + public let topHits: [Suggestion] + public let duckduckgoSuggestions: [Suggestion] + public let localSuggestions: [Suggestion] public init(topHits: [Suggestion], duckduckgoSuggestions: [Suggestion],