1/* 2 * 3 * Copyright 2015 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19#import <UIKit/UIKit.h> 20#import <XCTest/XCTest.h> 21 22#import <RxLibrary/GRXBufferedPipe.h> 23#import <RxLibrary/GRXWriteable.h> 24#import <RxLibrary/GRXWriter.h> 25 26#define TEST_TIMEOUT 1 27 28// A mock of a GRXSingleValueHandler block that can be queried for how many times it was called and 29// what were the last values passed to it. 30// 31// TODO(jcanizales): Move this to a test util library, and add tests for it. 32@interface CapturingSingleValueHandler : NSObject 33@property(nonatomic, readonly) void (^block)(id value, NSError *errorOrNil); 34@property(nonatomic, readonly) NSUInteger timesCalled; 35@property(nonatomic, readonly) id value; 36@property(nonatomic, readonly) NSError *errorOrNil; 37+ (instancetype)handler; 38@end 39 40@implementation CapturingSingleValueHandler 41+ (instancetype)handler { 42 return [[self alloc] init]; 43} 44 45- (GRXSingleHandler)block { 46 return ^(id value, NSError *errorOrNil) { 47 ++_timesCalled; 48 _value = value; 49 _errorOrNil = errorOrNil; 50 }; 51} 52@end 53 54// TODO(jcanizales): Split into one file per tested class. 55 56@interface RxLibraryUnitTests : XCTestCase 57@end 58 59@implementation RxLibraryUnitTests 60 61+ (void)setUp { 62 NSLog(@"GRPCClientTests Started"); 63} 64 65#pragma mark Writeable 66 67- (void)testWriteableSingleHandlerIsCalledForValue { 68 // Given: 69 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 70 id anyValue = @7; 71 72 // If: 73 id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block]; 74 [writeable writeValue:anyValue]; 75 [writeable writesFinishedWithError:nil]; 76 77 // Then: 78 XCTAssertEqual(handler.timesCalled, 1); 79 XCTAssertEqualObjects(handler.value, anyValue); 80 XCTAssertEqualObjects(handler.errorOrNil, nil); 81} 82 83- (void)testWriteableSingleHandlerIsCalledForError { 84 // Given: 85 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 86 NSError *anyError = [NSError errorWithDomain:@"domain" code:7 userInfo:nil]; 87 88 // If: 89 id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block]; 90 [writeable writesFinishedWithError:anyError]; 91 92 // Then: 93 XCTAssertEqual(handler.timesCalled, 1); 94 XCTAssertEqualObjects(handler.value, nil); 95 XCTAssertEqualObjects(handler.errorOrNil, anyError); 96} 97 98- (void)testWriteableSingleHandlerIsCalledOnlyOnce_ValueThenError { 99 // Given: 100 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 101 id anyValue = @7; 102 NSError *anyError = [NSError errorWithDomain:@"domain" code:7 userInfo:nil]; 103 104 // If: 105 id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block]; 106 [writeable writeValue:anyValue]; 107 [writeable writesFinishedWithError:anyError]; 108 109 // Then: 110 XCTAssertEqual(handler.timesCalled, 1); 111 XCTAssertEqualObjects(handler.value, anyValue); 112 XCTAssertEqualObjects(handler.errorOrNil, nil); 113} 114 115- (void)testWriteableSingleHandlerIsCalledOnlyOnce_ValueThenValue { 116 // Given: 117 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 118 id anyValue = @7; 119 120 // If: 121 id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block]; 122 [writeable writeValue:anyValue]; 123 [writeable writeValue:anyValue]; 124 [writeable writesFinishedWithError:nil]; 125 126 // Then: 127 XCTAssertEqual(handler.timesCalled, 1); 128 XCTAssertEqualObjects(handler.value, anyValue); 129 XCTAssertEqualObjects(handler.errorOrNil, nil); 130} 131 132- (void)testWriteableSingleHandlerFailsOnEmptyWriter { 133 // Given: 134 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 135 136 // If: 137 id<GRXWriteable> writeable = [GRXWriteable writeableWithSingleHandler:handler.block]; 138 [writeable writesFinishedWithError:nil]; 139 140 // Then: 141 XCTAssertEqual(handler.timesCalled, 1); 142 XCTAssertEqualObjects(handler.value, nil); 143 XCTAssertNotNil(handler.errorOrNil); 144} 145 146#pragma mark BufferedPipe 147 148- (void)testBufferedPipePropagatesValue { 149 __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Response received"]; 150 // Given: 151 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 152 id<GRXWriteable> writeable = 153 [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil) { 154 handler.block(value, errorOrNil); 155 [expectation fulfill]; 156 }]; 157 158 id anyValue = @7; 159 160 // If: 161 GRXBufferedPipe *pipe = [GRXBufferedPipe pipe]; 162 [pipe startWithWriteable:writeable]; 163 [pipe writeValue:anyValue]; 164 [pipe writesFinishedWithError:nil]; 165 166 // Then: 167 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; 168 XCTAssertEqual(handler.timesCalled, 1); 169 XCTAssertEqualObjects(handler.value, anyValue); 170 XCTAssertEqualObjects(handler.errorOrNil, nil); 171} 172 173- (void)testBufferedPipePropagatesError { 174 __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Response received"]; 175 // Given: 176 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 177 id<GRXWriteable> writeable = 178 [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil) { 179 handler.block(value, errorOrNil); 180 [expectation fulfill]; 181 }]; 182 NSError *anyError = [NSError errorWithDomain:@"domain" code:7 userInfo:nil]; 183 184 // If: 185 GRXBufferedPipe *pipe = [GRXBufferedPipe pipe]; 186 [pipe startWithWriteable:writeable]; 187 [pipe writesFinishedWithError:anyError]; 188 189 // Then: 190 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; 191 XCTAssertEqual(handler.timesCalled, 1); 192 XCTAssertEqualObjects(handler.value, nil); 193 XCTAssertEqualObjects(handler.errorOrNil, anyError); 194} 195 196- (void)testBufferedPipeFinishWriteWhilePaused { 197 __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Response received"]; 198 // Given: 199 CapturingSingleValueHandler *handler = [CapturingSingleValueHandler handler]; 200 id<GRXWriteable> writeable = 201 [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil) { 202 handler.block(value, errorOrNil); 203 [expectation fulfill]; 204 }]; 205 id anyValue = @7; 206 207 // If: 208 GRXBufferedPipe *pipe = [GRXBufferedPipe pipe]; 209 // Write something, then finish 210 [pipe writeValue:anyValue]; 211 [pipe writesFinishedWithError:nil]; 212 // then start the writeable 213 [pipe startWithWriteable:writeable]; 214 215 // Then: 216 [self waitForExpectationsWithTimeout:TEST_TIMEOUT handler:nil]; 217 XCTAssertEqual(handler.timesCalled, 1); 218 XCTAssertEqualObjects(handler.value, anyValue); 219 XCTAssertEqualObjects(handler.errorOrNil, nil); 220} 221 222#define WRITE_ROUNDS (1000) 223- (void)testBufferedPipeResumeWhenDealloc { 224 id anyValue = @7; 225 id<GRXWriteable> writeable = 226 [GRXWriteable writeableWithSingleHandler:^(id value, NSError *errorOrNil){ 227 }]; 228 229 // Release after alloc; 230 GRXBufferedPipe *pipe = [GRXBufferedPipe pipe]; 231 pipe = nil; 232 233 // Release after write but before start 234 pipe = [GRXBufferedPipe pipe]; 235 for (int i = 0; i < WRITE_ROUNDS; i++) { 236 [pipe writeValue:anyValue]; 237 } 238 pipe = nil; 239 240 // Release after start but not write 241 pipe = [GRXBufferedPipe pipe]; 242 [pipe startWithWriteable:writeable]; 243 pipe = nil; 244 245 // Release after start and write 246 pipe = [GRXBufferedPipe pipe]; 247 for (int i = 0; i < WRITE_ROUNDS; i++) { 248 [pipe writeValue:anyValue]; 249 } 250 [pipe startWithWriteable:writeable]; 251 pipe = nil; 252 253 // Release after start, write and pause 254 pipe = [GRXBufferedPipe pipe]; 255 [pipe startWithWriteable:writeable]; 256 for (int i = 0; i < WRITE_ROUNDS; i++) { 257 [pipe writeValue:anyValue]; 258 } 259 pipe.state = GRXWriterStatePaused; 260 for (int i = 0; i < WRITE_ROUNDS; i++) { 261 [pipe writeValue:anyValue]; 262 } 263 pipe = nil; 264 265 // Release after start, write, pause and finish 266 pipe = [GRXBufferedPipe pipe]; 267 [pipe startWithWriteable:writeable]; 268 for (int i = 0; i < WRITE_ROUNDS; i++) { 269 [pipe writeValue:anyValue]; 270 } 271 pipe.state = GRXWriterStatePaused; 272 for (int i = 0; i < WRITE_ROUNDS; i++) { 273 [pipe writeValue:anyValue]; 274 } 275 [pipe finishWithError:nil]; 276 pipe = nil; 277 278 // Release after start, write, pause, finish and resume 279 pipe = [GRXBufferedPipe pipe]; 280 [pipe startWithWriteable:writeable]; 281 for (int i = 0; i < WRITE_ROUNDS; i++) { 282 [pipe writeValue:anyValue]; 283 } 284 pipe.state = GRXWriterStatePaused; 285 for (int i = 0; i < WRITE_ROUNDS; i++) { 286 [pipe writeValue:anyValue]; 287 } 288 [pipe finishWithError:nil]; 289 pipe.state = GRXWriterStateStarted; 290 pipe = nil; 291} 292 293@end 294