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