import XCTest import CoreData @testable import Wikipedia class TalkPageLocalHandlerTests: XCTestCase { let urlString1 = "https://en.wikipedia.org/api/rest_v1/page/talk/Username1" let urlString2 = "https://en.wikipedia.org/api/rest_v1/page/talk/Username2" let urlString3 = "https://es.wikipedia.org/api/rest_v1/page/talk/Username1" var tempDataStore: MWKDataStore! var moc: NSManagedObjectContext! override func setUp() { super.setUp() tempDataStore = MWKDataStore.temporary() moc = tempDataStore.viewContext } override func tearDown() { tempDataStore.removeFolderAtBasePath() tempDataStore = nil super.tearDown() } func testCreateFirstTalkPageSavesToDatabase() { // confirm no talk pages in DB let fetchRequest: NSFetchRequest = TalkPage.fetchRequest() guard let firstResults = try? tempDataStore.viewContext.fetch(fetchRequest) else { XCTFail("Failure fetching initial talk pages") return } XCTAssertEqual(firstResults.count, 0, "Expected zero existing talk pages at first") // add network talk page guard let json = wmf_bundle().wmf_data(fromContentsOfFile: TalkPageTestHelpers.TalkPageJSONType.original.fileName, ofType: "json"), let talkPage = TalkPageTestHelpers.networkTalkPage(for: urlString1, data: json, revisionId: 1) else { XCTFail("Failure stubbing out network talk page") return } // create db talk page guard let dbTalkPage = moc.createTalkPage(with: talkPage) else { XCTFail("Failure to create db talk page") return } // assert db talk page values let keyedUrlString = URL(string: urlString1)?.wmf_databaseKey XCTAssertNotNil(dbTalkPage.key) XCTAssertEqual(dbTalkPage.key, keyedUrlString, "Unexpected key") XCTAssertEqual(dbTalkPage.revisionId, 1, "Unexpected revisionId") XCTAssertEqual(dbTalkPage.topics?.count, 6, "Unexpected topic count") let topics = dbTalkPage.topics?.allObjects.sorted { ($0 as! TalkPageTopic).sort < ($1 as! TalkPageTopic).sort } if let introTopic = topics?[0] as? TalkPageTopic { XCTAssertEqual(introTopic.title, "", "Unexpected topic title") XCTAssertEqual(introTopic.replies?.count, 1, "Unexpected replies count") let replies = introTopic.replies?.allObjects.sorted { ($0 as! TalkPageReply).sort < ($1 as! TalkPageReply).sort } if let firstReply = replies?[0] as? TalkPageReply { XCTAssertEqual(firstReply.text, "Hello! This is some introduction text on my talk page. L8erz, TSevener (WMF) (talk) 20:48, 21 June 2019 (UTC)", "Unexpected replies html") } else { XCTFail("Unexpected first reply type") } } else { XCTFail("Unexpected intro topic type") } if let firstTopic = topics?[1] as? TalkPageTopic { XCTAssertEqual(firstTopic.title, "Let’s talk about talk pages", "Unexpected topic title") XCTAssertEqual(firstTopic.replies?.count, 3, "Unexpected topic items count") let replies = firstTopic.replies?.allObjects.sorted { ($0 as! TalkPageReply).sort < ($1 as! TalkPageReply).sort } if let firstReply = replies?[0] as? TalkPageReply { XCTAssertEqual(firstReply.text, "Hello, I am testing a new topic from the iOS app. It is fun. 47.184.10.84 20:50, 21 June 2019 (UTC)") XCTAssertEqual(firstReply.depth, 0, "Unexpected reply depth") } else { XCTFail("Unexpected first reply type") } if let secondReply = replies?[1] as? TalkPageReply { XCTAssertEqual(secondReply.text, "Hello back! This is a nested reply. TSevener (WMF) (talk) 20:51, 21 June 2019 (UTC)") XCTAssertEqual(secondReply.depth, 1, "Unexpected reply depth") } else { XCTFail("Unexpected second reply type") } if let thirdReply = replies?[2] as? TalkPageReply { XCTAssertEqual(thirdReply.text, "Yes I see, I am nested as well. 47.184.10.84 20:52, 21 June 2019 (UTC)") XCTAssertEqual(thirdReply.depth, 2, "Unexpected reply depth") } else { XCTFail("Unexpected third reply type") } } else { XCTFail("Unexpected first topic type") } if let secondTopic = topics?[2] as? TalkPageTopic { XCTAssertEqual(secondTopic.title, "Subtopic time") XCTAssertEqual(secondTopic.replies?.count, 2, "Unexpected topic items count") } if let thirdTopic = topics?[3] as? TalkPageTopic { XCTAssertEqual(thirdTopic.title, "Sub sub topic") XCTAssertEqual(thirdTopic.replies?.count, 2, "Unexpected topic items count") } if let fourthTopic = topics?[4] as? TalkPageTopic { XCTAssertEqual(fourthTopic.title, "Topic Part Deux") XCTAssertEqual(fourthTopic.replies?.count, 9, "Unexpected topic items count") } if let fifthTopic = topics?[5] as? TalkPageTopic { XCTAssertEqual(fifthTopic.title, "Topic Part Trois") XCTAssertEqual(fifthTopic.replies?.count, 1, "Unexpected topic items count") } // confirm one talk page exists in DB guard let secondResults = try? tempDataStore.viewContext.fetch(fetchRequest) else { XCTFail("Failure fetching saved talk pages") return } XCTAssertEqual(secondResults.count, 1, "Expected 1 talk page in DB") XCTAssertEqual(secondResults.first, dbTalkPage) } func testExistingTalkPagePullsFromDB() { // confirm no talk pages in DB let fetchRequest: NSFetchRequest = TalkPage.fetchRequest() guard let firstResults = try? tempDataStore.viewContext.fetch(fetchRequest) else { XCTFail("Failure fetching initial talk pages") return } XCTAssertEqual(firstResults.count, 0, "Expected zero existing talk pages at first") // add network talk page guard let json = wmf_bundle().wmf_data(fromContentsOfFile: TalkPageTestHelpers.TalkPageJSONType.original.fileName, ofType: "json"), let talkPage = TalkPageTestHelpers.networkTalkPage(for: urlString1, data: json, revisionId: 1) else { XCTFail("Failure stubbing out network talk page") return } // create db talk page guard let dbTalkPage = moc.createTalkPage(with: talkPage) else { XCTFail("Failure to create db talk page") return } // confirm asking for existing talk page with key pulls same talk page guard let existingTalkPage = try? moc.talkPage(for: URL(string: urlString1)!) else { XCTFail("Pull existing talk page fails") return } XCTAssertEqual(existingTalkPage, dbTalkPage, "Unexpected existing talk page value") // confirm asking for urlString2 pulls nothing do { let nonexistantTalkPage = try moc.talkPage(for: URL(string: urlString2)!) XCTAssertNil(nonexistantTalkPage) } catch { XCTFail("Pull existing talk page fails") } } func testUpdateExistingTalkPageUpdatesValues() { // confirm no talk pages in DB let fetchRequest: NSFetchRequest = TalkPage.fetchRequest() guard let firstResults = try? tempDataStore.viewContext.fetch(fetchRequest) else { XCTFail("Failure fetching initial talk pages") return } XCTAssertEqual(firstResults.count, 0, "Expected zero existing talk pages at first") // add network talk page guard let originalJson = wmf_bundle().wmf_data(fromContentsOfFile: TalkPageTestHelpers.TalkPageJSONType.original.fileName, ofType: "json"), let talkPage = TalkPageTestHelpers.networkTalkPage(for: urlString1, data: originalJson, revisionId: 1) else { XCTFail("Failure stubbing out network talk page") return } // create db talk page guard let dbTalkPage = moc.createTalkPage(with: talkPage) else { XCTFail("Failure to create db talk page") return } // mark last topic as read to confirm it stays read after updating. let topics = dbTalkPage.topics?.allObjects.sorted { ($0 as! TalkPageTopic).sort < ($1 as! TalkPageTopic).sort } if let fifthTopic = topics?[5] as? TalkPageTopic { fifthTopic.content?.isRead = true do { try moc.save() } catch { XCTFail("Failure to save isRead flag") } } // get updated talk page payload guard let updatedJson = wmf_bundle().wmf_data(fromContentsOfFile: TalkPageTestHelpers.TalkPageJSONType.updated.fileName, ofType: "json"), let updatedTalkPage = TalkPageTestHelpers.networkTalkPage(for: urlString1, data: updatedJson, revisionId: 1) else { XCTFail("Failure stubbing out network talk page") return } // update local talk page with new talk page guard let updatedDbTalkPage = moc.updateTalkPage(dbTalkPage, with: updatedTalkPage) else { XCTFail("Failure updating existing local talk page") return } XCTAssertEqual(updatedDbTalkPage.topics?.count, 3, "Unexpected topic count") let updatedTopics = updatedDbTalkPage.topics?.allObjects.sorted { ($0 as! TalkPageTopic).sort < ($1 as! TalkPageTopic).sort } if let introTopic = updatedTopics?[0] as? TalkPageTopic { XCTAssertEqual(introTopic.title, "", "Unexpected topic title") XCTAssertEqual(introTopic.replies?.count, 1, "Unexpected replies count") let replies = introTopic.replies?.allObjects.sorted { ($0 as! TalkPageReply).sort < ($1 as! TalkPageReply).sort } if let firstReply = replies?[0] as? TalkPageReply { XCTAssertEqual(firstReply.text, "Hello! This is some introduction text on my talk page. L8erz, TSevener (WMF) (talk) 20:48, 21 June 2019 (UTC)", "Unexpected replies html") } else { XCTFail("Unexpected first reply type") } } else { XCTFail("Unexpected intro topic type") } if let firstTopic = updatedTopics?[1] as? TalkPageTopic { XCTAssertEqual(firstTopic.title, "Topic Part Deux", "Unexpected topic title") XCTAssertEqual(firstTopic.replies?.count, 11, "Unexpected topic items count") let replies = firstTopic.replies?.allObjects.sorted { ($0 as! TalkPageReply).sort < ($1 as! TalkPageReply).sort } if let firstReply = replies?[0] as? TalkPageReply { XCTAssertEqual(firstReply.text, "Also injecting something in the front because why not. 🤷‍♀️ TSevener (WMF) (talk) 21:17, 21 June 2019 (UTC)") XCTAssertEqual(firstReply.depth, 0, "Unexpected reply depth") } else { XCTFail("Unexpected first reply type") } if let secondReply = replies?[1] as? TalkPageReply { XCTAssertEqual(secondReply.text, "Ok try this on for size - can you put a link in a topic title from the iOS app? Only time will tell. 47.184.10.84 20:57, 21 June 2019 (UTC)") XCTAssertEqual(secondReply.depth, 0, "Unexpected reply depth") } else { XCTFail("Unexpected second reply type") } if let thirdReply = replies?[2] as? TalkPageReply { XCTAssertEqual(thirdReply.text, "It certainly seems so. It is good we tested this my friend. TSevener (WMF) (talk) 20:58, 21 June 2019 (UTC)") XCTAssertEqual(thirdReply.depth, 1, "Unexpected reply depth") } else { XCTFail("Unexpected third reply type") } } else { XCTFail("Unexpected first topic type") } if let secondTopic = updatedTopics?[2] as? TalkPageTopic { XCTAssertEqual(secondTopic.title, "Topic Part Trois") XCTAssertEqual(secondTopic.replies?.count, 1, "Unexpected topic items count") XCTAssertTrue(secondTopic.content?.isRead ?? false, "isRead flag flipped back to false after reorder.") } // confirm one talk page exists in DB guard let secondResults = try? tempDataStore.viewContext.fetch(fetchRequest) else { XCTFail("Failure fetching saved talk pages") return } XCTAssertEqual(secondResults.count, 1, "Expected 1 talk page in DB") XCTAssertEqual(secondResults.first, dbTalkPage) } }