Compare commits
13 Commits
7f6112da45
...
2ed93e447a
Author | SHA1 | Date |
---|---|---|
Brent Simmons | 2ed93e447a | |
Brent Simmons | 16ed322209 | |
Brent Simmons | c491fd2b88 | |
Brent Simmons | d962fc5e1e | |
Brent Simmons | 45c08cd155 | |
Brent Simmons | a579126e92 | |
Brent Simmons | d024e6049d | |
Brent Simmons | 5760705784 | |
Brent Simmons | 544dcf651d | |
Brent Simmons | efe413bef7 | |
Brent Simmons | c75f3a8e88 | |
Brent Simmons | 6adbc8245d | |
Brent Simmons | 66e169d552 |
|
@ -409,7 +409,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||
|
||||
func updateAccountFeeds(parsedItems: Set<ParsedItem>) async throws {
|
||||
|
||||
let feedIDsAndItems = parsedItemsKeyedByFeedURL(parsedItems)
|
||||
let feedIDsAndItems = FeedlyUtilities.parsedItemsKeyedByFeedURL(parsedItems)
|
||||
try await updateAccountFeedsWithItems(feedIDsAndItems: feedIDsAndItems)
|
||||
}
|
||||
|
||||
|
@ -451,26 +451,6 @@ final class FeedlyAccountDelegate: AccountDelegate {
|
|||
return feedsAndFolders
|
||||
}
|
||||
|
||||
func parsedItemsKeyedByFeedURL(_ parsedItems: Set<ParsedItem>) -> [String: Set<ParsedItem>] {
|
||||
|
||||
var d = [String: Set<ParsedItem>]()
|
||||
|
||||
for parsedItem in parsedItems {
|
||||
let key = parsedItem.feedURL
|
||||
let value: Set<ParsedItem> = {
|
||||
if var items = d[key] {
|
||||
items.insert(parsedItem)
|
||||
return items
|
||||
} else {
|
||||
return [parsedItem]
|
||||
}
|
||||
}()
|
||||
d[key] = value
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
func downloadArticles(missingArticleIDs: Set<String>?, updatedArticleIDs: Set<String>?) async throws {
|
||||
|
||||
let allArticleIDs: Set<String> = {
|
||||
|
|
|
@ -1,116 +0,0 @@
|
|||
//
|
||||
// FeedlyGetStreamIDsOperationTests.swift
|
||||
// AccountTests
|
||||
//
|
||||
// Created by Kiel Gillard on 23/10/19.
|
||||
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Account
|
||||
|
||||
class FeedlyGetStreamIDsOperationTests: XCTestCase {
|
||||
|
||||
private var account: Account!
|
||||
private let support = FeedlyTestSupport()
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
account = support.makeTestAccount()
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
if let account = account {
|
||||
support.destroy(account)
|
||||
}
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
func testGetStreamIDsFailure() {
|
||||
let service = TestGetStreamIDsService()
|
||||
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
|
||||
|
||||
let getStreamIDs = FeedlyGetStreamIDsOperation(account: account, resource: resource, service: service, continuation: nil, newerThan: nil, unreadOnly: nil, log: support.log)
|
||||
|
||||
service.mockResult = .failure(URLError(.fileDoesNotExist))
|
||||
|
||||
let completionExpectation = expectation(description: "Did Finish")
|
||||
getStreamIDs.completionBlock = { _ in
|
||||
completionExpectation.fulfill()
|
||||
}
|
||||
|
||||
MainThreadOperationQueue.shared.add(getStreamIDs)
|
||||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
XCTAssertNil(getStreamIDs.streamIDs)
|
||||
}
|
||||
|
||||
func testValuesPassingForGetStreamIDs() {
|
||||
let service = TestGetStreamIDsService()
|
||||
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
|
||||
|
||||
let continuation: String? = "gfdsa"
|
||||
let newerThan: Date? = Date(timeIntervalSinceReferenceDate: 1000)
|
||||
let unreadOnly: Bool? = false
|
||||
|
||||
let getStreamIDs = FeedlyGetStreamIDsOperation(account: account, resource: resource, service: service, continuation: continuation, newerThan: newerThan, unreadOnly: unreadOnly, log: support.log)
|
||||
|
||||
let mockStreamIDs = FeedlyStreamIDs(continuation: "1234", ids: ["item/1", "item/2", "item/3"])
|
||||
service.mockResult = .success(mockStreamIDs)
|
||||
service.getStreamIDsExpectation = expectation(description: "Did Call Service")
|
||||
service.parameterTester = { serviceResource, serviceContinuation, serviceNewerThan, serviceUnreadOnly in
|
||||
// Verify these values given to the operation are passed to the service.
|
||||
XCTAssertEqual(serviceResource.id, resource.id)
|
||||
XCTAssertEqual(serviceContinuation, continuation)
|
||||
XCTAssertEqual(serviceNewerThan, newerThan)
|
||||
XCTAssertEqual(serviceUnreadOnly, unreadOnly)
|
||||
}
|
||||
|
||||
let completionExpectation = expectation(description: "Did Finish")
|
||||
getStreamIDs.completionBlock = { _ in
|
||||
completionExpectation.fulfill()
|
||||
}
|
||||
|
||||
MainThreadOperationQueue.shared.add(getStreamIDs)
|
||||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
guard let streamIDs = getStreamIDs.streamIDs else {
|
||||
XCTFail("\(FeedlyGetStreamIDsOperation.self) did not store the stream.")
|
||||
return
|
||||
}
|
||||
|
||||
XCTAssertEqual(streamIDs.continuation, mockStreamIDs.continuation)
|
||||
XCTAssertEqual(streamIDs.ids, mockStreamIDs.ids)
|
||||
}
|
||||
|
||||
func testGetStreamIDsFromJSON() {
|
||||
let support = FeedlyTestSupport()
|
||||
let (transport, caller) = support.makeMockNetworkStack()
|
||||
let jsonName = "JSON/feedly_unreads_1000"
|
||||
transport.testFiles["/v3/streams/ids"] = "\(jsonName).json"
|
||||
|
||||
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
|
||||
let getStreamIDs = FeedlyGetStreamIDsOperation(account: account, resource: resource, service: caller, continuation: nil, newerThan: nil, unreadOnly: nil, log: support.log)
|
||||
|
||||
let completionExpectation = expectation(description: "Did Finish")
|
||||
getStreamIDs.completionBlock = { _ in
|
||||
completionExpectation.fulfill()
|
||||
}
|
||||
|
||||
MainThreadOperationQueue.shared.add(getStreamIDs)
|
||||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
guard let streamIDs = getStreamIDs.streamIDs else {
|
||||
return XCTFail("Expected to have a stream of identifiers.")
|
||||
}
|
||||
|
||||
let streamIDsJSON = support.testJSON(named: jsonName) as! [String:Any]
|
||||
|
||||
let continuation = streamIDsJSON["continuation"] as! String
|
||||
XCTAssertEqual(streamIDs.continuation, continuation)
|
||||
XCTAssertEqual(streamIDs.ids, streamIDsJSON["ids"] as! [String])
|
||||
}
|
||||
}
|
|
@ -51,47 +51,6 @@ class FeedlyLogoutOperationTests: XCTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
func testCancel() {
|
||||
let service = TestFeedlyLogoutService()
|
||||
service.logoutExpectation = expectation(description: "Did Call Logout")
|
||||
service.logoutExpectation?.isInverted = true
|
||||
|
||||
let accessToken: Credentials
|
||||
let refreshToken: Credentials
|
||||
do {
|
||||
(accessToken, refreshToken) = try getTokens(for: account)
|
||||
} catch {
|
||||
XCTFail("Could not retrieve credentials to verify their integrity later.")
|
||||
return
|
||||
}
|
||||
|
||||
let logout = FeedlyLogoutOperation(account: account, service: service, log: support.log)
|
||||
|
||||
// If this expectation is not fulfilled, the operation is not calling `didFinish`.
|
||||
let completionExpectation = expectation(description: "Did Finish")
|
||||
logout.completionBlock = { _ in
|
||||
completionExpectation.fulfill()
|
||||
}
|
||||
|
||||
MainThreadOperationQueue.shared.add(logout)
|
||||
|
||||
MainThreadOperationQueue.shared.cancelOperations([logout])
|
||||
|
||||
waitForExpectations(timeout: 1)
|
||||
|
||||
XCTAssertTrue(logout.isCanceled)
|
||||
|
||||
do {
|
||||
let accountAccessToken = try account.retrieveCredentials(type: .oauthAccessToken)
|
||||
let accountRefreshToken = try account.retrieveCredentials(type: .oauthRefreshToken)
|
||||
|
||||
XCTAssertEqual(accountAccessToken, accessToken)
|
||||
XCTAssertEqual(accountRefreshToken, refreshToken)
|
||||
} catch {
|
||||
XCTFail("Could not verify tokens were left intact. Did the operation delete them?")
|
||||
}
|
||||
}
|
||||
|
||||
func testLogoutSuccess() {
|
||||
let service = TestFeedlyLogoutService()
|
||||
service.logoutExpectation = expectation(description: "Did Call Logout")
|
||||
|
|
|
@ -1,98 +0,0 @@
|
|||
//
|
||||
// FeedlyOrganiseParsedItemsByFeedOperationTests.swift
|
||||
// AccountTests
|
||||
//
|
||||
// Created by Kiel Gillard on 24/10/19.
|
||||
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Account
|
||||
import Parser
|
||||
|
||||
class FeedlyOrganiseParsedItemsByFeedOperationTests: XCTestCase {
|
||||
|
||||
private var account: Account!
|
||||
private let support = FeedlyTestSupport()
|
||||
|
||||
override func setUp() {
|
||||
super.setUp()
|
||||
account = support.makeTestAccount()
|
||||
}
|
||||
|
||||
override func tearDown() {
|
||||
if let account = account {
|
||||
support.destroy(account)
|
||||
}
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
struct TestParsedItemsProvider: FeedlyParsedItemProviding {
|
||||
let parsedItemProviderName = "TestParsedItemsProvider"
|
||||
var resource: FeedlyResourceID
|
||||
var parsedEntries: Set<ParsedItem>
|
||||
}
|
||||
|
||||
func testNoEntries() {
|
||||
let entries = support.makeParsedItemTestDataFor(numberOfFeeds: 0, numberOfItemsInFeeds: 0)
|
||||
let resource = FeedlyCategoryResourceID(id: "user/12345/category/6789")
|
||||
let parsedEntries = Set(entries.values.flatMap { $0 })
|
||||
let provider = TestParsedItemsProvider(resource: resource, parsedEntries: parsedEntries)
|
||||
|
||||
let organise = FeedlyOrganiseParsedItemsByFeedOperation(account: account, parsedItemProvider: provider, log: support.log)
|
||||
|
||||
let completionExpectation = expectation(description: "Did Finish")
|
||||
organise.completionBlock = { _ in
|
||||
completionExpectation.fulfill()
|
||||
}
|
||||
|
||||
MainThreadOperationQueue.shared.add(organise)
|
||||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
let itemsAndFeedIDs = organise.parsedItemsKeyedByFeedID
|
||||
XCTAssertEqual(itemsAndFeedIDs, entries)
|
||||
}
|
||||
|
||||
func testGroupsOneEntryByFeedId() {
|
||||
let entries = support.makeParsedItemTestDataFor(numberOfFeeds: 1, numberOfItemsInFeeds: 1)
|
||||
let resource = FeedlyCategoryResourceID(id: "user/12345/category/6789")
|
||||
let parsedEntries = Set(entries.values.flatMap { $0 })
|
||||
let provider = TestParsedItemsProvider(resource: resource, parsedEntries: parsedEntries)
|
||||
|
||||
let organise = FeedlyOrganiseParsedItemsByFeedOperation(account: account, parsedItemProvider: provider, log: support.log)
|
||||
|
||||
let completionExpectation = expectation(description: "Did Finish")
|
||||
organise.completionBlock = { _ in
|
||||
completionExpectation.fulfill()
|
||||
}
|
||||
|
||||
MainThreadOperationQueue.shared.add(organise)
|
||||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
let itemsAndFeedIDs = organise.parsedItemsKeyedByFeedID
|
||||
XCTAssertEqual(itemsAndFeedIDs, entries)
|
||||
}
|
||||
|
||||
func testGroupsManyEntriesByFeedId() {
|
||||
let entries = support.makeParsedItemTestDataFor(numberOfFeeds: 100, numberOfItemsInFeeds: 100)
|
||||
let resource = FeedlyCategoryResourceID(id: "user/12345/category/6789")
|
||||
let parsedEntries = Set(entries.values.flatMap { $0 })
|
||||
let provider = TestParsedItemsProvider(resource: resource, parsedEntries: parsedEntries)
|
||||
|
||||
let organise = FeedlyOrganiseParsedItemsByFeedOperation(account: account, parsedItemProvider: provider, log: support.log)
|
||||
|
||||
let completionExpectation = expectation(description: "Did Finish")
|
||||
organise.completionBlock = { _ in
|
||||
completionExpectation.fulfill()
|
||||
}
|
||||
|
||||
MainThreadOperationQueue.shared.add(organise)
|
||||
|
||||
waitForExpectations(timeout: 2)
|
||||
|
||||
let itemsAndFeedIDs = organise.parsedItemsKeyedByFeedID
|
||||
XCTAssertEqual(itemsAndFeedIDs, entries)
|
||||
}
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
//
|
||||
// FeedlyTestSecrets.swift
|
||||
//
|
||||
//
|
||||
// Created by Maurice Parker on 8/4/20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Secrets
|
||||
|
||||
struct FeedlyTestSecrets: SecretsProvider {
|
||||
var mercuryClientId = ""
|
||||
var mercuryClientSecret = ""
|
||||
var feedlyClientId = ""
|
||||
var feedlyClientSecret = ""
|
||||
var inoreaderAppId = ""
|
||||
var inoreaderAppKey = ""
|
||||
}
|
|
@ -271,41 +271,4 @@ class FeedlyTestSupport {
|
|||
XCTAssertEqual(items.count, entries.count)
|
||||
XCTAssertTrue(missing.isEmpty, "Failed to create \(FeedlyEntry.self) values from objects in the JSON with these ids.")
|
||||
}
|
||||
|
||||
func makeParsedItemTestDataFor(numberOfFeeds: Int, numberOfItemsInFeeds: Int) -> [String: Set<ParsedItem>] {
|
||||
let ids = (0..<numberOfFeeds).map { "feed/\($0)" }
|
||||
let feedIDsAndItemCounts = ids.map { ($0, numberOfItemsInFeeds) }
|
||||
|
||||
let entries = feedIDsAndItemCounts.map { (feedId, count) -> (String, [Int]) in
|
||||
return (feedId, (0..<count).map { $0 })
|
||||
|
||||
}.map { pair -> (String, Set<ParsedItem>) in
|
||||
let items = pair.1.map { index -> ParsedItem in
|
||||
ParsedItem(syncServiceID: "\(pair.0)/articles/\(index)",
|
||||
uniqueID: UUID().uuidString,
|
||||
feedURL: pair.0,
|
||||
url: "http://localhost/",
|
||||
externalURL: "http://localhost/\(pair.0)/articles/\(index).html",
|
||||
title: "Title\(index)",
|
||||
language: nil,
|
||||
contentHTML: "Content \(index) HTML.",
|
||||
contentText: "Content \(index) Text",
|
||||
summary: nil,
|
||||
imageURL: nil,
|
||||
bannerImageURL: nil,
|
||||
datePublished: nil,
|
||||
dateModified: nil,
|
||||
authors: nil,
|
||||
tags: nil,
|
||||
attachments: nil)
|
||||
}
|
||||
return (pair.0, Set(items))
|
||||
}.reduce([String: Set<ParsedItem>](minimumCapacity: feedIDsAndItemCounts.count)) { (dict, pair) in
|
||||
var mutant = dict
|
||||
mutant[pair.0] = pair.1
|
||||
return mutant
|
||||
}
|
||||
|
||||
return entries
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,11 +8,10 @@
|
|||
|
||||
import Foundation
|
||||
import Web
|
||||
|
||||
@testable import Account
|
||||
|
||||
class TestAccountManager {
|
||||
|
||||
final class TestAccountManager {
|
||||
|
||||
static let shared = TestAccountManager()
|
||||
|
||||
var accountsFolder: URL {
|
||||
|
|
|
@ -258,10 +258,7 @@ public protocol FeedlyAPICallerDelegate: AnyObject {
|
|||
throw URLError(.cannotDecodeContentData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension FeedlyAPICaller {
|
||||
|
||||
@discardableResult
|
||||
@MainActor public func addFeed(with feedID: FeedlyFeedResourceID, title: String? = nil, toCollectionWith collectionID: String) async throws -> [FeedlyFeed] {
|
||||
|
||||
|
@ -294,10 +291,7 @@ extension FeedlyAPICaller {
|
|||
|
||||
return collectionFeeds
|
||||
}
|
||||
}
|
||||
|
||||
extension FeedlyAPICaller {
|
||||
|
||||
/// https://tools.ietf.org/html/rfc6749#section-4.1
|
||||
|
||||
/// Provides the URL request that allows users to consent to the client having access to their information. Typically loaded by a web view.
|
||||
|
@ -338,10 +332,7 @@ extension FeedlyAPICaller {
|
|||
|
||||
return tokenResponse
|
||||
}
|
||||
}
|
||||
|
||||
extension FeedlyAPICaller {
|
||||
|
||||
/// Access tokens expire. Perform a request for a fresh access token given the long life refresh token received when authorization was granted.
|
||||
///
|
||||
/// [Documentation](https://tools.ietf.org/html/rfc6749#section-6)
|
||||
|
@ -362,10 +353,7 @@ extension FeedlyAPICaller {
|
|||
|
||||
return tokenResponse
|
||||
}
|
||||
}
|
||||
|
||||
extension FeedlyAPICaller {
|
||||
|
||||
public func getCollections() async throws -> Set<FeedlyCollection> {
|
||||
|
||||
guard !isSuspended else { throw TransportError.suspended }
|
||||
|
@ -379,10 +367,7 @@ extension FeedlyAPICaller {
|
|||
|
||||
return Set(collections)
|
||||
}
|
||||
}
|
||||
|
||||
extension FeedlyAPICaller {
|
||||
|
||||
@MainActor public func getStreamContents(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?) async throws -> FeedlyStream {
|
||||
|
||||
guard !isSuspended else { throw TransportError.suspended }
|
||||
|
@ -432,10 +417,7 @@ extension FeedlyAPICaller {
|
|||
|
||||
return collections
|
||||
}
|
||||
}
|
||||
|
||||
extension FeedlyAPICaller {
|
||||
|
||||
@MainActor public func getStreamIDs(for resource: FeedlyResourceID, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool?) async throws -> FeedlyStreamIDs {
|
||||
|
||||
guard !isSuspended else { throw TransportError.suspended }
|
||||
|
@ -485,10 +467,7 @@ extension FeedlyAPICaller {
|
|||
|
||||
return collections
|
||||
}
|
||||
}
|
||||
|
||||
extension FeedlyAPICaller {
|
||||
|
||||
@MainActor public func getEntries(for ids: Set<String>) async throws -> [FeedlyEntry] {
|
||||
|
||||
guard !isSuspended else { throw TransportError.suspended }
|
||||
|
@ -505,10 +484,7 @@ extension FeedlyAPICaller {
|
|||
|
||||
return entries
|
||||
}
|
||||
}
|
||||
|
||||
extension FeedlyAPICaller {
|
||||
|
||||
private struct MarkerEntriesBody: Encodable {
|
||||
let type = "entries"
|
||||
var action: String
|
||||
|
@ -533,10 +509,7 @@ extension FeedlyAPICaller {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension FeedlyAPICaller {
|
||||
|
||||
public func getFeeds(for query: String, count: Int, localeIdentifier: String) async throws -> FeedlyFeedsSearchResponse {
|
||||
|
||||
guard !isSuspended else { throw TransportError.suspended }
|
||||
|
@ -563,9 +536,6 @@ extension FeedlyAPICaller {
|
|||
|
||||
return searchResponse
|
||||
}
|
||||
}
|
||||
|
||||
extension FeedlyAPICaller {
|
||||
|
||||
public func logout() async throws {
|
||||
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
//
|
||||
// FeedlyUtilities.swift
|
||||
//
|
||||
//
|
||||
// Created by Brent Simmons on 5/17/24.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Parser
|
||||
|
||||
public final class FeedlyUtilities {
|
||||
|
||||
public static func parsedItemsKeyedByFeedURL(_ parsedItems: Set<ParsedItem>) -> [String: Set<ParsedItem>] {
|
||||
|
||||
var d = [String: Set<ParsedItem>]()
|
||||
|
||||
for parsedItem in parsedItems {
|
||||
let key = parsedItem.feedURL
|
||||
var parsedItems = d[key] ?? Set<ParsedItem>()
|
||||
parsedItems.insert(parsedItem)
|
||||
d[key] = parsedItems
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
}
|
|
@ -7,14 +7,14 @@
|
|||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Account
|
||||
@testable import Feedly
|
||||
|
||||
final class FeedlyEntryParserTests: XCTestCase {
|
||||
|
||||
class FeedlyEntryParserTests: XCTestCase {
|
||||
|
||||
func testParsing() {
|
||||
let content = FeedlyEntry.Content(content: "Test Content", direction: .leftToRight)
|
||||
let summary = FeedlyEntry.Content(content: "Test Summary", direction: .leftToRight)
|
||||
let origin = FeedlyOrigin(title: "Test Feed", streamId: "tests://feeds/1", htmlUrl: nil)
|
||||
let origin = FeedlyOrigin(title: "Test Feed", streamID: "tests://feeds/1", htmlURL: nil)
|
||||
let canonicalLink = FeedlyLink(href: "tests://feeds/1/entries/1", type: "text/html")
|
||||
let tags = [
|
||||
FeedlyTag(id: "tests/tags/1", label: "Tag 1"),
|
||||
|
@ -43,7 +43,7 @@ class FeedlyEntryParserTests: XCTestCase {
|
|||
XCTAssertEqual(parser.title, entry.title)
|
||||
XCTAssertEqual(parser.contentHMTL, content.content)
|
||||
XCTAssertEqual(parser.summary, summary.content)
|
||||
XCTAssertEqual(parser.datePublished, .distantPast)
|
||||
XCTAssertEqual(parser.datePublished, Date.distantPast)
|
||||
XCTAssertEqual(parser.dateModified, Date(timeIntervalSinceReferenceDate: 0))
|
||||
|
||||
guard let item = parser.parsedItemRepresentation else {
|
||||
|
@ -76,7 +76,7 @@ class FeedlyEntryParserTests: XCTestCase {
|
|||
let content = FeedlyEntry.Content(content: "<div style=\"direction:rtl;text-align:right\">Test Content</div>", direction: .rightToLeft)
|
||||
let summaryContent = "Test Summary"
|
||||
let summary = FeedlyEntry.Content(content: "<div style=\"direction:rtl;text-align:right\">\(summaryContent)</div>", direction: .rightToLeft)
|
||||
let origin = FeedlyOrigin(title: "Test Feed", streamId: "tests://feeds/1", htmlUrl: nil)
|
||||
let origin = FeedlyOrigin(title: "Test Feed", streamID: "tests://feeds/1", htmlURL: nil)
|
||||
let title = "Test Entry 1"
|
||||
let entry = FeedlyEntry(id: "tests/feeds/1/entries/1",
|
||||
title: "<div style=\"direction:rtl;text-align:right\">\(title)</div>",
|
|
@ -7,10 +7,10 @@
|
|||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Account
|
||||
@testable import Feedly
|
||||
|
||||
final class FeedlyFeedParserTests: XCTestCase {
|
||||
|
||||
class FeedlyFeedParserTests: XCTestCase {
|
||||
|
||||
func testParsing() {
|
||||
let name = "Test Feed"
|
||||
let website = "tests://nnw/feed/1"
|
|
@ -7,11 +7,11 @@
|
|||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Account
|
||||
@testable import Feedly
|
||||
|
||||
class FeedlyResourceIDTests: XCTestCase {
|
||||
|
||||
func testFeedResourceID() {
|
||||
final class FeedlyResourceIDTests: XCTestCase {
|
||||
|
||||
@MainActor func testFeedResourceID() {
|
||||
let expectedUrl = "http://ranchero.com/blog/atom.xml"
|
||||
|
||||
let feedResource = FeedlyFeedResourceID(id: "feed/\(expectedUrl)")
|
|
@ -7,10 +7,10 @@
|
|||
//
|
||||
|
||||
import XCTest
|
||||
@testable import Account
|
||||
@testable import Feedly
|
||||
|
||||
final class FeedlyTextSanitizationTests: XCTestCase {
|
||||
|
||||
class FeedlyTextSanitizationTests: XCTestCase {
|
||||
|
||||
func testRTLSanitization() {
|
||||
|
||||
let targetsAndExpectations: [(target: String?, expectation: String?)] = [
|
|
@ -0,0 +1,87 @@
|
|||
//
|
||||
// FeedlyUtilitiesTests.swift
|
||||
// AccountTests
|
||||
//
|
||||
// Created by Kiel Gillard on 24/10/19.
|
||||
// Copyright © 2019 Ranchero Software, LLC. All rights reserved.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Parser
|
||||
@testable import Feedly
|
||||
|
||||
final class FeedlyUtilitiesTests: XCTestCase {
|
||||
|
||||
// MARK: - Test parsedItemsKeyedByFeedURL
|
||||
|
||||
func testParsedItemsKeyedByFeedURL_Empty() {
|
||||
|
||||
let testDictionary = makeParsedItemTestDataFor(numberOfFeeds: 0, numberOfItemsInFeeds: 0)
|
||||
let parsedItems = parsedItemsFromDictionary(testDictionary)
|
||||
|
||||
let resultDictionary = FeedlyUtilities.parsedItemsKeyedByFeedURL(parsedItems)
|
||||
let expectedDictionary = testDictionary
|
||||
XCTAssertEqual(resultDictionary, expectedDictionary)
|
||||
}
|
||||
|
||||
func testParsedItemsKeyedByFeedURL_OneFeedOneItem() {
|
||||
|
||||
let testDictionary = makeParsedItemTestDataFor(numberOfFeeds: 1, numberOfItemsInFeeds: 1)
|
||||
let parsedItems = parsedItemsFromDictionary(testDictionary)
|
||||
|
||||
let resultDictionary = FeedlyUtilities.parsedItemsKeyedByFeedURL(parsedItems)
|
||||
let expectedDictionary = testDictionary
|
||||
XCTAssertEqual(resultDictionary, expectedDictionary)
|
||||
}
|
||||
|
||||
func testParsedItemsKeyedByFeedURL_ManyFeedsManyItems() {
|
||||
|
||||
let testDictionary = makeParsedItemTestDataFor(numberOfFeeds: 100, numberOfItemsInFeeds: 100)
|
||||
let parsedItems = parsedItemsFromDictionary(testDictionary)
|
||||
|
||||
let resultDictionary = FeedlyUtilities.parsedItemsKeyedByFeedURL(parsedItems)
|
||||
let expectedDictionary = testDictionary
|
||||
XCTAssertEqual(resultDictionary, expectedDictionary)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private extension FeedlyUtilitiesTests {
|
||||
|
||||
func makeParsedItemTestDataFor(numberOfFeeds: Int, numberOfItemsInFeeds: Int) -> [String: Set<ParsedItem>] {
|
||||
|
||||
var d = [String: Set<ParsedItem>]()
|
||||
|
||||
for feedIndex in 0..<numberOfFeeds {
|
||||
let feedID = "feed/\(feedIndex)"
|
||||
|
||||
var items = Set<ParsedItem>()
|
||||
|
||||
for parsedItemIndex in 0..<numberOfItemsInFeeds {
|
||||
let parsedItem = makeTestParsedItem(feedID, parsedItemIndex)
|
||||
items.insert(parsedItem)
|
||||
}
|
||||
|
||||
d[feedID] = items
|
||||
}
|
||||
|
||||
return d
|
||||
}
|
||||
|
||||
func makeTestParsedItem(_ feedID: String, _ index: Int) -> ParsedItem {
|
||||
|
||||
ParsedItem(syncServiceID: "\(feedID)/articles/\(index)", uniqueID: UUID().uuidString, feedURL: feedID, url: "http://localhost/", externalURL: "http://localhost/\(feedID)/articles/\(index).html", title: "Title\(index)", language: nil, contentHTML: "Content \(index) HTML.", contentText: "Content \(index) Text", summary: nil, imageURL: nil, bannerImageURL: nil, datePublished: nil, dateModified: nil, authors: nil, tags: nil, attachments: nil)
|
||||
}
|
||||
|
||||
func parsedItemsFromDictionary(_ d: [String: Set<ParsedItem>]) -> Set<ParsedItem> {
|
||||
|
||||
var parsedItems = Set<ParsedItem>()
|
||||
|
||||
for (key, value) in d {
|
||||
parsedItems.formUnion(value)
|
||||
}
|
||||
|
||||
return parsedItems
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue