• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2012 The Chromium Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/apple/foundation_util.h"
6
7#include <CoreFoundation/CoreFoundation.h>
8#import <Foundation/Foundation.h>
9#include <limits.h>
10#include <stddef.h>
11
12#include "base/apple/scoped_cftyperef.h"
13#include "base/files/file_path.h"
14#include "base/format_macros.h"
15#include "base/strings/stringprintf.h"
16#include "build/build_config.h"
17#include "testing/gmock/include/gmock/gmock.h"
18#include "testing/gtest/include/gtest/gtest.h"
19#import "testing/gtest_mac.h"
20
21using testing::ElementsAreArray;
22
23namespace base::apple {
24
25TEST(FoundationUtilTest, CFCast) {
26  // Build out the CF types to be tested as empty containers.
27  ScopedCFTypeRef<CFTypeRef> test_array(
28      CFArrayCreate(nullptr, nullptr, 0, &kCFTypeArrayCallBacks));
29  ScopedCFTypeRef<CFTypeRef> test_array_mutable(
30      CFArrayCreateMutable(nullptr, 0, &kCFTypeArrayCallBacks));
31  ScopedCFTypeRef<CFTypeRef> test_bag(
32      CFBagCreate(nullptr, nullptr, 0, &kCFTypeBagCallBacks));
33  ScopedCFTypeRef<CFTypeRef> test_bag_mutable(
34      CFBagCreateMutable(nullptr, 0, &kCFTypeBagCallBacks));
35  CFTypeRef test_bool = kCFBooleanTrue;
36  ScopedCFTypeRef<CFTypeRef> test_data(CFDataCreate(nullptr, nullptr, 0));
37  ScopedCFTypeRef<CFTypeRef> test_data_mutable(CFDataCreateMutable(nullptr, 0));
38  ScopedCFTypeRef<CFTypeRef> test_date(CFDateCreate(nullptr, 0));
39  ScopedCFTypeRef<CFTypeRef> test_dict(CFDictionaryCreate(
40      nullptr, nullptr, nullptr, 0, &kCFTypeDictionaryKeyCallBacks,
41      &kCFTypeDictionaryValueCallBacks));
42  ScopedCFTypeRef<CFTypeRef> test_dict_mutable(
43      CFDictionaryCreateMutable(nullptr, 0, &kCFTypeDictionaryKeyCallBacks,
44                                &kCFTypeDictionaryValueCallBacks));
45  int int_val = 256;
46  ScopedCFTypeRef<CFTypeRef> test_number(
47      CFNumberCreate(nullptr, kCFNumberIntType, &int_val));
48  CFTypeRef test_null = kCFNull;
49  ScopedCFTypeRef<CFTypeRef> test_set(
50      CFSetCreate(nullptr, nullptr, 0, &kCFTypeSetCallBacks));
51  ScopedCFTypeRef<CFTypeRef> test_set_mutable(
52      CFSetCreateMutable(nullptr, 0, &kCFTypeSetCallBacks));
53  ScopedCFTypeRef<CFTypeRef> test_str(CFStringCreateWithBytes(
54      nullptr, nullptr, 0, kCFStringEncodingASCII, false));
55  CFTypeRef test_str_const = CFSTR("hello");
56  ScopedCFTypeRef<CFTypeRef> test_str_mutable(
57      CFStringCreateMutable(nullptr, 0));
58
59  // Make sure the allocations of CF types are good.
60  EXPECT_TRUE(test_array);
61  EXPECT_TRUE(test_array_mutable);
62  EXPECT_TRUE(test_bag);
63  EXPECT_TRUE(test_bag_mutable);
64  EXPECT_TRUE(test_bool);
65  EXPECT_TRUE(test_data);
66  EXPECT_TRUE(test_data_mutable);
67  EXPECT_TRUE(test_date);
68  EXPECT_TRUE(test_dict);
69  EXPECT_TRUE(test_dict_mutable);
70  EXPECT_TRUE(test_number);
71  EXPECT_TRUE(test_null);
72  EXPECT_TRUE(test_set);
73  EXPECT_TRUE(test_set_mutable);
74  EXPECT_TRUE(test_str);
75  EXPECT_TRUE(test_str_const);
76  EXPECT_TRUE(test_str_mutable);
77
78  // Casting the CFTypeRef objects correctly provides the same pointer.
79  EXPECT_EQ(test_array.get(), CFCast<CFArrayRef>(test_array.get()));
80  EXPECT_EQ(test_array_mutable.get(),
81            CFCast<CFArrayRef>(test_array_mutable.get()));
82  EXPECT_EQ(test_bag.get(), CFCast<CFBagRef>(test_bag.get()));
83  EXPECT_EQ(test_bag_mutable.get(), CFCast<CFBagRef>(test_bag_mutable.get()));
84  EXPECT_EQ(test_bool, CFCast<CFBooleanRef>(test_bool));
85  EXPECT_EQ(test_data.get(), CFCast<CFDataRef>(test_data.get()));
86  EXPECT_EQ(test_data_mutable.get(),
87            CFCast<CFDataRef>(test_data_mutable.get()));
88  EXPECT_EQ(test_date.get(), CFCast<CFDateRef>(test_date.get()));
89  EXPECT_EQ(test_dict.get(), CFCast<CFDictionaryRef>(test_dict.get()));
90  EXPECT_EQ(test_dict_mutable.get(),
91            CFCast<CFDictionaryRef>(test_dict_mutable.get()));
92  EXPECT_EQ(test_number.get(), CFCast<CFNumberRef>(test_number.get()));
93  EXPECT_EQ(test_null, CFCast<CFNullRef>(test_null));
94  EXPECT_EQ(test_set.get(), CFCast<CFSetRef>(test_set.get()));
95  EXPECT_EQ(test_set_mutable.get(), CFCast<CFSetRef>(test_set_mutable.get()));
96  EXPECT_EQ(test_str.get(), CFCast<CFStringRef>(test_str.get()));
97  EXPECT_EQ(test_str_const, CFCast<CFStringRef>(test_str_const));
98  EXPECT_EQ(test_str_mutable.get(),
99            CFCast<CFStringRef>(test_str_mutable.get()));
100
101  // When given an incorrect CF cast, provide nullptr.
102  EXPECT_FALSE(CFCast<CFStringRef>(test_array.get()));
103  EXPECT_FALSE(CFCast<CFStringRef>(test_array_mutable.get()));
104  EXPECT_FALSE(CFCast<CFStringRef>(test_bag.get()));
105  EXPECT_FALSE(CFCast<CFSetRef>(test_bag_mutable.get()));
106  EXPECT_FALSE(CFCast<CFSetRef>(test_bool));
107  EXPECT_FALSE(CFCast<CFNullRef>(test_data.get()));
108  EXPECT_FALSE(CFCast<CFDictionaryRef>(test_data_mutable.get()));
109  EXPECT_FALSE(CFCast<CFDictionaryRef>(test_date.get()));
110  EXPECT_FALSE(CFCast<CFNumberRef>(test_dict.get()));
111  EXPECT_FALSE(CFCast<CFDateRef>(test_dict_mutable.get()));
112  EXPECT_FALSE(CFCast<CFDataRef>(test_number.get()));
113  EXPECT_FALSE(CFCast<CFDataRef>(test_null));
114  EXPECT_FALSE(CFCast<CFBooleanRef>(test_set.get()));
115  EXPECT_FALSE(CFCast<CFBagRef>(test_set_mutable.get()));
116  EXPECT_FALSE(CFCast<CFBagRef>(test_str.get()));
117  EXPECT_FALSE(CFCast<CFArrayRef>(test_str_const));
118  EXPECT_FALSE(CFCast<CFArrayRef>(test_str_mutable.get()));
119
120  // Giving a nullptr provides a nullptr.
121  EXPECT_FALSE(CFCast<CFArrayRef>(nullptr));
122  EXPECT_FALSE(CFCast<CFBagRef>(nullptr));
123  EXPECT_FALSE(CFCast<CFBooleanRef>(nullptr));
124  EXPECT_FALSE(CFCast<CFDataRef>(nullptr));
125  EXPECT_FALSE(CFCast<CFDateRef>(nullptr));
126  EXPECT_FALSE(CFCast<CFDictionaryRef>(nullptr));
127  EXPECT_FALSE(CFCast<CFNullRef>(nullptr));
128  EXPECT_FALSE(CFCast<CFNumberRef>(nullptr));
129  EXPECT_FALSE(CFCast<CFSetRef>(nullptr));
130  EXPECT_FALSE(CFCast<CFStringRef>(nullptr));
131
132  // CFCastStrict: correct cast results in correct pointer being returned.
133  EXPECT_EQ(test_array.get(), CFCastStrict<CFArrayRef>(test_array.get()));
134  EXPECT_EQ(test_array_mutable.get(),
135            CFCastStrict<CFArrayRef>(test_array_mutable.get()));
136  EXPECT_EQ(test_bag.get(), CFCastStrict<CFBagRef>(test_bag.get()));
137  EXPECT_EQ(test_bag_mutable.get(),
138            CFCastStrict<CFBagRef>(test_bag_mutable.get()));
139  EXPECT_EQ(test_bool, CFCastStrict<CFBooleanRef>(test_bool));
140  EXPECT_EQ(test_data.get(), CFCastStrict<CFDataRef>(test_data.get()));
141  EXPECT_EQ(test_data_mutable.get(),
142            CFCastStrict<CFDataRef>(test_data_mutable.get()));
143  EXPECT_EQ(test_date.get(), CFCastStrict<CFDateRef>(test_date.get()));
144  EXPECT_EQ(test_dict.get(), CFCastStrict<CFDictionaryRef>(test_dict.get()));
145  EXPECT_EQ(test_dict_mutable.get(),
146            CFCastStrict<CFDictionaryRef>(test_dict_mutable.get()));
147  EXPECT_EQ(test_number.get(), CFCastStrict<CFNumberRef>(test_number.get()));
148  EXPECT_EQ(test_null, CFCastStrict<CFNullRef>(test_null));
149  EXPECT_EQ(test_set.get(), CFCastStrict<CFSetRef>(test_set.get()));
150  EXPECT_EQ(test_set_mutable.get(),
151            CFCastStrict<CFSetRef>(test_set_mutable.get()));
152  EXPECT_EQ(test_str.get(), CFCastStrict<CFStringRef>(test_str.get()));
153  EXPECT_EQ(test_str_const, CFCastStrict<CFStringRef>(test_str_const));
154  EXPECT_EQ(test_str_mutable.get(),
155            CFCastStrict<CFStringRef>(test_str_mutable.get()));
156
157  // CFCastStrict: Giving a nullptr provides a nullptr.
158  EXPECT_FALSE(CFCastStrict<CFArrayRef>(nullptr));
159  EXPECT_FALSE(CFCastStrict<CFBagRef>(nullptr));
160  EXPECT_FALSE(CFCastStrict<CFBooleanRef>(nullptr));
161  EXPECT_FALSE(CFCastStrict<CFDataRef>(nullptr));
162  EXPECT_FALSE(CFCastStrict<CFDateRef>(nullptr));
163  EXPECT_FALSE(CFCastStrict<CFDictionaryRef>(nullptr));
164  EXPECT_FALSE(CFCastStrict<CFNullRef>(nullptr));
165  EXPECT_FALSE(CFCastStrict<CFNumberRef>(nullptr));
166  EXPECT_FALSE(CFCastStrict<CFSetRef>(nullptr));
167  EXPECT_FALSE(CFCastStrict<CFStringRef>(nullptr));
168}
169
170TEST(FoundationUtilTest, ObjCCast) {
171  @autoreleasepool {
172    id test_array = @[];
173    id test_array_mutable = [NSMutableArray array];
174    id test_data = [NSData data];
175    id test_data_mutable = [NSMutableData dataWithCapacity:10];
176    id test_date = [NSDate date];
177    id test_dict = @{@"meaning" : @42};
178    id test_dict_mutable = [NSMutableDictionary dictionaryWithCapacity:10];
179    id test_number = @42;
180    id test_null = [NSNull null];
181    id test_set = [NSSet setWithObject:@"string object"];
182    id test_set_mutable = [NSMutableSet setWithCapacity:10];
183    id test_str = [NSString string];
184    id test_str_const = @"bonjour";
185    id test_str_mutable = [NSMutableString stringWithCapacity:10];
186
187    // Make sure the allocations of NS types are good.
188    EXPECT_TRUE(test_array);
189    EXPECT_TRUE(test_array_mutable);
190    EXPECT_TRUE(test_data);
191    EXPECT_TRUE(test_data_mutable);
192    EXPECT_TRUE(test_date);
193    EXPECT_TRUE(test_dict);
194    EXPECT_TRUE(test_dict_mutable);
195    EXPECT_TRUE(test_number);
196    EXPECT_TRUE(test_null);
197    EXPECT_TRUE(test_set);
198    EXPECT_TRUE(test_set_mutable);
199    EXPECT_TRUE(test_str);
200    EXPECT_TRUE(test_str_const);
201    EXPECT_TRUE(test_str_mutable);
202
203    // Casting the id correctly provides the same pointer.
204    EXPECT_EQ(test_array, ObjCCast<NSArray>(test_array));
205    EXPECT_EQ(test_array_mutable, ObjCCast<NSArray>(test_array_mutable));
206    EXPECT_EQ(test_data, ObjCCast<NSData>(test_data));
207    EXPECT_EQ(test_data_mutable, ObjCCast<NSData>(test_data_mutable));
208    EXPECT_EQ(test_date, ObjCCast<NSDate>(test_date));
209    EXPECT_EQ(test_dict, ObjCCast<NSDictionary>(test_dict));
210    EXPECT_EQ(test_dict_mutable, ObjCCast<NSDictionary>(test_dict_mutable));
211    EXPECT_EQ(test_number, ObjCCast<NSNumber>(test_number));
212    EXPECT_EQ(test_null, ObjCCast<NSNull>(test_null));
213    EXPECT_EQ(test_set, ObjCCast<NSSet>(test_set));
214    EXPECT_EQ(test_set_mutable, ObjCCast<NSSet>(test_set_mutable));
215    EXPECT_EQ(test_str, ObjCCast<NSString>(test_str));
216    EXPECT_EQ(test_str_const, ObjCCast<NSString>(test_str_const));
217    EXPECT_EQ(test_str_mutable, ObjCCast<NSString>(test_str_mutable));
218
219    // When given an incorrect ObjC cast, provide nil.
220    EXPECT_FALSE(ObjCCast<NSString>(test_array));
221    EXPECT_FALSE(ObjCCast<NSString>(test_array_mutable));
222    EXPECT_FALSE(ObjCCast<NSString>(test_data));
223    EXPECT_FALSE(ObjCCast<NSString>(test_data_mutable));
224    EXPECT_FALSE(ObjCCast<NSSet>(test_date));
225    EXPECT_FALSE(ObjCCast<NSSet>(test_dict));
226    EXPECT_FALSE(ObjCCast<NSNumber>(test_dict_mutable));
227    EXPECT_FALSE(ObjCCast<NSNull>(test_number));
228    EXPECT_FALSE(ObjCCast<NSDictionary>(test_null));
229    EXPECT_FALSE(ObjCCast<NSDictionary>(test_set));
230    EXPECT_FALSE(ObjCCast<NSDate>(test_set_mutable));
231    EXPECT_FALSE(ObjCCast<NSData>(test_str));
232    EXPECT_FALSE(ObjCCast<NSData>(test_str_const));
233    EXPECT_FALSE(ObjCCast<NSArray>(test_str_mutable));
234
235    // Giving a nil provides a nil.
236    EXPECT_FALSE(ObjCCast<NSArray>(nil));
237    EXPECT_FALSE(ObjCCast<NSData>(nil));
238    EXPECT_FALSE(ObjCCast<NSDate>(nil));
239    EXPECT_FALSE(ObjCCast<NSDictionary>(nil));
240    EXPECT_FALSE(ObjCCast<NSNull>(nil));
241    EXPECT_FALSE(ObjCCast<NSNumber>(nil));
242    EXPECT_FALSE(ObjCCast<NSSet>(nil));
243    EXPECT_FALSE(ObjCCast<NSString>(nil));
244
245    // ObjCCastStrict: correct cast results in correct pointer being returned.
246    EXPECT_EQ(test_array, ObjCCastStrict<NSArray>(test_array));
247    EXPECT_EQ(test_array_mutable, ObjCCastStrict<NSArray>(test_array_mutable));
248    EXPECT_EQ(test_data, ObjCCastStrict<NSData>(test_data));
249    EXPECT_EQ(test_data_mutable, ObjCCastStrict<NSData>(test_data_mutable));
250    EXPECT_EQ(test_date, ObjCCastStrict<NSDate>(test_date));
251    EXPECT_EQ(test_dict, ObjCCastStrict<NSDictionary>(test_dict));
252    EXPECT_EQ(test_dict_mutable,
253              ObjCCastStrict<NSDictionary>(test_dict_mutable));
254    EXPECT_EQ(test_number, ObjCCastStrict<NSNumber>(test_number));
255    EXPECT_EQ(test_null, ObjCCastStrict<NSNull>(test_null));
256    EXPECT_EQ(test_set, ObjCCastStrict<NSSet>(test_set));
257    EXPECT_EQ(test_set_mutable, ObjCCastStrict<NSSet>(test_set_mutable));
258    EXPECT_EQ(test_str, ObjCCastStrict<NSString>(test_str));
259    EXPECT_EQ(test_str_const, ObjCCastStrict<NSString>(test_str_const));
260    EXPECT_EQ(test_str_mutable, ObjCCastStrict<NSString>(test_str_mutable));
261
262    // ObjCCastStrict: Giving a nil provides a nil.
263    EXPECT_FALSE(ObjCCastStrict<NSArray>(nil));
264    EXPECT_FALSE(ObjCCastStrict<NSData>(nil));
265    EXPECT_FALSE(ObjCCastStrict<NSDate>(nil));
266    EXPECT_FALSE(ObjCCastStrict<NSDictionary>(nil));
267    EXPECT_FALSE(ObjCCastStrict<NSNull>(nil));
268    EXPECT_FALSE(ObjCCastStrict<NSNumber>(nil));
269    EXPECT_FALSE(ObjCCastStrict<NSSet>(nil));
270    EXPECT_FALSE(ObjCCastStrict<NSString>(nil));
271  }
272}
273
274TEST(FoundationUtilTest, GetValueFromDictionary) {
275  int one = 1, two = 2, three = 3;
276
277  ScopedCFTypeRef<CFNumberRef> cf_one(
278      CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &one));
279  ScopedCFTypeRef<CFNumberRef> cf_two(
280      CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &two));
281  ScopedCFTypeRef<CFNumberRef> cf_three(
282      CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &three));
283
284  CFStringRef keys[] = {CFSTR("one"), CFSTR("two"), CFSTR("three")};
285  CFNumberRef values[] = {cf_one.get(), cf_two.get(), cf_three.get()};
286
287  static_assert(std::size(keys) == std::size(values),
288                "keys and values arrays must have the same size");
289
290  ScopedCFTypeRef<CFDictionaryRef> test_dict(CFDictionaryCreate(
291      kCFAllocatorDefault, reinterpret_cast<const void**>(keys),
292      reinterpret_cast<const void**>(values), std::size(values),
293      &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
294
295  // GetValueFromDictionary<>(_, _) should produce the correct
296  // expected output.
297  EXPECT_EQ(values[0],
298            GetValueFromDictionary<CFNumberRef>(test_dict.get(), CFSTR("one")));
299  EXPECT_EQ(values[1],
300            GetValueFromDictionary<CFNumberRef>(test_dict.get(), CFSTR("two")));
301  EXPECT_EQ(values[2], GetValueFromDictionary<CFNumberRef>(test_dict.get(),
302                                                           CFSTR("three")));
303
304  // Bad input should produce bad output.
305  EXPECT_FALSE(
306      GetValueFromDictionary<CFNumberRef>(test_dict.get(), CFSTR("four")));
307  EXPECT_FALSE(
308      GetValueFromDictionary<CFStringRef>(test_dict.get(), CFSTR("one")));
309}
310
311TEST(FoundationUtilTest, FilePathToNSURL) {
312  EXPECT_NSEQ(nil, FilePathToNSURL(FilePath()));
313  EXPECT_NSEQ([NSURL fileURLWithPath:@"/a/b"],
314              FilePathToNSURL(FilePath("/a/b")));
315  EXPECT_NSEQ([NSURL fileURLWithPath:@"a/b"], FilePathToNSURL(FilePath("a/b")));
316}
317
318TEST(FoundationUtilTest, FilePathToNSString) {
319  EXPECT_NSEQ(nil, FilePathToNSString(FilePath()));
320  EXPECT_NSEQ(@"/a/b", FilePathToNSString(FilePath("/a/b")));
321  EXPECT_NSEQ(@"a/b", FilePathToNSString(FilePath("a/b")));
322}
323
324TEST(FoundationUtilTest, NSStringToFilePath) {
325  EXPECT_EQ(FilePath(), NSStringToFilePath(nil));
326  EXPECT_EQ(FilePath(), NSStringToFilePath(@""));
327  EXPECT_EQ(FilePath("/a/b"), NSStringToFilePath(@"/a/b"));
328  EXPECT_EQ(FilePath("a/b"), NSStringToFilePath(@"a/b"));
329}
330
331TEST(FoundationUtilTest, NSURLToFilePath) {
332  EXPECT_EQ(FilePath(), NSURLToFilePath(nil));
333  EXPECT_EQ(FilePath(),
334            NSURLToFilePath([NSURL URLWithString:@"http://google.com/"]));
335  EXPECT_EQ(FilePath("a/b"), NSURLToFilePath([NSURL fileURLWithPath:@"a/b"]));
336  EXPECT_EQ(FilePath("/a/b"), NSURLToFilePath([NSURL fileURLWithPath:@"/a/b"]));
337}
338
339TEST(FoundationUtilTest, ConversionComposition) {
340  // macOS "file system representation" is a bespoke Unicode decomposition.
341  // Verifying that U+00E9 (LATIN SMALL LETTER E WITH ACUTE) ends up decomposed
342  // into U+0065 (LATIN SMALL LETTER E) and U+0301 (COMBINING ACUTE ACCENT) is a
343  // decent one-off test to ensure that this is happening.
344  FilePath original_path("\u00E9");
345
346  FilePath result_string_path =
347      NSStringToFilePath(FilePathToNSString(original_path));
348  EXPECT_EQ("\u0065\u0301", result_string_path.value());
349
350  FilePath result_url_path = NSURLToFilePath(FilePathToNSURL(original_path));
351  EXPECT_EQ("\u0065\u0301", result_url_path.value());
352}
353
354TEST(FoundationUtilTest, FilePathToCFURL) {
355  EXPECT_EQ(ScopedCFTypeRef<CFURLRef>(), FilePathToCFURL(FilePath()));
356  ScopedCFTypeRef<CFURLRef> absolute_url(CFURLCreateWithFileSystemPath(
357      nullptr, CFSTR("/a/b"), kCFURLPOSIXPathStyle, /*isDirectory=*/false));
358  EXPECT_TRUE(
359      CFEqual(absolute_url.get(), FilePathToCFURL(FilePath("/a/b")).get()));
360  ScopedCFTypeRef<CFURLRef> relative_url(CFURLCreateWithFileSystemPath(
361      nullptr, CFSTR("a/b"), kCFURLPOSIXPathStyle, /*isDirectory=*/false));
362  EXPECT_TRUE(
363      CFEqual(relative_url.get(), FilePathToCFURL(FilePath("a/b")).get()));
364}
365
366TEST(FoundationUtilTest, FilePathToCFString) {
367  EXPECT_EQ(ScopedCFTypeRef<CFStringRef>(), FilePathToCFString(FilePath()));
368  EXPECT_TRUE(
369      CFEqual(CFSTR("/a/b"), FilePathToCFString(FilePath("/a/b")).get()));
370  EXPECT_TRUE(CFEqual(CFSTR("a/b"), FilePathToCFString(FilePath("a/b")).get()));
371}
372
373TEST(FoundationUtilTest, CFStringToFilePath) {
374  EXPECT_EQ(FilePath(), CFStringToFilePath(nil));
375  EXPECT_EQ(FilePath(), CFStringToFilePath(CFSTR("")));
376  EXPECT_EQ(FilePath("/a/b"), CFStringToFilePath(CFSTR("/a/b")));
377  EXPECT_EQ(FilePath("a/b"), CFStringToFilePath(CFSTR("a/b")));
378}
379
380TEST(FoundationUtilTest, CFURLToFilePath) {
381  EXPECT_EQ(FilePath(), CFURLToFilePath(nil));
382  ScopedCFTypeRef<CFURLRef> non_file_url(
383      CFURLCreateWithString(nullptr, CFSTR("http://google.com/"), nullptr));
384  EXPECT_EQ(FilePath(), CFURLToFilePath(non_file_url.get()));
385  ScopedCFTypeRef<CFURLRef> absolute_url(CFURLCreateWithFileSystemPath(
386      nullptr, CFSTR("/a/b"), kCFURLPOSIXPathStyle, /*isDirectory=*/false));
387  EXPECT_EQ(FilePath("/a/b"), CFURLToFilePath(absolute_url.get()));
388  ScopedCFTypeRef<CFURLRef> relative_url(CFURLCreateWithFileSystemPath(
389      nullptr, CFSTR("a/b"), kCFURLPOSIXPathStyle, /*isDirectory=*/false));
390  EXPECT_EQ(FilePath("a/b"), CFURLToFilePath(relative_url.get()));
391}
392
393TEST(FoundationUtilTest, CFRangeToNSRange) {
394  NSRange range_out;
395  EXPECT_TRUE(CFRangeToNSRange(CFRangeMake(10, 5), &range_out));
396  EXPECT_EQ(10UL, range_out.location);
397  EXPECT_EQ(5UL, range_out.length);
398  EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(-1, 5), &range_out));
399  EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(5, -1), &range_out));
400  EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(-1, -1), &range_out));
401  EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(LONG_MAX, LONG_MAX), &range_out));
402  EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(LONG_MIN, LONG_MAX), &range_out));
403}
404
405TEST(StringNumberConversionsTest, FormatNSInteger) {
406  // The PRI[dxu]NS macro assumes that NSInteger is a typedef to "int" on
407  // 32-bit architecture and a typedef to "long" on 64-bit architecture
408  // (respectively "unsigned int" and "unsigned long" for NSUInteger). Use
409  // pointer incompatibility to validate this at compilation.
410#if defined(ARCH_CPU_64_BITS)
411  typedef long FormatNSIntegerAsType;
412  typedef unsigned long FormatNSUIntegerAsType;
413#else
414  typedef int FormatNSIntegerAsType;
415  typedef unsigned int FormatNSUIntegerAsType;
416#endif  // defined(ARCH_CPU_64_BITS)
417
418  NSInteger some_nsinteger;
419  [[maybe_unused]] FormatNSIntegerAsType* pointer_to_some_nsinteger =
420      &some_nsinteger;
421
422  NSUInteger some_nsuinteger;
423  [[maybe_unused]] FormatNSUIntegerAsType* pointer_to_some_nsuinteger =
424      &some_nsuinteger;
425
426  // Check that format specifier works correctly for NSInteger.
427  const struct {
428    NSInteger value;
429    const char* expected;
430    const char* expected_hex;
431  } nsinteger_cases[] = {
432#if !defined(ARCH_CPU_64_BITS)
433    {12345678, "12345678", "bc614e"},
434    {-12345678, "-12345678", "ff439eb2"},
435#else
436    {12345678, "12345678", "bc614e"},
437    {-12345678, "-12345678", "ffffffffff439eb2"},
438    {137451299150l, "137451299150", "2000bc614e"},
439    {-137451299150l, "-137451299150", "ffffffdfff439eb2"},
440#endif  // !defined(ARCH_CPU_64_BITS)
441  };
442
443  for (const auto& nsinteger_case : nsinteger_cases) {
444    EXPECT_EQ(nsinteger_case.expected,
445              StringPrintf("%" PRIdNS, nsinteger_case.value));
446    EXPECT_EQ(nsinteger_case.expected_hex,
447              StringPrintf("%" PRIxNS, nsinteger_case.value));
448  }
449
450  // Check that format specifier works correctly for NSUInteger.
451  const struct {
452    NSUInteger value;
453    const char* expected;
454    const char* expected_hex;
455  } nsuinteger_cases[] = {
456#if !defined(ARCH_CPU_64_BITS)
457    {12345678u, "12345678", "bc614e"},
458    {4282621618u, "4282621618", "ff439eb2"},
459#else
460    {12345678u, "12345678", "bc614e"},
461    {4282621618u, "4282621618", "ff439eb2"},
462    {137451299150ul, "137451299150", "2000bc614e"},
463    {18446743936258252466ul, "18446743936258252466", "ffffffdfff439eb2"},
464#endif  // !defined(ARCH_CPU_64_BITS)
465  };
466
467  for (const auto& nsuinteger_case : nsuinteger_cases) {
468    EXPECT_EQ(nsuinteger_case.expected,
469              StringPrintf("%" PRIuNS, nsuinteger_case.value));
470    EXPECT_EQ(nsuinteger_case.expected_hex,
471              StringPrintf("%" PRIxNS, nsuinteger_case.value));
472  }
473}
474
475TEST(FoundationUtilTest, NSDataToSpan) {
476  {
477    NSData* data = [NSData data];
478    span<const uint8_t> span = NSDataToSpan(data);
479    EXPECT_TRUE(span.empty());
480  }
481
482  {
483    NSMutableData* data = [NSMutableData data];
484    span<uint8_t> span = NSMutableDataToSpan(data);
485    EXPECT_TRUE(span.empty());
486  }
487
488  const char buffer[4] = {0, CHAR_MAX, 0, CHAR_MAX};
489
490  {
491    NSData* data = [NSData dataWithBytes:buffer length:sizeof(buffer)];
492    span<const uint8_t> span = NSDataToSpan(data);
493    EXPECT_THAT(span, ElementsAreArray(buffer));
494  }
495
496  {
497    NSMutableData* data = [NSMutableData dataWithBytes:buffer
498                                                length:sizeof(buffer)];
499    span<uint8_t> span = NSMutableDataToSpan(data);
500    EXPECT_THAT(span, ElementsAreArray(buffer));
501    span[0] = 123;
502    EXPECT_EQ(static_cast<const char*>(data.bytes)[0], 123);
503  }
504}
505
506TEST(FoundationUtilTest, CFDataToSpan) {
507  {
508    ScopedCFTypeRef<CFDataRef> data(CFDataCreate(nullptr, nullptr, 0));
509    span<const uint8_t> span = CFDataToSpan(data.get());
510    EXPECT_TRUE(span.empty());
511  }
512
513  {
514    ScopedCFTypeRef<CFMutableDataRef> data(CFDataCreateMutable(nullptr, 0));
515    span<uint8_t> span = CFMutableDataToSpan(data.get());
516    EXPECT_TRUE(span.empty());
517  }
518
519  const uint8_t buffer[4] = {0, CHAR_MAX, 0, CHAR_MAX};
520
521  {
522    ScopedCFTypeRef<CFDataRef> data(
523        CFDataCreate(nullptr, buffer, sizeof(buffer)));
524    span<const uint8_t> data_span = CFDataToSpan(data.get());
525    EXPECT_EQ(span(buffer), data_span);
526    EXPECT_THAT(data_span, ElementsAreArray(buffer));
527  }
528
529  {
530    ScopedCFTypeRef<CFMutableDataRef> data(CFDataCreateMutable(nullptr, 0));
531    CFDataAppendBytes(data.get(), buffer, sizeof(buffer));
532    span<uint8_t> data_span = CFMutableDataToSpan(data.get());
533    EXPECT_EQ(span(buffer), data_span);
534    data_span[0] = 123;
535    EXPECT_EQ(CFDataGetBytePtr(data.get())[0], 123);
536  }
537}
538
539#define EXPECT_LOG_EQ(expected, val) \
540  EXPECT_EQ(expected, (std::ostringstream() << (val)).str())
541
542TEST(FoundationLoggingTest, ObjCObject) {
543  EXPECT_LOG_EQ("Hello, world!", @"Hello, world!");
544}
545
546TEST(FoundationLoggingTest, ObjCNil) {
547  EXPECT_LOG_EQ("(nil)", static_cast<id>(nil));
548}
549
550TEST(FoundationLoggingTest, CFRange) {
551  EXPECT_LOG_EQ("{0, 100}", CFRangeMake(0, 100));
552}
553
554TEST(FoundationLoggingTest, NSRange) {
555  EXPECT_LOG_EQ("{0, 100}", NSMakeRange(0, 100));
556}
557
558}  // namespace base::apple
559