| Flutter iOS Embedder |

flutter_standard_codec_unittest.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterCodecs.h"
6
7 #include "gtest/gtest.h"
8
9 FLUTTER_ASSERT_ARC
10
11 @interface Pair : NSObject
12 @property(atomic, readonly, strong, nullable) NSObject* left;
13 @property(atomic, readonly, strong, nullable) NSObject* right;
14 - (instancetype)initWithLeft:(NSObject*)first right:(NSObject*)right;
15 @end
16
17 @implementation Pair
18 - (instancetype)initWithLeft:(NSObject*)left right:(NSObject*)right {
19 self = [super init];
20 if (self) {
21 _left = left;
22 _right = right;
23 }
24 return self;
25 }
26 @end
27
28 static const UInt8 kDATE = 128;
29 static const UInt8 kPAIR = 129;
30
31 @interface ExtendedWriter : FlutterStandardWriter
32 - (void)writeValue:(id)value;
33 @end
34
35 @implementation ExtendedWriter
36 - (void)writeValue:(id)value {
37 if ([value isKindOfClass:[NSDate class]]) {
38 [self writeByte:kDATE];
39 NSDate* date = value;
40 NSTimeInterval time = date.timeIntervalSince1970;
41 SInt64 ms = (SInt64)(time * 1000.0);
42 [self writeBytes:&ms length:8];
43 } else if ([value isKindOfClass:[Pair class]]) {
44 Pair* pair = value;
45 [self writeByte:kPAIR];
46 [self writeValue:pair.left];
47 [self writeValue:pair.right];
48 } else {
49 [super writeValue:value];
50 }
51 }
52 @end
53
54 @interface ExtendedReader : FlutterStandardReader
55 - (id)readValueOfType:(UInt8)type;
56 @end
57
58 @implementation ExtendedReader
59 - (id)readValueOfType:(UInt8)type {
60 switch (type) {
61 case kDATE: {
62 SInt64 value;
63 [self readBytes:&value length:8];
64 NSTimeInterval time = [NSNumber numberWithLong:value].doubleValue / 1000.0;
65 return [NSDate dateWithTimeIntervalSince1970:time];
66 }
67 case kPAIR: {
68 return [[Pair alloc] initWithLeft:[self readValue] right:[self readValue]];
69 }
70 default:
71 return [super readValueOfType:type];
72 }
73 }
74 @end
75
76 @interface ExtendedReaderWriter : FlutterStandardReaderWriter
77 - (FlutterStandardWriter*)writerWithData:(NSMutableData*)data;
78 - (FlutterStandardReader*)readerWithData:(NSData*)data;
79 @end
80
81 @implementation ExtendedReaderWriter
82 - (FlutterStandardWriter*)writerWithData:(NSMutableData*)data {
83 return [[ExtendedWriter alloc] initWithData:data];
84 }
85 - (FlutterStandardReader*)readerWithData:(NSData*)data {
86 return [[ExtendedReader alloc] initWithData:data];
87 }
88 @end
89
90 static void CheckEncodeDecode(id value, NSData* expectedEncoding) {
91 FlutterStandardMessageCodec* codec = [FlutterStandardMessageCodec sharedInstance];
92 NSData* encoded = [codec encode:value];
93 if (expectedEncoding == nil) {
94 ASSERT_TRUE(encoded == nil);
95 } else {
96 ASSERT_TRUE([encoded isEqual:expectedEncoding]);
97 }
98 id decoded = [codec decode:encoded];
99 if (value == nil || value == [NSNull null]) {
100 ASSERT_TRUE(decoded == nil);
101 } else {
102 ASSERT_TRUE([value isEqual:decoded]);
103 }
104 }
105
106 static void CheckEncodeDecode(id value) {
107 FlutterStandardMessageCodec* codec = [FlutterStandardMessageCodec sharedInstance];
108 NSData* encoded = [codec encode:value];
109 id decoded = [codec decode:encoded];
110 if (value == nil || value == [NSNull null]) {
111 ASSERT_TRUE(decoded == nil);
112 } else {
113 ASSERT_TRUE([value isEqual:decoded]);
114 }
115 }
116
117 TEST(FlutterStandardCodec, CanDecodeZeroLength) {
118 FlutterStandardMessageCodec* codec = [FlutterStandardMessageCodec sharedInstance];
119 id decoded = [codec decode:[NSData data]];
120 ASSERT_TRUE(decoded == nil);
121 }
122
123 TEST(FlutterStandardCodec, CanEncodeAndDecodeNil) {
124 CheckEncodeDecode(nil, nil);
125 }
126
127 TEST(FlutterStandardCodec, CanEncodeAndDecodeNSNull) {
128 uint8_t bytes[1] = {0x00};
129 CheckEncodeDecode([NSNull null], [NSData dataWithBytes:bytes length:1]);
130 }
131
132 TEST(FlutterStandardCodec, CanEncodeAndDecodeYes) {
133 uint8_t bytes[1] = {0x01};
134 CheckEncodeDecode(@YES, [NSData dataWithBytes:bytes length:1]);
135 }
136
137 TEST(FlutterStandardCodec, CanEncodeAndDecodeNo) {
138 uint8_t bytes[1] = {0x02};
139 CheckEncodeDecode(@NO, [NSData dataWithBytes:bytes length:1]);
140 }
141
142 TEST(FlutterStandardCodec, CanEncodeAndDecodeUInt8) {
143 uint8_t bytes[5] = {0x03, 0xfe, 0x00, 0x00, 0x00};
144 UInt8 value = 0xfe;
145 CheckEncodeDecode(@(value), [NSData dataWithBytes:bytes length:5]);
146 }
147
148 TEST(FlutterStandardCodec, CanEncodeAndDecodeUInt16) {
149 uint8_t bytes[5] = {0x03, 0xdc, 0xfe, 0x00, 0x00};
150 UInt16 value = 0xfedc;
151 CheckEncodeDecode(@(value), [NSData dataWithBytes:bytes length:5]);
152 }
153
154 TEST(FlutterStandardCodec, CanEncodeAndDecodeUInt32) {
155 uint8_t bytes[9] = {0x04, 0x09, 0xba, 0xdc, 0xfe, 0x00, 0x00, 0x00, 0x00};
156 UInt32 value = 0xfedcba09;
157 CheckEncodeDecode(@(value), [NSData dataWithBytes:bytes length:9]);
158 }
159
160 TEST(FlutterStandardCodec, CanEncodeUInt64) {
161 FlutterStandardMessageCodec* codec = [FlutterStandardMessageCodec sharedInstance];
162 UInt64 u64 = 0xfffffffffffffffa;
163 uint8_t bytes[9] = {0x04, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
164 NSData* encoded = [codec encode:@(u64)];
165 ASSERT_TRUE([encoded isEqual:[NSData dataWithBytes:bytes length:9]]);
166 }
167
168 TEST(FlutterStandardCodec, CanEncodeAndDecodeSInt8) {
169 uint8_t bytes[5] = {0x03, 0xfe, 0xff, 0xff, 0xff};
170 SInt8 value = 0xfe;
171 CheckEncodeDecode(@(value), [NSData dataWithBytes:bytes length:5]);
172 }
173
174 TEST(FlutterStandardCodec, CanEncodeAndDecodeSInt16) {
175 uint8_t bytes[5] = {0x03, 0xdc, 0xfe, 0xff, 0xff};
176 SInt16 value = 0xfedc;
177 CheckEncodeDecode(@(value), [NSData dataWithBytes:bytes length:5]);
178 }
179
180 TEST(FlutterStandardCodec, CanEncodeAndDecodeSInt32) {
181 uint8_t bytes[5] = {0x03, 0x78, 0x56, 0x34, 0x12};
182 CheckEncodeDecode(@(0x12345678), [NSData dataWithBytes:bytes length:5]);
183 }
184
185 TEST(FlutterStandardCodec, CanEncodeAndDecodeSInt64) {
186 uint8_t bytes[9] = {0x04, 0xef, 0xcd, 0xab, 0x90, 0x78, 0x56, 0x34, 0x12};
187 CheckEncodeDecode(@(0x1234567890abcdef), [NSData dataWithBytes:bytes length:9]);
188 }
189
190 TEST(FlutterStandardCodec, CanEncodeAndDecodeFloat32) {
191 uint8_t bytes[16] = {0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
192 0x00, 0x00, 0x00, 0x60, 0xfb, 0x21, 0x09, 0x40};
193 CheckEncodeDecode(@3.1415927f, [NSData dataWithBytes:bytes length:16]);
194 }
195
196 TEST(FlutterStandardCodec, CanEncodeAndDecodeFloat64) {
197 uint8_t bytes[16] = {0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
198 0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40};
199 CheckEncodeDecode(@3.14159265358979311599796346854, [NSData dataWithBytes:bytes length:16]);
200 }
201
202 TEST(FlutterStandardCodec, CanEncodeAndDecodeString) {
203 uint8_t bytes[13] = {0x07, 0x0b, 0x68, 0x65, 0x6c, 0x6c, 0x6f,
204 0x20, 0x77, 0x6f, 0x72, 0x6c, 0x64};
205 CheckEncodeDecode(@"hello world", [NSData dataWithBytes:bytes length:13]);
206 }
207
208 TEST(FlutterStandardCodec, CanEncodeAndDecodeStringWithNonAsciiCodePoint) {
209 uint8_t bytes[7] = {0x07, 0x05, 0x68, 0xe2, 0x98, 0xba, 0x77};
210 CheckEncodeDecode(@"h\u263Aw", [NSData dataWithBytes:bytes length:7]);
211 }
212
213 TEST(FlutterStandardCodec, CanEncodeAndDecodeStringWithNonBMPCodePoint) {
214 uint8_t bytes[8] = {0x07, 0x06, 0x68, 0xf0, 0x9f, 0x98, 0x82, 0x77};
215 CheckEncodeDecode(@"h\U0001F602w", [NSData dataWithBytes:bytes length:8]);
216 }
217
218 TEST(FlutterStandardCodec, CanEncodeAndDecodeArray) {
219 NSArray* value = @[ [NSNull null], @"hello", @3.14, @47, @{@42 : @"nested"} ];
220 CheckEncodeDecode(value);
221 }
222
223 TEST(FlutterStandardCodec, CanEncodeAndDecodeDictionary) {
224 NSDictionary* value =
225 @{@"a" : @3.14,
226 @"b" : @47,
227 [NSNull null] : [NSNull null],
228 @3.14 : @[ @"nested" ]};
229 CheckEncodeDecode(value);
230 }
231
232 TEST(FlutterStandardCodec, CanEncodeAndDecodeByteArray) {
233 uint8_t bytes[4] = {0xBA, 0x5E, 0xBA, 0x11};
234 NSData* data = [NSData dataWithBytes:bytes length:4];
235 FlutterStandardTypedData* value = [FlutterStandardTypedData typedDataWithBytes:data];
236 CheckEncodeDecode(value);
237 }
238
239 TEST(FlutterStandardCodec, CanEncodeAndDecodeNSData) {
240 FlutterStandardMessageCodec* codec = [FlutterStandardMessageCodec sharedInstance];
241 uint8_t bytes[4] = {0xBA, 0x5E, 0xBA, 0x11};
242 NSData* data = [NSData dataWithBytes:bytes length:4];
243 FlutterStandardTypedData* standardData = [FlutterStandardTypedData typedDataWithBytes:data];
244
245 NSData* encoded = [codec encode:data];
246 ASSERT_TRUE([encoded isEqual:[codec encode:standardData]]);
247 }
248
249 TEST(FlutterStandardCodec, CanEncodeAndDecodeInt32Array) {
250 uint8_t bytes[8] = {0xBA, 0x5E, 0xBA, 0x11, 0xff, 0xff, 0xff, 0xff};
251 NSData* data = [NSData dataWithBytes:bytes length:8];
252 FlutterStandardTypedData* value = [FlutterStandardTypedData typedDataWithInt32:data];
253 CheckEncodeDecode(value);
254 }
255
256 TEST(FlutterStandardCodec, CanEncodeAndDecodeInt64Array) {
257 uint8_t bytes[8] = {0xBA, 0x5E, 0xBA, 0x11, 0xff, 0xff, 0xff, 0xff};
258 NSData* data = [NSData dataWithBytes:bytes length:8];
259 FlutterStandardTypedData* value = [FlutterStandardTypedData typedDataWithInt64:data];
260 CheckEncodeDecode(value);
261 }
262
263 TEST(FlutterStandardCodec, CanEncodeAndDecodeFloat32Array) {
264 uint8_t bytes[8] = {0xd8, 0x0f, 0x49, 0x40, 0x00, 0x00, 0x7a, 0x44};
265 NSData* data = [NSData dataWithBytes:bytes length:8];
266 FlutterStandardTypedData* value = [FlutterStandardTypedData typedDataWithFloat32:data];
267 CheckEncodeDecode(value);
268 }
269
270 TEST(FlutterStandardCodec, CanEncodeAndDecodeFloat64Array) {
271 uint8_t bytes[16] = {0xBA, 0x5E, 0xBA, 0x11, 0xff, 0xff, 0xff, 0xff,
272 0xBA, 0x5E, 0xBA, 0x11, 0xff, 0xff, 0xff, 0xff};
273 NSData* data = [NSData dataWithBytes:bytes length:16];
274 FlutterStandardTypedData* value = [FlutterStandardTypedData typedDataWithFloat64:data];
275 CheckEncodeDecode(value);
276 }
277
278 TEST(FlutterStandardCodec, HandlesMethodCallsWithNilArguments) {
279 FlutterStandardMethodCodec* codec = [FlutterStandardMethodCodec sharedInstance];
280 FlutterMethodCall* call = [FlutterMethodCall methodCallWithMethodName:@"hello" arguments:nil];
281 NSData* encoded = [codec encodeMethodCall:call];
282 FlutterMethodCall* decoded = [codec decodeMethodCall:encoded];
283 ASSERT_TRUE([decoded isEqual:call]);
284 }
285
286 TEST(FlutterStandardCodec, HandlesMethodCallsWithSingleArgument) {
287 FlutterStandardMethodCodec* codec = [FlutterStandardMethodCodec sharedInstance];
288 FlutterMethodCall* call = [FlutterMethodCall methodCallWithMethodName:@"hello" arguments:@42];
289 NSData* encoded = [codec encodeMethodCall:call];
290 FlutterMethodCall* decoded = [codec decodeMethodCall:encoded];
291 ASSERT_TRUE([decoded isEqual:call]);
292 }
293
294 TEST(FlutterStandardCodec, HandlesMethodCallsWithArgumentList) {
295 FlutterStandardMethodCodec* codec = [FlutterStandardMethodCodec sharedInstance];
296 NSArray* arguments = @[ @42, @"world" ];
297 FlutterMethodCall* call = [FlutterMethodCall methodCallWithMethodName:@"hello"
298 arguments:arguments];
299 NSData* encoded = [codec encodeMethodCall:call];
300 FlutterMethodCall* decoded = [codec decodeMethodCall:encoded];
301 ASSERT_TRUE([decoded isEqual:call]);
302 }
303
304 TEST(FlutterStandardCodec, HandlesSuccessEnvelopesWithNilResult) {
305 FlutterStandardMethodCodec* codec = [FlutterStandardMethodCodec sharedInstance];
306 NSData* encoded = [codec encodeSuccessEnvelope:nil];
307 id decoded = [codec decodeEnvelope:encoded];
308 ASSERT_TRUE(decoded == nil);
309 }
310
311 TEST(FlutterStandardCodec, HandlesSuccessEnvelopesWithSingleResult) {
312 FlutterStandardMethodCodec* codec = [FlutterStandardMethodCodec sharedInstance];
313 NSData* encoded = [codec encodeSuccessEnvelope:@42];
314 id decoded = [codec decodeEnvelope:encoded];
315 ASSERT_TRUE([decoded isEqual:@42]);
316 }
317
318 TEST(FlutterStandardCodec, HandlesSuccessEnvelopesWithResultMap) {
319 FlutterStandardMethodCodec* codec = [FlutterStandardMethodCodec sharedInstance];
320 NSDictionary* result = @{@"a" : @42, @42 : @"a"};
321 NSData* encoded = [codec encodeSuccessEnvelope:result];
322 id decoded = [codec decodeEnvelope:encoded];
323 ASSERT_TRUE([decoded isEqual:result]);
324 }
325
326 TEST(FlutterStandardCodec, HandlesErrorEnvelopes) {
327 FlutterStandardMethodCodec* codec = [FlutterStandardMethodCodec sharedInstance];
328 NSDictionary* details = @{@"a" : @42, @42 : @"a"};
329 FlutterError* error = [FlutterError errorWithCode:@"errorCode"
330 message:@"something failed"
331 details:details];
332 NSData* encoded = [codec encodeErrorEnvelope:error];
333 id decoded = [codec decodeEnvelope:encoded];
334 ASSERT_TRUE([decoded isEqual:error]);
335 }
336
337 TEST(FlutterStandardCodec, HandlesSubclasses) {
338 ExtendedReaderWriter* extendedReaderWriter = [[ExtendedReaderWriter alloc] init];
339 FlutterStandardMessageCodec* codec =
340 [FlutterStandardMessageCodec codecWithReaderWriter:extendedReaderWriter];
341 Pair* pair = [[Pair alloc] initWithLeft:@1 right:@2];
342 NSData* encoded = [codec encode:pair];
343 Pair* decoded = [codec decode:encoded];
344 ASSERT_TRUE([pair.left isEqual:decoded.left]);
345 ASSERT_TRUE([pair.right isEqual:decoded.right]);
346 }
FLUTTER_ASSERT_ARC
#define FLUTTER_ASSERT_ARC
Definition: FlutterMacros.h:44
+[FlutterStandardTypedData typedDataWithFloat64:]
instancetype typedDataWithFloat64:(NSData *data)
Definition: FlutterStandardCodec.mm:162
-[FlutterStandardWriter writeValue:]
void writeValue:(id value)
Definition: FlutterStandardCodec.mm:347
+[FlutterMethodCall methodCallWithMethodName:arguments:]
instancetype methodCallWithMethodName:arguments:(NSString *method,[arguments] id _Nullable arguments)
-[FlutterStandardReader readBytes:length:]
void readBytes:length:(void *destination,[length] NSUInteger length)
Definition: FlutterStandardCodec.mm:371
-[FlutterStandardWriter writeByte:]
void writeByte:(UInt8 value)
Definition: FlutterStandardCodec.mm:213
FlutterError
Definition: FlutterCodecs.h:246
+[FlutterStandardTypedData typedDataWithBytes:]
instancetype typedDataWithBytes:(NSData *data)
Definition: FlutterStandardCodec.mm:146
+[FlutterStandardTypedData typedDataWithInt64:]
instancetype typedDataWithInt64:(NSData *data)
Definition: FlutterStandardCodec.mm:154
Pair::right
NSObject * right
Definition: flutter_standard_codec_unittest.mm:13
FlutterStandardReader
Definition: FlutterCodecs.h:132
FlutterStandardReaderWriter
Definition: FlutterCodecs.h:172
+[FlutterStandardTypedData typedDataWithInt32:]
instancetype typedDataWithInt32:(NSData *data)
Definition: FlutterStandardCodec.mm:150
+[FlutterError errorWithCode:message:details:]
instancetype errorWithCode:message:details:(NSString *code,[message] NSString *_Nullable message,[details] id _Nullable details)
FlutterStandardMessageCodec
Definition: FlutterCodecs.h:209
FlutterMethodCall
Definition: FlutterCodecs.h:220
Pair
Definition: flutter_standard_codec_unittest.mm:11
FlutterStandardWriter
Definition: FlutterCodecs.h:92
-[FlutterMessageCodec-p encode:]
NSData *_Nullable encode:(id _Nullable message)
+[FlutterStandardTypedData typedDataWithFloat32:]
instancetype typedDataWithFloat32:(NSData *data)
Definition: FlutterStandardCodec.mm:158
FlutterCodecs.h
CheckEncodeDecode
static void CheckEncodeDecode(id value, NSData *expectedEncoding)
Definition: flutter_standard_codec_unittest.mm:90
ExtendedWriter
Definition: flutter_standard_codec_unittest.mm:31
+[FlutterStandardMessageCodec codecWithReaderWriter:]
instancetype codecWithReaderWriter:(FlutterStandardReaderWriter *readerWriter)
Definition: FlutterStandardCodec.mm:24
FlutterStandardTypedData
Definition: FlutterCodecs.h:298
-[FlutterStandardReader readValue]
nullable id readValue()
Definition: FlutterStandardCodec.mm:400
-[FlutterMessageCodec-p decode:]
id _Nullable decode:(NSData *_Nullable message)
kDATE
static const UInt8 kDATE
Definition: flutter_standard_codec_unittest.mm:28
-[FlutterStandardReader readValueOfType:]
nullable id readValueOfType:(UInt8 type)
Definition: FlutterStandardCodec.mm:429
Pair::left
NSObject * left
Definition: flutter_standard_codec_unittest.mm:12
id
int32_t id
Definition: SemanticsObjectTestMocks.h:20
-[ExtendedWriter writeValue:]
void writeValue:(id value)
Definition: flutter_standard_codec_unittest.mm:36
-[FlutterStandardWriter writeBytes:length:]
void writeBytes:length:(const void *bytes,[length] NSUInteger length)
Definition: FlutterStandardCodec.mm:217
FlutterStandardMethodCodec
Definition: FlutterCodecs.h:467
ExtendedReaderWriter
Definition: flutter_standard_codec_unittest.mm:76
TEST
TEST(FlutterStandardCodec, CanDecodeZeroLength)
Definition: flutter_standard_codec_unittest.mm:117
ExtendedReader
Definition: flutter_standard_codec_unittest.mm:54
+[FlutterMessageCodec-p sharedInstance]
instancetype sharedInstance()
kPAIR
static const UInt8 kPAIR
Definition: flutter_standard_codec_unittest.mm:29