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 
6 
7 #include "gtest/gtest.h"
8 
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 
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 
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 
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) {
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) {
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) {
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) {
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];
236  CheckEncodeDecode(value);
237 }
238 
239 TEST(FlutterStandardCodec, CanEncodeAndDecodeNSData) {
241  uint8_t bytes[4] = {0xBA, 0x5E, 0xBA, 0x11};
242  NSData* data = [NSData dataWithBytes:bytes length:4];
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];
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];
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];
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];
275  CheckEncodeDecode(value);
276 }
277 
278 TEST(FlutterStandardCodec, HandlesMethodCallsWithNilArguments) {
279  FlutterStandardMethodCodec* codec = [FlutterStandardMethodCodec sharedInstance];
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];
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" ];
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];
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