Skip to content

Instantly share code, notes, and snippets.

@appleios
Last active December 17, 2015 08:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save appleios/df89dd84edd152bbdaf1 to your computer and use it in GitHub Desktop.
Save appleios/df89dd84edd152bbdaf1 to your computer and use it in GitHub Desktop.
cheaper-tdd (tools: specta, expecta)
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
typedef enum : NSUInteger {
/**
result == _Failed && resultDescription == _NoSectionsYet @b==>
which means that the messageCountArray contains no section info.
result == _Failed && resultDescription == _PlainIndexOutOfBounds @b==>
which means that the plainIndex is greater than the maximal possible plain index available in given sections (the resulting indexPath contains (section == lastSectionIndex, row == lastPossibleRowInLastSection + 1).
*/
VIOSPlain2GroupedIndexTranslationResult_Failed = 1,
/**
result == _Ok && resultDescription == _SectionAndRowExists @b==>
which means that translation has succeeded and the indexPath contains correct section/row info.
*/
VIOSPlain2GroupedIndexTranslationResult_Ok = 2,
} VIOSPlain2GroupedIndexTranslationResultType;
typedef enum : NSUInteger {
VIOSPlain2GroupedIndexTranslationResultDescription_NoSectionsYet = 1,
VIOSPlain2GroupedIndexTranslationResultDescription_SectionAndRowExists = 2,
VIOSPlain2GroupedIndexTranslationResultDescription_PlainIndexOutOfBounds = 3
} VIOSPlain2GroupedIndexTranslationResultDescriptionType;
@protocol VIOSPlain2GrounedIndexTranslationResultProtocol <NSObject>
- (VIOSPlain2GroupedIndexTranslationResultType)result;
- (VIOSPlain2GroupedIndexTranslationResultDescriptionType)resultDescription;
- (NSIndexPath*)indexPath;
@end
@protocol VIOSPlain2GroupedIndexTranslationProtocol <NSObject>
/**
@brief Translates plain index into section/row indexPath.
@param plainIndex plain index to be translated.
@param messageCountArray an array containing info about the counts of messages in each seaction.
@returns An object describing 3 possible results (see docs for @VIOSPlain2GroupedIndexTranslationResultType).
*/
- (id<VIOSPlain2GrounedIndexTranslationResultProtocol>)indexPathFromPlainIndex:(NSInteger)plainIndex
withMessageCountArray:(NSArray*)messageCountArray;
@end
@interface VIOSPlain2GroupedIndexTranslationService : NSObject <VIOSPlain2GroupedIndexTranslationProtocol>
- (id<VIOSPlain2GrounedIndexTranslationResultProtocol>)indexPathFromPlainIndex:(NSInteger)plainIndex
withMessageCountArray:(NSArray*)messageCountArray;
@end
#import "VIOSPlain2GroupedIndexTranslationService.h"
@interface Plain2GrouedIndex_Result_Private : NSObject <VIOSPlain2GrounedIndexTranslationResultProtocol>
@property (assign, nonatomic) VIOSPlain2GroupedIndexTranslationResultType result;
@property (assign, nonatomic) VIOSPlain2GroupedIndexTranslationResultDescriptionType resultDescription;
@property (strong, nonatomic) NSIndexPath *indexPath;
+ (instancetype)resultWithType:(VIOSPlain2GroupedIndexTranslationResultType)result description:(VIOSPlain2GroupedIndexTranslationResultDescriptionType)description indexPath:(NSIndexPath*)indexPath;
@end
@implementation Plain2GrouedIndex_Result_Private
- (instancetype)initWithResultType:(VIOSPlain2GroupedIndexTranslationResultType)result description:(VIOSPlain2GroupedIndexTranslationResultDescriptionType)description indexPath:(NSIndexPath*)indexPath
{
self = [super init];
if (self) {
self.result = result;
self.resultDescription = description;
self.indexPath = indexPath;
}
return self;
}
+ (instancetype)resultWithType:(VIOSPlain2GroupedIndexTranslationResultType)result description:(VIOSPlain2GroupedIndexTranslationResultDescriptionType)description indexPath:(NSIndexPath *)indexPath
{
return [[self alloc] initWithResultType:result description:description indexPath:indexPath];
}
@end
@implementation VIOSPlain2GroupedIndexTranslationService
- (instancetype)init
{
self = [super init];
if (self) {
}
return self;
}
- (id<VIOSPlain2GrounedIndexTranslationResultProtocol>)indexPathFromPlainIndex:(NSInteger)plainIndex
withMessageCountArray:(NSArray*)messageCountArray
{
NSInteger totalSectionCount = messageCountArray.count;
NSInteger s, r, i, t;
BOOL found;
if (totalSectionCount == 0) {
return [Plain2GrouedIndex_Result_Private resultWithType:VIOSPlain2GroupedIndexTranslationResult_Failed description:VIOSPlain2GroupedIndexTranslationResultDescription_NoSectionsYet indexPath:nil];
}
found = NO;
t = [messageCountArray[0] integerValue];
if (plainIndex < t) {
s = 0;
r = plainIndex;
} else { // plainIndex >= t
s = -1;
r = -1;
for (i = 1; i<totalSectionCount; i++) {
NSInteger si = [messageCountArray[i] integerValue];
if ( t+si > plainIndex) {
found = YES;
s = i;
r = plainIndex - t;
if (r == si) {
s = i+1;
r = 0;
}
break;
} else {
t += si;
}
}
if (!found) {
NSInteger indexOfLastSection = totalSectionCount - 1;
NSInteger countOfRowsInLastSection = [messageCountArray[indexOfLastSection] integerValue];
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:countOfRowsInLastSection inSection:indexOfLastSection];
return [Plain2GrouedIndex_Result_Private resultWithType:VIOSPlain2GroupedIndexTranslationResult_Failed description:VIOSPlain2GroupedIndexTranslationResultDescription_PlainIndexOutOfBounds indexPath:indexPath];
}
}
assert(s>=0 && r>=0);
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:r inSection:s];
return [Plain2GrouedIndex_Result_Private resultWithType:VIOSPlain2GroupedIndexTranslationResult_Ok description:VIOSPlain2GroupedIndexTranslationResultDescription_SectionAndRowExists indexPath:indexPath];
}
@end
#import <Foundation/Foundation.h>
#import <Specta/Specta.h>
#import <Expecta/Expecta.h>
#import <OCMock/OCMock.h>
//sut import
#import "VIOSPlain2GroupedIndexTranslationService.h"
SpecBegin(VIOSPlain2GroupedIndexTranslationService)
describe(@"SUT", ^{
// sut
__block id<VIOSPlain2GroupedIndexTranslationProtocol> sut = nil;
beforeEach(^{
sut = [[VIOSPlain2GroupedIndexTranslationService alloc] init];
});
afterEach(^{
});
void (^translateAndTest)(int, int, int, NSArray *) = ^(int n, int sec, int row, NSArray *sectionCounts){
id<VIOSPlain2GrounedIndexTranslationResultProtocol> result = [sut indexPathFromPlainIndex:n withMessageCountArray:sectionCounts];
NSIndexPath *i = [result indexPath];
expect([result result] == VIOSPlain2GroupedIndexTranslationResult_Ok).beTruthy();
expect(i.section).equal(sec);
expect(i.row).equal(row);
};
it(@"should work on non-linear sections", ^{
// given
NSMutableArray *sectionCounts = [[NSMutableArray alloc] initWithCapacity:6];
sectionCounts[0] = @(4);
sectionCounts[1] = @(8);
sectionCounts[2] = @(5);
sectionCounts[3] = @(2);
sectionCounts[4] = @(5);
sectionCounts[5] = @(3);
// then
translateAndTest(0, 0, 0, sectionCounts);
translateAndTest(1, 0, 1, sectionCounts);
translateAndTest(2, 0, 2, sectionCounts);
translateAndTest(3, 0, 3, sectionCounts);
translateAndTest(4, 1, 0, sectionCounts);
translateAndTest(5, 1, 1, sectionCounts);
translateAndTest(6, 1, 2, sectionCounts);
translateAndTest(7, 1, 3, sectionCounts);
translateAndTest(8, 1, 4, sectionCounts);
translateAndTest(9, 1, 5, sectionCounts);
translateAndTest(10, 1, 6, sectionCounts);
translateAndTest(11, 1, 7, sectionCounts);
translateAndTest(12, 2, 0, sectionCounts);
translateAndTest(13, 2, 1, sectionCounts);
translateAndTest(14, 2, 2, sectionCounts);
translateAndTest(15, 2, 3, sectionCounts);
translateAndTest(16, 2, 4, sectionCounts);
translateAndTest(17, 3, 0, sectionCounts);
translateAndTest(18, 3, 1, sectionCounts);
translateAndTest(19, 4, 0, sectionCounts);
translateAndTest(20, 4, 1, sectionCounts);
translateAndTest(21, 4, 2, sectionCounts);
translateAndTest(22, 4, 3, sectionCounts);
translateAndTest(23, 4, 4, sectionCounts);
translateAndTest(24, 5, 0, sectionCounts);
translateAndTest(25, 5, 1, sectionCounts);
translateAndTest(26, 5, 2, sectionCounts);
});
it(@"should work with linear 5x5 matrix", ^{
const int N = 5;
NSMutableArray *sectionCounts = [[NSMutableArray alloc] initWithCapacity:N];
for(int i = 0; i < N; i++) {
sectionCounts[i] = @(N);
}
for(int i = 0; i < N*N; i++) {
translateAndTest(i, i/N, i%N, sectionCounts);
}
});
it(@"should return nil when no sectiosn", ^{
// when
id<VIOSPlain2GrounedIndexTranslationResultProtocol> result = [sut indexPathFromPlainIndex:10 withMessageCountArray:nil];
// then
expect([result result] == VIOSPlain2GroupedIndexTranslationResult_Failed).beTruthy();
expect([result resultDescription] == VIOSPlain2GroupedIndexTranslationResultDescription_NoSectionsYet).beTruthy();
});
it(@"should return last section when plainIndex can not be placed within any section", ^{
// given
NSMutableArray *sectionCounts = [[NSMutableArray alloc] initWithCapacity:2];
sectionCounts[0] = @(2);
sectionCounts[1] = @(3);
// when
id<VIOSPlain2GrounedIndexTranslationResultProtocol> result = [sut indexPathFromPlainIndex:5 withMessageCountArray:sectionCounts];
expect([result result] == VIOSPlain2GroupedIndexTranslationResult_Failed).beTruthy();
expect([result resultDescription] == VIOSPlain2GroupedIndexTranslationResultDescription_PlainIndexOutOfBounds).beTruthy();
NSIndexPath *i = [result indexPath];
// then
expect(i.section).equal(1);
expect(i.row).equal(3);
});
});
SpecEnd
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment