#import <Foundation/Foundation.h>


#pragma mark - Protocols


@protocol Feed <NSObject>
@end


@protocol Folder <NSObject>

@property (readonly, strong) NSArray<id<Feed>> *feeds;
- (void)addFeeds:(NSArray<id<Feed>> *)feeds;
/* … */

@end


#pragma mark Local implementations


@interface LocalFeed : NSObject <Feed>
@end
@implementation LocalFeed
@end


@interface LocalFolder : NSObject <Folder>
@property (strong) NSArray<id<Feed>> *feeds;
- (void)addFeeds:(NSArray<id<Feed>> *)feeds;
@end


@implementation LocalFolder
- (instancetype)init {
    if (!(self = [super init])) { return nil; }
    self->_feeds = [NSArray new];
    return self;
}
- (void)addFeeds:(NSArray<id<Feed>> *)feeds {
    self.feeds = [self.feeds arrayByAddingObjectsFromArray:feeds];
}
@end


#pragma mark - FeedBin implementations


@interface FeedBinFeed : NSObject <Feed>
@end
@implementation FeedBinFeed
@end

@interface FeedBinFolder : NSObject <Folder>
@property (strong) NSArray<id<Feed>> *feeds;
- (void)addFeeds:(NSArray<id<Feed>> *)feeds;
@end

@implementation FeedBinFolder
- (instancetype)init {
    if (!(self = [super init])) { return nil; }
    self->_feeds = [NSArray new];
    return self;
}
- (void)addFeeds:(NSArray<id<Feed>> *)feeds {
    self.feeds = [self.feeds arrayByAddingObjectsFromArray:feeds];
}
@end


#pragma mark - Testing


#import <XCTest/XCTest.h>


#pragma mark - Base test class


@interface FolderTests : XCTestCase

- (id<Folder>)folder;
- (id<Feed>)feed;

@end


@implementation FolderTests

- (id<Folder>)folder {
    return [LocalFolder new];
}

- (id<Feed>)feed {
    return [LocalFeed new];
}

- (void)testAddFeed {
    id<Folder> testFolder = [self folder];
    id<Feed> testFeed = [self feed];
    [testFolder addFeeds:@[testFeed]];
    XCTAssert([testFolder.feeds containsObject:testFeed]);
}

- (void)testAddThousandsOfFeeds {
    [self measureBlock:^{
        /* … */
    }];
}

@end


#pragma mark - FeedBin test class


@interface FeedBinFolderTests : FolderTests
@end

@implementation FeedBinFolderTests

- (id<Folder>)folder {
    return [FeedBinFolder new];
}

- (id<Feed>)feed {
    return [FeedBinFeed new];
}

- (void)testFeedBinSpecific {
    /* … */
}

@end

