Home | History | Annotate | Download | only in mac
      1 // Copyright (c) 2012 The Chromium 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 #include "base/mac/foundation_util.h"
      6 
      7 #include "base/basictypes.h"
      8 #include "base/compiler_specific.h"
      9 #include "base/files/file_path.h"
     10 #include "base/format_macros.h"
     11 #include "base/mac/scoped_cftyperef.h"
     12 #include "base/mac/scoped_nsautorelease_pool.h"
     13 #include "base/strings/stringprintf.h"
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 #import "testing/gtest_mac.h"
     16 
     17 namespace base {
     18 namespace mac {
     19 
     20 TEST(FoundationUtilTest, CFCast) {
     21   // Build out the CF types to be tested as empty containers.
     22   ScopedCFTypeRef<CFTypeRef> test_array(
     23       CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks));
     24   ScopedCFTypeRef<CFTypeRef> test_array_mutable(
     25       CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks));
     26   ScopedCFTypeRef<CFTypeRef> test_bag(
     27       CFBagCreate(NULL, NULL, 0, &kCFTypeBagCallBacks));
     28   ScopedCFTypeRef<CFTypeRef> test_bag_mutable(
     29       CFBagCreateMutable(NULL, 0, &kCFTypeBagCallBacks));
     30   CFTypeRef test_bool = kCFBooleanTrue;
     31   ScopedCFTypeRef<CFTypeRef> test_data(
     32       CFDataCreate(NULL, NULL, 0));
     33   ScopedCFTypeRef<CFTypeRef> test_data_mutable(
     34       CFDataCreateMutable(NULL, 0));
     35   ScopedCFTypeRef<CFTypeRef> test_date(
     36       CFDateCreate(NULL, 0));
     37   ScopedCFTypeRef<CFTypeRef> test_dict(
     38       CFDictionaryCreate(NULL, NULL, NULL, 0,
     39                          &kCFCopyStringDictionaryKeyCallBacks,
     40                          &kCFTypeDictionaryValueCallBacks));
     41   ScopedCFTypeRef<CFTypeRef> test_dict_mutable(
     42       CFDictionaryCreateMutable(NULL, 0,
     43                                 &kCFCopyStringDictionaryKeyCallBacks,
     44                                 &kCFTypeDictionaryValueCallBacks));
     45   int int_val = 256;
     46   ScopedCFTypeRef<CFTypeRef> test_number(
     47       CFNumberCreate(NULL, kCFNumberIntType, &int_val));
     48   CFTypeRef test_null = kCFNull;
     49   ScopedCFTypeRef<CFTypeRef> test_set(
     50       CFSetCreate(NULL, NULL, 0, &kCFTypeSetCallBacks));
     51   ScopedCFTypeRef<CFTypeRef> test_set_mutable(
     52       CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks));
     53   ScopedCFTypeRef<CFTypeRef> test_str(
     54       CFStringCreateWithBytes(NULL, NULL, 0, kCFStringEncodingASCII, false));
     55   CFTypeRef test_str_const = CFSTR("hello");
     56   ScopedCFTypeRef<CFTypeRef> test_str_mutable(CFStringCreateMutable(NULL, 0));
     57 
     58   // Make sure the allocations of CF types are good.
     59   EXPECT_TRUE(test_array);
     60   EXPECT_TRUE(test_array_mutable);
     61   EXPECT_TRUE(test_bag);
     62   EXPECT_TRUE(test_bag_mutable);
     63   EXPECT_TRUE(test_bool);
     64   EXPECT_TRUE(test_data);
     65   EXPECT_TRUE(test_data_mutable);
     66   EXPECT_TRUE(test_date);
     67   EXPECT_TRUE(test_dict);
     68   EXPECT_TRUE(test_dict_mutable);
     69   EXPECT_TRUE(test_number);
     70   EXPECT_TRUE(test_null);
     71   EXPECT_TRUE(test_set);
     72   EXPECT_TRUE(test_set_mutable);
     73   EXPECT_TRUE(test_str);
     74   EXPECT_TRUE(test_str_const);
     75   EXPECT_TRUE(test_str_mutable);
     76 
     77   // Casting the CFTypeRef objects correctly provides the same pointer.
     78   EXPECT_EQ(test_array, CFCast<CFArrayRef>(test_array));
     79   EXPECT_EQ(test_array_mutable, CFCast<CFArrayRef>(test_array_mutable));
     80   EXPECT_EQ(test_bag, CFCast<CFBagRef>(test_bag));
     81   EXPECT_EQ(test_bag_mutable, CFCast<CFBagRef>(test_bag_mutable));
     82   EXPECT_EQ(test_bool, CFCast<CFBooleanRef>(test_bool));
     83   EXPECT_EQ(test_data, CFCast<CFDataRef>(test_data));
     84   EXPECT_EQ(test_data_mutable, CFCast<CFDataRef>(test_data_mutable));
     85   EXPECT_EQ(test_date, CFCast<CFDateRef>(test_date));
     86   EXPECT_EQ(test_dict, CFCast<CFDictionaryRef>(test_dict));
     87   EXPECT_EQ(test_dict_mutable, CFCast<CFDictionaryRef>(test_dict_mutable));
     88   EXPECT_EQ(test_number, CFCast<CFNumberRef>(test_number));
     89   EXPECT_EQ(test_null, CFCast<CFNullRef>(test_null));
     90   EXPECT_EQ(test_set, CFCast<CFSetRef>(test_set));
     91   EXPECT_EQ(test_set_mutable, CFCast<CFSetRef>(test_set_mutable));
     92   EXPECT_EQ(test_str, CFCast<CFStringRef>(test_str));
     93   EXPECT_EQ(test_str_const, CFCast<CFStringRef>(test_str_const));
     94   EXPECT_EQ(test_str_mutable, CFCast<CFStringRef>(test_str_mutable));
     95 
     96   // When given an incorrect CF cast, provide NULL.
     97   EXPECT_FALSE(CFCast<CFStringRef>(test_array));
     98   EXPECT_FALSE(CFCast<CFStringRef>(test_array_mutable));
     99   EXPECT_FALSE(CFCast<CFStringRef>(test_bag));
    100   EXPECT_FALSE(CFCast<CFSetRef>(test_bag_mutable));
    101   EXPECT_FALSE(CFCast<CFSetRef>(test_bool));
    102   EXPECT_FALSE(CFCast<CFNullRef>(test_data));
    103   EXPECT_FALSE(CFCast<CFDictionaryRef>(test_data_mutable));
    104   EXPECT_FALSE(CFCast<CFDictionaryRef>(test_date));
    105   EXPECT_FALSE(CFCast<CFNumberRef>(test_dict));
    106   EXPECT_FALSE(CFCast<CFDateRef>(test_dict_mutable));
    107   EXPECT_FALSE(CFCast<CFDataRef>(test_number));
    108   EXPECT_FALSE(CFCast<CFDataRef>(test_null));
    109   EXPECT_FALSE(CFCast<CFBooleanRef>(test_set));
    110   EXPECT_FALSE(CFCast<CFBagRef>(test_set_mutable));
    111   EXPECT_FALSE(CFCast<CFBagRef>(test_str));
    112   EXPECT_FALSE(CFCast<CFArrayRef>(test_str_const));
    113   EXPECT_FALSE(CFCast<CFArrayRef>(test_str_mutable));
    114 
    115   // Giving a NULL provides a NULL.
    116   EXPECT_FALSE(CFCast<CFArrayRef>(NULL));
    117   EXPECT_FALSE(CFCast<CFBagRef>(NULL));
    118   EXPECT_FALSE(CFCast<CFBooleanRef>(NULL));
    119   EXPECT_FALSE(CFCast<CFDataRef>(NULL));
    120   EXPECT_FALSE(CFCast<CFDateRef>(NULL));
    121   EXPECT_FALSE(CFCast<CFDictionaryRef>(NULL));
    122   EXPECT_FALSE(CFCast<CFNullRef>(NULL));
    123   EXPECT_FALSE(CFCast<CFNumberRef>(NULL));
    124   EXPECT_FALSE(CFCast<CFSetRef>(NULL));
    125   EXPECT_FALSE(CFCast<CFStringRef>(NULL));
    126 
    127   // CFCastStrict: correct cast results in correct pointer being returned.
    128   EXPECT_EQ(test_array, CFCastStrict<CFArrayRef>(test_array));
    129   EXPECT_EQ(test_array_mutable, CFCastStrict<CFArrayRef>(test_array_mutable));
    130   EXPECT_EQ(test_bag, CFCastStrict<CFBagRef>(test_bag));
    131   EXPECT_EQ(test_bag_mutable, CFCastStrict<CFBagRef>(test_bag_mutable));
    132   EXPECT_EQ(test_bool, CFCastStrict<CFBooleanRef>(test_bool));
    133   EXPECT_EQ(test_data, CFCastStrict<CFDataRef>(test_data));
    134   EXPECT_EQ(test_data_mutable, CFCastStrict<CFDataRef>(test_data_mutable));
    135   EXPECT_EQ(test_date, CFCastStrict<CFDateRef>(test_date));
    136   EXPECT_EQ(test_dict, CFCastStrict<CFDictionaryRef>(test_dict));
    137   EXPECT_EQ(test_dict_mutable,
    138             CFCastStrict<CFDictionaryRef>(test_dict_mutable));
    139   EXPECT_EQ(test_number, CFCastStrict<CFNumberRef>(test_number));
    140   EXPECT_EQ(test_null, CFCastStrict<CFNullRef>(test_null));
    141   EXPECT_EQ(test_set, CFCastStrict<CFSetRef>(test_set));
    142   EXPECT_EQ(test_set_mutable, CFCastStrict<CFSetRef>(test_set_mutable));
    143   EXPECT_EQ(test_str, CFCastStrict<CFStringRef>(test_str));
    144   EXPECT_EQ(test_str_const, CFCastStrict<CFStringRef>(test_str_const));
    145   EXPECT_EQ(test_str_mutable, CFCastStrict<CFStringRef>(test_str_mutable));
    146 
    147   // CFCastStrict: Giving a NULL provides a NULL.
    148   EXPECT_FALSE(CFCastStrict<CFArrayRef>(NULL));
    149   EXPECT_FALSE(CFCastStrict<CFBagRef>(NULL));
    150   EXPECT_FALSE(CFCastStrict<CFBooleanRef>(NULL));
    151   EXPECT_FALSE(CFCastStrict<CFDataRef>(NULL));
    152   EXPECT_FALSE(CFCastStrict<CFDateRef>(NULL));
    153   EXPECT_FALSE(CFCastStrict<CFDictionaryRef>(NULL));
    154   EXPECT_FALSE(CFCastStrict<CFNullRef>(NULL));
    155   EXPECT_FALSE(CFCastStrict<CFNumberRef>(NULL));
    156   EXPECT_FALSE(CFCastStrict<CFSetRef>(NULL));
    157   EXPECT_FALSE(CFCastStrict<CFStringRef>(NULL));
    158 }
    159 
    160 TEST(FoundationUtilTest, ObjCCast) {
    161   ScopedNSAutoreleasePool pool;
    162 
    163   id test_array = [NSArray array];
    164   id test_array_mutable = [NSMutableArray array];
    165   id test_data = [NSData data];
    166   id test_data_mutable = [NSMutableData dataWithCapacity:10];
    167   id test_date = [NSDate date];
    168   id test_dict =
    169       [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:42]
    170                                   forKey:@"meaning"];
    171   id test_dict_mutable = [NSMutableDictionary dictionaryWithCapacity:10];
    172   id test_number = [NSNumber numberWithInt:42];
    173   id test_null = [NSNull null];
    174   id test_set = [NSSet setWithObject:@"string object"];
    175   id test_set_mutable = [NSMutableSet setWithCapacity:10];
    176   id test_str = [NSString string];
    177   id test_str_const = @"bonjour";
    178   id test_str_mutable = [NSMutableString stringWithCapacity:10];
    179 
    180   // Make sure the allocations of NS types are good.
    181   EXPECT_TRUE(test_array);
    182   EXPECT_TRUE(test_array_mutable);
    183   EXPECT_TRUE(test_data);
    184   EXPECT_TRUE(test_data_mutable);
    185   EXPECT_TRUE(test_date);
    186   EXPECT_TRUE(test_dict);
    187   EXPECT_TRUE(test_dict_mutable);
    188   EXPECT_TRUE(test_number);
    189   EXPECT_TRUE(test_null);
    190   EXPECT_TRUE(test_set);
    191   EXPECT_TRUE(test_set_mutable);
    192   EXPECT_TRUE(test_str);
    193   EXPECT_TRUE(test_str_const);
    194   EXPECT_TRUE(test_str_mutable);
    195 
    196   // Casting the id correctly provides the same pointer.
    197   EXPECT_EQ(test_array, ObjCCast<NSArray>(test_array));
    198   EXPECT_EQ(test_array_mutable, ObjCCast<NSArray>(test_array_mutable));
    199   EXPECT_EQ(test_data, ObjCCast<NSData>(test_data));
    200   EXPECT_EQ(test_data_mutable, ObjCCast<NSData>(test_data_mutable));
    201   EXPECT_EQ(test_date, ObjCCast<NSDate>(test_date));
    202   EXPECT_EQ(test_dict, ObjCCast<NSDictionary>(test_dict));
    203   EXPECT_EQ(test_dict_mutable, ObjCCast<NSDictionary>(test_dict_mutable));
    204   EXPECT_EQ(test_number, ObjCCast<NSNumber>(test_number));
    205   EXPECT_EQ(test_null, ObjCCast<NSNull>(test_null));
    206   EXPECT_EQ(test_set, ObjCCast<NSSet>(test_set));
    207   EXPECT_EQ(test_set_mutable, ObjCCast<NSSet>(test_set_mutable));
    208   EXPECT_EQ(test_str, ObjCCast<NSString>(test_str));
    209   EXPECT_EQ(test_str_const, ObjCCast<NSString>(test_str_const));
    210   EXPECT_EQ(test_str_mutable, ObjCCast<NSString>(test_str_mutable));
    211 
    212   // When given an incorrect ObjC cast, provide nil.
    213   EXPECT_FALSE(ObjCCast<NSString>(test_array));
    214   EXPECT_FALSE(ObjCCast<NSString>(test_array_mutable));
    215   EXPECT_FALSE(ObjCCast<NSString>(test_data));
    216   EXPECT_FALSE(ObjCCast<NSString>(test_data_mutable));
    217   EXPECT_FALSE(ObjCCast<NSSet>(test_date));
    218   EXPECT_FALSE(ObjCCast<NSSet>(test_dict));
    219   EXPECT_FALSE(ObjCCast<NSNumber>(test_dict_mutable));
    220   EXPECT_FALSE(ObjCCast<NSNull>(test_number));
    221   EXPECT_FALSE(ObjCCast<NSDictionary>(test_null));
    222   EXPECT_FALSE(ObjCCast<NSDictionary>(test_set));
    223   EXPECT_FALSE(ObjCCast<NSDate>(test_set_mutable));
    224   EXPECT_FALSE(ObjCCast<NSData>(test_str));
    225   EXPECT_FALSE(ObjCCast<NSData>(test_str_const));
    226   EXPECT_FALSE(ObjCCast<NSArray>(test_str_mutable));
    227 
    228   // Giving a nil provides a nil.
    229   EXPECT_FALSE(ObjCCast<NSArray>(nil));
    230   EXPECT_FALSE(ObjCCast<NSData>(nil));
    231   EXPECT_FALSE(ObjCCast<NSDate>(nil));
    232   EXPECT_FALSE(ObjCCast<NSDictionary>(nil));
    233   EXPECT_FALSE(ObjCCast<NSNull>(nil));
    234   EXPECT_FALSE(ObjCCast<NSNumber>(nil));
    235   EXPECT_FALSE(ObjCCast<NSSet>(nil));
    236   EXPECT_FALSE(ObjCCast<NSString>(nil));
    237 
    238   // ObjCCastStrict: correct cast results in correct pointer being returned.
    239   EXPECT_EQ(test_array, ObjCCastStrict<NSArray>(test_array));
    240   EXPECT_EQ(test_array_mutable,
    241             ObjCCastStrict<NSArray>(test_array_mutable));
    242   EXPECT_EQ(test_data, ObjCCastStrict<NSData>(test_data));
    243   EXPECT_EQ(test_data_mutable,
    244             ObjCCastStrict<NSData>(test_data_mutable));
    245   EXPECT_EQ(test_date, ObjCCastStrict<NSDate>(test_date));
    246   EXPECT_EQ(test_dict, ObjCCastStrict<NSDictionary>(test_dict));
    247   EXPECT_EQ(test_dict_mutable,
    248             ObjCCastStrict<NSDictionary>(test_dict_mutable));
    249   EXPECT_EQ(test_number, ObjCCastStrict<NSNumber>(test_number));
    250   EXPECT_EQ(test_null, ObjCCastStrict<NSNull>(test_null));
    251   EXPECT_EQ(test_set, ObjCCastStrict<NSSet>(test_set));
    252   EXPECT_EQ(test_set_mutable,
    253             ObjCCastStrict<NSSet>(test_set_mutable));
    254   EXPECT_EQ(test_str, ObjCCastStrict<NSString>(test_str));
    255   EXPECT_EQ(test_str_const,
    256             ObjCCastStrict<NSString>(test_str_const));
    257   EXPECT_EQ(test_str_mutable,
    258             ObjCCastStrict<NSString>(test_str_mutable));
    259 
    260   // ObjCCastStrict: Giving a nil provides a nil.
    261   EXPECT_FALSE(ObjCCastStrict<NSArray>(nil));
    262   EXPECT_FALSE(ObjCCastStrict<NSData>(nil));
    263   EXPECT_FALSE(ObjCCastStrict<NSDate>(nil));
    264   EXPECT_FALSE(ObjCCastStrict<NSDictionary>(nil));
    265   EXPECT_FALSE(ObjCCastStrict<NSNull>(nil));
    266   EXPECT_FALSE(ObjCCastStrict<NSNumber>(nil));
    267   EXPECT_FALSE(ObjCCastStrict<NSSet>(nil));
    268   EXPECT_FALSE(ObjCCastStrict<NSString>(nil));
    269 }
    270 
    271 TEST(FoundationUtilTest, GetValueFromDictionary) {
    272   int one = 1, two = 2, three = 3;
    273 
    274   ScopedCFTypeRef<CFNumberRef> cf_one(
    275       CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &one));
    276   ScopedCFTypeRef<CFNumberRef> cf_two(
    277       CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &two));
    278   ScopedCFTypeRef<CFNumberRef> cf_three(
    279       CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &three));
    280 
    281   CFStringRef keys[] = { CFSTR("one"), CFSTR("two"), CFSTR("three") };
    282   CFNumberRef values[] = { cf_one, cf_two, cf_three };
    283 
    284   COMPILE_ASSERT(arraysize(keys) == arraysize(values),
    285                  keys_and_values_arraysizes_are_different);
    286 
    287   ScopedCFTypeRef<CFDictionaryRef> test_dict(
    288       CFDictionaryCreate(kCFAllocatorDefault,
    289                          reinterpret_cast<const void**>(keys),
    290                          reinterpret_cast<const void**>(values),
    291                          arraysize(values),
    292                          &kCFCopyStringDictionaryKeyCallBacks,
    293                          &kCFTypeDictionaryValueCallBacks));
    294 
    295   // GetValueFromDictionary<>(_, _) should produce the correct
    296   // expected output.
    297   EXPECT_EQ(values[0],
    298             GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("one")));
    299   EXPECT_EQ(values[1],
    300             GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("two")));
    301   EXPECT_EQ(values[2],
    302             GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("three")));
    303 
    304   // Bad input should produce bad output.
    305   EXPECT_FALSE(GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("four")));
    306   EXPECT_FALSE(GetValueFromDictionary<CFStringRef>(test_dict, CFSTR("one")));
    307 }
    308 
    309 TEST(FoundationUtilTest, FilePathToNSString) {
    310   EXPECT_NSEQ(nil, FilePathToNSString(FilePath()));
    311   EXPECT_NSEQ(@"/a/b", FilePathToNSString(FilePath("/a/b")));
    312 }
    313 
    314 TEST(FoundationUtilTest, NSStringToFilePath) {
    315   EXPECT_EQ(FilePath(), NSStringToFilePath(nil));
    316   EXPECT_EQ(FilePath(), NSStringToFilePath(@""));
    317   EXPECT_EQ(FilePath("/a/b"), NSStringToFilePath(@"/a/b"));
    318 }
    319 
    320 TEST(StringNumberConversionsTest, FormatNSInteger) {
    321   // The PRI[dxu]NS macro assumes that NSInteger is a typedef to "int" on
    322   // 32-bit architecture and a typedef to "long" on 64-bit architecture
    323   // (respectively "unsigned int" and "unsigned long" for NSUInteger). Use
    324   // pointer incompatibility to validate this at compilation.
    325 #if defined(ARCH_CPU_64_BITS)
    326   typedef long FormatNSIntegerAsType;
    327   typedef unsigned long FormatNSUIntegerAsType;
    328 #else
    329   typedef int FormatNSIntegerAsType;
    330   typedef unsigned int FormatNSUIntegerAsType;
    331 #endif  // defined(ARCH_CPU_64_BITS)
    332 
    333   NSInteger some_nsinteger;
    334   FormatNSIntegerAsType* pointer_to_some_nsinteger ALLOW_UNUSED =
    335       &some_nsinteger;
    336 
    337   NSUInteger some_nsuinteger;
    338   FormatNSUIntegerAsType* pointer_to_some_nsuinteger ALLOW_UNUSED =
    339       &some_nsuinteger;
    340 
    341   // Check that format specifier works correctly for NSInteger.
    342   const struct {
    343     NSInteger value;
    344     const char* expected;
    345     const char* expected_hex;
    346   } nsinteger_cases[] = {
    347 #if !defined(ARCH_CPU_64_BITS)
    348     {12345678, "12345678", "bc614e"},
    349     {-12345678, "-12345678", "ff439eb2"},
    350 #else
    351     {12345678, "12345678", "bc614e"},
    352     {-12345678, "-12345678", "ffffffffff439eb2"},
    353     {137451299150l, "137451299150", "2000bc614e"},
    354     {-137451299150l, "-137451299150", "ffffffdfff439eb2"},
    355 #endif  // !defined(ARCH_CPU_64_BITS)
    356   };
    357 
    358   for (size_t i = 0; i < arraysize(nsinteger_cases); ++i) {
    359     EXPECT_EQ(nsinteger_cases[i].expected,
    360               StringPrintf("%" PRIdNS, nsinteger_cases[i].value));
    361     EXPECT_EQ(nsinteger_cases[i].expected_hex,
    362               StringPrintf("%" PRIxNS, nsinteger_cases[i].value));
    363   }
    364 
    365   // Check that format specifier works correctly for NSUInteger.
    366   const struct {
    367     NSUInteger value;
    368     const char* expected;
    369     const char* expected_hex;
    370   } nsuinteger_cases[] = {
    371 #if !defined(ARCH_CPU_64_BITS)
    372     {12345678u, "12345678", "bc614e"},
    373     {4282621618u, "4282621618", "ff439eb2"},
    374 #else
    375     {12345678u, "12345678", "bc614e"},
    376     {4282621618u, "4282621618", "ff439eb2"},
    377     {137451299150ul, "137451299150", "2000bc614e"},
    378     {18446743936258252466ul, "18446743936258252466", "ffffffdfff439eb2"},
    379 #endif  // !defined(ARCH_CPU_64_BITS)
    380   };
    381 
    382   for (size_t i = 0; i < arraysize(nsuinteger_cases); ++i) {
    383     EXPECT_EQ(nsuinteger_cases[i].expected,
    384               StringPrintf("%" PRIuNS, nsuinteger_cases[i].value));
    385     EXPECT_EQ(nsuinteger_cases[i].expected_hex,
    386               StringPrintf("%" PRIxNS, nsuinteger_cases[i].value));
    387   }
    388 }
    389 
    390 }  // namespace mac
    391 }  // namespace base
    392