Skip to content

Commit

Permalink
Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
bwaresiak committed Aug 4, 2023
1 parent c594ecf commit 90500e2
Show file tree
Hide file tree
Showing 3 changed files with 344 additions and 1 deletion.
6 changes: 6 additions & 0 deletions DuckDuckGo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1432,6 +1432,8 @@
9833913327AAAEEE00DAF119 /* EmbeddedTrackerDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9833913227AAAEEE00DAF119 /* EmbeddedTrackerDataTests.swift */; };
983DFB2528B67036006B7E34 /* UserContentUpdating.swift in Sources */ = {isa = PBXBuildFile; fileRef = 983DFB2428B67036006B7E34 /* UserContentUpdating.swift */; };
984FD3BF299ACF35007334DD /* Bookmarks in Frameworks */ = {isa = PBXBuildFile; productRef = 984FD3BE299ACF35007334DD /* Bookmarks */; };
986189E62A7CFB3E001B4519 /* LocalBookmarkStoreSavingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 986189E52A7CFB3E001B4519 /* LocalBookmarkStoreSavingTests.swift */; };
986189E72A7CFB3E001B4519 /* LocalBookmarkStoreSavingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 986189E52A7CFB3E001B4519 /* LocalBookmarkStoreSavingTests.swift */; };
987799ED299998B1005D8EB6 /* Bookmarks in Frameworks */ = {isa = PBXBuildFile; productRef = 987799EC299998B1005D8EB6 /* Bookmarks */; };
987799F12999993C005D8EB6 /* LegacyBookmarkStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 987799EF2999993C005D8EB6 /* LegacyBookmarkStore.swift */; };
987799F22999993C005D8EB6 /* LegacyBookmarkStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 987799EF2999993C005D8EB6 /* LegacyBookmarkStore.swift */; };
Expand Down Expand Up @@ -2661,6 +2663,7 @@
9833913027AAA4B500DAF119 /* trackerData.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = trackerData.json; sourceTree = "<group>"; };
9833913227AAAEEE00DAF119 /* EmbeddedTrackerDataTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmbeddedTrackerDataTests.swift; sourceTree = "<group>"; };
983DFB2428B67036006B7E34 /* UserContentUpdating.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserContentUpdating.swift; sourceTree = "<group>"; };
986189E52A7CFB3E001B4519 /* LocalBookmarkStoreSavingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalBookmarkStoreSavingTests.swift; sourceTree = "<group>"; };
987799EF2999993C005D8EB6 /* LegacyBookmarkStore.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyBookmarkStore.swift; sourceTree = "<group>"; };
987799F02999993C005D8EB6 /* LegacyBookmarksStoreMigration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LegacyBookmarksStoreMigration.swift; sourceTree = "<group>"; };
987799F52999996B005D8EB6 /* BookmarkDatabase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BookmarkDatabase.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -5197,6 +5200,7 @@
isa = PBXGroup;
children = (
AA652CB025DD825B009059CC /* LocalBookmarkStoreTests.swift */,
986189E52A7CFB3E001B4519 /* LocalBookmarkStoreSavingTests.swift */,
AA652CDA25DDAB32009059CC /* BookmarkStoreMock.swift */,
);
path = Services;
Expand Down Expand Up @@ -8152,6 +8156,7 @@
3706FE3F293F661700E42796 /* FileStoreMock.swift in Sources */,
3706FE40293F661700E42796 /* BWResponseTests.swift in Sources */,
3706FE41293F661700E42796 /* DownloadListCoordinatorTests.swift in Sources */,
986189E72A7CFB3E001B4519 /* LocalBookmarkStoreSavingTests.swift in Sources */,
3706FE42293F661700E42796 /* BWMessageIdGeneratorTests.swift in Sources */,
3706FE43293F661700E42796 /* TestDataModel.xcdatamodeld in Sources */,
3706FE44293F661700E42796 /* GeolocationServiceTests.swift in Sources */,
Expand Down Expand Up @@ -9171,6 +9176,7 @@
B69B50452726C5C200758A2B /* AtbParserTests.swift in Sources */,
B6106BAF26A7C6180013B453 /* PermissionStoreMock.swift in Sources */,
4B98D27A28D95F1A003C2B6F /* ChromiumFaviconsReaderTests.swift in Sources */,
986189E62A7CFB3E001B4519 /* LocalBookmarkStoreSavingTests.swift in Sources */,
AA652CD325DDA6E9009059CC /* LocalBookmarkManagerTests.swift in Sources */,
CBDD5DE329A67F2700832877 /* MockConfigurationStore.swift in Sources */,
B63ED0DC26AE7B1E00A9DAD1 /* WebViewMock.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion DuckDuckGo/Bookmarks/Services/LocalBookmarkStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ final class LocalBookmarkStore: BookmarkStore {
if let parent = parent,
let parentFetchRequestResult = try? context.fetch(BaseBookmarkEntity.singleEntity(with: parent.id)).first {
parentEntity = parentFetchRequestResult
} else if let root = BookmarkUtils.fetchRootFolder(context) {
} else if let root = bookmarksRoot(in: context) {
parentEntity = root
} else {
Pixel.fire(.debug(event: .missingParent))
Expand Down
337 changes: 337 additions & 0 deletions UnitTests/Bookmarks/Services/LocalBookmarkStoreSavingTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,337 @@
//
// LocalBookmarkStoreSavingTests.swift
//
// Copyright © 2023 DuckDuckGo. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

import Foundation
import Bookmarks
import XCTest
import CoreData
@testable import DuckDuckGo_Privacy_Browser

final class LocalBookmarkStoreSavingTests: XCTestCase {

enum LocalError: Error {
case example
}

// MARK: Save/Delete

let container = CoreData.bookmarkContainer()
var store: LocalBookmarkStore!

override func setUp() {
super.setUp()

BookmarkUtils.prepareFoldersStructure(in: container.viewContext)

do {
try container.viewContext.save()
} catch {
XCTFail("Could not prepare Bookmarks Structure")
}

store = LocalBookmarkStore {
self.container.newBackgroundContext()
}
}

func testWhenThereIsNoErrorThenDataIsSaved() throws {
let otherContext = container.newBackgroundContext()

try store.applyChangesAndSave { context in
let root = BookmarkUtils.fetchRootFolder(context)
_ = BookmarkEntity.makeBookmark(title: "T", url: "h", parent: root!, context: context)
}

otherContext.performAndWait {
let root = BookmarkUtils.fetchRootFolder(otherContext)
XCTAssertEqual(root?.childrenArray.first?.title, "T")
XCTAssertEqual(root?.childrenArray.first?.url, "h")
}
}

func testWhenThereIsNoErrorThenDataIsSaved_Closures() throws {
let otherContext = container.newBackgroundContext()

let expectation = expectation(description: "Did save")

store.applyChangesAndSave { context in
let root = BookmarkUtils.fetchRootFolder(context)
_ = BookmarkEntity.makeBookmark(title: "T", url: "h", parent: root!, context: context)
} onError: { _ in
XCTFail("Error not expected")
} onDidSave: {
expectation.fulfill()
}

wait(for: [expectation], timeout: 5)

otherContext.performAndWait {
let root = BookmarkUtils.fetchRootFolder(otherContext)
XCTAssertEqual(root?.childrenArray.first?.title, "T")
XCTAssertEqual(root?.childrenArray.first?.url, "h")
}
}

func testWhenThereIsExplicitErrorThenOnErrorIsCalled() {
let otherContext = container.newBackgroundContext()

do {
try store.applyChangesAndSave { context in
let root = BookmarkUtils.fetchRootFolder(context)
_ = BookmarkEntity.makeBookmark(title: "T", url: "h", parent: root!, context: context)

throw LocalError.example
}
XCTFail("Exception should be thrown")
} catch {
XCTAssertEqual(error as? LocalError, .example)
}

otherContext.performAndWait {
let root = BookmarkUtils.fetchRootFolder(otherContext)
XCTAssert(root!.childrenArray.isEmpty)
}
}

func testWhenThereIsExplicitErrorThenOnErrorIsCalled_Closures() {
let otherContext = container.newBackgroundContext()

let expectation = expectation(description: "OnError")

store.applyChangesAndSave { context in
let root = BookmarkUtils.fetchRootFolder(context)
_ = BookmarkEntity.makeBookmark(title: "T", url: "h", parent: root!, context: context)

throw LocalError.example
} onError: { error in
expectation.fulfill()
XCTAssertEqual(error as? LocalError, .example)
} onDidSave: {
XCTFail("Should not save")
}

wait(for: [expectation], timeout: 5)

otherContext.performAndWait {
let root = BookmarkUtils.fetchRootFolder(otherContext)
XCTAssert(root!.childrenArray.isEmpty)
}
}

func testWhenThereIsSaveErrorThenOnErrorIsCalled() {
let otherContext = container.newBackgroundContext()

do {
try store.applyChangesAndSave { context in
let root = BookmarkUtils.fetchRootFolder(context)
let folder = BookmarkEntity.makeFolder(title: "Folder", parent: root!, context: context)
folder.url = "incorrect value"
}
XCTFail("Exception should be thrown")
} catch {
XCTAssertEqual(error as? BookmarkEntity.Error, BookmarkEntity.Error.folderHasURL)
}

otherContext.performAndWait {
let root = BookmarkUtils.fetchRootFolder(otherContext)
XCTAssert(root!.childrenArray.isEmpty)
}
}

func testWhenThereIsSaveErrorThenOnErrorIsCalled_Closures() {
let otherContext = container.newBackgroundContext()

let expectation = expectation(description: "OnError")

store.applyChangesAndSave { context in
let root = BookmarkUtils.fetchRootFolder(context)
let folder = BookmarkEntity.makeFolder(title: "Folder", parent: root!, context: context)
folder.url = "incorrect value"
} onError: { error in
expectation.fulfill()
XCTAssertEqual(error as? BookmarkEntity.Error, BookmarkEntity.Error.folderHasURL)
} onDidSave: {
XCTFail("Should not save")
}

wait(for: [expectation], timeout: 5)

otherContext.performAndWait {
let root = BookmarkUtils.fetchRootFolder(otherContext)
XCTAssert(root!.childrenArray.isEmpty)
}
}

func testWhenThereIsMergeErrorThenSaveRetries() {

let otherContext = container.newBackgroundContext()

do {
try store.applyChangesAndSave { context in
let root = BookmarkUtils.fetchRootFolder(context)
_ = BookmarkEntity.makeBookmark(title: "T", url: "h", parent: root!, context: context)

otherContext.performAndWait {
let root = BookmarkUtils.fetchRootFolder(otherContext)

// Only store on first pass
guard root?.childrenArray.isEmpty ?? false else { return }

_ = BookmarkEntity.makeBookmark(title: "Inner", url: "i", parent: root!, context: otherContext)
do {
try otherContext.save()
} catch {
XCTFail("Could not save inner object")
}
}
}
} catch {
XCTFail("Exception should not be thrown")
}

otherContext.performAndWait {
otherContext.reset()
let root = BookmarkUtils.fetchRootFolder(otherContext)
let children = root?.childrenArray ?? []

XCTAssertEqual(children.count, 2)
XCTAssertEqual(Set(children.map { $0.title }), ["T", "Inner"])
}
}

func testWhenThereIsMergeErrorThenSaveRetries_Closures() {

let otherContext = container.newBackgroundContext()

let expectation = expectation(description: "On DidSave")

store.applyChangesAndSave { context in
let root = BookmarkUtils.fetchRootFolder(context)
_ = BookmarkEntity.makeBookmark(title: "T", url: "h", parent: root!, context: context)

otherContext.performAndWait {
let root = BookmarkUtils.fetchRootFolder(otherContext)

// Only store on first pass
guard root?.childrenArray.isEmpty ?? false else { return }

_ = BookmarkEntity.makeBookmark(title: "Inner", url: "i", parent: root!, context: otherContext)
do {
try otherContext.save()
} catch {
XCTFail("Could not save inner object")
}
}
} onError: { _ in
XCTFail("No error expected")
} onDidSave: {
expectation.fulfill()
}

wait(for: [expectation], timeout: 5)

otherContext.performAndWait {
otherContext.reset()
let root = BookmarkUtils.fetchRootFolder(otherContext)
let children = root?.childrenArray ?? []

XCTAssertEqual(children.count, 2)
XCTAssertEqual(Set(children.map { $0.title }), ["T", "Inner"])
}
}

func testWhenThereIsRecurringMergeErrorThenOnErrorIsCalled() {
let otherContext = container.newBackgroundContext()

do {
try store.applyChangesAndSave { context in
let root = BookmarkUtils.fetchRootFolder(context)
_ = BookmarkEntity.makeBookmark(title: "T", url: "h", parent: root!, context: context)

otherContext.performAndWait {
let root = BookmarkUtils.fetchRootFolder(otherContext)
_ = BookmarkEntity.makeBookmark(title: "Inner", url: "i", parent: root!, context: otherContext)
do {
try otherContext.save()
} catch {
XCTFail("Could not save inner object")
}
}
}
XCTFail("Should trow an error")
} catch {
if case LocalBookmarkStore.BookmarkStoreError.saveLoopError(let wrappedError) = error, let wrappedError {
XCTAssertEqual((wrappedError as NSError).code, NSManagedObjectMergeError)
} else {
XCTFail("Loop Error expected")
}
}

otherContext.performAndWait {
otherContext.reset()
let root = BookmarkUtils.fetchRootFolder(otherContext)
let children = root?.childrenArray ?? []

XCTAssertEqual(children.count, 4)
XCTAssertEqual(Set(children.map { $0.title }), ["Inner"])
}
}

func testWhenThereIsRecurringMergeErrorThenOnErrorIsCalled_Closures() {
let otherContext = container.newBackgroundContext()

let expectation = expectation(description: "OnError")

store.applyChangesAndSave { context in
let root = BookmarkUtils.fetchRootFolder(context)
_ = BookmarkEntity.makeBookmark(title: "T", url: "h", parent: root!, context: context)

otherContext.performAndWait {
let root = BookmarkUtils.fetchRootFolder(otherContext)
_ = BookmarkEntity.makeBookmark(title: "Inner", url: "i", parent: root!, context: otherContext)
do {
try otherContext.save()
} catch {
XCTFail("Could not save inner object")
}
}
} onError: { error in
expectation.fulfill()

if case LocalBookmarkStore.BookmarkStoreError.saveLoopError(let wrappedError) = error, let wrappedError {
XCTAssertEqual((wrappedError as NSError).code, NSManagedObjectMergeError)
} else {
XCTFail("Loop Error expected")
}
} onDidSave: {

}

wait(for: [expectation], timeout: 5)

otherContext.performAndWait {
otherContext.reset()
let root = BookmarkUtils.fetchRootFolder(otherContext)
let children = root?.childrenArray ?? []

XCTAssertEqual(children.count, 4)
XCTAssertEqual(Set(children.map { $0.title }), ["Inner"])
}
}

}

0 comments on commit 90500e2

Please sign in to comment.