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