| // |
| // RACStreamExamples.m |
| // ReactiveCocoa |
| // |
| // Created by Justin Spahr-Summers on 2012-11-01. |
| // Copyright (c) 2012 GitHub, Inc. All rights reserved. |
| // |
| |
| #import "RACStreamExamples.h" |
| |
| #import "RACStream.h" |
| #import "RACUnit.h" |
| #import "RACTuple.h" |
| |
| NSString * const RACStreamExamples = @"RACStreamExamples"; |
| NSString * const RACStreamExamplesClass = @"RACStreamExamplesClass"; |
| NSString * const RACStreamExamplesInfiniteStream = @"RACStreamExamplesInfiniteStream"; |
| NSString * const RACStreamExamplesVerifyValuesBlock = @"RACStreamExamplesVerifyValuesBlock"; |
| |
| SharedExampleGroupsBegin(RACStreamExamples) |
| |
| sharedExamplesFor(RACStreamExamples, ^(NSDictionary *data) { |
| __block Class streamClass; |
| __block void (^verifyValues)(RACStream *, NSArray *); |
| __block RACStream *infiniteStream; |
| |
| __block RACStream *(^streamWithValues)(NSArray *); |
| |
| before(^{ |
| streamClass = data[RACStreamExamplesClass]; |
| verifyValues = data[RACStreamExamplesVerifyValuesBlock]; |
| infiniteStream = data[RACStreamExamplesInfiniteStream]; |
| streamWithValues = [^(NSArray *values) { |
| RACStream *stream = [streamClass empty]; |
| |
| for (id value in values) { |
| stream = [stream concat:[streamClass return:value]]; |
| } |
| |
| return stream; |
| } copy]; |
| }); |
| |
| it(@"should return an empty stream", ^{ |
| RACStream *stream = [streamClass empty]; |
| verifyValues(stream, @[]); |
| }); |
| |
| it(@"should lift a value into a stream", ^{ |
| RACStream *stream = [streamClass return:RACUnit.defaultUnit]; |
| verifyValues(stream, @[ RACUnit.defaultUnit ]); |
| }); |
| |
| describe(@"-concat:", ^{ |
| it(@"should concatenate two streams", ^{ |
| RACStream *stream = [[streamClass return:@0] concat:[streamClass return:@1]]; |
| verifyValues(stream, @[ @0, @1 ]); |
| }); |
| |
| it(@"should concatenate three streams", ^{ |
| RACStream *stream = [[[streamClass return:@0] concat:[streamClass return:@1]] concat:[streamClass return:@2]]; |
| verifyValues(stream, @[ @0, @1, @2 ]); |
| }); |
| |
| it(@"should concatenate around an empty stream", ^{ |
| RACStream *stream = [[[streamClass return:@0] concat:[streamClass empty]] concat:[streamClass return:@2]]; |
| verifyValues(stream, @[ @0, @2 ]); |
| }); |
| }); |
| |
| it(@"should flatten", ^{ |
| RACStream *stream = [[streamClass return:[streamClass return:RACUnit.defaultUnit]] flatten]; |
| verifyValues(stream, @[ RACUnit.defaultUnit ]); |
| }); |
| |
| describe(@"-bind:", ^{ |
| it(@"should return the result of binding a single value", ^{ |
| RACStream *stream = [[streamClass return:@0] bind:^{ |
| return ^(NSNumber *value, BOOL *stop) { |
| NSNumber *newValue = @(value.integerValue + 1); |
| return [streamClass return:newValue]; |
| }; |
| }]; |
| |
| verifyValues(stream, @[ @1 ]); |
| }); |
| |
| it(@"should concatenate the result of binding multiple values", ^{ |
| RACStream *baseStream = streamWithValues(@[ @0, @1 ]); |
| RACStream *stream = [baseStream bind:^{ |
| return ^(NSNumber *value, BOOL *stop) { |
| NSNumber *newValue = @(value.integerValue + 1); |
| return [streamClass return:newValue]; |
| }; |
| }]; |
| |
| verifyValues(stream, @[ @1, @2 ]); |
| }); |
| |
| it(@"should concatenate with an empty result from binding a value", ^{ |
| RACStream *baseStream = streamWithValues(@[ @0, @1, @2 ]); |
| RACStream *stream = [baseStream bind:^{ |
| return ^(NSNumber *value, BOOL *stop) { |
| if (value.integerValue == 1) return [streamClass empty]; |
| |
| NSNumber *newValue = @(value.integerValue + 1); |
| return [streamClass return:newValue]; |
| }; |
| }]; |
| |
| verifyValues(stream, @[ @1, @3 ]); |
| }); |
| |
| it(@"should terminate immediately when returning nil", ^{ |
| RACStream *stream = [infiniteStream bind:^{ |
| return ^ id (id _, BOOL *stop) { |
| return nil; |
| }; |
| }]; |
| |
| verifyValues(stream, @[]); |
| }); |
| |
| it(@"should terminate after one value when setting 'stop'", ^{ |
| RACStream *stream = [infiniteStream bind:^{ |
| return ^ id (id value, BOOL *stop) { |
| *stop = YES; |
| return [streamClass return:value]; |
| }; |
| }]; |
| |
| verifyValues(stream, @[ RACUnit.defaultUnit ]); |
| }); |
| |
| it(@"should terminate immediately when returning nil and setting 'stop'", ^{ |
| RACStream *stream = [infiniteStream bind:^{ |
| return ^ id (id _, BOOL *stop) { |
| *stop = YES; |
| return nil; |
| }; |
| }]; |
| |
| verifyValues(stream, @[]); |
| }); |
| |
| it(@"should be restartable even with block state", ^{ |
| NSArray *values = @[ @0, @1, @2 ]; |
| RACStream *baseStream = streamWithValues(values); |
| |
| RACStream *countingStream = [baseStream bind:^{ |
| __block NSUInteger counter = 0; |
| |
| return ^(id x, BOOL *stop) { |
| return [streamClass return:@(counter++)]; |
| }; |
| }]; |
| |
| verifyValues(countingStream, @[ @0, @1, @2 ]); |
| verifyValues(countingStream, @[ @0, @1, @2 ]); |
| }); |
| |
| it(@"should be interleavable even with block state", ^{ |
| NSArray *values = @[ @0, @1, @2 ]; |
| RACStream *baseStream = streamWithValues(values); |
| |
| RACStream *countingStream = [baseStream bind:^{ |
| __block NSUInteger counter = 0; |
| |
| return ^(id x, BOOL *stop) { |
| return [streamClass return:@(counter++)]; |
| }; |
| }]; |
| |
| // Just so +zip:reduce: thinks this is a unique stream. |
| RACStream *anotherStream = [[streamClass empty] concat:countingStream]; |
| |
| RACStream *zipped = [streamClass zip:@[ countingStream, anotherStream ] reduce:^(NSNumber *v1, NSNumber *v2) { |
| return @(v1.integerValue + v2.integerValue); |
| }]; |
| |
| verifyValues(zipped, @[ @0, @2, @4 ]); |
| }); |
| }); |
| |
| describe(@"-flattenMap:", ^{ |
| it(@"should return a single mapped result", ^{ |
| RACStream *stream = [[streamClass return:@0] flattenMap:^(NSNumber *value) { |
| NSNumber *newValue = @(value.integerValue + 1); |
| return [streamClass return:newValue]; |
| }]; |
| |
| verifyValues(stream, @[ @1 ]); |
| }); |
| |
| it(@"should concatenate the results of mapping multiple values", ^{ |
| RACStream *baseStream = streamWithValues(@[ @0, @1 ]); |
| RACStream *stream = [baseStream flattenMap:^(NSNumber *value) { |
| NSNumber *newValue = @(value.integerValue + 1); |
| return [streamClass return:newValue]; |
| }]; |
| |
| verifyValues(stream, @[ @1, @2 ]); |
| }); |
| |
| it(@"should concatenate with an empty result from mapping a value", ^{ |
| RACStream *baseStream = streamWithValues(@[ @0, @1, @2 ]); |
| RACStream *stream = [baseStream flattenMap:^(NSNumber *value) { |
| if (value.integerValue == 1) return [streamClass empty]; |
| |
| NSNumber *newValue = @(value.integerValue + 1); |
| return [streamClass return:newValue]; |
| }]; |
| |
| verifyValues(stream, @[ @1, @3 ]); |
| }); |
| |
| it(@"should treat nil streams like empty streams", ^{ |
| RACStream *baseStream = streamWithValues(@[ @0, @1, @2 ]); |
| RACStream *stream = [baseStream flattenMap:^ RACStream * (NSNumber *value) { |
| if (value.integerValue == 1) return nil; |
| |
| NSNumber *newValue = @(value.integerValue + 1); |
| return [streamClass return:newValue]; |
| }]; |
| |
| verifyValues(stream, @[ @1, @3 ]); |
| }); |
| }); |
| |
| it(@"should map", ^{ |
| RACStream *baseStream = streamWithValues(@[ @0, @1, @2 ]); |
| RACStream *stream = [baseStream map:^(NSNumber *value) { |
| return @(value.integerValue + 1); |
| }]; |
| |
| verifyValues(stream, @[ @1, @2, @3 ]); |
| }); |
| |
| it(@"should map and replace", ^{ |
| RACStream *baseStream = streamWithValues(@[ @0, @1, @2 ]); |
| RACStream *stream = [baseStream mapReplace:RACUnit.defaultUnit]; |
| |
| verifyValues(stream, @[ RACUnit.defaultUnit, RACUnit.defaultUnit, RACUnit.defaultUnit ]); |
| }); |
| |
| it(@"should filter", ^{ |
| RACStream *baseStream = streamWithValues(@[ @0, @1, @2, @3, @4, @5, @6 ]); |
| RACStream *stream = [baseStream filter:^ BOOL (NSNumber *value) { |
| return value.integerValue % 2 == 0; |
| }]; |
| |
| verifyValues(stream, @[ @0, @2, @4, @6 ]); |
| }); |
| |
| describe(@"-ignore:", ^{ |
| it(@"should ignore a value", ^{ |
| RACStream *baseStream = streamWithValues(@[ @0, @1, @2, @3, @4, @5, @6 ]); |
| RACStream *stream = [baseStream ignore:@1]; |
| |
| verifyValues(stream, @[ @0, @2, @3, @4, @5, @6 ]); |
| }); |
| |
| it(@"should ignore based on object equality", ^{ |
| RACStream *baseStream = streamWithValues(@[ @"0", @"1", @"2", @"3", @"4", @"5", @"6" ]); |
| |
| NSMutableString *valueToIgnore = [[NSMutableString alloc] init]; |
| [valueToIgnore appendString:@"1"]; |
| RACStream *stream = [baseStream ignore:valueToIgnore]; |
| |
| verifyValues(stream, @[ @"0", @"2", @"3", @"4", @"5", @"6" ]); |
| }); |
| }); |
| |
| it(@"should start with a value", ^{ |
| RACStream *stream = [[streamClass return:@1] startWith:@0]; |
| verifyValues(stream, @[ @0, @1 ]); |
| }); |
| |
| describe(@"-skip:", ^{ |
| __block NSArray *values; |
| __block RACStream *stream; |
| |
| before(^{ |
| values = @[ @0, @1, @2 ]; |
| stream = streamWithValues(values); |
| }); |
| |
| it(@"should skip any valid number of values", ^{ |
| for (NSUInteger i = 0; i < values.count; i++) { |
| verifyValues([stream skip:i], [values subarrayWithRange:NSMakeRange(i, values.count - i)]); |
| } |
| }); |
| |
| it(@"should return an empty stream when skipping too many values", ^{ |
| verifyValues([stream skip:4], @[]); |
| }); |
| }); |
| |
| describe(@"-take:", ^{ |
| describe(@"with three values", ^{ |
| __block NSArray *values; |
| __block RACStream *stream; |
| |
| before(^{ |
| values = @[ @0, @1, @2 ]; |
| stream = streamWithValues(values); |
| }); |
| |
| it(@"should take any valid number of values", ^{ |
| for (NSUInteger i = 0; i < values.count; i++) { |
| verifyValues([stream take:i], [values subarrayWithRange:NSMakeRange(0, i)]); |
| } |
| }); |
| |
| it(@"should return the same stream when taking too many values", ^{ |
| verifyValues([stream take:4], values); |
| }); |
| }); |
| |
| it(@"should take and terminate from an infinite stream", ^{ |
| verifyValues([infiniteStream take:0], @[]); |
| verifyValues([infiniteStream take:1], @[ RACUnit.defaultUnit ]); |
| verifyValues([infiniteStream take:2], @[ RACUnit.defaultUnit, RACUnit.defaultUnit ]); |
| }); |
| |
| it(@"should take and terminate from a single-item stream", ^{ |
| NSArray *values = @[ RACUnit.defaultUnit ]; |
| RACStream *stream = streamWithValues(values); |
| verifyValues([stream take:1], values); |
| }); |
| }); |
| |
| describe(@"zip stream creation methods", ^{ |
| __block NSArray *valuesOne; |
| |
| __block RACStream *streamOne; |
| __block RACStream *streamTwo; |
| __block RACStream *streamThree; |
| __block NSArray *threeStreams; |
| |
| __block NSArray *oneStreamTuples; |
| __block NSArray *twoStreamTuples; |
| __block NSArray *threeStreamTuples; |
| |
| before(^{ |
| valuesOne = @[ @"Ada", @"Bob", @"Dea" ]; |
| NSArray *valuesTwo = @[ @"eats", @"cooks", @"jumps" ]; |
| NSArray *valuesThree = @[ @"fish", @"bear", @"rock" ]; |
| |
| streamOne = streamWithValues(valuesOne); |
| streamTwo = streamWithValues(valuesTwo); |
| streamThree = streamWithValues(valuesThree); |
| threeStreams = @[ streamOne, streamTwo, streamThree ]; |
| |
| oneStreamTuples = @[ |
| RACTuplePack(valuesOne[0]), |
| RACTuplePack(valuesOne[1]), |
| RACTuplePack(valuesOne[2]), |
| ]; |
| |
| twoStreamTuples = @[ |
| RACTuplePack(valuesOne[0], valuesTwo[0]), |
| RACTuplePack(valuesOne[1], valuesTwo[1]), |
| RACTuplePack(valuesOne[2], valuesTwo[2]), |
| ]; |
| |
| threeStreamTuples = @[ |
| RACTuplePack(valuesOne[0], valuesTwo[0], valuesThree[0]), |
| RACTuplePack(valuesOne[1], valuesTwo[1], valuesThree[1]), |
| RACTuplePack(valuesOne[2], valuesTwo[2], valuesThree[2]), |
| ]; |
| }); |
| |
| describe(@"-zipWith:", ^{ |
| it(@"should make a stream of tuples", ^{ |
| RACStream *stream = [streamOne zipWith:streamTwo]; |
| verifyValues(stream, twoStreamTuples); |
| }); |
| |
| it(@"should truncate streams", ^{ |
| RACStream *shortStream = streamWithValues(@[ @"now", @"later" ]); |
| RACStream *stream = [streamOne zipWith:shortStream]; |
| |
| verifyValues(stream, @[ |
| RACTuplePack(valuesOne[0], @"now"), |
| RACTuplePack(valuesOne[1], @"later") |
| ]); |
| }); |
| |
| it(@"should work on infinite streams", ^{ |
| RACStream *stream = [streamOne zipWith:infiniteStream]; |
| verifyValues(stream, @[ |
| RACTuplePack(valuesOne[0], RACUnit.defaultUnit), |
| RACTuplePack(valuesOne[1], RACUnit.defaultUnit), |
| RACTuplePack(valuesOne[2], RACUnit.defaultUnit) |
| ]); |
| }); |
| |
| it(@"should handle multiples of the same stream", ^{ |
| RACStream *stream = [streamOne zipWith:streamOne]; |
| verifyValues(stream, @[ |
| RACTuplePack(valuesOne[0], valuesOne[0]), |
| RACTuplePack(valuesOne[1], valuesOne[1]), |
| RACTuplePack(valuesOne[2], valuesOne[2]), |
| ]); |
| }); |
| }); |
| |
| describe(@"+zip:reduce:", ^{ |
| it(@"should reduce values", ^{ |
| RACStream *stream = [streamClass zip:threeStreams reduce:^ NSString * (id x, id y, id z) { |
| return [NSString stringWithFormat:@"%@ %@ %@", x, y, z]; |
| }]; |
| verifyValues(stream, @[ @"Ada eats fish", @"Bob cooks bear", @"Dea jumps rock" ]); |
| }); |
| |
| it(@"should truncate streams", ^{ |
| RACStream *shortStream = streamWithValues(@[ @"now", @"later" ]); |
| NSArray *streams = [threeStreams arrayByAddingObject:shortStream]; |
| RACStream *stream = [streamClass zip:streams reduce:^ NSString * (id w, id x, id y, id z) { |
| return [NSString stringWithFormat:@"%@ %@ %@ %@", w, x, y, z]; |
| }]; |
| verifyValues(stream, @[ @"Ada eats fish now", @"Bob cooks bear later" ]); |
| }); |
| |
| it(@"should work on infinite streams", ^{ |
| NSArray *streams = [threeStreams arrayByAddingObject:infiniteStream]; |
| RACStream *stream = [streamClass zip:streams reduce:^ NSString * (id w, id x, id y, id z) { |
| return [NSString stringWithFormat:@"%@ %@ %@", w, x, y]; |
| }]; |
| verifyValues(stream, @[ @"Ada eats fish", @"Bob cooks bear", @"Dea jumps rock" ]); |
| }); |
| |
| it(@"should handle multiples of the same stream", ^{ |
| NSArray *streams = @[ streamOne, streamOne, streamTwo, streamThree, streamTwo, streamThree ]; |
| RACStream *stream = [streamClass zip:streams reduce:^ NSString * (id x1, id x2, id y1, id z1, id y2, id z2) { |
| return [NSString stringWithFormat:@"%@ %@ %@ %@ %@ %@", x1, x2, y1, z1, y2, z2]; |
| }]; |
| verifyValues(stream, @[ @"Ada Ada eats fish eats fish", @"Bob Bob cooks bear cooks bear", @"Dea Dea jumps rock jumps rock" ]); |
| }); |
| }); |
| |
| describe(@"+zip:", ^{ |
| it(@"should make a stream of tuples out of single value", ^{ |
| RACStream *stream = [streamClass zip:@[ streamOne ]]; |
| verifyValues(stream, oneStreamTuples); |
| }); |
| |
| it(@"should make a stream of tuples out of an array of streams", ^{ |
| RACStream *stream = [streamClass zip:threeStreams]; |
| verifyValues(stream, threeStreamTuples); |
| }); |
| |
| it(@"should make an empty stream if given an empty array", ^{ |
| RACStream *stream = [streamClass zip:@[]]; |
| verifyValues(stream, @[]); |
| }); |
| |
| it(@"should make a stream of tuples out of an enumerator of streams", ^{ |
| RACStream *stream = [streamClass zip:threeStreams.objectEnumerator]; |
| verifyValues(stream, threeStreamTuples); |
| }); |
| |
| it(@"should make an empty stream if given an empty enumerator", ^{ |
| RACStream *stream = [streamClass zip:@[].objectEnumerator]; |
| verifyValues(stream, @[]); |
| }); |
| }); |
| }); |
| |
| describe(@"+concat:", ^{ |
| __block NSArray *streams = nil; |
| __block NSArray *result = nil; |
| |
| before(^{ |
| RACStream *a = [streamClass return:@0]; |
| RACStream *b = [streamClass empty]; |
| RACStream *c = streamWithValues(@[ @1, @2, @3 ]); |
| RACStream *d = [streamClass return:@4]; |
| RACStream *e = [streamClass return:@5]; |
| RACStream *f = [streamClass empty]; |
| RACStream *g = [streamClass empty]; |
| RACStream *h = streamWithValues(@[ @6, @7 ]); |
| streams = @[ a, b, c, d, e, f, g, h ]; |
| result = @[ @0, @1, @2, @3, @4, @5, @6, @7 ]; |
| }); |
| |
| it(@"should concatenate an array of streams", ^{ |
| RACStream *stream = [streamClass concat:streams]; |
| verifyValues(stream, result); |
| }); |
| |
| it(@"should concatenate an enumerator of streams", ^{ |
| RACStream *stream = [streamClass concat:streams.objectEnumerator]; |
| verifyValues(stream, result); |
| }); |
| }); |
| |
| it(@"should scan", ^{ |
| RACStream *stream = streamWithValues(@[ @1, @2, @3, @4 ]); |
| RACStream *scanned = [stream scanWithStart:@0 reduce:^(NSNumber *running, NSNumber *next) { |
| return @(running.integerValue + next.integerValue); |
| }]; |
| |
| verifyValues(scanned, @[ @1, @3, @6, @10 ]); |
| }); |
| |
| describe(@"taking with a predicate", ^{ |
| NSArray *values = @[ @0, @1, @2, @3, @0, @2, @4 ]; |
| |
| __block RACStream *stream; |
| |
| before(^{ |
| stream = streamWithValues(values); |
| }); |
| |
| it(@"should take until a predicate is true", ^{ |
| RACStream *taken = [stream takeUntilBlock:^ BOOL (NSNumber *x) { |
| return x.integerValue >= 3; |
| }]; |
| |
| verifyValues(taken, @[ @0, @1, @2 ]); |
| }); |
| |
| it(@"should take while a predicate is true", ^{ |
| RACStream *taken = [stream takeWhileBlock:^ BOOL (NSNumber *x) { |
| return x.integerValue <= 1; |
| }]; |
| |
| verifyValues(taken, @[ @0, @1 ]); |
| }); |
| |
| it(@"should take a full stream", ^{ |
| RACStream *taken = [stream takeWhileBlock:^ BOOL (NSNumber *x) { |
| return x.integerValue <= 10; |
| }]; |
| |
| verifyValues(taken, values); |
| }); |
| |
| it(@"should return an empty stream", ^{ |
| RACStream *taken = [stream takeWhileBlock:^ BOOL (NSNumber *x) { |
| return x.integerValue < 0; |
| }]; |
| |
| verifyValues(taken, @[]); |
| }); |
| |
| it(@"should terminate an infinite stream", ^{ |
| RACStream *infiniteCounter = [infiniteStream scanWithStart:@0 reduce:^(NSNumber *running, id _) { |
| return @(running.unsignedIntegerValue + 1); |
| }]; |
| |
| RACStream *taken = [infiniteCounter takeWhileBlock:^ BOOL (NSNumber *x) { |
| return x.integerValue <= 5; |
| }]; |
| |
| verifyValues(taken, @[ @1, @2, @3, @4, @5 ]); |
| }); |
| }); |
| |
| describe(@"skipping with a predicate", ^{ |
| NSArray *values = @[ @0, @1, @2, @3, @0, @2, @4 ]; |
| |
| __block RACStream *stream; |
| |
| before(^{ |
| stream = streamWithValues(values); |
| }); |
| |
| it(@"should skip until a predicate is true", ^{ |
| RACStream *taken = [stream skipUntilBlock:^ BOOL (NSNumber *x) { |
| return x.integerValue >= 3; |
| }]; |
| |
| verifyValues(taken, @[ @3, @0, @2, @4 ]); |
| }); |
| |
| it(@"should skip while a predicate is true", ^{ |
| RACStream *taken = [stream skipWhileBlock:^ BOOL (NSNumber *x) { |
| return x.integerValue <= 1; |
| }]; |
| |
| verifyValues(taken, @[ @2, @3, @0, @2, @4 ]); |
| }); |
| |
| it(@"should skip a full stream", ^{ |
| RACStream *taken = [stream skipWhileBlock:^ BOOL (NSNumber *x) { |
| return x.integerValue <= 10; |
| }]; |
| |
| verifyValues(taken, @[]); |
| }); |
| |
| it(@"should finish skipping immediately", ^{ |
| RACStream *taken = [stream skipWhileBlock:^ BOOL (NSNumber *x) { |
| return x.integerValue < 0; |
| }]; |
| |
| verifyValues(taken, values); |
| }); |
| }); |
| |
| describe(@"-combinePreviousWithStart:reduce:", ^{ |
| NSArray *values = @[ @1, @2, @3 ]; |
| __block RACStream *stream; |
| beforeEach(^{ |
| stream = streamWithValues(values); |
| }); |
| |
| it(@"should pass the previous next into the reduce block", ^{ |
| NSMutableArray *previouses = [NSMutableArray array]; |
| RACStream *mapped = [stream combinePreviousWithStart:nil reduce:^(id previous, id next) { |
| [previouses addObject:previous ?: RACTupleNil.tupleNil]; |
| return next; |
| }]; |
| |
| verifyValues(mapped, @[ @1, @2, @3 ]); |
| |
| NSArray *expected = @[ RACTupleNil.tupleNil, @1, @2 ]; |
| expect(previouses).to.equal(expected); |
| }); |
| |
| it(@"should send the combined value", ^{ |
| RACStream *mapped = [stream combinePreviousWithStart:@1 reduce:^(NSNumber *previous, NSNumber *next) { |
| return [NSString stringWithFormat:@"%lu - %lu", (unsigned long)previous.unsignedIntegerValue, (unsigned long)next.unsignedIntegerValue]; |
| }]; |
| |
| verifyValues(mapped, @[ @"1 - 1", @"1 - 2", @"2 - 3" ]); |
| }); |
| }); |
| |
| it(@"should reduce tuples", ^{ |
| RACStream *stream = streamWithValues(@[ |
| RACTuplePack(@"foo", @"bar"), |
| RACTuplePack(@"buzz", @"baz"), |
| RACTuplePack(@"", @"_") |
| ]); |
| |
| RACStream *reduced = [stream reduceEach:^(NSString *a, NSString *b) { |
| return [a stringByAppendingString:b]; |
| }]; |
| |
| verifyValues(reduced, @[ @"foobar", @"buzzbaz", @"_" ]); |
| }); |
| }); |
| |
| SharedExampleGroupsEnd |