deep-linking-sample/Apps/Wikipedia/WikipediaUnitTests/Code/TalkPageLocalHandlerTests.swift
Javier Cicchelli 9bcdaa697b [Setup] Basic project structure (#1)
This PR contains all the work related to setting up this project as required to implement the [Assignment](https://repo.rock-n-code.com/rock-n-code/deep-linking-assignment/wiki/Assignment) on top, as intended.

To summarise this work:
- [x] created a new **Xcode** project;
- [x] cloned the `Wikipedia` app and inserted it into the **Xcode** project;
- [x] created the `Locations` app and also, its `Libraries` package;
- [x] created the `Shared` package to share dependencies between the apps;
- [x] added a `Makefile` file and implemented some **environment** and **help** commands.

Co-authored-by: Javier Cicchelli <javier@rock-n-code.com>
Reviewed-on: rock-n-code/deep-linking-assignment#1
2023-04-08 18:37:13 +00:00

286 lines
14 KiB
Swift
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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> = 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, <a href='./User:TSevener_(WMF)' title='User:TSevener (WMF)'>TSevener (WMF)</a> (<a href='./User_talk:TSevener_(WMF)' title='User talk:TSevener (WMF)'>talk</a>) 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, "Lets 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 <a href='./IOS' title='IOS'>iOS</a> app. It is fun. <a href='./Special:Contributions/47.184.10.84' title='Special:Contributions/47.184.10.84'>47.184.10.84</a> 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. <a href='./User:TSevener_(WMF)' title='User:TSevener (WMF)'>TSevener (WMF)</a> (<a href='./User_talk:TSevener_(WMF)' title='User talk:TSevener (WMF)'>talk</a>) 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. <a href='./Special:Contributions/47.184.10.84' title='Special:Contributions/47.184.10.84'>47.184.10.84</a> 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 <a href='./Part' title='Part'>Part</a> Deux")
XCTAssertEqual(fourthTopic.replies?.count, 9, "Unexpected topic items count")
}
if let fifthTopic = topics?[5] as? TalkPageTopic {
XCTAssertEqual(fifthTopic.title, "Topic <a href='./Part' title='Part'>Part</a> 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> = 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> = 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, <a href='./User:TSevener_(WMF)' title='User:TSevener (WMF)'>TSevener (WMF)</a> (<a href='./User_talk:TSevener_(WMF)' title='User talk:TSevener (WMF)'>talk</a>) 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 <a href='./Part' title='Part'>Part</a> 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. 🤷‍♀️ <a href='./User:TSevener_(WMF)' title='User:TSevener (WMF)'>TSevener (WMF)</a> (<a href='./User_talk:TSevener_(WMF)' title='User talk:TSevener (WMF)'>talk</a>) 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. <a href='./Special:Contributions/47.184.10.84' title='Special:Contributions/47.184.10.84'>47.184.10.84</a> 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. <a href='./User:TSevener_(WMF)' title='User:TSevener (WMF)'>TSevener (WMF)</a> (<a href='./User_talk:TSevener_(WMF)' title='User talk:TSevener (WMF)'>talk</a>) 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 <a href='./Part' title='Part'>Part</a> 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)
}
}