Id -> ID renaming.

This commit is contained in:
Brent Simmons 2024-04-07 16:09:23 -07:00
parent c62e3293a6
commit 53215c1f80
70 changed files with 535 additions and 535 deletions

View File

@ -1038,13 +1038,13 @@ private extension FeedbinAccountDelegate {
os_log(.debug, log: log, "Syncing feeds with %ld subscriptions.", subscriptions.count)
let subFeedIds = subscriptions.map { String($0.feedID) }
let subFeedIDs = subscriptions.map { String($0.feedID) }
// Remove any feeds that are no longer in the subscriptions
if let folders = account.folders {
for folder in folders {
for feed in folder.topLevelFeeds {
if !subFeedIds.contains(feed.feedID) {
if !subFeedIDs.contains(feed.feedID) {
folder.removeFeed(feed)
}
}
@ -1052,7 +1052,7 @@ private extension FeedbinAccountDelegate {
}
for feed in account.topLevelFeeds {
if !subFeedIds.contains(feed.feedID) {
if !subFeedIDs.contains(feed.feedID) {
account.removeFeed(feed)
}
}
@ -1061,9 +1061,9 @@ private extension FeedbinAccountDelegate {
var subscriptionsToAdd = Set<FeedbinSubscription>()
subscriptions.forEach { subscription in
let subFeedId = String(subscription.feedID)
let subFeedID = String(subscription.feedID)
if let feed = account.existingFeed(withFeedID: subFeedId) {
if let feed = account.existingFeed(withFeedID: subFeedID) {
feed.name = subscription.name
// If the name has been changed on the server remove the locally edited name
feed.editedName = nil
@ -1122,11 +1122,11 @@ private extension FeedbinAccountDelegate {
}
// Add any feeds not in the folder
let folderFeedIds = folder.topLevelFeeds.map { $0.feedID }
let folderFeedIDs = folder.topLevelFeeds.map { $0.feedID }
for tagging in groupedTaggings {
let taggingFeedID = String(tagging.feedID)
if !folderFeedIds.contains(taggingFeedID) {
if !folderFeedIDs.contains(taggingFeedID) {
guard let feed = account.existingFeed(withFeedID: taggingFeedID) else {
continue
}

View File

@ -84,13 +84,13 @@ extension NewsBlurAccountDelegate {
os_log(.debug, log: log, "Syncing feeds with %ld feeds.", feeds.count)
let newsBlurFeedIds = feeds.map { String($0.feedID) }
let newsBlurFeedIDs = feeds.map { String($0.feedID) }
// Remove any feeds that are no longer in the subscriptions
if let folders = account.folders {
for folder in folders {
for feed in folder.topLevelFeeds {
if !newsBlurFeedIds.contains(feed.feedID) {
if !newsBlurFeedIDs.contains(feed.feedID) {
folder.removeFeed(feed)
}
}
@ -98,7 +98,7 @@ extension NewsBlurAccountDelegate {
}
for feed in account.topLevelFeeds {
if !newsBlurFeedIds.contains(feed.feedID) {
if !newsBlurFeedIDs.contains(feed.feedID) {
account.removeFeed(feed)
}
}
@ -106,9 +106,9 @@ extension NewsBlurAccountDelegate {
// Add any feeds we don't have and update any we do
var feedsToAdd = Set<NewsBlurFeed>()
feeds.forEach { feed in
let subFeedId = String(feed.feedID)
let subFeedID = String(feed.feedID)
if let feed = account.existingFeed(withFeedID: subFeedId) {
if let feed = account.existingFeed(withFeedID: subFeedID) {
feed.name = feed.name
// If the name has been changed on the server remove the locally edited name
feed.editedName = nil
@ -169,11 +169,11 @@ extension NewsBlurAccountDelegate {
}
// Add any feeds not in the folder
let folderFeedIds = folder.topLevelFeeds.map { $0.feedID }
let folderFeedIDs = folder.topLevelFeeds.map { $0.feedID }
for relationship in folderRelationships {
let folderFeedID = String(relationship.feedID)
if !folderFeedIds.contains(folderFeedID) {
if !folderFeedIDs.contains(folderFeedID) {
guard let feed = account.existingFeed(withFeedID: folderFeedID) else {
continue
}

View File

@ -816,7 +816,7 @@ final class NewsBlurAccountDelegate: AccountDelegate {
}
func accountDidInitialize(_ account: Account) {
credentials = try? account.retrieveCredentials(type: .newsBlurSessionId)
credentials = try? account.retrieveCredentials(type: .newsBlurSessionID)
}
func accountWillBeDeleted(_ account: Account) {

View File

@ -570,13 +570,13 @@ private extension ReaderAPIAccountDelegate {
os_log(.debug, log: log, "Syncing feeds with %ld subscriptions.", subscriptions.count)
let subFeedIds = subscriptions.map { $0.feedID }
let subFeedIDs = subscriptions.map { $0.feedID }
// Remove any feeds that are no longer in the subscriptions
if let folders = account.folders {
for folder in folders {
for feed in folder.topLevelFeeds {
if !subFeedIds.contains(feed.feedID) {
if !subFeedIDs.contains(feed.feedID) {
folder.removeFeed(feed)
}
}
@ -584,7 +584,7 @@ private extension ReaderAPIAccountDelegate {
}
for feed in account.topLevelFeeds {
if !subFeedIds.contains(feed.feedID) {
if !subFeedIDs.contains(feed.feedID) {
account.clearFeedMetadata(feed)
account.removeFeed(feed)
}
@ -644,11 +644,11 @@ private extension ReaderAPIAccountDelegate {
}
// Add any feeds not in the folder
let folderFeedIds = folder.topLevelFeeds.map { $0.feedID }
let folderFeedIDs = folder.topLevelFeeds.map { $0.feedID }
for subscription in groupedTaggings {
let taggingFeedID = subscription.feedID
if !folderFeedIds.contains(taggingFeedID) {
if !folderFeedIDs.contains(taggingFeedID) {
guard let feed = account.existingFeed(withFeedID: taggingFeedID) else {
continue
}

View File

@ -247,8 +247,8 @@ enum CloudKitAccountZoneError: LocalizedError {
query(ckQuery) { result in
switch result {
case .success(let records):
let feedExternalIds = records.map { $0.externalID }
completion(.success(feedExternalIds))
let feedExternalIDs = records.map { $0.externalID }
completion(.success(feedExternalIDs))
case .failure(let error):
completion(.failure(error))
}

View File

@ -147,9 +147,9 @@ private extension CloudKitAcountZoneDelegate {
feed.homePageURL = homePageURL
let existingContainers = account.existingContainers(withFeed: feed)
let existingContainerExternalIds = existingContainers.compactMap { $0.externalID }
let existingContainerExternalIDs = existingContainers.compactMap { $0.externalID }
let diff = containerExternalIDs.difference(from: existingContainerExternalIds)
let diff = containerExternalIDs.difference(from: existingContainerExternalIDs)
for change in diff {
switch change {

View File

@ -294,13 +294,13 @@ final class FeedlyAPICaller {
completion(.failure(CredentialsError.incompleteCredentials))
}
}
guard let encodedId = encodeForURLPath(id) else {
guard let encodedID = encodeForURLPath(id) else {
return DispatchQueue.main.async {
completion(.failure(FeedlyAccountDelegateError.unexpectedResourceId(id)))
completion(.failure(FeedlyAccountDelegateError.unexpectedResourceID(id)))
}
}
var components = baseUrlComponents
components.percentEncodedPath = "/v3/collections/\(encodedId)"
components.percentEncodedPath = "/v3/collections/\(encodedID)"
guard let url = components.url else {
fatalError("\(components) does not produce a valid URL.")
@ -326,7 +326,7 @@ final class FeedlyAPICaller {
}
}
func removeFeed(_ feedId: String, fromCollectionWith collectionId: String, completion: @escaping (Result<Void, Error>) -> ()) {
func removeFeed(_ feedId: String, fromCollectionWith collectionID: String, completion: @escaping (Result<Void, Error>) -> ()) {
guard !isSuspended else {
return DispatchQueue.main.async {
completion(.failure(TransportError.suspended))
@ -339,14 +339,14 @@ final class FeedlyAPICaller {
}
}
guard let encodedCollectionId = encodeForURLPath(collectionId) else {
guard let encodedCollectionID = encodeForURLPath(collectionID) else {
return DispatchQueue.main.async {
completion(.failure(FeedlyAccountDelegateError.unexpectedResourceId(collectionId)))
completion(.failure(FeedlyAccountDelegateError.unexpectedResourceID(collectionID)))
}
}
var components = baseUrlComponents
components.percentEncodedPath = "/v3/collections/\(encodedCollectionId)/feeds/.mdelete"
components.percentEncodedPath = "/v3/collections/\(encodedCollectionID)/feeds/.mdelete"
guard let url = components.url else {
fatalError("\(components) does not produce a valid URL.")
@ -390,7 +390,7 @@ final class FeedlyAPICaller {
extension FeedlyAPICaller: FeedlyAddFeedToCollectionService {
func addFeed(with feedId: FeedlyFeedResourceId, title: String? = nil, toCollectionWith collectionId: String, completion: @escaping (Result<[FeedlyFeed], Error>) -> ()) {
func addFeed(with feedId: FeedlyFeedResourceID, title: String? = nil, toCollectionWith collectionID: String, completion: @escaping (Result<[FeedlyFeed], Error>) -> ()) {
guard !isSuspended else {
return DispatchQueue.main.async {
completion(.failure(TransportError.suspended))
@ -403,13 +403,13 @@ extension FeedlyAPICaller: FeedlyAddFeedToCollectionService {
}
}
guard let encodedId = encodeForURLPath(collectionId) else {
guard let encodedID = encodeForURLPath(collectionID) else {
return DispatchQueue.main.async {
completion(.failure(FeedlyAccountDelegateError.unexpectedResourceId(collectionId)))
completion(.failure(FeedlyAccountDelegateError.unexpectedResourceID(collectionID)))
}
}
var components = baseUrlComponents
components.percentEncodedPath = "/v3/collections/\(encodedId)/feeds"
components.percentEncodedPath = "/v3/collections/\(encodedID)/feeds"
guard let url = components.url else {
fatalError("\(components) does not produce a valid URL.")
@ -606,7 +606,7 @@ extension FeedlyAPICaller: FeedlyGetCollectionsService {
extension FeedlyAPICaller: FeedlyGetStreamContentsService {
@MainActor func getStreamContents(for resource: FeedlyResourceId, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ()) {
@MainActor func getStreamContents(for resource: FeedlyResourceID, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ()) {
guard !isSuspended else {
return DispatchQueue.main.async {
completion(.failure(TransportError.suspended))
@ -672,9 +672,9 @@ extension FeedlyAPICaller: FeedlyGetStreamContentsService {
}
}
extension FeedlyAPICaller: FeedlyGetStreamIdsService {
extension FeedlyAPICaller: FeedlyGetStreamIDsService {
@MainActor func getStreamIds(for resource: FeedlyResourceId, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIds, Error>) -> ()) {
@MainActor func getStreamIDs(for resource: FeedlyResourceID, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIDs, Error>) -> ()) {
guard !isSuspended else {
return DispatchQueue.main.async {
completion(.failure(TransportError.suspended))
@ -725,7 +725,7 @@ extension FeedlyAPICaller: FeedlyGetStreamIdsService {
request.addValue("application/json", forHTTPHeaderField: "Accept-Type")
request.addValue("OAuth \(accessToken)", forHTTPHeaderField: HTTPRequestHeader.authorization)
send(request: request, resultType: FeedlyStreamIds.self, dateDecoding: .millisecondsSince1970, keyDecoding: .convertFromSnakeCase) { result in
send(request: request, resultType: FeedlyStreamIDs.self, dateDecoding: .millisecondsSince1970, keyDecoding: .convertFromSnakeCase) { result in
switch result {
case .success(let (_, collections)):
if let response = collections {
@ -800,10 +800,10 @@ extension FeedlyAPICaller: FeedlyMarkArticlesService {
private struct MarkerEntriesBody: Encodable {
let type = "entries"
var action: String
var entryIds: [String]
var entryIDs: [String]
}
func mark(_ articleIds: Set<String>, as action: FeedlyMarkAction, completion: @escaping (Result<Void, Error>) -> ()) {
func mark(_ articleIDs: Set<String>, as action: FeedlyMarkAction, completion: @escaping (Result<Void, Error>) -> ()) {
guard !isSuspended else {
return DispatchQueue.main.async {
completion(.failure(TransportError.suspended))
@ -822,12 +822,12 @@ extension FeedlyAPICaller: FeedlyMarkArticlesService {
fatalError("\(components) does not produce a valid URL.")
}
let articleIdChunks = Array(articleIds).chunked(into: 300)
let articleIDChunks = Array(articleIDs).chunked(into: 300)
let dispatchGroup = DispatchGroup()
var groupError: Error? = nil
for articleIdChunk in articleIdChunks {
for articleIDChunk in articleIDChunks {
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: HTTPRequestHeader.contentType)
@ -835,7 +835,7 @@ extension FeedlyAPICaller: FeedlyMarkArticlesService {
request.addValue("OAuth \(accessToken)", forHTTPHeaderField: HTTPRequestHeader.authorization)
do {
let body = MarkerEntriesBody(action: action.actionValue, entryIds: Array(articleIdChunk))
let body = MarkerEntriesBody(action: action.actionValue, entryIDs: Array(articleIDChunk))
let encoder = JSONEncoder()
let data = try encoder.encode(body)
request.httpBody = data

View File

@ -30,7 +30,7 @@ extension FeedlyAccountDelegate: OAuthAuthorizationGranting {
static func oauthAuthorizationCodeGrantRequest(secretsProvider: SecretsProvider) -> URLRequest {
let client = environment.oauthAuthorizationClient(secretsProvider: secretsProvider)
let authorizationRequest = OAuthAuthorizationRequest(clientId: client.id,
let authorizationRequest = OAuthAuthorizationRequest(clientID: client.id,
redirectUri: client.redirectUri,
scope: oauthAuthorizationGrantScope,
state: client.state)

View File

@ -139,7 +139,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
let log = self.log
let syncAllOperation = FeedlySyncAllOperation(account: account, feedlyUserId: credentials.username, caller: caller, database: database, lastSuccessfulFetchStartDate: accountMetadata?.lastArticleFetchStartTime, downloadProgress: refreshProgress, log: log)
let syncAllOperation = FeedlySyncAllOperation(account: account, feedlyUserID: credentials.username, caller: caller, database: database, lastSuccessfulFetchStartDate: accountMetadata?.lastArticleFetchStartTime, downloadProgress: refreshProgress, log: log)
syncAllOperation.downloadProgress = refreshProgress
@ -234,15 +234,15 @@ final class FeedlyAccountDelegate: AccountDelegate {
let group = DispatchGroup()
let ingestUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: credentials.username, service: caller, database: database, newerThan: nil, log: log)
let ingestUnread = FeedlyIngestUnreadArticleIDsOperation(account: account, userID: credentials.username, service: caller, database: database, newerThan: nil, log: log)
group.enter()
ingestUnread.completionBlock = { _ in
group.leave()
}
let ingestStarred = FeedlyIngestStarredArticleIdsOperation(account: account, userId: credentials.username, service: caller, database: database, newerThan: nil, log: log)
let ingestStarred = FeedlyIngestStarredArticleIDsOperation(account: account, userID: credentials.username, service: caller, database: database, newerThan: nil, log: log)
group.enter()
ingestStarred.completionBlock = { _ in
@ -447,7 +447,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
feedName: name,
searchService: caller,
addToCollectionService: caller,
syncUnreadIdsService: caller,
syncUnreadIDsService: caller,
getStreamContentsService: caller,
database: database,
container: container,
@ -483,18 +483,18 @@ final class FeedlyAccountDelegate: AccountDelegate {
}
func renameFeed(for account: Account, with feed: Feed, to name: String, completion: @escaping (Result<Void, Error>) -> Void) {
let folderCollectionIds = account.folders?.filter { $0.has(feed) }.compactMap { $0.externalID }
guard let collectionIds = folderCollectionIds, let collectionId = collectionIds.first else {
let folderCollectionIDs = account.folders?.filter { $0.has(feed) }.compactMap { $0.externalID }
guard let collectionIDs = folderCollectionIDs, let collectionID = collectionIDs.first else {
completion(.failure(FeedlyAccountDelegateError.unableToRenameFeed(feed.nameForDisplay, name)))
return
}
let feedId = FeedlyFeedResourceId(id: feed.feedID)
let feedID = FeedlyFeedResourceID(id: feed.feedID)
let editedNameBefore = feed.editedName
// Adding an existing feed updates it.
// Updating feed name in one folder/collection updates it for all folders/collections.
caller.addFeed(with: feedId, title: name, toCollectionWith: collectionId) { result in
caller.addFeed(with: feedID, title: name, toCollectionWith: collectionID) { result in
switch result {
case .success:
completion(.success(()))
@ -531,7 +531,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
throw FeedlyAccountDelegateError.notLoggedIn
}
let resource = FeedlyFeedResourceId(id: feed.feedID)
let resource = FeedlyFeedResourceID(id: feed.feedID)
let addExistingFeed = try FeedlyAddExistingFeedOperation(account: account,
credentials: credentials,
resource: resource,
@ -571,13 +571,13 @@ final class FeedlyAccountDelegate: AccountDelegate {
}
private func removeFeed(for account: Account, with feed: Feed, from container: Container, completion: @escaping (Result<Void, Error>) -> Void) {
guard let folder = container as? Folder, let collectionId = folder.externalID else {
guard let folder = container as? Folder, let collectionID = folder.externalID else {
return DispatchQueue.main.async {
completion(.failure(FeedlyAccountDelegateError.unableToRemoveFeed(feed.nameForDisplay)))
}
}
caller.removeFeed(feed.feedID, fromCollectionWith: collectionId) { result in
caller.removeFeed(feed.feedID, fromCollectionWith: collectionID) { result in
switch result {
case .success:
completion(.success(()))

View File

@ -10,7 +10,7 @@ import Foundation
enum FeedlyAccountDelegateError: LocalizedError {
case notLoggedIn
case unexpectedResourceId(String)
case unexpectedResourceID(String)
case unableToAddFolder(String)
case unableToRenameFolder(String, String)
case unableToRemoveFolder(String)
@ -25,9 +25,9 @@ enum FeedlyAccountDelegateError: LocalizedError {
case .notLoggedIn:
return NSLocalizedString("Please add the Feedly account again. If this problem persists, open Keychain Access and delete all feedly.com entries, then try again.", comment: "Feedly Credentials not found.")
case .unexpectedResourceId(let resourceId):
case .unexpectedResourceID(let resourceID):
let template = NSLocalizedString("Could not encode the identifier “%@”.", comment: "Feedly Could not encode resource id to send to Feedly.")
return String(format: template, resourceId)
return String(format: template, resourceID)
case .unableToAddFolder(let name):
let template = NSLocalizedString("Could not create a folder named “%@”.", comment: "Feedly Could not create a folder/collection.")
@ -67,7 +67,7 @@ enum FeedlyAccountDelegateError: LocalizedError {
case .notLoggedIn:
return nil
case .unexpectedResourceId:
case .unexpectedResourceID:
let template = NSLocalizedString("Please contact NetNewsWire support.", comment: "Feedly Recovery suggestion for not being able to encode a resource id to send to Feedly..")
return String(format: template)

View File

@ -16,10 +16,10 @@ import Foundation
throw FeedlyAccountDelegateError.addFeedChooseFolder
}
guard let collectionId = folder.externalID else {
guard let collectionID = folder.externalID else {
throw FeedlyAccountDelegateError.addFeedInvalidFolder(folder.nameForDisplay)
}
return (folder, collectionId)
return (folder, collectionID)
}
}

View File

@ -9,12 +9,12 @@
import Foundation
protocol FeedlyResourceProviding {
@MainActor var resource: FeedlyResourceId { get }
@MainActor var resource: FeedlyResourceID { get }
}
extension FeedlyFeedResourceId: FeedlyResourceProviding {
extension FeedlyFeedResourceID: FeedlyResourceProviding {
var resource: FeedlyResourceId {
var resource: FeedlyResourceID {
return self
}
}

View File

@ -23,7 +23,7 @@ final class FeedlyEntryIdentifierProvider: FeedlyEntryIdentifierProviding {
entryIDs.formUnion(provider.entryIDs)
}
@MainActor func addEntryIDs(in articleIds: [String]) {
entryIDs.formUnion(articleIds)
@MainActor func addEntryIDs(in articleIDs: [String]) {
entryIDs.formUnion(articleIDs)
}
}

View File

@ -21,7 +21,7 @@ struct FeedlyEntryParser {
/// When ingesting articles, the feedURL must match a feed's `feedID` for the article to be reachable between it and its matching feed. It reminds me of a foreign key.
var feedUrl: String? {
guard let id = entry.origin?.streamId else {
guard let id = entry.origin?.streamID else {
// At this point, check Feedly's API isn't glitching or the response has not changed structure.
assertionFailure("Entries need to be traceable to a feed or this entry will be dropped.")
return nil

View File

@ -22,7 +22,7 @@ struct FeedlyFeedParser {
}
var url: String {
let resource = FeedlyFeedResourceId(id: feed.id)
let resource = FeedlyFeedResourceID(id: feed.id)
return resource.url
}

View File

@ -10,6 +10,6 @@ import Foundation
struct FeedlyOrigin: Decodable {
let title: String?
let streamId: String?
let streamID: String?
let htmlUrl: String?
}

View File

@ -1,5 +1,5 @@
//
// FeedlyResourceId.swift
// FeedlyResourceID.swift
// Account
//
// Created by Kiel Gillard on 3/10/19.
@ -8,20 +8,20 @@
import Foundation
/// The kinds of Resource Ids is documented here: https://developer.feedly.com/cloud/
protocol FeedlyResourceId {
/// The kinds of Resource IDs is documented here: https://developer.feedly.com/cloud/
protocol FeedlyResourceID {
/// The resource Id from Feedly.
/// The resource ID from Feedly.
@MainActor var id: String { get }
}
/// The Feed Resource is documented here: https://developer.feedly.com/cloud/
struct FeedlyFeedResourceId: FeedlyResourceId {
struct FeedlyFeedResourceID: FeedlyResourceID {
let id: String
/// The location of the kind of resource a concrete type represents.
/// If the concrete type cannot strip the resource type from the Id, it should just return the Id
/// since the Id is a legitimate URL.
/// If the concrete type cannot strip the resource type from the ID, it should just return the ID
/// since the ID is a legitimate URL.
/// This is basically assuming Feedly prefixes source feed URLs with `feed/`.
/// It is not documented as such and could potentially change.
/// Feedly does not include the source feed URL as a separate field.
@ -38,48 +38,48 @@ struct FeedlyFeedResourceId: FeedlyResourceId {
}
}
extension FeedlyFeedResourceId {
extension FeedlyFeedResourceID {
init(url: String) {
self.id = "feed/\(url)"
}
}
struct FeedlyCategoryResourceId: FeedlyResourceId {
struct FeedlyCategoryResourceID: FeedlyResourceID {
let id: String
enum Global {
static func uncategorized(for userId: String) -> FeedlyCategoryResourceId {
static func uncategorized(for userID: String) -> FeedlyCategoryResourceID {
// https://developer.feedly.com/cloud/#global-resource-ids
let id = "user/\(userId)/category/global.uncategorized"
return FeedlyCategoryResourceId(id: id)
let id = "user/\(userID)/category/global.uncategorized"
return FeedlyCategoryResourceID(id: id)
}
/// All articles from all the feeds the user subscribes to.
static func all(for userId: String) -> FeedlyCategoryResourceId {
static func all(for userID: String) -> FeedlyCategoryResourceID {
// https://developer.feedly.com/cloud/#global-resource-ids
let id = "user/\(userId)/category/global.all"
return FeedlyCategoryResourceId(id: id)
let id = "user/\(userID)/category/global.all"
return FeedlyCategoryResourceID(id: id)
}
/// All articles from all the feeds the user loves most.
static func mustRead(for userId: String) -> FeedlyCategoryResourceId {
static func mustRead(for userID: String) -> FeedlyCategoryResourceID {
// https://developer.feedly.com/cloud/#global-resource-ids
let id = "user/\(userId)/category/global.must"
return FeedlyCategoryResourceId(id: id)
let id = "user/\(userID)/category/global.must"
return FeedlyCategoryResourceID(id: id)
}
}
}
struct FeedlyTagResourceId: FeedlyResourceId {
struct FeedlyTagResourceID: FeedlyResourceID {
let id: String
enum Global {
static func saved(for userId: String) -> FeedlyTagResourceId {
static func saved(for userID: String) -> FeedlyTagResourceID {
// https://developer.feedly.com/cloud/#global-resource-ids
let id = "user/\(userId)/tag/global.saved"
return FeedlyTagResourceId(id: id)
let id = "user/\(userID)/tag/global.saved"
return FeedlyTagResourceID(id: id)
}
}
}

View File

@ -1,5 +1,5 @@
//
// FeedlyStreamIds.swift
// FeedlyStreamIDs.swift
// Account
//
// Created by Kiel Gillard on 18/10/19.
@ -8,7 +8,7 @@
import Foundation
struct FeedlyStreamIds: Decodable {
struct FeedlyStreamIDs: Decodable {
let continuation: String?
let ids: [String]

View File

@ -17,13 +17,13 @@ public struct OAuthRefreshAccessTokenRequest: Encodable {
public var scope: String?
// Possibly not part of the standard but specific to certain implementations (e.g.: Feedly).
public var clientId: String
public var clientID: String
public var clientSecret: String
public init(refreshToken: String, scope: String?, client: OAuthAuthorizationClient) {
self.refreshToken = refreshToken
self.scope = scope
self.clientId = client.id
self.clientID = client.id
self.clientSecret = client.secret
}
}

View File

@ -30,13 +30,13 @@ public struct OAuthAuthorizationClient: Equatable {
/// https://tools.ietf.org/html/rfc6749#section-4.1.1
public struct OAuthAuthorizationRequest {
public let responseType = "code"
public var clientId: String
public var clientID: String
public var redirectUri: String
public var scope: String
public var state: String?
public init(clientId: String, redirectUri: String, scope: String, state: String?) {
self.clientId = clientId
public init(clientID: String, redirectUri: String, scope: String, state: String?) {
self.clientID = clientID
self.redirectUri = redirectUri
self.scope = scope
self.state = state
@ -45,7 +45,7 @@ public struct OAuthAuthorizationRequest {
public var queryItems: [URLQueryItem] {
return [
URLQueryItem(name: "response_type", value: responseType),
URLQueryItem(name: "client_id", value: clientId),
URLQueryItem(name: "client_id", value: clientID),
URLQueryItem(name: "scope", value: scope),
URLQueryItem(name: "redirect_uri", value: redirectUri),
]
@ -114,7 +114,7 @@ public struct OAuthAccessTokenRequest: Encodable {
public var code: String
public var redirectUri: String
public var state: String?
public var clientId: String
public var clientID: String
// Possibly not part of the standard but specific to certain implementations (e.g.: Feedly).
public var clientSecret: String
@ -124,7 +124,7 @@ public struct OAuthAccessTokenRequest: Encodable {
self.code = authorizationResponse.code
self.redirectUri = client.redirectUri
self.state = authorizationResponse.state
self.clientId = client.id
self.clientID = client.id
self.clientSecret = client.secret
self.scope = scope
}

View File

@ -17,10 +17,10 @@ import Core
private let operationQueue = MainThreadOperationQueue()
var addCompletionHandler: ((Result<Void, Error>) -> ())?
@MainActor init(account: Account, credentials: Credentials, resource: FeedlyFeedResourceId, service: FeedlyAddFeedToCollectionService, container: Container, progress: DownloadProgress, log: OSLog, customFeedName: String? = nil) throws {
@MainActor init(account: Account, credentials: Credentials, resource: FeedlyFeedResourceID, service: FeedlyAddFeedToCollectionService, container: Container, progress: DownloadProgress, log: OSLog, customFeedName: String? = nil) throws {
let validator = FeedlyFeedContainerValidator(container: container)
let (folder, collectionId) = try validator.getValidContainer()
let (folder, collectionID) = try validator.getValidContainer()
self.operationQueue.suspend()
@ -28,7 +28,7 @@ import Core
self.downloadProgress = progress
let addRequest = FeedlyAddFeedToCollectionOperation(folder: folder, feedResource: resource, feedName: customFeedName, collectionId: collectionId, service: service)
let addRequest = FeedlyAddFeedToCollectionOperation(folder: folder, feedResource: resource, feedName: customFeedName, collectionID: collectionID, service: service)
addRequest.delegate = self
addRequest.downloadProgress = progress
self.operationQueue.add(addRequest)

View File

@ -10,33 +10,33 @@ import Foundation
import CommonErrors
protocol FeedlyAddFeedToCollectionService {
func addFeed(with feedId: FeedlyFeedResourceId, title: String?, toCollectionWith collectionId: String, completion: @escaping (Result<[FeedlyFeed], Error>) -> ())
func addFeed(with feedId: FeedlyFeedResourceID, title: String?, toCollectionWith collectionID: String, completion: @escaping (Result<[FeedlyFeed], Error>) -> ())
}
final class FeedlyAddFeedToCollectionOperation: FeedlyOperation, FeedlyFeedsAndFoldersProviding, FeedlyResourceProviding {
let feedName: String?
let collectionId: String
let collectionID: String
let service: FeedlyAddFeedToCollectionService
let folder: Folder
let feedResource: FeedlyFeedResourceId
let feedResource: FeedlyFeedResourceID
init(folder: Folder, feedResource: FeedlyFeedResourceId, feedName: String? = nil, collectionId: String, service: FeedlyAddFeedToCollectionService) {
init(folder: Folder, feedResource: FeedlyFeedResourceID, feedName: String? = nil, collectionID: String, service: FeedlyAddFeedToCollectionService) {
self.folder = folder
self.feedResource = feedResource
self.feedName = feedName
self.collectionId = collectionId
self.collectionID = collectionID
self.service = service
}
private(set) var feedsAndFolders = [([FeedlyFeed], Folder)]()
var resource: FeedlyResourceId {
var resource: FeedlyResourceID {
return feedResource
}
override func run() {
service.addFeed(with: feedResource, title: feedName, toCollectionWith: collectionId) { [weak self] result in
service.addFeed(with: feedResource, title: feedName, toCollectionWith: collectionID) { [weak self] result in
guard let self = self else {
return
}
@ -56,9 +56,9 @@ private extension FeedlyAddFeedToCollectionOperation {
case .success(let feedlyFeeds):
feedsAndFolders = [(feedlyFeeds, folder)]
let feedsWithCreatedFeedId = feedlyFeeds.filter { $0.id == resource.id }
let feedsWithCreatedFeedID = feedlyFeeds.filter { $0.id == resource.id }
if feedsWithCreatedFeedId.isEmpty {
if feedsWithCreatedFeedID.isEmpty {
didFinish(with: AccountError.createErrorNotFound)
} else {
didFinish()

View File

@ -18,24 +18,24 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
private let operationQueue = MainThreadOperationQueue()
private let folder: Folder
private let collectionId: String
private let collectionID: String
private let url: String
private let account: Account
private let credentials: Credentials
private let database: SyncDatabase
private let feedName: String?
private let addToCollectionService: FeedlyAddFeedToCollectionService
private let syncUnreadIdsService: FeedlyGetStreamIdsService
private let syncUnreadIDsService: FeedlyGetStreamIDsService
private let getStreamContentsService: FeedlyGetStreamContentsService
private let log: OSLog
private var feedResourceId: FeedlyFeedResourceId?
private var feedResourceID: FeedlyFeedResourceID?
var addCompletionHandler: ((Result<Feed, Error>) -> ())?
@MainActor init(account: Account, credentials: Credentials, url: String, feedName: String?, searchService: FeedlySearchService, addToCollectionService: FeedlyAddFeedToCollectionService, syncUnreadIdsService: FeedlyGetStreamIdsService, getStreamContentsService: FeedlyGetStreamContentsService, database: SyncDatabase, container: Container, progress: DownloadProgress, log: OSLog) throws {
@MainActor init(account: Account, credentials: Credentials, url: String, feedName: String?, searchService: FeedlySearchService, addToCollectionService: FeedlyAddFeedToCollectionService, syncUnreadIDsService: FeedlyGetStreamIDsService, getStreamContentsService: FeedlyGetStreamContentsService, database: SyncDatabase, container: Container, progress: DownloadProgress, log: OSLog) throws {
let validator = FeedlyFeedContainerValidator(container: container)
(self.folder, self.collectionId) = try validator.getValidContainer()
(self.folder, self.collectionID) = try validator.getValidContainer()
self.url = url
self.operationQueue.suspend()
@ -44,7 +44,7 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
self.database = database
self.feedName = feedName
self.addToCollectionService = addToCollectionService
self.syncUnreadIdsService = syncUnreadIdsService
self.syncUnreadIDsService = syncUnreadIDsService
self.getStreamContentsService = getStreamContentsService
self.log = log
@ -84,10 +84,10 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
return didFinish(with: AccountError.createErrorNotFound)
}
let feedResourceId = FeedlyFeedResourceId(id: first.feedId)
self.feedResourceId = feedResourceId
let feedResourceID = FeedlyFeedResourceID(id: first.feedId)
self.feedResourceID = feedResourceID
let addRequest = FeedlyAddFeedToCollectionOperation(folder: folder, feedResource: feedResourceId, feedName: feedName, collectionId: collectionId, service: addToCollectionService)
let addRequest = FeedlyAddFeedToCollectionOperation(folder: folder, feedResource: feedResourceID, feedName: feedName, collectionID: collectionID, service: addToCollectionService)
addRequest.delegate = self
addRequest.downloadProgress = downloadProgress
operationQueue.add(addRequest)
@ -98,13 +98,13 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
createFeeds.downloadProgress = downloadProgress
operationQueue.add(createFeeds)
let syncUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: credentials.username, service: syncUnreadIdsService, database: database, newerThan: nil, log: log)
let syncUnread = FeedlyIngestUnreadArticleIDsOperation(account: account, userID: credentials.username, service: syncUnreadIDsService, database: database, newerThan: nil, log: log)
syncUnread.addDependency(createFeeds)
syncUnread.downloadProgress = downloadProgress
syncUnread.delegate = self
operationQueue.add(syncUnread)
let syncFeed = FeedlySyncStreamContentsOperation(account: account, resource: feedResourceId, service: getStreamContentsService, isPagingEnabled: false, newerThan: nil, log: log)
let syncFeed = FeedlySyncStreamContentsOperation(account: account, resource: feedResourceID, service: getStreamContentsService, isPagingEnabled: false, newerThan: nil, log: log)
syncFeed.addDependency(syncUnread)
syncFeed.downloadProgress = downloadProgress
syncFeed.delegate = self
@ -138,7 +138,7 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
guard let handler = addCompletionHandler else {
return
}
if let feedResource = feedResourceId, let feed = folder.existingFeed(withFeedID: feedResource.id) {
if let feedResource = feedResourceID, let feed = folder.existingFeed(withFeedID: feedResource.id) {
handler(.success(feed))
}
else {

View File

@ -15,17 +15,17 @@ class FeedlyDownloadArticlesOperation: FeedlyOperation {
private let account: Account
private let log: OSLog
private let missingArticleEntryIdProvider: FeedlyEntryIdentifierProviding
private let updatedArticleEntryIdProvider: FeedlyEntryIdentifierProviding
private let missingArticleEntryIDProvider: FeedlyEntryIdentifierProviding
private let updatedArticleEntryIDProvider: FeedlyEntryIdentifierProviding
private let getEntriesService: FeedlyGetEntriesService
private let operationQueue = MainThreadOperationQueue()
private let finishOperation: FeedlyCheckpointOperation
@MainActor init(account: Account, missingArticleEntryIdProvider: FeedlyEntryIdentifierProviding, updatedArticleEntryIdProvider: FeedlyEntryIdentifierProviding, getEntriesService: FeedlyGetEntriesService, log: OSLog) {
@MainActor init(account: Account, missingArticleEntryIDProvider: FeedlyEntryIdentifierProviding, updatedArticleEntryIDProvider: FeedlyEntryIdentifierProviding, getEntriesService: FeedlyGetEntriesService, log: OSLog) {
self.account = account
self.operationQueue.suspend()
self.missingArticleEntryIdProvider = missingArticleEntryIdProvider
self.updatedArticleEntryIdProvider = updatedArticleEntryIdProvider
self.missingArticleEntryIDProvider = missingArticleEntryIDProvider
self.updatedArticleEntryIDProvider = updatedArticleEntryIDProvider
self.getEntriesService = getEntriesService
self.finishOperation = FeedlyCheckpointOperation()
self.log = log
@ -35,16 +35,16 @@ class FeedlyDownloadArticlesOperation: FeedlyOperation {
}
override func run() {
var articleIds = missingArticleEntryIdProvider.entryIDs
articleIds.formUnion(updatedArticleEntryIdProvider.entryIDs)
var articleIDs = missingArticleEntryIDProvider.entryIDs
articleIDs.formUnion(updatedArticleEntryIDProvider.entryIDs)
os_log(.debug, log: log, "Requesting %{public}i articles.", articleIds.count)
os_log(.debug, log: log, "Requesting %{public}i articles.", articleIDs.count)
let feedlyAPILimitBatchSize = 1000
for articleIds in Array(articleIds).chunked(into: feedlyAPILimitBatchSize) {
for articleIDs in Array(articleIDs).chunked(into: feedlyAPILimitBatchSize) {
Task { @MainActor in
let provider = FeedlyEntryIdentifierProvider(entryIDs: Set(articleIds))
let provider = FeedlyEntryIdentifierProvider(entryIDs: Set(articleIDs))
let getEntries = FeedlyGetEntriesOperation(service: getEntriesService, provider: provider, log: log)
getEntries.delegate = self
self.operationQueue.add(getEntries)

View File

@ -1,5 +1,5 @@
//
// FeedlyFetchIdsForMissingArticlesOperation.swift
// FeedlyFetchIDsForMissingArticlesOperation.swift
// Account
//
// Created by Kiel Gillard on 7/1/20.
@ -9,7 +9,7 @@
import Foundation
import os.log
final class FeedlyFetchIdsForMissingArticlesOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
final class FeedlyFetchIDsForMissingArticlesOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
private let account: Account

View File

@ -38,9 +38,9 @@ final class FeedlyGetEntriesOperation: FeedlyOperation, FeedlyEntryProviding, Fe
// TODO: Fix the below. Theres an error on the os.log line: "Expression type '()' is ambiguous without more context"
// if parsed.count != entries.count {
// let entryIds = Set(entries.map { $0.id })
// let parsedIds = Set(parsed.map { $0.uniqueID })
// let difference = entryIds.subtracting(parsedIds)
// let entryIDs = Set(entries.map { $0.id })
// let parsedIDs = Set(parsed.map { $0.uniqueID })
// let difference = entryIDs.subtracting(parsedIDs)
// os_log(.debug, log: log, "%{public}@ dropping articles with ids: %{public}@.", self, difference)
// }

View File

@ -27,7 +27,7 @@ protocol FeedlyGetStreamContentsOperationDelegate: AnyObject {
final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProviding, FeedlyParsedItemProviding {
@MainActor struct ResourceProvider: FeedlyResourceProviding {
var resource: FeedlyResourceId
var resource: FeedlyResourceID
}
let resourceProvider: FeedlyResourceProviding
@ -55,9 +55,9 @@ final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProvid
})
if parsed.count != entries.count {
let entryIds = Set(entries.map { $0.id })
let parsedIds = Set(parsed.map { $0.uniqueID })
let difference = entryIds.subtracting(parsedIds)
let entryIDs = Set(entries.map { $0.id })
let parsedIDs = Set(parsed.map { $0.uniqueID })
let difference = entryIDs.subtracting(parsedIDs)
os_log(.debug, log: log, "Dropping articles with ids: %{public}@.", difference)
}
@ -83,7 +83,7 @@ final class FeedlyGetStreamContentsOperation: FeedlyOperation, FeedlyEntryProvid
weak var streamDelegate: FeedlyGetStreamContentsOperationDelegate?
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamContentsService, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool? = nil, log: OSLog) {
init(account: Account, resource: FeedlyResourceID, service: FeedlyGetStreamContentsService, continuation: String? = nil, newerThan: Date?, unreadOnly: Bool? = nil, log: OSLog) {
self.account = account
self.resourceProvider = ResourceProvider(resource: resource)
self.service = service

View File

@ -1,5 +1,5 @@
//
// FeedlyGetStreamIdsOperation.swift
// FeedlyGetStreamIDsOperation.swift
// Account
//
// Created by Kiel Gillard on 18/10/19.
@ -9,32 +9,32 @@
import Foundation
import os.log
protocol FeedlyGetStreamIdsOperationDelegate: AnyObject {
func feedlyGetStreamIdsOperation(_ operation: FeedlyGetStreamIdsOperation, didGet streamIds: FeedlyStreamIds)
protocol FeedlyGetStreamIDsOperationDelegate: AnyObject {
func feedlyGetStreamIDsOperation(_ operation: FeedlyGetStreamIDsOperation, didGet streamIDs: FeedlyStreamIDs)
}
/// Single responsibility is to get the stream ids from Feedly.
final class FeedlyGetStreamIdsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
final class FeedlyGetStreamIDsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
var entryIDs: Set<String> {
guard let ids = streamIds?.ids else {
guard let ids = streamIDs?.ids else {
assertionFailure("Has this operation been addeded as a dependency on the caller?")
return []
}
return Set(ids)
}
private(set) var streamIds: FeedlyStreamIds?
private(set) var streamIDs: FeedlyStreamIDs?
let account: Account
let service: FeedlyGetStreamIdsService
let service: FeedlyGetStreamIDsService
let continuation: String?
let resource: FeedlyResourceId
let resource: FeedlyResourceID
let unreadOnly: Bool?
let newerThan: Date?
let log: OSLog
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, continuation: String? = nil, newerThan: Date? = nil, unreadOnly: Bool?, log: OSLog) {
init(account: Account, resource: FeedlyResourceID, service: FeedlyGetStreamIDsService, continuation: String? = nil, newerThan: Date? = nil, unreadOnly: Bool?, log: OSLog) {
self.account = account
self.resource = resource
self.service = service
@ -44,15 +44,15 @@ final class FeedlyGetStreamIdsOperation: FeedlyOperation, FeedlyEntryIdentifierP
self.log = log
}
weak var streamIdsDelegate: FeedlyGetStreamIdsOperationDelegate?
weak var streamIDsDelegate: FeedlyGetStreamIDsOperationDelegate?
override func run() {
service.getStreamIds(for: resource, continuation: continuation, newerThan: newerThan, unreadOnly: unreadOnly) { result in
service.getStreamIDs(for: resource, continuation: continuation, newerThan: newerThan, unreadOnly: unreadOnly) { result in
switch result {
case .success(let stream):
self.streamIds = stream
self.streamIDs = stream
self.streamIdsDelegate?.feedlyGetStreamIdsOperation(self, didGet: stream)
self.streamIDsDelegate?.feedlyGetStreamIDsOperation(self, didGet: stream)
self.didFinish()

View File

@ -1,5 +1,5 @@
//
// FeedlyGetUpdatedArticleIdsOperation.swift
// FeedlyGetUpdatedArticleIDsOperation.swift
// Account
//
// Created by Kiel Gillard on 11/1/20.
@ -14,15 +14,15 @@ import Secrets
///
/// Typically, it pages through the article ids of the global.all stream.
/// When all the article ids are collected, it is the responsibility of another operation to download them when appropriate.
class FeedlyGetUpdatedArticleIdsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
class FeedlyGetUpdatedArticleIDsOperation: FeedlyOperation, FeedlyEntryIdentifierProviding {
private let account: Account
private let resource: FeedlyResourceId
private let service: FeedlyGetStreamIdsService
private let resource: FeedlyResourceID
private let service: FeedlyGetStreamIDsService
private let newerThan: Date?
private let log: OSLog
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, newerThan: Date?, log: OSLog) {
init(account: Account, resource: FeedlyResourceID, service: FeedlyGetStreamIDsService, newerThan: Date?, log: OSLog) {
self.account = account
self.resource = resource
self.service = service
@ -30,48 +30,48 @@ class FeedlyGetUpdatedArticleIdsOperation: FeedlyOperation, FeedlyEntryIdentifie
self.log = log
}
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, newerThan: Date?, log: OSLog) {
let all = FeedlyCategoryResourceId.Global.all(for: userId)
convenience init(account: Account, userID: String, service: FeedlyGetStreamIDsService, newerThan: Date?, log: OSLog) {
let all = FeedlyCategoryResourceID.Global.all(for: userID)
self.init(account: account, resource: all, service: service, newerThan: newerThan, log: log)
}
var entryIDs: Set<String> {
return storedUpdatedArticleIds
return storedUpdatedArticleIDs
}
private var storedUpdatedArticleIds = Set<String>()
private var storedUpdatedArticleIDs = Set<String>()
override func run() {
getStreamIds(nil)
getStreamIDs(nil)
}
private func getStreamIds(_ continuation: String?) {
private func getStreamIDs(_ continuation: String?) {
guard let date = newerThan else {
os_log(.debug, log: log, "No date provided so everything must be new (nothing is updated).")
didFinish()
return
}
service.getStreamIds(for: resource, continuation: continuation, newerThan: date, unreadOnly: nil, completion: didGetStreamIds(_:))
service.getStreamIDs(for: resource, continuation: continuation, newerThan: date, unreadOnly: nil, completion: didGetStreamIDs(_:))
}
private func didGetStreamIds(_ result: Result<FeedlyStreamIds, Error>) {
private func didGetStreamIDs(_ result: Result<FeedlyStreamIDs, Error>) {
guard !isCanceled else {
didFinish()
return
}
switch result {
case .success(let streamIds):
storedUpdatedArticleIds.formUnion(streamIds.ids)
case .success(let streamIDs):
storedUpdatedArticleIDs.formUnion(streamIDs.ids)
guard let continuation = streamIds.continuation else {
os_log(.debug, log: log, "%{public}i articles updated since last successful sync start date.", storedUpdatedArticleIds.count)
guard let continuation = streamIDs.continuation else {
os_log(.debug, log: log, "%{public}i articles updated since last successful sync start date.", storedUpdatedArticleIDs.count)
didFinish()
return
}
getStreamIds(continuation)
getStreamIDs(continuation)
case .failure(let error):
didFinish(with: error)

View File

@ -1,5 +1,5 @@
//
// FeedlyIngestStarredArticleIdsOperation.swift
// FeedlyIngestStarredArticleIDsOperation.swift
// Account
//
// Created by Kiel Gillard on 15/10/19.
@ -17,21 +17,21 @@ import Secrets
/// When all the article ids are collected, a status is created for each.
/// The article ids previously marked as starred but not collected become unstarred.
/// So this operation has side effects *for the entire account* it operates on.
final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation {
final class FeedlyIngestStarredArticleIDsOperation: FeedlyOperation {
private let account: Account
private let resource: FeedlyResourceId
private let service: FeedlyGetStreamIdsService
private let resource: FeedlyResourceID
private let service: FeedlyGetStreamIDsService
private let database: SyncDatabase
private var remoteEntryIds = Set<String>()
private var remoteEntryIDs = Set<String>()
private let log: OSLog
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
let resource = FeedlyTagResourceId.Global.saved(for: userId)
convenience init(account: Account, userID: String, service: FeedlyGetStreamIDsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
let resource = FeedlyTagResourceID.Global.saved(for: userID)
self.init(account: account, resource: resource, service: service, database: database, newerThan: newerThan, log: log)
}
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
init(account: Account, resource: FeedlyResourceID, service: FeedlyGetStreamIDsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
self.account = account
self.resource = resource
self.service = service
@ -40,30 +40,30 @@ final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation {
}
override func run() {
getStreamIds(nil)
getStreamIDs(nil)
}
private func getStreamIds(_ continuation: String?) {
service.getStreamIds(for: resource, continuation: continuation, newerThan: nil, unreadOnly: nil, completion: didGetStreamIds(_:))
private func getStreamIDs(_ continuation: String?) {
service.getStreamIDs(for: resource, continuation: continuation, newerThan: nil, unreadOnly: nil, completion: didGetStreamIDs(_:))
}
private func didGetStreamIds(_ result: Result<FeedlyStreamIds, Error>) {
private func didGetStreamIDs(_ result: Result<FeedlyStreamIDs, Error>) {
guard !isCanceled else {
didFinish()
return
}
switch result {
case .success(let streamIds):
case .success(let streamIDs):
remoteEntryIDs.formUnion(streamIDs.ids)
remoteEntryIds.formUnion(streamIds.ids)
guard let continuation = streamIds.continuation else {
removeEntryIdsWithPendingStatus()
guard let continuation = streamIDs.continuation else {
removeEntryIDsWithPendingStatus()
return
}
getStreamIds(continuation)
getStreamIDs(continuation)
case .failure(let error):
didFinish(with: error)
@ -71,7 +71,7 @@ final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation {
}
/// Do not override pending statuses with the remote statuses of the same articles, otherwise an article will temporarily re-acquire the remote status before the pending status is pushed and subseqently pulled.
private func removeEntryIdsWithPendingStatus() {
private func removeEntryIDsWithPendingStatus() {
guard !isCanceled else {
didFinish()
return
@ -81,7 +81,7 @@ final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation {
do {
if let pendingArticleIDs = try await self.database.selectPendingStarredStatusArticleIDs() {
self.remoteEntryIds.subtract(pendingArticleIDs)
self.remoteEntryIDs.subtract(pendingArticleIDs)
}
self.updateStarredStatuses()
} catch {
@ -120,7 +120,7 @@ final class FeedlyIngestStarredArticleIdsOperation: FeedlyOperation {
var markAsStarredError: Error?
var markAsUnstarredError: Error?
let remoteStarredArticleIDs = remoteEntryIds
let remoteStarredArticleIDs = remoteEntryIDs
do {
try await account.markAsStarred(remoteStarredArticleIDs)
} catch {

View File

@ -1,5 +1,5 @@
//
// FeedlyIngestStreamArticleIdsOperation.swift
// FeedlyIngestStreamArticleIDsOperation.swift
// Account
//
// Created by Kiel Gillard on 9/1/20.
@ -16,34 +16,34 @@ import Database
/// Typically, it pages through the article ids of the global.all stream.
/// As the article ids are collected, a default read status is created for each.
/// So this operation has side effects *for the entire account* it operates on.
class FeedlyIngestStreamArticleIdsOperation: FeedlyOperation {
class FeedlyIngestStreamArticleIDsOperation: FeedlyOperation {
private let account: Account
private let resource: FeedlyResourceId
private let service: FeedlyGetStreamIdsService
private let resource: FeedlyResourceID
private let service: FeedlyGetStreamIDsService
private let log: OSLog
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, log: OSLog) {
init(account: Account, resource: FeedlyResourceID, service: FeedlyGetStreamIDsService, log: OSLog) {
self.account = account
self.resource = resource
self.service = service
self.log = log
}
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, log: OSLog) {
let all = FeedlyCategoryResourceId.Global.all(for: userId)
convenience init(account: Account, userID: String, service: FeedlyGetStreamIDsService, log: OSLog) {
let all = FeedlyCategoryResourceID.Global.all(for: userID)
self.init(account: account, resource: all, service: service, log: log)
}
override func run() {
getStreamIds(nil)
getStreamIDs(nil)
}
private func getStreamIds(_ continuation: String?) {
service.getStreamIds(for: resource, continuation: continuation, newerThan: nil, unreadOnly: nil, completion: didGetStreamIds(_:))
private func getStreamIDs(_ continuation: String?) {
service.getStreamIDs(for: resource, continuation: continuation, newerThan: nil, unreadOnly: nil, completion: didGetStreamIDs(_:))
}
private func didGetStreamIds(_ result: Result<FeedlyStreamIds, Error>) {
private func didGetStreamIDs(_ result: Result<FeedlyStreamIDs, Error>) {
guard !isCanceled else {
didFinish()
return
@ -62,7 +62,7 @@ class FeedlyIngestStreamArticleIdsOperation: FeedlyOperation {
return
}
self.getStreamIds(continuation)
self.getStreamIDs(continuation)
} catch {
self.didFinish(with: error)
return

View File

@ -1,5 +1,5 @@
//
// FeedlyIngestUnreadArticleIdsOperation.swift
// FeedlyIngestUnreadArticleIDsOperation.swift
// Account
//
// Created by Kiel Gillard on 18/10/19.
@ -18,21 +18,21 @@ import Secrets
/// When all the unread article ids are collected, a status is created for each.
/// The article ids previously marked as unread but not collected become read.
/// So this operation has side effects *for the entire account* it operates on.
final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation {
final class FeedlyIngestUnreadArticleIDsOperation: FeedlyOperation {
private let account: Account
private let resource: FeedlyResourceId
private let service: FeedlyGetStreamIdsService
private let resource: FeedlyResourceID
private let service: FeedlyGetStreamIDsService
private let database: SyncDatabase
private var remoteEntryIds = Set<String>()
private var remoteEntryIDs = Set<String>()
private let log: OSLog
convenience init(account: Account, userId: String, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
let resource = FeedlyCategoryResourceId.Global.all(for: userId)
convenience init(account: Account, userID: String, service: FeedlyGetStreamIDsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
let resource = FeedlyCategoryResourceID.Global.all(for: userID)
self.init(account: account, resource: resource, service: service, database: database, newerThan: newerThan, log: log)
}
init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamIdsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
init(account: Account, resource: FeedlyResourceID, service: FeedlyGetStreamIDsService, database: SyncDatabase, newerThan: Date?, log: OSLog) {
self.account = account
self.resource = resource
self.service = service
@ -41,30 +41,30 @@ final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation {
}
override func run() {
getStreamIds(nil)
getStreamIDs(nil)
}
private func getStreamIds(_ continuation: String?) {
service.getStreamIds(for: resource, continuation: continuation, newerThan: nil, unreadOnly: true, completion: didGetStreamIds(_:))
private func getStreamIDs(_ continuation: String?) {
service.getStreamIDs(for: resource, continuation: continuation, newerThan: nil, unreadOnly: true, completion: didGetStreamIDs(_:))
}
private func didGetStreamIds(_ result: Result<FeedlyStreamIds, Error>) {
private func didGetStreamIDs(_ result: Result<FeedlyStreamIDs, Error>) {
guard !isCanceled else {
didFinish()
return
}
switch result {
case .success(let streamIds):
case .success(let streamIDs):
remoteEntryIDs.formUnion(streamIDs.ids)
remoteEntryIds.formUnion(streamIds.ids)
guard let continuation = streamIds.continuation else {
removeEntryIdsWithPendingStatus()
guard let continuation = streamIDs.continuation else {
removeEntryIDsWithPendingStatus()
return
}
getStreamIds(continuation)
getStreamIDs(continuation)
case .failure(let error):
didFinish(with: error)
@ -72,7 +72,7 @@ final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation {
}
/// Do not override pending statuses with the remote statuses of the same articles, otherwise an article will temporarily re-acquire the remote status before the pending status is pushed and subseqently pulled.
private func removeEntryIdsWithPendingStatus() {
private func removeEntryIDsWithPendingStatus() {
guard !isCanceled else {
didFinish()
return
@ -82,7 +82,7 @@ final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation {
do {
if let pendingArticleIDs = try await self.database.selectPendingReadStatusArticleIDs() {
self.remoteEntryIds.subtract(pendingArticleIDs)
self.remoteEntryIDs.subtract(pendingArticleIDs)
}
self.updateUnreadStatuses()
} catch {
@ -116,7 +116,7 @@ final class FeedlyIngestUnreadArticleIdsOperation: FeedlyOperation {
return
}
let remoteUnreadArticleIDs = remoteEntryIds
let remoteUnreadArticleIDs = remoteEntryIDs
Task { @MainActor in

View File

@ -12,7 +12,7 @@ import os.log
protocol FeedlyParsedItemsByFeedProviding {
var parsedItemsByFeedProviderName: String { get }
var parsedItemsKeyedByFeedId: [String: Set<ParsedItem>] { get }
var parsedItemsKeyedByFeedID: [String: Set<ParsedItem>] { get }
}
/// Group articles by their feeds.
@ -26,12 +26,12 @@ final class FeedlyOrganiseParsedItemsByFeedOperation: FeedlyOperation, FeedlyPar
return name ?? String(describing: Self.self)
}
var parsedItemsKeyedByFeedId: [String : Set<ParsedItem>] {
var parsedItemsKeyedByFeedID: [String : Set<ParsedItem>] {
precondition(Thread.isMainThread) // Needs to be on main thread because Feed is a main-thread-only model type.
return itemsKeyedByFeedId
return itemsKeyedByFeedID
}
private var itemsKeyedByFeedId = [String: Set<ParsedItem>]()
private var itemsKeyedByFeedID = [String: Set<ParsedItem>]()
init(account: Account, parsedItemProvider: FeedlyParsedItemProviding, log: OSLog) {
self.account = account
@ -62,6 +62,6 @@ final class FeedlyOrganiseParsedItemsByFeedOperation: FeedlyOperation, FeedlyPar
os_log(.debug, log: log, "Grouped %i items by %i feeds for %@", items.count, dict.count, parsedItemProvider.parsedItemProviderName)
itemsKeyedByFeedId = dict
itemsKeyedByFeedID = dict
}
}

View File

@ -45,7 +45,7 @@ final class FeedlyRequestStreamsOperation: FeedlyOperation {
// TODO: Prioritise the must read collection/category before others so the most important content for the user loads first.
for collection in collectionsProvider.collections {
let resource = FeedlyCategoryResourceId(id: collection.id)
let resource = FeedlyCategoryResourceID(id: collection.id)
let operation = FeedlyGetStreamContentsOperation(account: account,
resource: resource,
service: service,

View File

@ -53,12 +53,12 @@ private extension FeedlySendArticleStatusesOperation {
let group = DispatchGroup()
for pairing in statuses {
let articleIds = pending.filter { $0.key == pairing.status && $0.flag == pairing.flag }
guard !articleIds.isEmpty else {
let articleIDs = pending.filter { $0.key == pairing.status && $0.flag == pairing.flag }
guard !articleIDs.isEmpty else {
continue
}
let ids = Set(articleIds.map { $0.articleID })
let ids = Set(articleIDs.map { $0.articleID })
let database = self.database
group.enter()
service.mark(ids, as: pairing.action) { result in

View File

@ -34,7 +34,7 @@ final class FeedlySyncAllOperation: FeedlyOperation {
///
/// Download articles for statuses at the union of those statuses without its corresponding article and those included in 3 (changed since last successful sync).
///
@MainActor init(account: Account, feedlyUserId: String, lastSuccessfulFetchStartDate: Date?, markArticlesService: FeedlyMarkArticlesService, getUnreadService: FeedlyGetStreamIdsService, getCollectionsService: FeedlyGetCollectionsService, getStreamContentsService: FeedlyGetStreamContentsService, getStarredService: FeedlyGetStreamIdsService, getStreamIdsService: FeedlyGetStreamIdsService, getEntriesService: FeedlyGetEntriesService, database: SyncDatabase, downloadProgress: DownloadProgress, log: OSLog) {
@MainActor init(account: Account, feedlyUserID: String, lastSuccessfulFetchStartDate: Date?, markArticlesService: FeedlyMarkArticlesService, getUnreadService: FeedlyGetStreamIDsService, getCollectionsService: FeedlyGetCollectionsService, getStreamContentsService: FeedlyGetStreamContentsService, getStarredService: FeedlyGetStreamIDsService, getStreamIDsService: FeedlyGetStreamIDsService, getEntriesService: FeedlyGetEntriesService, database: SyncDatabase, downloadProgress: DownloadProgress, log: OSLog) {
self.syncUUID = UUID()
self.log = log
self.operationQueue.suspend()
@ -68,53 +68,53 @@ final class FeedlySyncAllOperation: FeedlyOperation {
createFeedsOperation.addDependency(mirrorCollectionsAsFolders)
self.operationQueue.add(createFeedsOperation)
let getAllArticleIds = FeedlyIngestStreamArticleIdsOperation(account: account, userId: feedlyUserId, service: getStreamIdsService, log: log)
getAllArticleIds.delegate = self
getAllArticleIds.downloadProgress = downloadProgress
getAllArticleIds.addDependency(createFeedsOperation)
self.operationQueue.add(getAllArticleIds)
let getAllArticleIDs = FeedlyIngestStreamArticleIDsOperation(account: account, userID: feedlyUserID, service: getStreamIDsService, log: log)
getAllArticleIDs.delegate = self
getAllArticleIDs.downloadProgress = downloadProgress
getAllArticleIDs.addDependency(createFeedsOperation)
self.operationQueue.add(getAllArticleIDs)
// Get each page of unread article ids in the global.all stream for the last 31 days (nil = Feedly API default).
let getUnread = FeedlyIngestUnreadArticleIdsOperation(account: account, userId: feedlyUserId, service: getUnreadService, database: database, newerThan: nil, log: log)
let getUnread = FeedlyIngestUnreadArticleIDsOperation(account: account, userID: feedlyUserID, service: getUnreadService, database: database, newerThan: nil, log: log)
getUnread.delegate = self
getUnread.addDependency(getAllArticleIds)
getUnread.addDependency(getAllArticleIDs)
getUnread.downloadProgress = downloadProgress
self.operationQueue.add(getUnread)
// Get each page of the article ids which have been update since the last successful fetch start date.
// If the date is nil, this operation provides an empty set (everything is new, nothing is updated).
let getUpdated = FeedlyGetUpdatedArticleIdsOperation(account: account, userId: feedlyUserId, service: getStreamIdsService, newerThan: lastSuccessfulFetchStartDate, log: log)
let getUpdated = FeedlyGetUpdatedArticleIDsOperation(account: account, userID: feedlyUserID, service: getStreamIDsService, newerThan: lastSuccessfulFetchStartDate, log: log)
getUpdated.delegate = self
getUpdated.downloadProgress = downloadProgress
getUpdated.addDependency(createFeedsOperation)
self.operationQueue.add(getUpdated)
// Get each page of the article ids for starred articles.
let getStarred = FeedlyIngestStarredArticleIdsOperation(account: account, userId: feedlyUserId, service: getStarredService, database: database, newerThan: nil, log: log)
let getStarred = FeedlyIngestStarredArticleIDsOperation(account: account, userID: feedlyUserID, service: getStarredService, database: database, newerThan: nil, log: log)
getStarred.delegate = self
getStarred.downloadProgress = downloadProgress
getStarred.addDependency(createFeedsOperation)
self.operationQueue.add(getStarred)
// Now all the possible article ids we need have a status, fetch the article ids for missing articles.
let getMissingIds = FeedlyFetchIdsForMissingArticlesOperation(account: account)
getMissingIds.delegate = self
getMissingIds.downloadProgress = downloadProgress
getMissingIds.addDependency(getAllArticleIds)
getMissingIds.addDependency(getUnread)
getMissingIds.addDependency(getStarred)
getMissingIds.addDependency(getUpdated)
self.operationQueue.add(getMissingIds)
let getMissingIDs = FeedlyFetchIDsForMissingArticlesOperation(account: account)
getMissingIDs.delegate = self
getMissingIDs.downloadProgress = downloadProgress
getMissingIDs.addDependency(getAllArticleIDs)
getMissingIDs.addDependency(getUnread)
getMissingIDs.addDependency(getStarred)
getMissingIDs.addDependency(getUpdated)
self.operationQueue.add(getMissingIDs)
// Download all the missing and updated articles
let downloadMissingArticles = FeedlyDownloadArticlesOperation(account: account,
missingArticleEntryIdProvider: getMissingIds,
updatedArticleEntryIdProvider: getUpdated,
missingArticleEntryIDProvider: getMissingIDs,
updatedArticleEntryIDProvider: getUpdated,
getEntriesService: getEntriesService,
log: log)
downloadMissingArticles.delegate = self
downloadMissingArticles.downloadProgress = downloadProgress
downloadMissingArticles.addDependency(getMissingIds)
downloadMissingArticles.addDependency(getMissingIDs)
downloadMissingArticles.addDependency(getUpdated)
self.operationQueue.add(downloadMissingArticles)
@ -126,8 +126,8 @@ final class FeedlySyncAllOperation: FeedlyOperation {
self.operationQueue.add(finishOperation)
}
@MainActor convenience init(account: Account, feedlyUserId: String, caller: FeedlyAPICaller, database: SyncDatabase, lastSuccessfulFetchStartDate: Date?, downloadProgress: DownloadProgress, log: OSLog) {
self.init(account: account, feedlyUserId: feedlyUserId, lastSuccessfulFetchStartDate: lastSuccessfulFetchStartDate, markArticlesService: caller, getUnreadService: caller, getCollectionsService: caller, getStreamContentsService: caller, getStarredService: caller, getStreamIdsService: caller, getEntriesService: caller, database: database, downloadProgress: downloadProgress, log: log)
@MainActor convenience init(account: Account, feedlyUserID: String, caller: FeedlyAPICaller, database: SyncDatabase, lastSuccessfulFetchStartDate: Date?, downloadProgress: DownloadProgress, log: OSLog) {
self.init(account: account, feedlyUserID: feedlyUserID, lastSuccessfulFetchStartDate: lastSuccessfulFetchStartDate, markArticlesService: caller, getUnreadService: caller, getCollectionsService: caller, getStreamContentsService: caller, getStarredService: caller, getStreamIDsService: caller, getEntriesService: caller, database: database, downloadProgress: downloadProgress, log: log)
}
override func run() {

View File

@ -16,7 +16,7 @@ import Core
final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationDelegate, FeedlyGetStreamContentsOperationDelegate, FeedlyCheckpointOperationDelegate {
private let account: Account
private let resource: FeedlyResourceId
private let resource: FeedlyResourceID
private let operationQueue = MainThreadOperationQueue()
private let service: FeedlyGetStreamContentsService
private let newerThan: Date?
@ -24,7 +24,7 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
private let log: OSLog
private let finishOperation: FeedlyCheckpointOperation
@MainActor init(account: Account, resource: FeedlyResourceId, service: FeedlyGetStreamContentsService, isPagingEnabled: Bool, newerThan: Date?, log: OSLog) {
@MainActor init(account: Account, resource: FeedlyResourceID, service: FeedlyGetStreamContentsService, isPagingEnabled: Bool, newerThan: Date?, log: OSLog) {
self.account = account
self.resource = resource
self.service = service
@ -42,7 +42,7 @@ final class FeedlySyncStreamContentsOperation: FeedlyOperation, FeedlyOperationD
}
@MainActor convenience init(account: Account, credentials: Credentials, service: FeedlyGetStreamContentsService, newerThan: Date?, log: OSLog) {
let all = FeedlyCategoryResourceId.Global.all(for: credentials.username)
let all = FeedlyCategoryResourceID.Global.all(for: credentials.username)
self.init(account: account, resource: all, service: service, isPagingEnabled: true, newerThan: newerThan, log: log)
}

View File

@ -27,7 +27,7 @@ final class FeedlyUpdateAccountFeedsWithItemsOperation: FeedlyOperation {
override func run() {
let feedIDsAndItems = organisedItemsProvider.parsedItemsKeyedByFeedId
let feedIDsAndItems = organisedItemsProvider.parsedItemsKeyedByFeedID
Task { @MainActor in
do {

View File

@ -9,5 +9,5 @@
import Foundation
protocol FeedlyGetStreamContentsService: AnyObject {
func getStreamContents(for resource: FeedlyResourceId, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ())
func getStreamContents(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ())
}

View File

@ -1,5 +1,5 @@
//
// FeedlyGetStreamIdsService.swift
// FeedlyGetStreamIDsService.swift
// Account
//
// Created by Kiel Gillard on 21/10/19.
@ -8,6 +8,6 @@
import Foundation
protocol FeedlyGetStreamIdsService: AnyObject {
func getStreamIds(for resource: FeedlyResourceId, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIds, Error>) -> ())
protocol FeedlyGetStreamIDsService: AnyObject {
func getStreamIDs(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIDs, Error>) -> ())
}

View File

@ -31,5 +31,5 @@ enum FeedlyMarkAction: String {
}
protocol FeedlyMarkArticlesService: AnyObject {
func mark(_ articleIds: Set<String>, as action: FeedlyMarkAction, completion: @escaping (Result<Void, Error>) -> ())
func mark(_ articleIDs: Set<String>, as action: FeedlyMarkAction, completion: @escaping (Result<Void, Error>) -> ())
}

View File

@ -36,7 +36,7 @@ public extension URLRequest {
URLQueryItem(name: "password", value: credentials.secret),
]
httpBody = postData.enhancedPercentEncodedQuery?.data(using: .utf8)
case .newsBlurSessionId:
case .newsBlurSessionID:
setValue("\(NewsBlurAPICaller.sessionIDCookieKey)=\(credentials.secret)", forHTTPHeaderField: "Cookie")
httpShouldHandleCookies = true
case .readerBasic:

View File

@ -64,7 +64,7 @@ class FeedlyCreateFeedsForCollectionFoldersOperationTests: XCTestCase {
waitForExpectations(timeout: 2)
let feedIds = Set([feedsForFolderOne, feedsForFolderTwo]
let feedIDs = Set([feedsForFolderOne, feedsForFolderTwo]
.flatMap { $0 }
.map { $0.id })
@ -73,28 +73,28 @@ class FeedlyCreateFeedsForCollectionFoldersOperationTests: XCTestCase {
.map { $0.title })
let accountFeeds = account.flattenedFeeds()
let ingestedIds = Set(accountFeeds.map { $0.feedID })
let ingestedIDs = Set(accountFeeds.map { $0.feedID })
let ingestedTitles = Set(accountFeeds.map { $0.nameForDisplay })
let missingIds = feedIds.subtracting(ingestedIds)
let missingIDs = feedIDs.subtracting(ingestedIDs)
let missingTitles = feedTitles.subtracting(ingestedTitles)
XCTAssertTrue(missingIds.isEmpty, "Failed to ingest feeds with these ids.")
XCTAssertTrue(missingIDs.isEmpty, "Failed to ingest feeds with these ids.")
XCTAssertTrue(missingTitles.isEmpty, "Failed to ingest feeds with these titles.")
let expectedFolderAndFeedIds = namesAndFeeds
let expectedFolderAndFeedIDs = namesAndFeeds
.sorted { $0.0.id < $1.0.id }
.map { folder, feeds -> [String: [String]] in
return [folder.id: feeds.map { $0.id }.sorted(by: <)]
}
let ingestedFolderAndFeedIds = (account.folders ?? Set())
let ingestedFolderAndFeedIDs = (account.folders ?? Set())
.sorted { $0.externalID! < $1.externalID! }
.compactMap { folder -> [String: [String]]? in
return [folder.externalID!: folder.topLevelFeeds.map { $0.feedID }.sorted(by: <)]
}
XCTAssertEqual(expectedFolderAndFeedIds, ingestedFolderAndFeedIds, "Did not ingest feeds in their corresponding folders.")
XCTAssertEqual(expectedFolderAndFeedIDs, ingestedFolderAndFeedIDs, "Did not ingest feeds in their corresponding folders.")
}
func testRemoveFeeds() {
@ -157,7 +157,7 @@ class FeedlyCreateFeedsForCollectionFoldersOperationTests: XCTestCase {
waitForExpectations(timeout: 2)
let feedIds = Set([feedsForFolderOne, feedsForFolderTwo]
let feedIDs = Set([feedsForFolderOne, feedsForFolderTwo]
.flatMap { $0 }
.map { $0.id })
@ -166,30 +166,30 @@ class FeedlyCreateFeedsForCollectionFoldersOperationTests: XCTestCase {
.map { $0.title })
let accountFeeds = account.flattenedFeeds()
let ingestedIds = Set(accountFeeds.map { $0.feedID })
let ingestedIDs = Set(accountFeeds.map { $0.feedID })
let ingestedTitles = Set(accountFeeds.map { $0.nameForDisplay })
XCTAssertEqual(ingestedIds.count, feedIds.count)
XCTAssertEqual(ingestedIDs.count, feedIDs.count)
XCTAssertEqual(ingestedTitles.count, feedTitles.count)
let missingIds = feedIds.subtracting(ingestedIds)
let missingIDs = feedIDs.subtracting(ingestedIDs)
let missingTitles = feedTitles.subtracting(ingestedTitles)
XCTAssertTrue(missingIds.isEmpty, "Failed to ingest feeds with these ids.")
XCTAssertTrue(missingIDs.isEmpty, "Failed to ingest feeds with these ids.")
XCTAssertTrue(missingTitles.isEmpty, "Failed to ingest feeds with these titles.")
let expectedFolderAndFeedIds = namesAndFeeds
let expectedFolderAndFeedIDs = namesAndFeeds
.sorted { $0.0.id < $1.0.id }
.map { folder, feeds -> [String: [String]] in
return [folder.id: feeds.map { $0.id }.sorted(by: <)]
}
let ingestedFolderAndFeedIds = (account.folders ?? Set())
let ingestedFolderAndFeedIDs = (account.folders ?? Set())
.sorted { $0.externalID! < $1.externalID! }
.compactMap { folder -> [String: [String]]? in
return [folder.externalID!: folder.topLevelFeeds.map { $0.feedID }.sorted(by: <)]
}
XCTAssertEqual(expectedFolderAndFeedIds, ingestedFolderAndFeedIds, "Did not ingest feeds to their corresponding folders.")
XCTAssertEqual(expectedFolderAndFeedIDs, ingestedFolderAndFeedIDs, "Did not ingest feeds to their corresponding folders.")
}
}

View File

@ -38,7 +38,7 @@ class FeedlyEntryParserTests: XCTestCase {
let parser = FeedlyEntryParser(entry: entry)
XCTAssertEqual(parser.id, entry.id)
XCTAssertEqual(parser.feedUrl, origin.streamId)
XCTAssertEqual(parser.feedUrl, origin.streamID)
XCTAssertEqual(parser.externalUrl, canonicalLink.href)
XCTAssertEqual(parser.title, entry.title)
XCTAssertEqual(parser.contentHMTL, content.content)
@ -56,7 +56,7 @@ class FeedlyEntryParserTests: XCTestCase {
// The following is not an error.
// The feedURL must match the feedID for the article to be connected to its matching feed.
XCTAssertEqual(item.feedURL, origin.streamId)
XCTAssertEqual(item.feedURL, origin.streamID)
XCTAssertEqual(item.title, entry.title)
XCTAssertEqual(item.contentHTML, content.content)
XCTAssertEqual(item.contentText, nil, "Is it now free of HTML characters?")

View File

@ -36,21 +36,21 @@ class FeedlyGetCollectionsOperationTests: XCTestCase {
let ids = Set(getCollections.collections.map { $0.id })
let missingLabels = labelsInJSON.subtracting(labels)
let missingIds = idsInJSON.subtracting(ids)
let missingIDs = idsInJSON.subtracting(ids)
XCTAssertEqual(getCollections.collections.count, collections.count, "Mismatch between collections provided by operation and test JSON collections.")
XCTAssertTrue(missingLabels.isEmpty, "Collections with these labels did not have a corresponding \(FeedlyCollection.self) value with the same name.")
XCTAssertTrue(missingIds.isEmpty, "Collections with these ids did not have a corresponding \(FeedlyCollection.self) with the same id.")
XCTAssertTrue(missingIDs.isEmpty, "Collections with these ids did not have a corresponding \(FeedlyCollection.self) with the same id.")
for collection in collections {
let collectionId = collection["id"] as! String
let collectionID = collection["id"] as! String
let collectionFeeds = collection["feeds"] as! [[String: Any]]
let collectionFeedIds = Set(collectionFeeds.map { $0["id"] as! String })
for operationCollection in getCollections.collections where operationCollection.id == collectionId {
let feedIds = Set(operationCollection.feeds.map { $0.id })
let missingIds = collectionFeedIds.subtracting(feedIds)
XCTAssertTrue(missingIds.isEmpty, "Feeds with these ids were not found in the \"\(operationCollection.label)\" \(FeedlyCollection.self).")
let collectionFeedIDs = Set(collectionFeeds.map { $0["id"] as! String })
for operationCollection in getCollections.collections where operationCollection.id == collectionID {
let feedIDs = Set(operationCollection.feeds.map { $0.id })
let missingIDs = collectionFeedIDs.subtracting(feedIDs)
XCTAssertTrue(missingIDs.isEmpty, "Feeds with these ids were not found in the \"\(operationCollection.label)\" \(FeedlyCollection.self).")
}
}
}

View File

@ -28,7 +28,7 @@ class FeedlyGetStreamContentsOperationTests: XCTestCase {
func testGetStreamContentsFailure() {
let service = TestGetStreamContentsService()
let resource = FeedlyCategoryResourceId(id: "user/1234/category/5678")
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
let getStreamContents = FeedlyGetStreamContentsOperation(account: account, resource: resource, service: service, continuation: nil, newerThan: nil, unreadOnly: nil, log: support.log)
@ -48,7 +48,7 @@ class FeedlyGetStreamContentsOperationTests: XCTestCase {
func testValuesPassingForGetStreamContents() {
let service = TestGetStreamContentsService()
let resource = FeedlyCategoryResourceId(id: "user/1234/category/5678")
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
let continuation: String? = "abcdefg"
let newerThan: Date? = Date(timeIntervalSinceReferenceDate: 86)
@ -85,9 +85,9 @@ class FeedlyGetStreamContentsOperationTests: XCTestCase {
XCTAssertEqual(stream.updated, mockStream.updated)
XCTAssertEqual(stream.continuation, mockStream.continuation)
let streamIds = stream.items.map { $0.id }
let mockStreamIds = mockStream.items.map { $0.id }
XCTAssertEqual(streamIds, mockStreamIds)
let streamIDs = stream.items.map { $0.id }
let mockStreamIDs = mockStream.items.map { $0.id }
XCTAssertEqual(streamIDs, mockStreamIDs)
}
func testGetStreamContentsFromJSON() {
@ -96,7 +96,7 @@ class FeedlyGetStreamContentsOperationTests: XCTestCase {
let jsonName = "JSON/feedly_macintosh_initial"
transport.testFiles["/v3/streams/contents"] = "\(jsonName).json"
let resource = FeedlyCategoryResourceId(id: "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/5ca4d61d-e55d-4999-a8d1-c3b9d8789815")
let resource = FeedlyCategoryResourceID(id: "user/f2f031bd-f3e3-4893-a447-467a291c6d1e/category/5ca4d61d-e55d-4999-a8d1-c3b9d8789815")
let getStreamContents = FeedlyGetStreamContentsOperation(account: account, resource: resource, service: caller, continuation: nil, newerThan: nil, unreadOnly: nil, log: support.log)
let completionExpectation = expectation(description: "Did Finish")

View File

@ -1,5 +1,5 @@
//
// FeedlyGetStreamIdsOperationTests.swift
// FeedlyGetStreamIDsOperationTests.swift
// AccountTests
//
// Created by Kiel Gillard on 23/10/19.
@ -9,7 +9,7 @@
import XCTest
@testable import Account
class FeedlyGetStreamIdsOperationTests: XCTestCase {
class FeedlyGetStreamIDsOperationTests: XCTestCase {
private var account: Account!
private let support = FeedlyTestSupport()
@ -26,39 +26,39 @@ class FeedlyGetStreamIdsOperationTests: XCTestCase {
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)
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
getStreamIDs.completionBlock = { _ in
completionExpectation.fulfill()
}
MainThreadOperationQueue.shared.add(getStreamIds)
MainThreadOperationQueue.shared.add(getStreamIDs)
waitForExpectations(timeout: 2)
XCTAssertNil(getStreamIds.streamIds)
XCTAssertNil(getStreamIDs.streamIDs)
}
func testValuesPassingForGetStreamIds() {
let service = TestGetStreamIdsService()
let resource = FeedlyCategoryResourceId(id: "user/1234/category/5678")
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")
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)
@ -68,49 +68,49 @@ class FeedlyGetStreamIdsOperationTests: XCTestCase {
}
let completionExpectation = expectation(description: "Did Finish")
getStreamIds.completionBlock = { _ in
getStreamIDs.completionBlock = { _ in
completionExpectation.fulfill()
}
MainThreadOperationQueue.shared.add(getStreamIds)
MainThreadOperationQueue.shared.add(getStreamIDs)
waitForExpectations(timeout: 2)
guard let streamIds = getStreamIds.streamIds else {
XCTFail("\(FeedlyGetStreamIdsOperation.self) did not store the stream.")
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)
XCTAssertEqual(streamIDs.continuation, mockStreamIDs.continuation)
XCTAssertEqual(streamIDs.ids, mockStreamIDs.ids)
}
func testGetStreamIdsFromJSON() {
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 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
getStreamIDs.completionBlock = { _ in
completionExpectation.fulfill()
}
MainThreadOperationQueue.shared.add(getStreamIds)
MainThreadOperationQueue.shared.add(getStreamIDs)
waitForExpectations(timeout: 2)
guard let streamIds = getStreamIds.streamIds else {
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])
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])
}
}

View File

@ -47,16 +47,16 @@ class FeedlyMirrorCollectionsAsFoldersOperationTests: XCTestCase {
let folders = account.folders ?? Set()
let folderNames = Set(folders.compactMap { $0.nameForDisplay })
let folderExternalIds = Set(folders.compactMap { $0.externalID })
let folderExternalIDs = Set(folders.compactMap { $0.externalID })
let collectionLabels = Set(provider.collections.map { $0.label })
let collectionIds = Set(provider.collections.map { $0.id })
let collectionIDs = Set(provider.collections.map { $0.id })
let missingNames = collectionLabels.subtracting(folderNames)
let missingIds = collectionIds.subtracting(folderExternalIds)
let missingIDs = collectionIDs.subtracting(folderExternalIDs)
XCTAssertTrue(missingNames.isEmpty, "Collections with these labels have no corresponding folder.")
XCTAssertTrue(missingIds.isEmpty, "Collections with these ids have no corresponding folder.")
XCTAssertTrue(missingIDs.isEmpty, "Collections with these ids have no corresponding folder.")
// XCTAssertEqual(mirrorOperation.collectionsAndFolders.count, provider.collections.count, "Mismatch between collections and folders.")
}
@ -90,16 +90,16 @@ class FeedlyMirrorCollectionsAsFoldersOperationTests: XCTestCase {
let folders = account.folders ?? Set()
let folderNames = Set(folders.compactMap { $0.nameForDisplay })
let folderExternalIds = Set(folders.compactMap { $0.externalID })
let folderExternalIDs = Set(folders.compactMap { $0.externalID })
let collectionLabels = Set(provider.collections.map { $0.label })
let collectionIds = Set(provider.collections.map { $0.id })
let collectionIDs = Set(provider.collections.map { $0.id })
let remainingNames = folderNames.subtracting(collectionLabels)
let remainingIds = folderExternalIds.subtracting(collectionIds)
let remainingIDs = folderExternalIDs.subtracting(collectionIDs)
XCTAssertTrue(remainingNames.isEmpty, "Folders with these names remain with no corresponding collection.")
XCTAssertTrue(remainingIds.isEmpty, "Folders with these ids remain with no corresponding collection.")
XCTAssertTrue(remainingIDs.isEmpty, "Folders with these ids remain with no corresponding collection.")
XCTAssertTrue(removeFolders.feedsAndFolders.isEmpty)
}
@ -137,29 +137,29 @@ class FeedlyMirrorCollectionsAsFoldersOperationTests: XCTestCase {
let folders = account.folders ?? Set()
let folderNames = Set(folders.compactMap { $0.nameForDisplay })
let folderExternalIds = Set(folders.compactMap { $0.externalID })
let folderExternalIDs = Set(folders.compactMap { $0.externalID })
let collectionLabels = Set(provider.collections.map { $0.label })
let collectionIds = Set(provider.collections.map { $0.id })
let collectionIDs = Set(provider.collections.map { $0.id })
let missingNames = collectionLabels.subtracting(folderNames)
let missingIds = collectionIds.subtracting(folderExternalIds)
let missingIDs = collectionIDs.subtracting(folderExternalIDs)
XCTAssertTrue(missingNames.isEmpty, "Collections with these labels have no corresponding folder.")
XCTAssertTrue(missingIds.isEmpty, "Collections with these ids have no corresponding folder.")
XCTAssertTrue(missingIDs.isEmpty, "Collections with these ids have no corresponding folder.")
let collectionIdsAndFeedIds = provider.collections.map { collection -> [String:[String]] in
let collectionIDsAndFeedIDs = provider.collections.map { collection -> [String:[String]] in
return [collection.id: collection.feeds.map { $0.id }.sorted(by: <)]
}
let folderIdsAndFeedIds = mirrorOperation.feedsAndFolders.compactMap { feeds, folder -> [String:[String]]? in
let folderIDsAndFeedIDs = mirrorOperation.feedsAndFolders.compactMap { feeds, folder -> [String:[String]]? in
guard let id = folder.externalID else {
return nil
}
return [id: feeds.map { $0.id }.sorted(by: <)]
}
XCTAssertEqual(collectionIdsAndFeedIds, folderIdsAndFeedIds, "Did not map folders to feeds correctly.")
XCTAssertEqual(collectionIDsAndFeedIDs, folderIDsAndFeedIDs, "Did not map folders to feeds correctly.")
}
func testRemovingFolderRemovesFeeds() {

View File

@ -29,13 +29,13 @@ class FeedlyOrganiseParsedItemsByFeedOperationTests: XCTestCase {
struct TestParsedItemsProvider: FeedlyParsedItemProviding {
let parsedItemProviderName = "TestParsedItemsProvider"
var resource: FeedlyResourceId
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 resource = FeedlyCategoryResourceID(id: "user/12345/category/6789")
let parsedEntries = Set(entries.values.flatMap { $0 })
let provider = TestParsedItemsProvider(resource: resource, parsedEntries: parsedEntries)
@ -50,13 +50,13 @@ class FeedlyOrganiseParsedItemsByFeedOperationTests: XCTestCase {
waitForExpectations(timeout: 2)
let itemsAndFeedIds = organise.parsedItemsKeyedByFeedId
XCTAssertEqual(itemsAndFeedIds, entries)
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 resource = FeedlyCategoryResourceID(id: "user/12345/category/6789")
let parsedEntries = Set(entries.values.flatMap { $0 })
let provider = TestParsedItemsProvider(resource: resource, parsedEntries: parsedEntries)
@ -71,13 +71,13 @@ class FeedlyOrganiseParsedItemsByFeedOperationTests: XCTestCase {
waitForExpectations(timeout: 2)
let itemsAndFeedIds = organise.parsedItemsKeyedByFeedId
XCTAssertEqual(itemsAndFeedIds, entries)
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 resource = FeedlyCategoryResourceID(id: "user/12345/category/6789")
let parsedEntries = Set(entries.values.flatMap { $0 })
let provider = TestParsedItemsProvider(resource: resource, parsedEntries: parsedEntries)
@ -92,7 +92,7 @@ class FeedlyOrganiseParsedItemsByFeedOperationTests: XCTestCase {
waitForExpectations(timeout: 2)
let itemsAndFeedIds = organise.parsedItemsKeyedByFeedId
XCTAssertEqual(itemsAndFeedIds, entries)
let itemsAndFeedIDs = organise.parsedItemsKeyedByFeedID
XCTAssertEqual(itemsAndFeedIDs, entries)
}
}

View File

@ -1,5 +1,5 @@
//
// FeedlyResourceIdTests.swift
// FeedlyResourceIDTests.swift
// AccountTests
//
// Created by Kiel Gillard on 3/10/19.
@ -9,15 +9,15 @@
import XCTest
@testable import Account
class FeedlyResourceIdTests: XCTestCase {
class FeedlyResourceIDTests: XCTestCase {
func testFeedResourceId() {
func testFeedResourceID() {
let expectedUrl = "http://ranchero.com/blog/atom.xml"
let feedResource = FeedlyFeedResourceId(id: "feed/\(expectedUrl)")
let urlResource = FeedlyFeedResourceId(id: expectedUrl)
let otherResource = FeedlyFeedResourceId(id: "whiskey/\(expectedUrl)")
let invalidResource = FeedlyFeedResourceId(id: "")
let feedResource = FeedlyFeedResourceID(id: "feed/\(expectedUrl)")
let urlResource = FeedlyFeedResourceID(id: expectedUrl)
let otherResource = FeedlyFeedResourceID(id: "whiskey/\(expectedUrl)")
let invalidResource = FeedlyFeedResourceID(id: "")
XCTAssertEqual(feedResource.url, expectedUrl)
XCTAssertEqual(urlResource.url, expectedUrl)

View File

@ -46,8 +46,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
}
func testSendUnreadSuccess() {
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .read, flag: false) }
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .read, flag: false) }
let insertExpectation = expectation(description: "Inserted Statuses")
container.database.insertStatuses(statuses) { error in
@ -59,8 +59,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
let service = TestMarkArticlesService()
service.mockResult = .success(())
service.parameterTester = { serviceArticleIds, action in
XCTAssertEqual(serviceArticleIds, articleIds)
service.parameterTester = { serviceArticleIDs, action in
XCTAssertEqual(serviceArticleIDs, articleIDs)
XCTAssertEqual(action, .unread)
}
@ -89,8 +89,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
}
func testSendUnreadFailure() {
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .read, flag: false) }
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .read, flag: false) }
let insertExpectation = expectation(description: "Inserted Statuses")
container.database.insertStatuses(statuses) { error in
@ -102,8 +102,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
let service = TestMarkArticlesService()
service.mockResult = .failure(URLError(.timedOut))
service.parameterTester = { serviceArticleIds, action in
XCTAssertEqual(serviceArticleIds, articleIds)
service.parameterTester = { serviceArticleIDs, action in
XCTAssertEqual(serviceArticleIDs, articleIDs)
XCTAssertEqual(action, .unread)
}
@ -132,8 +132,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
}
func testSendReadSuccess() {
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .read, flag: true) }
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .read, flag: true) }
let insertExpectation = expectation(description: "Inserted Statuses")
container.database.insertStatuses(statuses) { error in
@ -145,8 +145,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
let service = TestMarkArticlesService()
service.mockResult = .success(())
service.parameterTester = { serviceArticleIds, action in
XCTAssertEqual(serviceArticleIds, articleIds)
service.parameterTester = { serviceArticleIDs, action in
XCTAssertEqual(serviceArticleIDs, articleIDs)
XCTAssertEqual(action, .read)
}
@ -175,8 +175,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
}
func testSendReadFailure() {
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .read, flag: true) }
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .read, flag: true) }
let insertExpectation = expectation(description: "Inserted Statuses")
container.database.insertStatuses(statuses) { error in
@ -188,8 +188,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
let service = TestMarkArticlesService()
service.mockResult = .failure(URLError(.timedOut))
service.parameterTester = { serviceArticleIds, action in
XCTAssertEqual(serviceArticleIds, articleIds)
service.parameterTester = { serviceArticleIDs, action in
XCTAssertEqual(serviceArticleIDs, articleIDs)
XCTAssertEqual(action, .read)
}
@ -218,8 +218,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
}
func testSendStarredSuccess() {
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .starred, flag: true) }
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .starred, flag: true) }
let insertExpectation = expectation(description: "Inserted Statuses")
container.database.insertStatuses(statuses) { error in
@ -231,8 +231,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
let service = TestMarkArticlesService()
service.mockResult = .success(())
service.parameterTester = { serviceArticleIds, action in
XCTAssertEqual(serviceArticleIds, articleIds)
service.parameterTester = { serviceArticleIDs, action in
XCTAssertEqual(serviceArticleIDs, articleIDs)
XCTAssertEqual(action, .saved)
}
@ -261,8 +261,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
}
func testSendStarredFailure() {
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .starred, flag: true) }
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .starred, flag: true) }
let insertExpectation = expectation(description: "Inserted Statuses")
container.database.insertStatuses(statuses) { error in
@ -274,8 +274,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
let service = TestMarkArticlesService()
service.mockResult = .failure(URLError(.timedOut))
service.parameterTester = { serviceArticleIds, action in
XCTAssertEqual(serviceArticleIds, articleIds)
service.parameterTester = { serviceArticleIDs, action in
XCTAssertEqual(serviceArticleIDs, articleIDs)
XCTAssertEqual(action, .saved)
}
@ -304,8 +304,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
}
func testSendUnstarredSuccess() {
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .starred, flag: false) }
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .starred, flag: false) }
let insertExpectation = expectation(description: "Inserted Statuses")
container.database.insertStatuses(statuses) { error in
@ -317,8 +317,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
let service = TestMarkArticlesService()
service.mockResult = .success(())
service.parameterTester = { serviceArticleIds, action in
XCTAssertEqual(serviceArticleIds, articleIds)
service.parameterTester = { serviceArticleIDs, action in
XCTAssertEqual(serviceArticleIDs, articleIDs)
XCTAssertEqual(action, .unsaved)
}
@ -347,8 +347,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
}
func testSendUnstarredFailure() {
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIds.map { SyncStatus(articleID: $0, key: .starred, flag: false) }
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
let statuses = articleIDs.map { SyncStatus(articleID: $0, key: .starred, flag: false) }
let insertExpectation = expectation(description: "Inserted Statuses")
container.database.insertStatuses(statuses) { error in
@ -360,8 +360,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
let service = TestMarkArticlesService()
service.mockResult = .failure(URLError(.timedOut))
service.parameterTester = { serviceArticleIds, action in
XCTAssertEqual(serviceArticleIds, articleIds)
service.parameterTester = { serviceArticleIDs, action in
XCTAssertEqual(serviceArticleIDs, articleIDs)
XCTAssertEqual(action, .unsaved)
}
@ -390,13 +390,13 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
}
func testSendAllSuccess() {
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
let keys = [SyncStatus.Key.read, .starred]
let flags = [true, false]
let statuses = articleIds.map { articleId -> SyncStatus in
let statuses = articleIDs.map { articleID -> SyncStatus in
let key = keys.randomElement()!
let flag = flags.randomElement()!
let status = SyncStatus(articleID: articleId, key: key, flag: flag)
let status = SyncStatus(articleID: articleID, key: key, flag: flag)
return status
}
@ -410,7 +410,7 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
let service = TestMarkArticlesService()
service.mockResult = .success(())
service.parameterTester = { serviceArticleIds, action in
service.parameterTester = { serviceArticleIDs, action in
let syncStatuses: [SyncStatus]
switch action {
case .read:
@ -422,8 +422,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
case .unsaved:
syncStatuses = statuses.filter { $0.key == .starred && $0.flag == false }
}
let expectedArticleIds = Set(syncStatuses.map { $0.articleID })
XCTAssertEqual(serviceArticleIds, expectedArticleIds)
let expectedArticleIDs = Set(syncStatuses.map { $0.articleID })
XCTAssertEqual(serviceArticleIDs, expectedArticleIDs)
}
let send = FeedlySendArticleStatusesOperation(database: container.database, service: service, log: support.log)
@ -450,13 +450,13 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
}
func testSendAllFailure() {
let articleIds = Set((0..<100).map { "feed/0/article/\($0)" })
let articleIDs = Set((0..<100).map { "feed/0/article/\($0)" })
let keys = [SyncStatus.Key.read, .starred]
let flags = [true, false]
let statuses = articleIds.map { articleId -> SyncStatus in
let statuses = articleIDs.map { articleID -> SyncStatus in
let key = keys.randomElement()!
let flag = flags.randomElement()!
let status = SyncStatus(articleID: articleId, key: key, flag: flag)
let status = SyncStatus(articleID: articleID, key: key, flag: flag)
return status
}
@ -470,7 +470,7 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
let service = TestMarkArticlesService()
service.mockResult = .failure(URLError(.timedOut))
service.parameterTester = { serviceArticleIds, action in
service.parameterTester = { serviceArticleIDs, action in
let syncStatuses: [SyncStatus]
switch action {
case .read:
@ -482,8 +482,8 @@ class FeedlySendArticleStatusesOperationTests: XCTestCase {
case .unsaved:
syncStatuses = statuses.filter { $0.key == .starred && $0.flag == false }
}
let expectedArticleIds = Set(syncStatuses.map { $0.articleID })
XCTAssertEqual(serviceArticleIds, expectedArticleIds)
let expectedArticleIDs = Set(syncStatuses.map { $0.articleID })
XCTAssertEqual(serviceArticleIDs, expectedArticleIDs)
}
let send = FeedlySendArticleStatusesOperation(database: container.database, service: service, log: support.log)

View File

@ -28,7 +28,7 @@ class FeedlySyncStreamContentsOperationTests: XCTestCase {
func testIngestsOnePageSuccess() throws {
let service = TestGetStreamContentsService()
let resource = FeedlyCategoryResourceId(id: "user/1234/category/5678")
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
let newerThan: Date? = Date(timeIntervalSinceReferenceDate: 0)
let items = service.makeMockFeedlyEntryItem()
service.mockResult = .success(FeedlyStream(id: resource.id, updated: nil, continuation: nil, items: items))
@ -55,14 +55,14 @@ class FeedlySyncStreamContentsOperationTests: XCTestCase {
waitForExpectations(timeout: 2)
let expectedArticleIds = Set(items.map { $0.id })
let expectedArticles = try account.fetchArticles(.articleIDs(expectedArticleIds))
XCTAssertEqual(expectedArticles.count, expectedArticleIds.count, "Did not fetch all the articles.")
let expectedArticleIDs = Set(items.map { $0.id })
let expectedArticles = try account.fetchArticles(.articleIDs(expectedArticleIDs))
XCTAssertEqual(expectedArticles.count, expectedArticleIDs.count, "Did not fetch all the articles.")
}
func testIngestsOnePageFailure() {
let service = TestGetStreamContentsService()
let resource = FeedlyCategoryResourceId(id: "user/1234/category/5678")
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
let newerThan: Date? = Date(timeIntervalSinceReferenceDate: 0)
service.mockResult = .failure(URLError(.timedOut))
@ -92,7 +92,7 @@ class FeedlySyncStreamContentsOperationTests: XCTestCase {
func testIngestsManyPagesSuccess() throws {
let service = TestGetPagedStreamContentsService()
let resource = FeedlyCategoryResourceId(id: "user/1234/category/5678")
let resource = FeedlyCategoryResourceID(id: "user/1234/category/5678")
let newerThan: Date? = Date(timeIntervalSinceReferenceDate: 0)
let continuations = (1...10).map { "\($0)" }
@ -131,8 +131,8 @@ class FeedlySyncStreamContentsOperationTests: XCTestCase {
waitForExpectations(timeout: 30)
// Find articles inserted.
let articleIds = Set(service.pages.values.map { $0.items }.flatMap { $0 }.map { $0.id })
let articles = try account.fetchArticles(.articleIDs(articleIds))
XCTAssertEqual(articleIds.count, articles.count)
let articleIDs = Set(service.pages.values.map { $0.items }.flatMap { $0 }.map { $0.id })
let articles = try account.fetchArticles(.articleIDs(articleIDs))
XCTAssertEqual(articleIDs.count, articles.count)
}
}

View File

@ -99,18 +99,18 @@ class FeedlyTestSupport {
func checkFoldersAndFeeds(in account: Account, againstCollectionsAndFeedsInJSONNamed name: String, subdirectory: String? = nil) {
let collections = testJSON(named: name, subdirectory: subdirectory) as! [[String:Any]]
let collectionNames = Set(collections.map { $0["label"] as! String })
let collectionIds = Set(collections.map { $0["id"] as! String })
let collectionIDs = Set(collections.map { $0["id"] as! String })
let folders = account.folders ?? Set()
let folderNames = Set(folders.compactMap { $0.name })
let folderIds = Set(folders.compactMap { $0.externalID })
let folderIDs = Set(folders.compactMap { $0.externalID })
let missingNames = collectionNames.subtracting(folderNames)
let missingIds = collectionIds.subtracting(folderIds)
let missingIDs = collectionIDs.subtracting(folderIDs)
XCTAssertEqual(folders.count, collections.count, "Mismatch between collections and folders.")
XCTAssertTrue(missingNames.isEmpty, "Collections with these names did not have a corresponding folder with the same name.")
XCTAssertTrue(missingIds.isEmpty, "Collections with these ids did not have a corresponding folder with the same id.")
XCTAssertTrue(missingIDs.isEmpty, "Collections with these ids did not have a corresponding folder with the same id.")
for collection in collections {
checkSingleFolderAndFeeds(in: account, againstOneCollectionAndFeedsInJSONPayload: collection)
@ -134,11 +134,11 @@ class FeedlyTestSupport {
XCTAssertEqual(collectionFeeds.count, folderFeeds.count)
let collectionFeedIds = Set(collectionFeeds.map { $0["id"] as! String })
let folderFeedIds = Set(folderFeeds.map { $0.feedID })
let missingFeedIds = collectionFeedIds.subtracting(folderFeedIds)
let collectionFeedIDs = Set(collectionFeeds.map { $0["id"] as! String })
let folderFeedIDs = Set(folderFeeds.map { $0.feedID })
let missingFeedIDs = collectionFeedIDs.subtracting(folderFeedIDs)
XCTAssertTrue(missingFeedIds.isEmpty, "Feeds with these ids were not found in the \"\(label)\" folder.")
XCTAssertTrue(missingFeedIDs.isEmpty, "Feeds with these ids were not found in the \"\(label)\" folder.")
}
func checkArticles(in account: Account, againstItemsInStreamInJSONNamed name: String, subdirectory: String? = nil) throws {
@ -152,7 +152,7 @@ class FeedlyTestSupport {
private struct ArticleItem {
var id: String
var feedId: String
var feedID: String
var content: String
var JSON: [String: Any]
var unread: Bool
@ -177,7 +177,7 @@ class FeedlyTestSupport {
self.id = item["id"] as! String
let origin = item["origin"] as! [String: Any]
self.feedId = origin["streamId"] as! String
self.feedID = origin["streamId"] as! String
let content = item["content"] as? [String: Any]
let summary = item["summary"] as? [String: Any]
@ -192,12 +192,12 @@ class FeedlyTestSupport {
let items = stream["items"] as! [[String: Any]]
let articleItems = items.map { ArticleItem(item: $0) }
let itemIds = Set(articleItems.map { $0.id })
let itemIDs = Set(articleItems.map { $0.id })
let articles = try testAccount.fetchArticles(.articleIDs(itemIds))
let articleIds = Set(articles.map { $0.articleID })
let articles = try testAccount.fetchArticles(.articleIDs(itemIDs))
let articleIDs = Set(articles.map { $0.articleID })
let missing = itemIds.subtracting(articleIds)
let missing = itemIDs.subtracting(articleIDs)
XCTAssertEqual(items.count, articles.count)
XCTAssertTrue(missing.isEmpty, "Items with these ids did not have a corresponding article with the same id.")
@ -212,61 +212,61 @@ class FeedlyTestSupport {
}
}
func checkUnreadStatuses(in account: Account, againstIdsInStreamInJSONNamed name: String, subdirectory: String? = nil, testCase: XCTestCase) {
let streamIds = testJSON(named: name, subdirectory: subdirectory) as! [String:Any]
checkUnreadStatuses(in: account, correspondToIdsInJSONPayload: streamIds, testCase: testCase)
func checkUnreadStatuses(in account: Account, againstIDsInStreamInJSONNamed name: String, subdirectory: String? = nil, testCase: XCTestCase) {
let streadIDs = testJSON(named: name, subdirectory: subdirectory) as! [String:Any]
checkUnreadStatuses(in: account, correspondToIDsInJSONPayload: streadIDs, testCase: testCase)
}
func checkUnreadStatuses(in testAccount: Account, correspondToIdsInJSONPayload streamIds: [String: Any], testCase: XCTestCase) {
let ids = Set(streamIds["ids"] as! [String])
let fetchIdsExpectation = testCase.expectation(description: "Fetch Article Ids")
testAccount.fetchUnreadArticleIDs { articleIdsResult in
func checkUnreadStatuses(in testAccount: Account, correspondToIDsInJSONPayload streadIDs: [String: Any], testCase: XCTestCase) {
let ids = Set(streadIDs["ids"] as! [String])
let fetchIDsExpectation = testCase.expectation(description: "Fetch Article IDs")
testAccount.fetchUnreadArticleIDs { articleIDsResult in
do {
let articleIds = try articleIdsResult.get()
let articleIDs = try articleIDsResult.get()
// Unread statuses can be paged from Feedly.
// Instead of joining test data, the best we can do is
// make sure that these ids are marked as unread (a subset of the total).
XCTAssertTrue(ids.isSubset(of: articleIds), "Some articles in `ids` are not marked as unread.")
fetchIdsExpectation.fulfill()
XCTAssertTrue(ids.isSubset(of: articleIDs), "Some articles in `ids` are not marked as unread.")
fetchIDsExpectation.fulfill()
} catch {
XCTFail("Error unwrapping article IDs: \(error)")
}
}
testCase.wait(for: [fetchIdsExpectation], timeout: 2)
testCase.wait(for: [fetchIDsExpectation], timeout: 2)
}
func checkStarredStatuses(in account: Account, againstItemsInStreamInJSONNamed name: String, subdirectory: String? = nil, testCase: XCTestCase) {
let streamIds = testJSON(named: name, subdirectory: subdirectory) as! [String:Any]
checkStarredStatuses(in: account, correspondToStreamItemsIn: streamIds, testCase: testCase)
let streadIDs = testJSON(named: name, subdirectory: subdirectory) as! [String:Any]
checkStarredStatuses(in: account, correspondToStreamItemsIn: streadIDs, testCase: testCase)
}
func checkStarredStatuses(in testAccount: Account, correspondToStreamItemsIn stream: [String: Any], testCase: XCTestCase) {
let items = stream["items"] as! [[String: Any]]
let ids = Set(items.map { $0["id"] as! String })
let fetchIdsExpectation = testCase.expectation(description: "Fetch Article Ids")
testAccount.fetchStarredArticleIDs { articleIdsResult in
let fetchIDsExpectation = testCase.expectation(description: "Fetch Article Ids")
testAccount.fetchStarredArticleIDs { articleIDsResult in
do {
let articleIds = try articleIdsResult.get()
let articleIDs = try articleIDsResult.get()
// Starred articles can be paged from Feedly.
// Instead of joining test data, the best we can do is
// make sure that these articles are marked as starred (a subset of the total).
XCTAssertTrue(ids.isSubset(of: articleIds), "Some articles in `ids` are not marked as starred.")
fetchIdsExpectation.fulfill()
XCTAssertTrue(ids.isSubset(of: articleIDs), "Some articles in `ids` are not marked as starred.")
fetchIDsExpectation.fulfill()
} catch {
XCTFail("Error unwrapping article IDs: \(error)")
}
}
testCase.wait(for: [fetchIdsExpectation], timeout: 2)
testCase.wait(for: [fetchIDsExpectation], timeout: 2)
}
func check(_ entries: [FeedlyEntry], correspondToStreamItemsIn stream: [String: Any]) {
let items = stream["items"] as! [[String: Any]]
let itemIds = Set(items.map { $0["id"] as! String })
let itemIDs = Set(items.map { $0["id"] as! String })
let articleIds = Set(entries.map { $0.id })
let articleIDs = Set(entries.map { $0.id })
let missing = itemIds.subtracting(articleIds)
let missing = itemIDs.subtracting(articleIDs)
XCTAssertEqual(items.count, entries.count)
XCTAssertTrue(missing.isEmpty, "Failed to create \(FeedlyEntry.self) values from objects in the JSON with these ids.")
@ -274,9 +274,9 @@ class FeedlyTestSupport {
func makeParsedItemTestDataFor(numberOfFeeds: Int, numberOfItemsInFeeds: Int) -> [String: Set<ParsedItem>] {
let ids = (0..<numberOfFeeds).map { "feed/\($0)" }
let feedIdsAndItemCounts = ids.map { ($0, numberOfItemsInFeeds) }
let feedIDsAndItemCounts = ids.map { ($0, numberOfItemsInFeeds) }
let entries = feedIdsAndItemCounts.map { (feedId, count) -> (String, [Int]) in
let entries = feedIDsAndItemCounts.map { (feedId, count) -> (String, [Int]) in
return (feedId, (0..<count).map { $0 })
}.map { pair -> (String, Set<ParsedItem>) in
@ -300,7 +300,7 @@ class FeedlyTestSupport {
attachments: nil)
}
return (pair.0, Set(items))
}.reduce([String: Set<ParsedItem>](minimumCapacity: feedIdsAndItemCounts.count)) { (dict, pair) in
}.reduce([String: Set<ParsedItem>](minimumCapacity: feedIDsAndItemCounts.count)) { (dict, pair) in
var mutant = dict
mutant[pair.0] = pair.1
return mutant

View File

@ -11,11 +11,11 @@ import XCTest
final class TestGetPagedStreamContentsService: FeedlyGetStreamContentsService {
var parameterTester: ((FeedlyResourceId, String?, Date?, Bool?) -> ())?
var parameterTester: ((FeedlyResourceID, String?, Date?, Bool?) -> ())?
var getStreamContentsExpectation: XCTestExpectation?
var pages = [String: FeedlyStream]()
func addAtLeastOnePage(for resource: FeedlyResourceId, continuations: [String], numberOfEntriesPerPage count: Int) {
func addAtLeastOnePage(for resource: FeedlyResourceID, continuations: [String], numberOfEntriesPerPage count: Int) {
pages = [String: FeedlyStream](minimumCapacity: continuations.count + 1)
// A continuation is an identifier for the next page.
@ -31,7 +31,7 @@ final class TestGetPagedStreamContentsService: FeedlyGetStreamContentsService {
}
}
private func makeStreamContents(for resource: FeedlyResourceId, continuation: String?, between range: Range<Int>) -> FeedlyStream {
private func makeStreamContents(for resource: FeedlyResourceID, continuation: String?, between range: Range<Int>) -> FeedlyStream {
let entries = range.map { index -> FeedlyEntry in
let content = FeedlyEntry.Content(content: "Content \(index)",
direction: .leftToRight)
@ -61,11 +61,11 @@ final class TestGetPagedStreamContentsService: FeedlyGetStreamContentsService {
return stream
}
static func getPagingKey(for stream: FeedlyResourceId, continuation: String?) -> String {
static func getPagingKey(for stream: FeedlyResourceID, continuation: String?) -> String {
return "\(stream.id)@\(continuation ?? "")"
}
func getStreamContents(for resource: FeedlyResourceId, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ()) {
func getStreamContents(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ()) {
let key = TestGetPagedStreamContentsService.getPagingKey(for: resource, continuation: continuation)
guard let page = pages[key] else {
XCTFail("Missing page for \(resource.id) and continuation \(String(describing: continuation)). Test may time out because the completion will not be called.")

View File

@ -1,5 +1,5 @@
//
// TestGetPagedStreamIdsService.swift
// TestGetPagedStreadIDsService.swift
// AccountTests
//
// Created by Kiel Gillard on 29/10/19.
@ -9,14 +9,14 @@
import XCTest
@testable import Account
final class TestGetPagedStreamIdsService: FeedlyGetStreamIdsService {
final class TestGetPagedStreadIDsService: FeedlyGetStreamIDsService {
var parameterTester: ((FeedlyResourceId, String?, Date?, Bool?) -> ())?
var getStreamIdsExpectation: XCTestExpectation?
var pages = [String: FeedlyStreamIds]()
var parameterTester: ((FeedlyResourceID, String?, Date?, Bool?) -> ())?
var getStreadIDsExpectation: XCTestExpectation?
var pages = [String: FeedlyStreamIDs]()
func addAtLeastOnePage(for resource: FeedlyResourceId, continuations: [String], numberOfEntriesPerPage count: Int) {
pages = [String: FeedlyStreamIds](minimumCapacity: continuations.count + 1)
func addAtLeastOnePage(for resource: FeedlyResourceID, continuations: [String], numberOfEntriesPerPage count: Int) {
pages = [String: FeedlyStreamIDs](minimumCapacity: continuations.count + 1)
// A continuation is an identifier for the next page.
// The first page has a nil identifier.
@ -25,24 +25,24 @@ final class TestGetPagedStreamIdsService: FeedlyGetStreamIdsService {
for index in -1..<continuations.count {
let nextIndex = index + 1
let continuation: String? = nextIndex < continuations.count ? continuations[nextIndex] : nil
let page = makeStreamIds(for: resource, continuation: continuation, between: 0..<count)
let key = TestGetPagedStreamIdsService.getPagingKey(for: resource, continuation: index < 0 ? nil : continuations[index])
let page = makeStreadIDs(for: resource, continuation: continuation, between: 0..<count)
let key = TestGetPagedStreadIDsService.getPagingKey(for: resource, continuation: index < 0 ? nil : continuations[index])
pages[key] = page
}
}
private func makeStreamIds(for resource: FeedlyResourceId, continuation: String?, between range: Range<Int>) -> FeedlyStreamIds {
let entryIds = range.map { _ in UUID().uuidString }
let stream = FeedlyStreamIds(continuation: continuation, ids: entryIds)
private func makeStreadIDs(for resource: FeedlyResourceID, continuation: String?, between range: Range<Int>) -> FeedlyStreamIDs {
let entryIDs = range.map { _ in UUID().uuidString }
let stream = FeedlyStreamIDs(continuation: continuation, ids: entryIDs)
return stream
}
static func getPagingKey(for stream: FeedlyResourceId, continuation: String?) -> String {
static func getPagingKey(for stream: FeedlyResourceID, continuation: String?) -> String {
return "\(stream.id)@\(continuation ?? "")"
}
func getStreamIds(for resource: FeedlyResourceId, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIds, Error>) -> ()) {
let key = TestGetPagedStreamIdsService.getPagingKey(for: resource, continuation: continuation)
func getStreamIDs(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIDs, Error>) -> ()) {
let key = TestGetPagedStreadIDsService.getPagingKey(for: resource, continuation: continuation)
guard let page = pages[key] else {
XCTFail("Missing page for \(resource.id) and continuation \(String(describing: continuation)). Test may time out because the completion will not be called.")
return
@ -50,7 +50,7 @@ final class TestGetPagedStreamIdsService: FeedlyGetStreamIdsService {
parameterTester?(resource, continuation, newerThan, unreadOnly)
DispatchQueue.main.async {
completion(.success(page))
self.getStreamIdsExpectation?.fulfill()
self.getStreadIDsExpectation?.fulfill()
}
}
}

View File

@ -12,10 +12,10 @@ import XCTest
final class TestGetStreamContentsService: FeedlyGetStreamContentsService {
var mockResult: Result<FeedlyStream, Error>?
var parameterTester: ((FeedlyResourceId, String?, Date?, Bool?) -> ())?
var parameterTester: ((FeedlyResourceID, String?, Date?, Bool?) -> ())?
var getStreamContentsExpectation: XCTestExpectation?
func getStreamContents(for resource: FeedlyResourceId, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ()) {
func getStreamContents(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStream, Error>) -> ()) {
guard let result = mockResult else {
XCTFail("Missing mock result. Test may time out because the completion will not be called.")
return

View File

@ -1,5 +1,5 @@
//
// TestGetStreamIdsService.swift
// TestGetStreadIDsService.swift
// AccountTests
//
// Created by Kiel Gillard on 29/10/19.
@ -9,13 +9,13 @@
import XCTest
@testable import Account
final class TestGetStreamIdsService: FeedlyGetStreamIdsService {
final class TestGetStreadIDsService: FeedlyGetStreamIDsService {
var mockResult: Result<FeedlyStreamIds, Error>?
var parameterTester: ((FeedlyResourceId, String?, Date?, Bool?) -> ())?
var getStreamIdsExpectation: XCTestExpectation?
var mockResult: Result<FeedlyStreamIDs, Error>?
var parameterTester: ((FeedlyResourceID, String?, Date?, Bool?) -> ())?
var getStreadIDsExpectation: XCTestExpectation?
func getStreamIds(for resource: FeedlyResourceId, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIds, Error>) -> ()) {
func getStreamIDs(for resource: FeedlyResourceID, continuation: String?, newerThan: Date?, unreadOnly: Bool?, completion: @escaping (Result<FeedlyStreamIDs, Error>) -> ()) {
guard let result = mockResult else {
XCTFail("Missing mock result. Test may time out because the completion will not be called.")
return
@ -23,7 +23,7 @@ final class TestGetStreamIdsService: FeedlyGetStreamIdsService {
parameterTester?(resource, continuation, newerThan, unreadOnly)
DispatchQueue.main.async {
completion(result)
self.getStreamIdsExpectation?.fulfill()
self.getStreadIDsExpectation?.fulfill()
}
}
}

View File

@ -15,10 +15,10 @@ class TestMarkArticlesService: FeedlyMarkArticlesService {
var parameterTester: ((Set<String>, FeedlyMarkAction) -> ())?
var mockResult: Result<Void, Error> = .success(())
func mark(_ articleIds: Set<String>, as action: FeedlyMarkAction, completion: @escaping (Result<Void, Error>) -> ()) {
func mark(_ articleIDs: Set<String>, as action: FeedlyMarkAction, completion: @escaping (Result<Void, Error>) -> ()) {
DispatchQueue.main.async {
self.parameterTester?(articleIds, action)
self.parameterTester?(articleIDs, action)
completion(self.mockResult)
self.didMarkExpectation?.fulfill()
}

View File

@ -108,7 +108,7 @@ class AccountsNewsBlurWindowController: NSWindowController {
do {
try self.account?.removeCredentials(type: .newsBlurBasic)
try self.account?.removeCredentials(type: .newsBlurSessionId)
try self.account?.removeCredentials(type: .newsBlurSessionID)
try self.account?.storeCredentials(credentials)
try self.account?.storeCredentials(validatedCredentials)

View File

@ -122,10 +122,10 @@ import Core
@objc(valueInFoldersWithUniqueID:)
func valueInFolders(withUniqueID id:NSNumber) -> ScriptableFolder? {
let folderId = id.intValue
let folderID = id.intValue
let foldersSet = account.folders ?? Set<Folder>()
let folders = Array(foldersSet)
guard let folder = folders.first(where:{$0.folderID == folderId}) else { return nil }
guard let folder = folders.first(where:{$0.folderID == folderID}) else { return nil }
return ScriptableFolder(folder, container:self)
}

View File

@ -30,9 +30,9 @@ extension ScriptingObjectContainer {
let containerClassDescription = self.scriptingClassDescription
let containerScriptObjectSpecifier = self.objectSpecifier
let scriptingKey = object.scriptingKey
let uniqueId = object.scriptingUniqueId
let uniqueID = object.scriptingUniqueId
let specifier = NSUniqueIDSpecifier(containerClassDescription:containerClassDescription,
containerSpecifier:containerScriptObjectSpecifier, key:scriptingKey, uniqueID: uniqueId)
containerSpecifier:containerScriptObjectSpecifier, key:scriptingKey, uniqueID: uniqueID)
return specifier
}
}

View File

@ -56,7 +56,7 @@ import Secrets
let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: url)
for cookie in cookies where cookie.name == Self.sessionIDCookieKey {
let credentials = Credentials(type: .newsBlurSessionId, username: username, secret: cookie.value)
let credentials = Credentials(type: .newsBlurSessionID, username: username, secret: cookie.value)
completion(.success(credentials))
return
}

View File

@ -20,7 +20,7 @@ public extension URLRequest {
}
let credentialsType = credentials.type
precondition(credentialsType == .newsBlurBasic || credentialsType == .newsBlurSessionId)
precondition(credentialsType == .newsBlurBasic || credentialsType == .newsBlurSessionID)
if credentialsType == .newsBlurBasic {
@ -34,7 +34,7 @@ public extension URLRequest {
]
httpBody = postData.enhancedPercentEncodedQuery?.data(using: .utf8)
} else if credentialsType == .newsBlurSessionId {
} else if credentialsType == .newsBlurSessionID {
setValue("\(NewsBlurAPICaller.sessionIDCookieKey)=\(credentials.secret)", forHTTPHeaderField: "Cookie")
httpShouldHandleCookies = true

View File

@ -64,7 +64,7 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
case subscriptionEdit = "/reader/api/0/subscription/edit"
case subscriptionAdd = "/reader/api/0/subscription/quickadd"
case contents = "/reader/api/0/stream/items/contents"
case itemIds = "/reader/api/0/stream/items/ids"
case itemIDs = "/reader/api/0/stream/items/ids"
case editTag = "/reader/api/0/edit-tag"
}
@ -452,7 +452,7 @@ public enum CreateReaderAPISubscriptionResult: Sendable {
}
let url = baseURL
.appendingPathComponent(ReaderAPIEndpoints.itemIds.rawValue)
.appendingPathComponent(ReaderAPIEndpoints.itemIDs.rawValue)
.appendingQueryItems(queryItems)
guard let callURL = url else {

View File

@ -16,7 +16,7 @@ public enum CredentialsError: Error, Sendable {
public enum CredentialsType: String, Sendable {
case basic = "password"
case newsBlurBasic = "newsBlurBasic"
case newsBlurSessionId = "newsBlurSessionId"
case newsBlurSessionID = "newsBlurSessionId"
case readerBasic = "readerBasic"
case readerAPIKey = "readerAPIKey"
case oauthAccessToken = "oauthAccessToken"

View File

@ -159,17 +159,17 @@ import CoreSpotlight
#endif
@objc func feedIconDidBecomeAvailable(_ note: Notification) {
guard let feed = note.userInfo?[UserInfoKey.feed] as? Feed, let activityFeedId = selectingActivity?.userInfo?[ArticlePathKey.feedID] as? String else {
guard let feed = note.userInfo?[UserInfoKey.feed] as? Feed, let activityFeedID = selectingActivity?.userInfo?[ArticlePathKey.feedID] as? String else {
return
}
#if os(iOS)
if let article = readingArticle, activityFeedId == article.feedID {
if let article = readingArticle, activityFeedID == article.feedID {
updateReadArticleSearchAttributes(with: article)
}
#endif
if activityFeedId == feed.feedID {
if activityFeedID == feed.feedID {
updateSelectingActivityFeedSearchAttributes(with: feed)
}
}

View File

@ -39,11 +39,11 @@ class SharingTests: XCTestCase {
}
private func article(titled title: String) -> Article {
let articleId = randomId()
return Article(accountID: randomId(),
articleID: articleId,
feedID: randomId(),
uniqueID: randomId(),
let articleID = randomID()
return Article(accountID: randomID(),
articleID: articleID,
feedID: randomID(),
uniqueID: randomID(),
title: title,
contentHTML: nil,
contentText: nil,
@ -54,11 +54,11 @@ class SharingTests: XCTestCase {
datePublished: nil,
dateModified: nil,
authors: nil,
status: ArticleStatus(articleID: articleId, read: true, dateArrived: Date())
status: ArticleStatus(articleID: articleID, read: true, dateArrived: Date())
)
}
private func randomId() -> String {
private func randomID() -> String {
return UUID().uuidString
}

View File

@ -137,7 +137,7 @@ class NewsBlurAccountViewController: UITableViewController {
do {
try self.account?.removeCredentials(type: .newsBlurBasic)
try self.account?.removeCredentials(type: .newsBlurSessionId)
try self.account?.removeCredentials(type: .newsBlurSessionID)
try self.account?.storeCredentials(credentials)
try self.account?.storeCredentials(validatedCredentials)

View File

@ -89,7 +89,7 @@ struct SidebarItemNode: Hashable {
private var lastSearchScope: SearchScope? = nil
private var isSearching: Bool = false
private var savedSearchArticles: ArticleArray? = nil
private var savedSearchArticleIds: Set<String>? = nil
private var savedSearchArticleIDs: Set<String>? = nil
private(set) var sortDirection = AppDefaults.shared.timelineSortDirection {
didSet {
@ -869,7 +869,7 @@ struct SidebarItemNode: Hashable {
isSearching = true
preSearchTimelineFeed = timelineFeed
savedSearchArticles = articles
savedSearchArticleIds = Set(articles.map { $0.articleID })
savedSearchArticleIDs = Set(articles.map { $0.articleID })
setTimelineFeed(nil, animated: true)
selectArticle(nil)
}
@ -887,7 +887,7 @@ struct SidebarItemNode: Hashable {
lastSearchString = ""
lastSearchScope = nil
preSearchTimelineFeed = nil
savedSearchArticleIds = nil
savedSearchArticleIDs = nil
savedSearchArticles = nil
isSearching = false
selectArticle(nil)
@ -909,7 +909,7 @@ struct SidebarItemNode: Hashable {
case .global:
setTimelineFeed(SmartFeed(delegate: SearchFeedDelegate(searchString: searchString)), animated: true)
case .timeline:
setTimelineFeed(SmartFeed(delegate: SearchTimelineFeedDelegate(searchString: searchString, articleIDs: savedSearchArticleIds!)), animated: true)
setTimelineFeed(SmartFeed(delegate: SearchTimelineFeedDelegate(searchString: searchString, articleIDs: savedSearchArticleIDs!)), animated: true)
}
lastSearchString = searchString

View File

@ -34,9 +34,9 @@ extension UIStoryboard {
func instantiateController<T>(ofType type: T.Type = T.self) -> T where T: UIViewController {
let storyboardId = String(describing: type)
guard let viewController = instantiateViewController(withIdentifier: storyboardId) as? T else {
print("Unable to load view with Scene Identifier: \(storyboardId)")
let storyboardID = String(describing: type)
guard let viewController = instantiateViewController(withIdentifier: storyboardID) as? T else {
print("Unable to load view with Scene Identifier: \(storyboardID)")
fatalError()
}