deep-linking-sample/Apps/Wikipedia/WikipediaUnitTests/Code/TalkPageControllerTests.swift

444 lines
18 KiB
Swift
Raw Normal View History

import XCTest
@testable import Wikipedia
@testable import WMF
fileprivate class MockTalkPageFetcher: OldTalkPageFetcher {
static var name = "Username1"
static var domain = "en.wikipedia.org"
var fetchCalled = false
private let data: Data
required init(session: Session, configuration: Configuration, data: Data) {
self.data = data
super.init(session: session, configuration: configuration)
}
required init(session: Session, configuration: Configuration) {
fatalError("init(session:configuration:) has not been implemented")
}
override func fetchTalkPage(urlTitle: String, displayTitle: String, siteURL: URL, revisionID: Int?, completion: @escaping (Result<NetworkTalkPage, Error>) -> Void) {
fetchCalled = true
if let networkTalkPage = TalkPageTestHelpers.networkTalkPage(for: "https://\(MockTalkPageFetcher.domain)/api/rest_v1/page/talk/\(urlTitle)", data: data, revisionId: MockArticleRevisionFetcher.revisionId) {
completion(.success(networkTalkPage))
} else {
XCTFail("Expected network talk page from helper")
}
}
}
fileprivate class MockArticleRevisionFetcher: WMFArticleRevisionFetcher {
static var revisionId: Int = 894272715
var resultsDictionary: [AnyHashable : Any] {
return ["batchcomplete": 1,
"query" : ["pages": [
["ns": 0,
"pageid": 2360669,
"revisions": [
["minor": 1,
"parentid": 894272641,
"revid": MockArticleRevisionFetcher.revisionId,
"size": 61252]
],
"title": "Benty Grange helmet"
]
]
]
]
}
override func fetchLatestRevisions(forArticleURL articleURL: URL!, resultLimit numberOfResults: UInt, startingWithRevision startRevisionId: NSNumber, endingWithRevision endRevisionId: NSNumber, failure: WMFErrorHandler!, success: WMFSuccessIdHandler!) -> URLSessionTask? {
do {
let revisionQueryResults = try WMFLegacySerializer.models(of: WMFRevisionQueryResults.self, fromArrayForKeyPath: "query.pages", inJSONDictionary: resultsDictionary, languageVariantCode: articleURL.wmf_languageVariantCode)
success(revisionQueryResults)
return nil
} catch {
XCTFail("Failure to create WMFRevisionQueryResults")
}
return nil
}
}
class TalkPageControllerTests: XCTestCase {
var tempDataStore: MWKDataStore!
var talkPageController: OldTalkPageController!
fileprivate var talkPageFetcher: MockTalkPageFetcher!
fileprivate var articleRevisionFetcher: MockArticleRevisionFetcher!
override func setUp() {
super.setUp()
tempDataStore = MWKDataStore.temporary()
if let data = wmf_bundle().wmf_data(fromContentsOfFile: TalkPageTestHelpers.TalkPageJSONType.original.fileName, ofType: "json") {
talkPageFetcher = MockTalkPageFetcher(session: tempDataStore.session, configuration: tempDataStore.configuration, data: data)
} else {
XCTFail("Failure setting up MockTalkPageFetcher")
}
articleRevisionFetcher = MockArticleRevisionFetcher()
talkPageController = OldTalkPageController(fetcher: talkPageFetcher, articleRevisionFetcher: articleRevisionFetcher, moc: tempDataStore.viewContext, title: "User talk:Username1", siteURL: URL(string: "https://en.wikipedia.org")!, type: .user)
MockArticleRevisionFetcher.revisionId = 894272715
}
override func tearDown() {
tempDataStore.removeFolderAtBasePath()
let fetchRequest: NSFetchRequest<TalkPage> = TalkPage.fetchRequest()
guard let firstResults = try? tempDataStore.viewContext.fetch(fetchRequest) else {
XCTFail("Unable to fetch results from fetch request")
return
}
for talkPage in firstResults {
tempDataStore.viewContext.delete(talkPage)
}
do {
try tempDataStore.save()
} catch {
XCTFail("Failure saving temporary data store")
}
tempDataStore = nil
super.tearDown()
}
func testInitialFetchSavesRecordInDB() {
// confirm no talk pages in DB at first
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")
let initialFetchCallback = expectation(description: "Waiting for initial fetch callback")
talkPageController.fetchTalkPage { (result) in
initialFetchCallback.fulfill()
switch result {
case .success(let dbTalkPageID):
// fetch from db again, confirm count is 1 and matches returned talk page
let fetchRequest: NSFetchRequest<TalkPage> = TalkPage.fetchRequest()
guard let results = try? self.tempDataStore.viewContext.fetch(fetchRequest) else {
XCTFail("Failure fetching initial talk pages")
return
}
let dbTalkPage = try? self.tempDataStore.viewContext.existingObject(with: dbTalkPageID.objectID) as? TalkPage
XCTAssertEqual(results.count, 1, "Expected one talk page in DB")
XCTAssertEqual(results.first, dbTalkPage)
XCTAssertEqual(dbTalkPage?.revisionId?.intValue, MockArticleRevisionFetcher.revisionId)
case .failure:
XCTFail("TalkPageController fetchTalkPage failure")
}
}
wait(for: [initialFetchCallback], timeout: 5)
}
/* //todo: this fails when run consecutively
func testFetchSameUserTwiceDoesNotAddMultipleTalkPageRecords() {
//confirm no talk pages in DB at first
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")
let initialFetchCallback = expectation(description: "Waiting for initial fetch callback")
talkPageController.fetchTalkPage { (result) in
initialFetchCallback.fulfill()
switch result {
case .success(let dbTalkPage):
//confirm count is 1 and matches returned talk page
let fetchRequest: NSFetchRequest<TalkPage> = TalkPage.fetchRequest()
guard let results = try? self.tempDataStore.viewContext.fetch(fetchRequest) else {
XCTFail("Failure fetching initial talk pages")
return
}
XCTAssertEqual(results.count, 1, "Expected one talk page in DB")
XCTAssertEqual(results.first, dbTalkPage)
case .failure:
XCTFail("TalkPageController fetchTalkPage failure")
}
}
wait(for: [initialFetchCallback], timeout: 5)
//same fetch again
let nextFetchCallback = expectation(description: "Waiting for next fetch callback")
talkPageController.fetchTalkPage { (result) in
nextFetchCallback.fulfill()
switch result {
case .success(let dbTalkPage):
//fetch from db again, confirm count is still 1 and matches returned talk page
let fetchRequest: NSFetchRequest<TalkPage> = TalkPage.fetchRequest()
guard let results = try? self.tempDataStore.viewContext.fetch(fetchRequest) else {
XCTFail("Failure fetching initial talk pages")
return
}
XCTAssertEqual(results.count, 1, "Expected one talk page in DB")
XCTAssertEqual(results.first, dbTalkPage)
case .failure:
XCTFail("TalkPageController fetchTalkPage failure")
}
}
wait(for: [nextFetchCallback], timeout: 5)
}
*/
func testFetchSameUserDifferentLanguageAddsMultipleTalkPageRecords() {
let initialFetchCallback = expectation(description: "Waiting for initial fetch callback")
talkPageController.fetchTalkPage { (result) in
initialFetchCallback.fulfill()
switch result {
case .success(let dbTalkPageID):
// fetch from db again, confirm count is 1 and matches returned talk page
let fetchRequest: NSFetchRequest<TalkPage> = TalkPage.fetchRequest()
guard let results = try? self.tempDataStore.viewContext.fetch(fetchRequest) else {
XCTFail("Failure fetching initial talk pages")
return
}
XCTAssertEqual(results.count, 1, "Expected one talk page in DB")
XCTAssertEqual(results.first?.objectID, dbTalkPageID.objectID)
case .failure:
XCTFail("TalkPageController fetchTalkPage failure")
}
}
wait(for: [initialFetchCallback], timeout: 5)
// fetch again for ES language
MockTalkPageFetcher.domain = "es.wikipedia.org"
talkPageController = OldTalkPageController(fetcher: talkPageFetcher, articleRevisionFetcher: articleRevisionFetcher, moc: tempDataStore.viewContext, title: "User talk:Username1", siteURL: URL(string: "https://es.wikipedia.org")!, type: .user)
let nextFetchCallback = expectation(description: "Waiting for next fetch callback")
talkPageController.fetchTalkPage { (result) in
nextFetchCallback.fulfill()
switch result {
case .success:
let fetchRequest: NSFetchRequest<TalkPage> = TalkPage.fetchRequest()
guard let results = try? self.tempDataStore.viewContext.fetch(fetchRequest) else {
XCTFail("Failure fetching initial talk pages")
return
}
XCTAssertEqual(results.count, 2, "Expected two talk pages in DB")
case .failure:
XCTFail("TalkPageController fetchTalkPage failure")
}
}
wait(for: [nextFetchCallback], timeout: 5)
}
func testFetchDifferentUserSameLanguageAddsMultipleTalkPageRecords() {
let initialFetchCallback = expectation(description: "Waiting for initial fetch callback")
talkPageController.fetchTalkPage { (result) in
initialFetchCallback.fulfill()
switch result {
case .success:
// fetch from db again, confirm count is 1 and matches returned talk page
let fetchRequest: NSFetchRequest<TalkPage> = TalkPage.fetchRequest()
guard let results = try? self.tempDataStore.viewContext.fetch(fetchRequest) else {
XCTFail("Failure fetching initial talk pages")
return
}
XCTAssertEqual(results.count, 1, "Expected one talk page in DB")
case .failure:
XCTFail("TalkPageController fetchTalkPage failure")
}
}
wait(for: [initialFetchCallback], timeout: 5)
MockTalkPageFetcher.name = "Username2"
talkPageController = OldTalkPageController(fetcher: talkPageFetcher, articleRevisionFetcher: articleRevisionFetcher, moc: tempDataStore.viewContext, title: "User talk:Username2", siteURL: URL(string: "https://en.wikipedia.org")!, type: .user)
let nextFetchCallback = expectation(description: "Waiting for next fetch callback")
talkPageController.fetchTalkPage { (result) in
nextFetchCallback.fulfill()
switch result {
case .success:
let fetchRequest: NSFetchRequest<TalkPage> = TalkPage.fetchRequest()
guard let results = try? self.tempDataStore.viewContext.fetch(fetchRequest) else {
XCTFail("Failure fetching initial talk pages")
return
}
XCTAssertEqual(results.count, 2, "Expected two talk pages in DB")
case .failure:
XCTFail("TalkPageController fetchTalkPage failure")
}
}
wait(for: [nextFetchCallback], timeout: 5)
}
func testFetchSameRevisionIdDoesNotCallFetcher() {
// confirm no talk pages in DB at first
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")
// initial fetch to populate DB
let initialFetchCallback = expectation(description: "Waiting for initial fetch callback")
var firstDBTalkPage: TalkPage?
talkPageController.fetchTalkPage { (result) in
initialFetchCallback.fulfill()
switch result {
case .success(let dbTalkPageID):
let dbTalkPage = try? self.tempDataStore.viewContext.existingObject(with: dbTalkPageID.objectID) as? TalkPage
firstDBTalkPage = dbTalkPage
XCTAssertEqual(dbTalkPage?.revisionId?.intValue, MockArticleRevisionFetcher.revisionId)
XCTAssertTrue(self.talkPageFetcher.fetchCalled, "Expected fetcher to be called for initial fetch")
case .failure:
XCTFail("TalkPageController fetchTalkPage failure")
}
}
wait(for: [initialFetchCallback], timeout: 5)
// reset fetchCalled
talkPageFetcher.fetchCalled = false
// make same fetch again, same revision ID. Confirm fetcher was never called and same talk page is returned
let secondFetchCallback = expectation(description: "Waiting for initial fetch callback")
talkPageController.fetchTalkPage { (result) in
switch result {
case .success(let dbTalkPageID):
guard !dbTalkPageID.isInitialLocalResult else {
return
}
let dbTalkPage = try? self.tempDataStore.viewContext.existingObject(with: dbTalkPageID.objectID) as? TalkPage
XCTAssertEqual(firstDBTalkPage, dbTalkPage)
XCTAssertEqual(dbTalkPage?.revisionId?.intValue, MockArticleRevisionFetcher.revisionId)
XCTAssertFalse(self.talkPageFetcher.fetchCalled, "Expected fetcher to not be called for second fetch")
case .failure:
XCTFail("TalkPageController fetchTalkPage failure")
}
secondFetchCallback.fulfill()
}
wait(for: [secondFetchCallback], timeout: 5)
}
/* //todo: this fails when run consecutively
func testIncrementedRevisionDoesCallFetcher() {
//confirm no talk pages in DB at first
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")
//initial fetch to populate DB
let initialFetchCallback = expectation(description: "Waiting for initial fetch callback")
var firstDBTalkPage: TalkPage?
talkPageController.fetchTalkPage { (result) in
initialFetchCallback.fulfill()
switch result {
case .success(let dbTalkPage):
firstDBTalkPage = dbTalkPage
XCTAssertEqual(dbTalkPage.revisionId, MockArticleRevisionFetcher.revisionId)
XCTAssertTrue(self.talkPageFetcher.fetchCalled, "Expected fetcher to be called for initial fetch")
case .failure:
XCTFail("TalkPageController fetchTalkPage failure")
}
}
wait(for: [initialFetchCallback], timeout: 5)
//reset fetchCalled
talkPageFetcher.fetchCalled = false
MockArticleRevisionFetcher.revisionId += 1
//make same fetch again, same revision ID. Confirm fetcher was never called and same talk page is returned
let secondFetchCallback = expectation(description: "Waiting for initial fetch callback")
talkPageController.fetchTalkPage { (result) in
secondFetchCallback.fulfill()
switch result {
case .success(let dbTalkPage):
XCTAssertEqual(firstDBTalkPage, dbTalkPage)
XCTAssertEqual(dbTalkPage.revisionId, MockArticleRevisionFetcher.revisionId)
XCTAssertTrue(self.talkPageFetcher.fetchCalled, "Expected fetcher to be called for second fetch")
case .failure:
XCTFail("TalkPageController fetchTalkPage failure")
}
}
wait(for: [secondFetchCallback], timeout: 5)
}
*/
}