nikolaykasyanov
3/7/2016 - 9:16 AM

MFBCollectionPreviewingAdapter.h

@import XCTest;
#import <OCMock/OCMock.h>

#import "MFBCollectionPreviewingAdapter.h"


@interface MFBCollectionPreviewingAdapterTests : XCTestCase

@end

@implementation MFBCollectionPreviewingAdapterTests {
    id _sourceViewMock;
    id _viewFactoryMock;
    id _committerMock;
    id _stateHolderMock;
    id _previewableViewControllerMock;

    MFBCollectionPreviewingAdapter *_adadpter;
    CGPoint _point;
    NSIndexPath *_indexPath;
    id _modelStub;
}

- (void)setUp
{
    [super setUp];

    _sourceViewMock = OCMProtocolMock(@protocol(MFBPreviewableCollectionView));
    _viewFactoryMock = OCMProtocolMock(@protocol(MFBCollectionPreviewingViewFactory));
    _committerMock = OCMProtocolMock(@protocol(MFBCollectionPreviewingCommitter));
    _stateHolderMock = OCMProtocolMock(@protocol(MFBPreviewableStateHolder));

    _adadpter = [MFBCollectionPreviewingAdapter new];

    _previewableViewControllerMock = OCMClassMock([UIViewController class]);

    [_adadpter registerViewController:_previewableViewControllerMock forPreviewingWithSourceView:_sourceViewMock];

    _adadpter.viewFactory = _viewFactoryMock;
    _adadpter.committer = _committerMock;
    _adadpter.stateHolder = _stateHolderMock;

    _point = CGPointMake(arc4random(), arc4random());
    _indexPath = [NSIndexPath indexPathForRow:(NSInteger) arc4random() inSection:0];
    _modelStub = [NSObject new];
}

- (void)test_RegisterViewController_CallsProperViewControllerMethod
{
    OCMVerify([_previewableViewControllerMock registerForPreviewingWithDelegate:_adadpter sourceView:_sourceViewMock]);
}

- (void)test_RegisterViewController_DoesNotRetainSourceView
{
    NS_VALID_UNTIL_END_OF_SCOPE MFBCollectionPreviewingAdapter *adapter = [MFBCollectionPreviewingAdapter new];
    id sourceViewStub = [NSObject new];
    __weak id sourceViewStubWeak = sourceViewStub;

    [adapter registerViewController:_previewableViewControllerMock forPreviewingWithSourceView:sourceViewStub];

    sourceViewStub = nil;

    XCTAssertNil(sourceViewStubWeak);
}

- (void)test_ViewControllerForLocation_NoIndexPath
{
    OCMExpect([_sourceViewMock mfb_previewableCollectionIndexPathForItemAtPoint:_point]).andReturn(nil);

    id viewController = [_adadpter previewingContext:(id) [NSObject new] viewControllerForLocation:_point];

    OCMVerifyAll(_sourceViewMock);
    XCTAssertNil(viewController);
}

- (void)test_ViewControllerForLocation_NoModelObject
{
    OCMStub([_sourceViewMock mfb_previewableCollectionIndexPathForItemAtPoint:_point]).andReturn(_indexPath);
    OCMExpect([_stateHolderMock previewingAdapter:_adadpter modelObjectForViewIndexPath:_indexPath]).andReturn(nil);

    id viewController = [_adadpter previewingContext:(id) [NSObject new] viewControllerForLocation:_point];

    OCMVerifyAll(_stateHolderMock);
    XCTAssertNil(viewController);
}

- (void)test_ViewControllerForLocation_ItemRectNotZero_AssignsItemRectToContext
{
    id previewingContextMock = OCMProtocolMock(@protocol(UIViewControllerPreviewing));
    CGRect itemRect = CGRectMake(10, 200, 500, 320);

    OCMStub([_sourceViewMock mfb_previewableCollectionIndexPathForItemAtPoint:_point]).andReturn(_indexPath);
    OCMStub([_stateHolderMock previewingAdapter:_adadpter modelObjectForViewIndexPath:_indexPath]).andReturn(_modelStub);
    OCMStub([_sourceViewMock mfb_previewableCollectionItemRectForIndexPath:_indexPath]).andReturn(itemRect);

    __unused id viewController = [_adadpter previewingContext:previewingContextMock viewControllerForLocation:_point];

    OCMVerify([previewingContextMock setSourceRect:itemRect]);
}

- (void)test_ViewControllerForLocation_ItemRectZero_DoesNotAssignItemRectToContext
{
    id previewingContextMock = OCMProtocolMock(@protocol(UIViewControllerPreviewing));
    CGRect itemRect = CGRectZero;

    OCMStub([_sourceViewMock mfb_previewableCollectionIndexPathForItemAtPoint:_point]).andReturn(_indexPath);
    OCMStub([_stateHolderMock previewingAdapter:_adadpter modelObjectForViewIndexPath:_indexPath]).andReturn(_modelStub);
    OCMStub([_sourceViewMock mfb_previewableCollectionItemRectForIndexPath:_indexPath]).andReturn(itemRect);
    [[[previewingContextMock reject] ignoringNonObjectArgs] setSourceRect:CGRectNull];

    __unused id viewController = [_adadpter previewingContext:previewingContextMock viewControllerForLocation:_point];
}

- (void)test_ViewControllerForLocation_AsksFactoryToBuildVC
{
    id expectedViewController = [NSObject new];

    OCMStub([_sourceViewMock mfb_previewableCollectionIndexPathForItemAtPoint:_point]).andReturn(_indexPath);
    OCMStub([_stateHolderMock previewingAdapter:_adadpter modelObjectForViewIndexPath:_indexPath]).andReturn(_modelStub);
    OCMStub([_viewFactoryMock previewingAdapter:_adadpter viewControllerForPreviewingModelObject:_modelStub]).andReturn(expectedViewController);

    id viewController = [_adadpter previewingContext:OCMProtocolMock(@protocol(UIViewControllerPreviewing)) viewControllerForLocation:_point];

    XCTAssertEqual(viewController, expectedViewController);
}

- (void)test_CommitViewController_ForwardsToCommitter
{
    id expectedViewController = [NSObject new];

    [_adadpter previewingContext:(id) [NSObject new] commitViewController:expectedViewController];

    OCMVerify([_committerMock previewingAdapter:_adadpter commitViewController:expectedViewController]);
}

@end
#import "MFBCollectionPreviewingAdapter.h"


NS_ASSUME_NONNULL_BEGIN

@implementation UITableView (MFBPreviewableCollectionView)

- (nullable NSIndexPath *)mfb_previewableCollectionIndexPathForItemAtPoint:(CGPoint)point
{
    return [self indexPathForRowAtPoint:point];
}

- (CGRect)mfb_previewableCollectionItemRectForIndexPath:(NSIndexPath *)indexPath
{
    return [self rectForRowAtIndexPath:indexPath];
}

@end


@implementation MFBCollectionPreviewingAdapter {
    __weak id<MFBPreviewableCollectionView> _sourceView;
}

- (void)registerViewController:(UIViewController *)viewController forPreviewingWithSourceView:(id)sourceView
{
    if (![viewController respondsToSelector:@selector(registerForPreviewingWithDelegate:sourceView:)]) {
        return;
    }

    [viewController registerForPreviewingWithDelegate:self sourceView:sourceView];

    _sourceView = sourceView;
}

- (nullable UIViewController *)previewingContext:(id<UIViewControllerPreviewing>)previewingContext viewControllerForLocation:(CGPoint)location
{
    NSIndexPath *indexPath = [_sourceView mfb_previewableCollectionIndexPathForItemAtPoint:location];

    if (!indexPath) {
        return nil;
    }

    id modelObject = [_stateHolder previewingAdapter:self modelObjectForViewIndexPath:indexPath];

    if (!modelObject) {
        return nil;
    }

    CGRect itemRect = [_sourceView mfb_previewableCollectionItemRectForIndexPath:indexPath];

    if (!CGRectEqualToRect(CGRectZero, itemRect)) {
        previewingContext.sourceRect = itemRect;
    }

    return [_viewFactory previewingAdapter:self viewControllerForPreviewingModelObject:modelObject];
}

- (void)previewingContext:(id<UIViewControllerPreviewing>)previewingContext commitViewController:(UIViewController *)viewControllerToCommit
{
    [_committer previewingAdapter:self commitViewController:viewControllerToCommit];
}

@end
@import UIKit;


NS_ASSUME_NONNULL_BEGIN

@protocol MFBPreviewableCollectionView

- (nullable NSIndexPath *)mfb_previewableCollectionIndexPathForItemAtPoint:(CGPoint)point;
- (CGRect)mfb_previewableCollectionItemRectForIndexPath:(NSIndexPath *)indexPath;

@end


@class MFBCollectionPreviewingAdapter;


@protocol MFBPreviewableStateHolder <NSObject>

- (nullable id)previewingAdapter:(MFBCollectionPreviewingAdapter *)adapter modelObjectForViewIndexPath:(NSIndexPath *)indexPath;

@end


@protocol MFBCollectionPreviewingViewFactory <NSObject>

- (UIViewController *)previewingAdapter:(MFBCollectionPreviewingAdapter *)adapter viewControllerForPreviewingModelObject:(id)modelObject;

@end


@protocol MFBCollectionPreviewingCommitter <NSObject>

- (void)previewingAdapter:(MFBCollectionPreviewingAdapter *)adapter commitViewController:(UIViewController *)viewController;

@end


@interface MFBCollectionPreviewingAdapter : NSObject <UIViewControllerPreviewingDelegate>

@property (nonatomic, weak) IBOutlet id<MFBPreviewableStateHolder> stateHolder;
@property (nonatomic, weak) IBOutlet id<MFBCollectionPreviewingViewFactory> viewFactory;
@property (nonatomic, weak) IBOutlet id<MFBCollectionPreviewingCommitter> committer;

- (void)registerViewController:(UIViewController *)viewController forPreviewingWithSourceView:(id<MFBPreviewableCollectionView>)sourceView;

@end


@interface UITableView (MFBPreviewableCollectionView) <MFBPreviewableCollectionView>

@end

NS_ASSUME_NONNULL_END