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
286 lines
14 KiB
Swift
286 lines
14 KiB
Swift
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, "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 <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)
|
||
}
|
||
}
|