Continue renaming Id to ID (and similar renames).

This commit is contained in:
Brent Simmons
2023-09-16 22:04:43 -07:00
parent dd8df6e6c5
commit 5e3086667d
60 changed files with 420 additions and 391 deletions

View File

@@ -872,13 +872,13 @@ private extension FeedbinAccountDelegate {
logger.debug("Syncing feeds with \(subscriptions.count, privacy: .public) subscriptions.")
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)
}
}
@@ -886,7 +886,7 @@ private extension FeedbinAccountDelegate {
}
for feed in account.topLevelFeeds {
if !subFeedIds.contains(feed.feedID) {
if !subFeedIDs.contains(feed.feedID) {
account.removeFeed(feed)
}
}
@@ -895,9 +895,9 @@ private extension FeedbinAccountDelegate {
var subscriptionsToAdd = Set<FeedbinSubscription>()
for subscription in subscriptions {
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
@@ -956,11 +956,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

@@ -81,13 +81,13 @@ extension NewsBlurAccountDelegate {
logger.debug("Syncing feeds with \(feeds.count, privacy: .public) feeds.")
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)
}
}
@@ -95,7 +95,7 @@ extension NewsBlurAccountDelegate {
}
for feed in account.topLevelFeeds {
if !newsBlurFeedIds.contains(feed.feedID) {
if !newsBlurFeedIDs.contains(feed.feedID) {
account.removeFeed(feed)
}
}
@@ -166,11 +166,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

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

View File

@@ -528,7 +528,7 @@ public enum ReaderAPIAccountDelegateError: LocalizedError {
addFeed(for: account, with: feed, to: to, completion: completion)
} else {
guard
let subscriptionId = feed.externalID,
let subscriptionID = feed.externalID,
let fromTag = (from as? Folder)?.name,
let toTag = (to as? Folder)?.name
else {
@@ -537,7 +537,7 @@ public enum ReaderAPIAccountDelegateError: LocalizedError {
}
refreshProgress.addToNumberOfTasksAndRemaining(1)
caller.moveSubscription(subscriptionID: subscriptionId, fromTag: fromTag, toTag: toTag) { result in
caller.moveSubscription(subscriptionID: subscriptionID, fromTag: fromTag, toTag: toTag) { result in
self.refreshProgress.completeTask()
switch result {
case .success:
@@ -784,13 +784,13 @@ private extension ReaderAPIAccountDelegate {
logger.debug("Syncing feeds with \(subscriptions.count, privacy: .public) subscriptions")
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)
}
}
@@ -798,7 +798,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)
}
@@ -832,11 +832,11 @@ private extension ReaderAPIAccountDelegate {
var taggedFeeds = dict
for category in subscription.categories {
if var taggedFeed = taggedFeeds[category.categoryId] {
if var taggedFeed = taggedFeeds[category.categoryID] {
taggedFeed.append(subscription)
taggedFeeds[category.categoryId] = taggedFeed
taggedFeeds[category.categoryID] = taggedFeed
} else {
taggedFeeds[category.categoryId] = [subscription]
taggedFeeds[category.categoryID] = [subscription]
}
}
@@ -858,11 +858,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
}
@@ -1080,7 +1080,7 @@ private extension ReaderAPIAccountDelegate {
// Hope the compiler is happy.
var parsedItems = Set<ParsedItem>()
for entry in entries {
guard let streamID = entry.origin.streamId else {
guard let streamID = entry.origin.streamID else {
continue
}

View File

@@ -245,8 +245,8 @@ final class CloudKitAccountZone: CloudKitZone {
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

@@ -148,9 +148,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

@@ -23,7 +23,7 @@ final class FeedlyAPICaller {
case sandbox
case cloud
var baseUrlComponents: URLComponents {
var baseURLComponents: URLComponents {
var components = URLComponents()
components.scheme = "https"
switch self{
@@ -48,12 +48,12 @@ final class FeedlyAPICaller {
}
private let transport: Transport
private let baseUrlComponents: URLComponents
private let baseURLComponents: URLComponents
private let uriComponentAllowed: CharacterSet
init(transport: Transport, api: API) {
self.transport = transport
self.baseUrlComponents = api.baseUrlComponents
self.baseURLComponents = api.baseURLComponents
var urlHostAllowed = CharacterSet.urlHostAllowed
urlHostAllowed.remove("+")
@@ -65,7 +65,7 @@ final class FeedlyAPICaller {
var credentials: Credentials?
var server: String? {
return baseUrlComponents.host
return baseURLComponents.host
}
func cancelAll() {
@@ -144,7 +144,7 @@ final class FeedlyAPICaller {
completion(.failure(CredentialsError.incompleteCredentials))
}
}
var components = baseUrlComponents
var components = baseURLComponents
components.path = "/v3/opml"
guard let url = components.url else {
@@ -184,7 +184,7 @@ final class FeedlyAPICaller {
completion(.failure(CredentialsError.incompleteCredentials))
}
}
var components = baseUrlComponents
var components = baseURLComponents
components.path = "/v3/collections"
guard let url = components.url else {
@@ -236,7 +236,7 @@ final class FeedlyAPICaller {
completion(.failure(CredentialsError.incompleteCredentials))
}
}
var components = baseUrlComponents
var components = baseURLComponents
components.path = "/v3/collections"
guard let url = components.url else {
@@ -293,13 +293,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)"
var components = baseURLComponents
components.percentEncodedPath = "/v3/collections/\(encodedID)"
guard let url = components.url else {
fatalError("\(components) does not produce a valid URL.")
@@ -325,7 +325,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))
@@ -338,14 +338,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"
var components = baseURLComponents
components.percentEncodedPath = "/v3/collections/\(encodedCollectionID)/feeds/.mdelete"
guard let url = components.url else {
fatalError("\(components) does not produce a valid URL.")
@@ -362,7 +362,7 @@ final class FeedlyAPICaller {
let id: String
}
let encoder = JSONEncoder()
let data = try encoder.encode([RemovableFeed(id: feedId)])
let data = try encoder.encode([RemovableFeed(id: feedID)])
request.httpBody = data
} catch {
return DispatchQueue.main.async {
@@ -389,7 +389,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))
@@ -402,13 +402,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"
var components = baseURLComponents
components.percentEncodedPath = "/v3/collections/\(encodedID)/feeds"
guard let url = components.url else {
fatalError("\(components) does not produce a valid URL.")
@@ -426,7 +426,7 @@ extension FeedlyAPICaller: FeedlyAddFeedToCollectionService {
var title: String?
}
let encoder = JSONEncoder()
let data = try encoder.encode(AddFeedBody(id: feedId.id, title: title))
let data = try encoder.encode(AddFeedBody(id: feedID.id, title: title))
request.httpBody = data
} catch {
return DispatchQueue.main.async {
@@ -451,8 +451,8 @@ extension FeedlyAPICaller: FeedlyAddFeedToCollectionService {
extension FeedlyAPICaller: OAuthAuthorizationCodeGrantRequesting {
static func authorizationCodeUrlRequest(for request: OAuthAuthorizationRequest, baseUrlComponents: URLComponents) -> URLRequest {
var components = baseUrlComponents
static func authorizationCodeURLRequest(for request: OAuthAuthorizationRequest, baseURLComponents: URLComponents) -> URLRequest {
var components = baseURLComponents
components.path = "/v3/auth/auth"
components.queryItems = request.queryItems
@@ -477,7 +477,7 @@ extension FeedlyAPICaller: OAuthAuthorizationCodeGrantRequesting {
}
}
var components = baseUrlComponents
var components = baseURLComponents
components.path = "/v3/auth/token"
guard let url = components.url else {
@@ -524,7 +524,7 @@ extension FeedlyAPICaller: OAuthAcessTokenRefreshRequesting {
}
}
var components = baseUrlComponents
var components = baseURLComponents
components.path = "/v3/auth/token"
guard let url = components.url else {
@@ -576,7 +576,7 @@ extension FeedlyAPICaller: FeedlyGetCollectionsService {
completion(.failure(CredentialsError.incompleteCredentials))
}
}
var components = baseUrlComponents
var components = baseURLComponents
components.path = "/v3/collections"
guard let url = components.url else {
@@ -618,7 +618,7 @@ extension FeedlyAPICaller: FeedlyGetStreamContentsService {
}
}
var components = baseUrlComponents
var components = baseURLComponents
components.path = "/v3/streams/contents"
var queryItems = [URLQueryItem]()
@@ -686,7 +686,7 @@ extension FeedlyAPICaller: FeedlyGetStreamIDsService {
}
}
var components = baseUrlComponents
var components = baseURLComponents
components.path = "/v3/streams/ids"
var queryItems = [URLQueryItem]()
@@ -754,7 +754,7 @@ extension FeedlyAPICaller: FeedlyGetEntriesService {
}
}
var components = baseUrlComponents
var components = baseURLComponents
components.path = "/v3/entries/.mget"
guard let url = components.url else {
@@ -799,10 +799,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))
@@ -814,18 +814,18 @@ extension FeedlyAPICaller: FeedlyMarkArticlesService {
completion(.failure(CredentialsError.incompleteCredentials))
}
}
var components = baseUrlComponents
var components = baseURLComponents
components.path = "/v3/markers"
guard let url = components.url else {
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"
@@ -834,7 +834,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
@@ -878,7 +878,7 @@ extension FeedlyAPICaller: FeedlySearchService {
}
}
var components = baseUrlComponents
var components = baseURLComponents
components.path = "/v3/search/feeds"
components.queryItems = [
@@ -926,7 +926,7 @@ extension FeedlyAPICaller: FeedlyLogoutService {
completion(.failure(CredentialsError.incompleteCredentials))
}
}
var components = baseUrlComponents
var components = baseURLComponents
components.path = "/v3/auth/logout"
guard let url = components.url else {

View File

@@ -30,12 +30,12 @@ extension FeedlyAccountDelegate: OAuthAuthorizationGranting {
static func oauthAuthorizationCodeGrantRequest() -> URLRequest {
let client = environment.oauthAuthorizationClient
let authorizationRequest = OAuthAuthorizationRequest(clientId: client.id,
redirectUri: client.redirectUri,
let authorizationRequest = OAuthAuthorizationRequest(clientID: client.id,
redirectURI: client.redirectURI,
scope: oauthAuthorizationGrantScope,
state: client.state)
let baseURLComponents = environment.baseUrlComponents
return FeedlyAPICaller.authorizationCodeUrlRequest(for: authorizationRequest, baseUrlComponents: baseURLComponents)
let baseURLComponents = environment.baseURLComponents
return FeedlyAPICaller.authorizationCodeURLRequest(for: authorizationRequest, baseURLComponents: baseURLComponents)
}
static func requestOAuthAccessToken(with response: OAuthAuthorizationResponse, transport: Transport, completion: @escaping (Result<OAuthAuthorizationGrant, Error>) -> ()) {

View File

@@ -195,7 +195,7 @@ final class FeedlyAccountDelegate: AccountDelegate, Logging {
}
let ingestStarred = FeedlyIngestStarredArticleIDsOperation(account: account, userId: credentials.username, service: caller, database: database, newerThan: nil)
let ingestStarred = FeedlyIngestStarredArticleIDsOperation(account: account, userID: credentials.username, service: caller, database: database, newerThan: nil)
group.enter()
ingestStarred.completionBlock = { _ in
@@ -377,18 +377,18 @@ final class FeedlyAccountDelegate: AccountDelegate, Logging {
}
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(()))
@@ -434,13 +434,13 @@ final class FeedlyAccountDelegate: AccountDelegate, Logging {
}
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)))
}
}
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

@@ -41,7 +41,7 @@ struct FeedlyEntry: Decodable {
/// the timestamp, in ms, when this article was re-processed and updated by the feedly Cloud servers.
let recrawled: Date?
/// the feed from which this article was crawled. If present, streamId will contain the feed id, title will contain the feed title, and htmlUrl will contain the feeds website.
/// the feed from which this article was crawled. If present, streamID will contain the feed id, title will contain the feed title, and htmlUrl will contain the feeds website.
let origin: FeedlyOrigin?
/// Used to help find the URL to visit an article on a web site.

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

@@ -44,7 +44,12 @@ struct FeedlyFeedsSearchResponse: Decodable {
struct Feed: Decodable {
let title: String
let feedId: String
let feedID: String
enum CodingKeys: String, CodingKey {
case title = "title"
case feedID = "feedId"
}
}
let results: [Feed]
@@ -61,8 +66,14 @@ struct FeedlyLink: Decodable {
struct FeedlyOrigin: Decodable {
let title: String?
let streamId: String?
let htmlUrl: String?
let streamID: String?
let htmlURL: String?
enum CodingKeys: String, CodingKey {
case title = "title"
case streamID = "streamId"
case htmlURL = "htmlUrl"
}
}
struct FeedlyStream: Decodable {

View File

@@ -1,5 +1,5 @@
//
// FeedlyResourceId.swift
// FeedlyResourceID.swift
// Account
//
// Created by Kiel Gillard on 3/10/19.
@@ -8,10 +8,10 @@
import Foundation
/// The kinds of Resource Ids is documented here: https://developer.feedly.com/cloud/
/// 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.
var id: String { get }
}
@@ -20,8 +20,8 @@ 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.

View File

@@ -59,8 +59,8 @@ public enum OAuthAccountAuthorizationOperationError: LocalizedError {
}
}
guard let redirectUri = URL(string: oauthClient.redirectUri), let scheme = redirectUri.scheme else {
assertionFailure("Could not get callback URL scheme from \(oauthClient.redirectUri)")
guard let redirectURI = URL(string: oauthClient.redirectURI), let scheme = redirectURI.scheme else {
assertionFailure("Could not get callback URL scheme from \(oauthClient.redirectURI)")
return DispatchQueue.main.async {
self.didEndAuthentication(url: nil, error: URLError(.badURL))
}

View File

@@ -17,13 +17,21 @@ 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
enum CodingKeys: String, CodingKey {
case grantType = "grantType"
case refreshToken = "refreshToken"
case scope = "scope"
case clientID = "clientId"
case clientSecret = "clientSecret"
}
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

@@ -16,7 +16,7 @@ extension OAuthAuthorizationClient {
/// These placeholders are substituted at build time using a Run Script phase with build settings.
/// https://developer.feedly.com/v3/auth/#authenticating-a-user-and-obtaining-an-auth-code
return OAuthAuthorizationClient(id: SecretsManager.provider.feedlyClientId,
redirectUri: "netnewswire://auth/feedly",
redirectURI: "netnewswire://auth/feedly",
state: nil,
secret: SecretsManager.provider.feedlyClientSecret)
}
@@ -27,9 +27,9 @@ extension OAuthAuthorizationClient {
/// The return value models public sandbox API values found at:
/// https://groups.google.com/forum/#!topic/feedly-cloud/WwQWMgDmOuw
/// They are due to expire on May 31st 2020.
/// Verify the sandbox URL host in the FeedlyAPICaller.API.baseUrlComponents method, too.
/// Verify the sandbox URL host in the FeedlyAPICaller.API.baseURLComponents method, too.
return OAuthAuthorizationClient(id: "sandbox",
redirectUri: "urn:ietf:wg:oauth:2.0:oob",
redirectURI: "urn:ietf:wg:oauth:2.0:oob",
state: nil,
secret: "4ZfZ5DvqmJ8vKgMj")
}

View File

@@ -14,13 +14,13 @@ import Secrets
/// Accounts are responsible for the scope.
public struct OAuthAuthorizationClient: Equatable {
public var id: String
public var redirectUri: String
public var redirectURI: String
public var state: String?
public var secret: String
public init(id: String, redirectUri: String, state: String?, secret: String) {
public init(id: String, redirectURI: String, state: String?, secret: String) {
self.id = id
self.redirectUri = redirectUri
self.redirectURI = redirectURI
self.state = state
self.secret = secret
}
@@ -30,14 +30,14 @@ 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 redirectUri: 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
self.redirectUri = redirectUri
public init(clientID: String, redirectURI: String, scope: String, state: String?) {
self.clientID = clientID
self.redirectURI = redirectURI
self.scope = scope
self.state = state
}
@@ -45,9 +45,9 @@ 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),
URLQueryItem(name: "redirect_uri", value: redirectURI),
]
}
}
@@ -62,7 +62,7 @@ public struct OAuthAuthorizationResponse {
public extension OAuthAuthorizationResponse {
init(url: URL, client: OAuthAuthorizationClient) throws {
guard let scheme = url.scheme, client.redirectUri.hasPrefix(scheme) else {
guard let scheme = url.scheme, client.redirectURI.hasPrefix(scheme) else {
throw URLError(.unsupportedURL)
}
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false) else {
@@ -112,19 +112,29 @@ public enum OAuthAuthorizationError: String {
public struct OAuthAccessTokenRequest: Encodable {
public let grantType = "authorization_code"
public var code: String
public var redirectUri: 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
public var scope: String
enum CodingKeys: String, CodingKey {
case grantType = "grantType"
case code = "code"
case redirectURI = "redirectUri"
case state = "state"
case clientID = "clientId"
case clientSecret = "clientSecret"
case scope = "scope"
}
public init(authorizationResponse: OAuthAuthorizationResponse, scope: String, client: OAuthAuthorizationClient) {
self.code = authorizationResponse.code
self.redirectUri = client.redirectUri
self.redirectURI = client.redirectURI
self.state = authorizationResponse.state
self.clientId = client.id
self.clientID = client.id
self.clientSecret = client.secret
self.scope = scope
}
@@ -155,8 +165,8 @@ public protocol OAuthAuthorizationCodeGrantRequesting {
/// Provides the URL request that allows users to consent to the client having access to their information. Typically loaded by a web view.
/// - Parameter request: The information about the client requesting authorization to be granted access tokens.
/// - Parameter baseUrlComponents: The scheme and host of the url except for the path.
static func authorizationCodeUrlRequest(for request: OAuthAuthorizationRequest, baseUrlComponents: URLComponents) -> URLRequest
/// - Parameter baseURLComponents: The scheme and host of the url except for the path.
static func authorizationCodeURLRequest(for request: OAuthAuthorizationRequest, baseURLComponents: URLComponents) -> URLRequest
/// Performs the request for the access token given an authorization code.

View File

@@ -19,7 +19,7 @@ class FeedlyAddExistingFeedOperation: FeedlyOperation, FeedlyOperationDelegate,
init(account: Account, credentials: Credentials, resource: FeedlyFeedResourceID, service: FeedlyAddFeedToCollectionService, container: Container, progress: DownloadProgress, customFeedName: String? = nil) throws {
let validator = FeedlyFeedContainerValidator(container: container)
let (folder, collectionId) = try validator.getValidContainer()
let (folder, collectionID) = try validator.getValidContainer()
self.operationQueue.suspend()
@@ -27,7 +27,7 @@ class FeedlyAddExistingFeedOperation: FeedlyOperation, FeedlyOperationDelegate,
self.downloadProgress = progress
let addRequest = FeedlyAddFeedToCollectionOperation(account: account, folder: folder, feedResource: resource, feedName: customFeedName, collectionID: collectionId, service: service)
let addRequest = FeedlyAddFeedToCollectionOperation(account: account, folder: folder, feedResource: resource, feedName: customFeedName, collectionID: collectionID, service: service)
addRequest.delegate = self
addRequest.downloadProgress = progress
self.operationQueue.add(addRequest)

View File

@@ -81,7 +81,7 @@ class FeedlyAddNewFeedOperation: FeedlyOperation, FeedlyOperationDelegate, Feedl
return didFinish(with: AccountError.createErrorNotFound)
}
let feedResourceID = FeedlyFeedResourceID(id: first.feedId)
let feedResourceID = FeedlyFeedResourceID(id: first.feedID)
self.feedResourceID = feedResourceID
let addRequest = FeedlyAddFeedToCollectionOperation(account: account, folder: folder, feedResource: feedResourceID, feedName: feedName, collectionID: collectionID, service: addToCollectionService)

View File

@@ -32,15 +32,15 @@ class FeedlyDownloadArticlesOperation: FeedlyOperation, Logging {
}
override func run() {
var articleIds = missingArticleEntryIDProvider.entryIDs
articleIds.formUnion(updatedArticleEntryIDProvider.entryIDs)
var articleIDs = missingArticleEntryIDProvider.entryIDs
articleIDs.formUnion(updatedArticleEntryIDProvider.entryIDs)
self.logger.debug("Requesting \(articleIds.count, privacy: .public) articles.")
self.logger.debug("Requesting \(articleIDs.count, privacy: .public) articles.")
let feedlyAPILimitBatchSize = 1000
for articleIds in Array(articleIds).chunked(into: feedlyAPILimitBatchSize) {
for articleIDs in Array(articleIDs).chunked(into: feedlyAPILimitBatchSize) {
let provider = FeedlyEntryIdentifierProvider(entryIDs: Set(articleIds))
let provider = FeedlyEntryIdentifierProvider(entryIDs: Set(articleIDs))
let getEntries = FeedlyGetEntriesOperation(account: account, service: getEntriesService, provider: provider)
getEntries.delegate = self
self.operationQueue.add(getEntries)

View File

@@ -22,8 +22,8 @@ final class FeedlyFetchIDsForMissingArticlesOperation: FeedlyOperation, FeedlyEn
override func run() {
account.fetchArticleIDsForStatusesWithoutArticlesNewerThanCutoffDate { result in
switch result {
case .success(let articleIds):
self.entryIDs.formUnion(articleIds)
case .success(let articleIDs):
self.entryIDs.formUnion(articleIDs)
self.didFinish()
case .failure(let error):

View File

@@ -25,8 +25,8 @@ final class FeedlyIngestStarredArticleIDsOperation: FeedlyOperation, Logging {
private let database: SyncDatabase
private var remoteEntryIDs = Set<String>()
convenience init(account: Account, userId: String, service: FeedlyGetStreamIDsService, database: SyncDatabase, newerThan: Date?) {
let resource = FeedlyTagResourceID.Global.saved(for: userId)
convenience init(account: Account, userID: String, service: FeedlyGetStreamIDsService, database: SyncDatabase, newerThan: Date?) {
let resource = FeedlyTagResourceID.Global.saved(for: userID)
self.init(account: account, resource: resource, service: service, database: database, newerThan: newerThan)
}

View File

@@ -27,8 +27,8 @@ class FeedlyIngestStreamArticleIDsOperation: FeedlyOperation, Logging {
self.service = service
}
convenience init(account: Account, userId: String, service: FeedlyGetStreamIDsService) {
let all = FeedlyCategoryResourceID.Global.all(for: userId)
convenience init(account: Account, userID: String, service: FeedlyGetStreamIDsService) {
let all = FeedlyCategoryResourceID.Global.all(for: userID)
self.init(account: account, resource: all, service: service)
}

View File

@@ -65,7 +65,7 @@ final class FeedlySyncAllOperation: FeedlyOperation, Logging {
createFeedsOperation.addDependency(mirrorCollectionsAsFolders)
self.operationQueue.add(createFeedsOperation)
let getAllArticleIDs = FeedlyIngestStreamArticleIDsOperation(account: account, userId: feedlyUserID, service: getStreamIDsService)
let getAllArticleIDs = FeedlyIngestStreamArticleIDsOperation(account: account, userID: feedlyUserID, service: getStreamIDsService)
getAllArticleIDs.delegate = self
getAllArticleIDs.downloadProgress = downloadProgress
getAllArticleIDs.addDependency(createFeedsOperation)
@@ -87,7 +87,7 @@ final class FeedlySyncAllOperation: FeedlyOperation, Logging {
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)
let getStarred = FeedlyIngestStarredArticleIDsOperation(account: account, userID: feedlyUserID, service: getStarredService, database: database, newerThan: nil)
getStarred.delegate = self
getStarred.downloadProgress = downloadProgress
getStarred.addDependency(createFeedsOperation)

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.SessionIdCookie)=\(credentials.secret)", forHTTPHeaderField: "Cookie")
httpShouldHandleCookies = true
case .readerBasic:

View File

@@ -65,7 +65,7 @@ class FeedlyCreateFeedsForCollectionFoldersOperationTests: XCTestCase {
waitForExpectations(timeout: 2)
let feedIds = Set([feedsForFolderOne, feedsForFolderTwo]
let feedIDs = Set([feedsForFolderOne, feedsForFolderTwo]
.flatMap { $0 }
.map { $0.id })
@@ -74,28 +74,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() {
@@ -158,7 +158,7 @@ class FeedlyCreateFeedsForCollectionFoldersOperationTests: XCTestCase {
waitForExpectations(timeout: 2)
let feedIds = Set([feedsForFolderOne, feedsForFolderTwo]
let feedIDs = Set([feedsForFolderOne, feedsForFolderTwo]
.flatMap { $0 }
.map { $0.id })
@@ -167,30 +167,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

@@ -14,7 +14,7 @@ class FeedlyEntryParserTests: XCTestCase {
func testParsing() {
let content = FeedlyEntry.Content(content: "Test Content", direction: .leftToRight)
let summary = FeedlyEntry.Content(content: "Test Summary", direction: .leftToRight)
let origin = FeedlyOrigin(title: "Test Feed", streamId: "tests://feeds/1", htmlUrl: nil)
let origin = FeedlyOrigin(title: "Test Feed", streamID: "tests://feeds/1", htmlURL: nil)
let canonicalLink = FeedlyLink(href: "tests://feeds/1/entries/1", type: "text/html")
let tags = [
FeedlyTag(id: "tests/tags/1", label: "Tag 1"),
@@ -38,8 +38,8 @@ class FeedlyEntryParserTests: XCTestCase {
let parser = FeedlyEntryParser(entry: entry)
XCTAssertEqual(parser.id, entry.id)
XCTAssertEqual(parser.feedUrl, origin.streamId)
XCTAssertEqual(parser.externalUrl, canonicalLink.href)
XCTAssertEqual(parser.feedURL, origin.streamID)
XCTAssertEqual(parser.externalURL, canonicalLink.href)
XCTAssertEqual(parser.title, entry.title)
XCTAssertEqual(parser.contentHMTL, content.content)
XCTAssertEqual(parser.summary, summary.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?")
@@ -76,7 +76,7 @@ class FeedlyEntryParserTests: XCTestCase {
let content = FeedlyEntry.Content(content: "<div style=\"direction:rtl;text-align:right\">Test Content</div>", direction: .rightToLeft)
let summaryContent = "Test Summary"
let summary = FeedlyEntry.Content(content: "<div style=\"direction:rtl;text-align:right\">\(summaryContent)</div>", direction: .rightToLeft)
let origin = FeedlyOrigin(title: "Test Feed", streamId: "tests://feeds/1", htmlUrl: nil)
let origin = FeedlyOrigin(title: "Test Feed", streamID: "tests://feeds/1", htmlURL: nil)
let title = "Test Entry 1"
let entry = FeedlyEntry(id: "tests/feeds/1/entries/1",
title: "<div style=\"direction:rtl;text-align:right\">\(title)</div>",
@@ -103,7 +103,7 @@ class FeedlyEntryParserTests: XCTestCase {
XCTAssertEqual(parser.contentHMTL, content.content)
}
func testLocatesCanonicalExternalUrl() {
func testLocatesCanonicalExternalURL() {
let canonicalLink = FeedlyLink(href: "tests://feeds/1/entries/1", type: "text/html")
let alternateLink = FeedlyLink(href: "tests://feeds/1/entries/alternate/1", type: "text/html")
let entry = FeedlyEntry(id: "tests/feeds/1/entries/1",
@@ -123,10 +123,10 @@ class FeedlyEntryParserTests: XCTestCase {
let parser = FeedlyEntryParser(entry: entry)
XCTAssertEqual(parser.externalUrl, canonicalLink.href)
XCTAssertEqual(parser.externalURL, canonicalLink.href)
}
func testLocatesAlternateExternalUrl() {
func testLocatesAlternateExternalURL() {
let canonicalLink = FeedlyLink(href: "tests://feeds/1/entries/1", type: "text/json")
let alternateLink = FeedlyLink(href: "tests://feeds/1/entries/alternate/1", type: nil)
let entry = FeedlyEntry(id: "tests/feeds/1/entries/1",
@@ -146,7 +146,7 @@ class FeedlyEntryParserTests: XCTestCase {
let parser = FeedlyEntryParser(entry: entry)
XCTAssertEqual(parser.externalUrl, alternateLink.href)
XCTAssertEqual(parser.externalURL, alternateLink.href)
}
func testContentPreferredToSummary() {

View File

@@ -37,21 +37,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 })
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).")
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

@@ -86,9 +86,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() {

View File

@@ -1,5 +1,5 @@
//
// FeedlyGetStreamIdsOperationTests.swift
// FeedlyGetStreamIDsOperationTests.swift
// AccountTests
//
// Created by Kiel Gillard on 23/10/19.
@@ -10,7 +10,7 @@ import XCTest
@testable import Account
import RSCore
class FeedlyGetStreamIdsOperationTests: XCTestCase {
class FeedlyGetStreamIDsOperationTests: XCTestCase {
private var account: Account!
private let support = FeedlyTestSupport()
@@ -27,39 +27,39 @@ class FeedlyGetStreamIdsOperationTests: XCTestCase {
super.tearDown()
}
func testGetStreamIdsFailure() {
let service = TestGetStreamIdsService()
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)
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()
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 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 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)
@@ -69,49 +69,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 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 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 continuation = streamIDsJSON["continuation"] as! String
XCTAssertEqual(streamIDs.continuation, continuation)
XCTAssertEqual(streamIDs.ids, streamIDsJSON["ids"] as! [String])
}
}

View File

@@ -48,16 +48,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.")
}
@@ -91,16 +91,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)
}
@@ -138,29 +138,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

@@ -30,7 +30,7 @@ class FeedlyOrganiseParsedItemsByFeedOperationTests: XCTestCase {
struct TestParsedItemsProvider: FeedlyParsedItemProviding {
let parsedItemProviderName = "TestParsedItemsProvider"
var resource: FeedlyResourceId
var resource: FeedlyResourceID
var parsedEntries: Set<ParsedItem>
}
@@ -51,11 +51,11 @@ class FeedlyOrganiseParsedItemsByFeedOperationTests: XCTestCase {
waitForExpectations(timeout: 2)
let itemsAndFeedIds = organise.parsedItemsKeyedByFeedId
XCTAssertEqual(itemsAndFeedIds, entries)
let itemsAndFeedIDs = organise.parsedItemsKeyedByFeedID
XCTAssertEqual(itemsAndFeedIDs, entries)
}
func testGroupsOneEntryByFeedId() {
func testGroupsOneEntryByFeedID() {
let entries = support.makeParsedItemTestDataFor(numberOfFeeds: 1, numberOfItemsInFeeds: 1)
let resource = FeedlyCategoryResourceID(id: "user/12345/category/6789")
let parsedEntries = Set(entries.values.flatMap { $0 })
@@ -72,11 +72,11 @@ class FeedlyOrganiseParsedItemsByFeedOperationTests: XCTestCase {
waitForExpectations(timeout: 2)
let itemsAndFeedIds = organise.parsedItemsKeyedByFeedId
XCTAssertEqual(itemsAndFeedIds, entries)
let itemsAndFeedIDs = organise.parsedItemsKeyedByFeedID
XCTAssertEqual(itemsAndFeedIDs, entries)
}
func testGroupsManyEntriesByFeedId() {
func testGroupsManyEntriesByFeedID() {
let entries = support.makeParsedItemTestDataFor(numberOfFeeds: 100, numberOfItemsInFeeds: 100)
let resource = FeedlyCategoryResourceID(id: "user/12345/category/6789")
let parsedEntries = Set(entries.values.flatMap { $0 })
@@ -93,7 +93,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,18 +9,18 @@
import XCTest
@testable import Account
class FeedlyResourceIdTests: XCTestCase {
class FeedlyResourceIDTests: XCTestCase {
func testFeedResourceId() {
let expectedUrl = "http://ranchero.com/blog/atom.xml"
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)
XCTAssertEqual(feedResource.url, expectedURL)
XCTAssertEqual(urlResource.url, expectedURL)
XCTAssertEqual(otherResource.url, otherResource.id)
XCTAssertEqual(invalidResource.url, invalidResource.id)
}

View File

@@ -47,8 +47,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
@@ -60,8 +60,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)
}
@@ -90,8 +90,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
@@ -103,8 +103,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)
}
@@ -133,8 +133,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
@@ -146,8 +146,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)
}
@@ -176,8 +176,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
@@ -189,8 +189,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)
}
@@ -219,8 +219,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
@@ -232,8 +232,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)
}
@@ -262,8 +262,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
@@ -275,8 +275,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)
}
@@ -305,8 +305,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
@@ -318,8 +318,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)
}
@@ -348,8 +348,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
@@ -361,8 +361,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)
}
@@ -391,13 +391,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
}
@@ -411,7 +411,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:
@@ -423,8 +423,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)
@@ -451,13 +451,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
}
@@ -471,7 +471,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:
@@ -483,8 +483,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

@@ -16,7 +16,7 @@ class FeedlyMockResponseProvider: TestTransportMockResponseProviding {
self.subdirectory = subdirectory
}
func mockResponseFileUrl(for components: URLComponents) -> URL? {
func mockResponseFileURL(for components: URLComponents) -> URL? {
let bundle = Bundle(for: FeedlyMockResponseProvider.self)
// Match request for collections to build a list of folders.

View File

@@ -56,9 +56,9 @@ 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() {
@@ -132,8 +132,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

@@ -43,7 +43,7 @@ class FeedlyTestSupport {
}
func makeMockOAuthClient() -> OAuthAuthorizationClient {
return OAuthAuthorizationClient(id: "test", redirectUri: "test://test/auth", state: nil, secret: "password")
return OAuthAuthorizationClient(id: "test", redirectURI: "test://test/auth", state: nil, secret: "password")
}
func removeCredentials(matching type: CredentialsType, from account: Account) {
@@ -103,18 +103,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)
@@ -138,11 +138,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 {
@@ -156,14 +156,14 @@ class FeedlyTestSupport {
private struct ArticleItem {
var id: String
var feedId: String
var feedID: String
var content: String
var JSON: [String: Any]
var unread: Bool
/// Convoluted external URL logic "documented" here:
/// https://groups.google.com/forum/#!searchin/feedly-cloud/feed$20url%7Csort:date/feedly-cloud/Rx3dVd4aTFQ/Hf1ZfLJoCQAJ
var externalUrl: String? {
var externalURL: String? {
return ((JSON["canonical"] as? [[String: Any]]) ?? (JSON["alternate"] as? [[String: Any]]))?.compactMap { link -> String? in
let href = link["href"] as? String
if let type = link["type"] as? String {
@@ -181,7 +181,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]
@@ -196,12 +196,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.")
@@ -210,67 +210,67 @@ class FeedlyTestSupport {
for item in articleItems where item.id == article.articleID {
XCTAssertEqual(article.uniqueID, item.id)
XCTAssertEqual(article.contentHTML, item.content)
XCTAssertEqual(article.feedID, item.feedId)
XCTAssertEqual(article.rawExternalLink, item.externalUrl)
XCTAssertEqual(article.feedID, item.feedID)
XCTAssertEqual(article.rawExternalLink, item.externalURL)
}
}
}
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 streamIDs = testJSON(named: name, subdirectory: subdirectory) as! [String:Any]
checkUnreadStatuses(in: account, correspondToIDsInJSONPayload: streamIDs, 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 streamIDs: [String: Any], testCase: XCTestCase) {
let ids = Set(streamIDs["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 streamIDs = testJSON(named: name, subdirectory: subdirectory) as! [String:Any]
checkStarredStatuses(in: account, correspondToStreamItemsIn: streamIDs, 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.")
@@ -278,10 +278,10 @@ 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
return (feedId, (0..<count).map { $0 })
let entries = feedIDsAndItemCounts.map { (feedID, count) -> (String, [Int]) in
return (feedID, (0..<count).map { $0 })
}.map { pair -> (String, Set<ParsedItem>) in
let items = pair.1.map { index -> ParsedItem in
@@ -304,7 +304,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,14 +31,14 @@ 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)
let origin = FeedlyOrigin(title: "Origin \(index)",
streamId: resource.id,
htmlUrl: "http://localhost/feedly/origin/\(index)")
streamID: resource.id,
htmlURL: "http://localhost/feedly/origin/\(index)")
return FeedlyEntry(id: "/articles/\(index)",
title: "Article \(index)",
@@ -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
// TestGetPagedStreamIDsService.swift
// AccountTests
//
// Created by Kiel Gillard on 29/10/19.
@@ -9,13 +9,13 @@
import XCTest
@testable import Account
final class TestGetPagedStreamIdsService: FeedlyGetStreamIDsService {
final class TestGetPagedStreamIDsService: FeedlyGetStreamIDsService {
var parameterTester: ((FeedlyResourceId, String?, Date?, Bool?) -> ())?
var getStreamIdsExpectation: XCTestExpectation?
var parameterTester: ((FeedlyResourceID, String?, Date?, Bool?) -> ())?
var getStreamIDsExpectation: XCTestExpectation?
var pages = [String: FeedlyStreamIDs]()
func addAtLeastOnePage(for resource: FeedlyResourceId, continuations: [String], numberOfEntriesPerPage count: Int) {
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.
@@ -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 = makeStreamIDs(for: resource, continuation: continuation, between: 0..<count)
let key = TestGetPagedStreamIDsService.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 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)
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 = TestGetPagedStreamIDsService.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.getStreamIDsExpectation?.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
@@ -28,7 +28,7 @@ final class TestGetStreamContentsService: FeedlyGetStreamContentsService {
}
func makeMockFeedlyEntryItem() -> [FeedlyEntry] {
let origin = FeedlyOrigin(title: "XCTest@localhost", streamId: "user/12345/category/67890", htmlUrl: "http://localhost/nnw/xctest")
let origin = FeedlyOrigin(title: "XCTest@localhost", streamID: "user/12345/category/67890", htmlURL: "http://localhost/nnw/xctest")
let content = FeedlyEntry.Content(content: "In the beginning...", direction: .leftToRight)
let items = [FeedlyEntry(id: "feeds/0/article/0",
title: "RSS Reader Ingests Man",

View File

@@ -1,5 +1,5 @@
//
// TestGetStreamIdsService.swift
// TestGetStreamIDsService.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 TestGetStreamIDsService: FeedlyGetStreamIDsService {
var mockResult: Result<FeedlyStreamIDs, Error>?
var parameterTester: ((FeedlyResourceId, String?, Date?, Bool?) -> ())?
var getStreamIdsExpectation: XCTestExpectation?
var parameterTester: ((FeedlyResourceID, String?, Date?, Bool?) -> ())?
var getStreamIDsExpectation: 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.getStreamIDsExpectation?.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

@@ -11,7 +11,7 @@ import RSWeb
import XCTest
protocol TestTransportMockResponseProviding: AnyObject {
func mockResponseFileUrl(for components: URLComponents) -> URL?
func mockResponseFileURL(for components: URLComponents) -> URL?
}
final class TestTransport: Transport {
@@ -23,7 +23,7 @@ final class TestTransport: Transport {
var testFiles = [String: String]()
var testStatusCodes = [String: Int]()
weak var mockResponseFileUrlProvider: TestTransportMockResponseProviding?
weak var mockResponseFileURLProvider: TestTransportMockResponseProviding?
private func httpResponse(for request: URLRequest, statusCode: Int = 200) -> HTTPURLResponse {
guard let url = request.url else {
@@ -45,12 +45,12 @@ final class TestTransport: Transport {
let response = httpResponse(for: request, statusCode: testStatusCodes[urlString] ?? 200)
let testFileURL: URL
if let provider = mockResponseFileUrlProvider {
guard let providerUrl = provider.mockResponseFileUrl(for: components) else {
if let provider = mockResponseFileURLProvider {
guard let providerURL = provider.mockResponseFileURL(for: components) else {
XCTFail("Test behaviour undefined. Mock provider failed to provide non-nil URL for \(components).")
return
}
testFileURL = providerUrl
testFileURL = providerURL
} else if let testKeyAndFileName = testFiles.first(where: { urlString.contains($0.key) }) {
testFileURL = Bundle.module.resourceURL!.appendingPathComponent(testKeyAndFileName.value)

View File

@@ -98,7 +98,7 @@ import Secrets
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

@@ -121,10 +121,10 @@ import RSCore
@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

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

View File

@@ -45,9 +45,9 @@ public class ArticleThemeDownloader: Logging {
private func moveTheme(from location: URL) throws -> URL {
var tmpFileName = location.lastPathComponent
tmpFileName = tmpFileName.replacingOccurrences(of: ".tmp", with: ".zip")
let fileUrl = downloadDirectory().appendingPathComponent("\(tmpFileName)")
try FileManager.default.moveItem(at: location, to: fileUrl)
return fileUrl
let fileURL = downloadDirectory().appendingPathComponent("\(tmpFileName)")
try FileManager.default.moveItem(at: location, to: fileURL)
return fileURL
}
/// Unzips the zip file

View File

@@ -116,7 +116,7 @@ extension Article {
return IconImageCache.shared.imageForArticle(self)
}
@MainActor func iconImageUrl(feed: Feed) -> URL? {
@MainActor func iconImageURL(feed: Feed) -> URL? {
if let image = iconImage() {
let fm = FileManager.default
var path = fm.urls(for: .cachesDirectory, in: .userDomainMask)[0]

View File

@@ -15,7 +15,7 @@ extension URL {
scheme == "mailto" ? URLComponents(url: self, resolvingAgainstBaseURL: false)?.path : nil
}
/// Percent encoded `mailto` URL for use with `canOpenUrl`. If the URL doesn't contain the `mailto` scheme, this is `nil`.
/// Percent encoded `mailto` URL for use with `canOpenURL`. If the URL doesn't contain the `mailto` scheme, this is `nil`.
var percentEncodedEmailAddress: URL? {
guard scheme == "mailto" else {
return nil

View File

@@ -80,7 +80,7 @@ private extension UserNotificationManager {
/// - Returns: A `UNNotificationAttachment` if an icon is available. Otherwise nil.
/// - Warning: In certain scenarios, this will return the `faviconTemplateImage`.
@MainActor func thumbnailAttachment(for article: Article, feed: Feed) -> UNNotificationAttachment? {
if let imageURL = article.iconImageUrl(feed: feed) {
if let imageURL = article.iconImageURL(feed: feed) {
let thumbnail = try? UNNotificationAttachment(identifier: feed.feedID, url: imageURL, options: nil)
return thumbnail
}

View File

@@ -56,7 +56,7 @@ public final class NewsBlurAPICaller {
let cookies = HTTPCookie.cookies(withResponseHeaderFields: headerFields, for: url)
for cookie in cookies where cookie.name == Self.SessionIdCookie {
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

@@ -121,11 +121,11 @@ public struct ReaderAPIAlternateLocation: Codable {
}
public struct ReaderAPIEntryOrigin: Codable {
public let streamId: String?
public let streamID: String?
let title: String?
enum CodingKeys: String, CodingKey {
case streamId = "streamId"
case streamID = "streamId"
case title = "title"
}
}

View File

@@ -82,11 +82,11 @@ public struct ReaderAPISubscription: Codable {
}
public struct ReaderAPICategory: Codable {
public let categoryId: String
public let categoryID: String
let categoryLabel: String
enum CodingKeys: String, CodingKey {
case categoryId = "id"
case categoryID = "id"
case categoryLabel = "label"
}
}

View File

@@ -32,12 +32,12 @@ class AppleScriptXCTestCase: XCTestCase {
var errorDict: NSDictionary? = nil
let testBundle = Bundle(for: type(of: self))
let url = testBundle.url(forResource:filename, withExtension:"scpt")
guard let testScriptUrl = url else {
guard let testScriptURL = url else {
XCTFail("Failed Getting script URL")
return nil
}
guard let testScript = NSAppleScript(contentsOf: testScriptUrl, error: &errorDict) else {
guard let testScript = NSAppleScript(contentsOf: testScriptURL, error: &errorDict) else {
print ("error is \(String(describing: errorDict))")
XCTFail("Failed initializing NSAppleScript")
return nil

View File

@@ -32,11 +32,11 @@ class ScriptingTests: AppleScriptXCTestCase {
XCTAssert( scriptResult?.stringValue == "Geoducks!")
}
func testGetUrlScript() {
func testGetURLScript() {
_ = doIndividualScript(filename: "testGetURL")
}
func testNameAndUrlOfEveryFeedScript() {
func testNameAndURLOfEveryFeedScript() {
_ = doIndividualScript(filename: "testNameAndUrlOfEveryFeed")
}

View File

@@ -144,7 +144,7 @@ import RSCore
do {
do {
try self.account?.removeCredentials(type: .newsBlurBasic)
try self.account?.removeCredentials(type: .newsBlurSessionId)
try self.account?.removeCredentials(type: .newsBlurSessionID)
} catch {
NewsBlurAddAccountView.logger.error("\(error.localizedDescription)")
}

View File

@@ -22,7 +22,7 @@ import RSCore
@State private var accountCredentials: Credentials?
@State private var accountUserName: String = ""
@State private var accountSecret: String = ""
@State private var accountAPIUrl: String = ""
@State private var accountAPIURL: String = ""
@State private var showProgressIndicator: Bool = false
@State private var accountError: (Error?, Bool) = (nil, false)
@@ -88,7 +88,7 @@ import RSCore
SecureField("Password", text: $accountSecret, prompt: Text("textfield.placeholder.password", comment: "Password"))
.textContentType(.password)
if accountType == .freshRSS && accountCredentials == nil {
TextField("FreshRSS URL", text: $accountAPIUrl, prompt: Text(verbatim: "fresh.rss.net/api/greader.php"))
TextField("FreshRSS URL", text: $accountAPIURL, prompt: Text(verbatim: "fresh.rss.net/api/greader.php"))
.autocorrectionDisabled()
.autocapitalization(.none)
}
@@ -147,7 +147,7 @@ import RSCore
if accountType == nil { return false }
switch accountType! {
case .freshRSS:
if (accountUserName.trimmingWhitespace.count == 0) || (accountSecret.trimmingWhitespace.count == 0) || (accountAPIUrl.trimmingWhitespace.count == 0) {
if (accountUserName.trimmingWhitespace.count == 0) || (accountSecret.trimmingWhitespace.count == 0) || (accountAPIURL.trimmingWhitespace.count == 0) {
return false
}
default:
@@ -215,7 +215,7 @@ import RSCore
private func apiURL() -> URL? {
switch accountType! {
case .freshRSS:
return URL(string: accountAPIUrl)!
return URL(string: accountAPIURL)!
case .inoreader:
return URL(string: ReaderAPIVariant.inoreader.host)!
case .bazQux:

View File

@@ -27,7 +27,7 @@ public class AddFeedIntentHandler: NSObject, AddFeedIntentHandling {
super.init()
}
public func resolveUrl(for intent: AddFeedIntent, with completion: @escaping (AddFeedUrlResolutionResult) -> Void) {
public func resolveURL(for intent: AddFeedIntent, with completion: @escaping (AddFeedURLResolutionResult) -> Void) {
guard let url = intent.url else {
completion(.unsupported(forReason: .required))
return