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#import <Cocoa/Cocoa.h> 6 7#include "base/mac/mac_util.h" 8 9#include "base/file_util.h" 10#include "base/files/file_path.h" 11#include "base/files/scoped_temp_dir.h" 12#include "base/mac/foundation_util.h" 13#include "base/mac/scoped_cftyperef.h" 14#include "base/mac/scoped_nsobject.h" 15#include "base/sys_info.h" 16#include "testing/gtest/include/gtest/gtest.h" 17#include "testing/platform_test.h" 18 19#include <errno.h> 20#include <sys/xattr.h> 21 22namespace base { 23namespace mac { 24 25namespace { 26 27typedef PlatformTest MacUtilTest; 28 29TEST_F(MacUtilTest, TestFSRef) { 30 FSRef ref; 31 std::string path("/System/Library"); 32 33 ASSERT_TRUE(FSRefFromPath(path, &ref)); 34 EXPECT_EQ(path, PathFromFSRef(ref)); 35} 36 37TEST_F(MacUtilTest, GetUserDirectoryTest) { 38 // Try a few keys, make sure they come back with non-empty paths. 39 FilePath caches_dir; 40 EXPECT_TRUE(GetUserDirectory(NSCachesDirectory, &caches_dir)); 41 EXPECT_FALSE(caches_dir.empty()); 42 43 FilePath application_support_dir; 44 EXPECT_TRUE(GetUserDirectory(NSApplicationSupportDirectory, 45 &application_support_dir)); 46 EXPECT_FALSE(application_support_dir.empty()); 47 48 FilePath library_dir; 49 EXPECT_TRUE(GetUserDirectory(NSLibraryDirectory, &library_dir)); 50 EXPECT_FALSE(library_dir.empty()); 51} 52 53TEST_F(MacUtilTest, TestLibraryPath) { 54 FilePath library_dir = GetUserLibraryPath(); 55 // Make sure the string isn't empty. 56 EXPECT_FALSE(library_dir.value().empty()); 57} 58 59TEST_F(MacUtilTest, TestGetAppBundlePath) { 60 FilePath out; 61 62 // Make sure it doesn't crash. 63 out = GetAppBundlePath(FilePath()); 64 EXPECT_TRUE(out.empty()); 65 66 // Some more invalid inputs. 67 const char* invalid_inputs[] = { 68 "/", "/foo", "foo", "/foo/bar.", "foo/bar.", "/foo/bar./bazquux", 69 "foo/bar./bazquux", "foo/.app", "//foo", 70 }; 71 for (size_t i = 0; i < arraysize(invalid_inputs); i++) { 72 out = GetAppBundlePath(FilePath(invalid_inputs[i])); 73 EXPECT_TRUE(out.empty()) << "loop: " << i; 74 } 75 76 // Some valid inputs; this and |expected_outputs| should be in sync. 77 struct { 78 const char *in; 79 const char *expected_out; 80 } valid_inputs[] = { 81 { "FooBar.app/", "FooBar.app" }, 82 { "/FooBar.app", "/FooBar.app" }, 83 { "/FooBar.app/", "/FooBar.app" }, 84 { "//FooBar.app", "//FooBar.app" }, 85 { "/Foo/Bar.app", "/Foo/Bar.app" }, 86 { "/Foo/Bar.app/", "/Foo/Bar.app" }, 87 { "/F/B.app", "/F/B.app" }, 88 { "/F/B.app/", "/F/B.app" }, 89 { "/Foo/Bar.app/baz", "/Foo/Bar.app" }, 90 { "/Foo/Bar.app/baz/", "/Foo/Bar.app" }, 91 { "/Foo/Bar.app/baz/quux.app/quuux", "/Foo/Bar.app" }, 92 { "/Applications/Google Foo.app/bar/Foo Helper.app/quux/Foo Helper", 93 "/Applications/Google Foo.app" }, 94 }; 95 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(valid_inputs); i++) { 96 out = GetAppBundlePath(FilePath(valid_inputs[i].in)); 97 EXPECT_FALSE(out.empty()) << "loop: " << i; 98 EXPECT_STREQ(valid_inputs[i].expected_out, 99 out.value().c_str()) << "loop: " << i; 100 } 101} 102 103TEST_F(MacUtilTest, TestExcludeFileFromBackups) { 104 // The file must already exist in order to set its exclusion property. 105 ScopedTempDir temp_dir_; 106 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 107 FilePath dummy_file_path = temp_dir_.path().Append("DummyFile"); 108 const char dummy_data[] = "All your base are belong to us!"; 109 // Dump something real into the file. 110 ASSERT_EQ(static_cast<int>(arraysize(dummy_data)), 111 WriteFile(dummy_file_path, dummy_data, arraysize(dummy_data))); 112 NSString* fileURLString = 113 [NSString stringWithUTF8String:dummy_file_path.value().c_str()]; 114 NSURL* fileURL = [NSURL URLWithString:fileURLString]; 115 // Initial state should be non-excluded. 116 EXPECT_FALSE(CSBackupIsItemExcluded(base::mac::NSToCFCast(fileURL), NULL)); 117 // Exclude the file. 118 EXPECT_TRUE(SetFileBackupExclusion(dummy_file_path)); 119 // SetFileBackupExclusion never excludes by path. 120 Boolean excluded_by_path = FALSE; 121 Boolean excluded = 122 CSBackupIsItemExcluded(base::mac::NSToCFCast(fileURL), &excluded_by_path); 123 EXPECT_TRUE(excluded); 124 EXPECT_FALSE(excluded_by_path); 125} 126 127TEST_F(MacUtilTest, NSObjectRetainRelease) { 128 base::scoped_nsobject<NSArray> array( 129 [[NSArray alloc] initWithObjects:@"foo", nil]); 130 EXPECT_EQ(1U, [array retainCount]); 131 132 NSObjectRetain(array); 133 EXPECT_EQ(2U, [array retainCount]); 134 135 NSObjectRelease(array); 136 EXPECT_EQ(1U, [array retainCount]); 137} 138 139TEST_F(MacUtilTest, IsOSEllipsis) { 140 int32 major, minor, bugfix; 141 base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix); 142 143 if (major == 10) { 144 if (minor == 6) { 145 EXPECT_TRUE(IsOSSnowLeopard()); 146 EXPECT_FALSE(IsOSLion()); 147 EXPECT_TRUE(IsOSLionOrEarlier()); 148 EXPECT_FALSE(IsOSLionOrLater()); 149 EXPECT_FALSE(IsOSMountainLion()); 150 EXPECT_TRUE(IsOSMountainLionOrEarlier()); 151 EXPECT_FALSE(IsOSMountainLionOrLater()); 152 EXPECT_FALSE(IsOSMavericks()); 153 EXPECT_TRUE(IsOSMavericksOrEarlier()); 154 EXPECT_FALSE(IsOSMavericksOrLater()); 155 EXPECT_FALSE(IsOSYosemite()); 156 EXPECT_FALSE(IsOSYosemiteOrLater()); 157 EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis()); 158 } else if (minor == 7) { 159 EXPECT_FALSE(IsOSSnowLeopard()); 160 EXPECT_TRUE(IsOSLion()); 161 EXPECT_TRUE(IsOSLionOrEarlier()); 162 EXPECT_TRUE(IsOSLionOrLater()); 163 EXPECT_FALSE(IsOSMountainLion()); 164 EXPECT_TRUE(IsOSMountainLionOrEarlier()); 165 EXPECT_FALSE(IsOSMountainLionOrLater()); 166 EXPECT_FALSE(IsOSMavericks()); 167 EXPECT_TRUE(IsOSMavericksOrEarlier()); 168 EXPECT_FALSE(IsOSMavericksOrLater()); 169 EXPECT_FALSE(IsOSYosemite()); 170 EXPECT_FALSE(IsOSYosemiteOrLater()); 171 EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis()); 172 } else if (minor == 8) { 173 EXPECT_FALSE(IsOSSnowLeopard()); 174 EXPECT_FALSE(IsOSLion()); 175 EXPECT_FALSE(IsOSLionOrEarlier()); 176 EXPECT_TRUE(IsOSLionOrLater()); 177 EXPECT_TRUE(IsOSMountainLion()); 178 EXPECT_TRUE(IsOSMountainLionOrEarlier()); 179 EXPECT_TRUE(IsOSMountainLionOrLater()); 180 EXPECT_FALSE(IsOSMavericks()); 181 EXPECT_TRUE(IsOSMavericksOrEarlier()); 182 EXPECT_FALSE(IsOSMavericksOrLater()); 183 EXPECT_FALSE(IsOSYosemite()); 184 EXPECT_FALSE(IsOSYosemiteOrLater()); 185 EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis()); 186 } else if (minor == 9) { 187 EXPECT_FALSE(IsOSSnowLeopard()); 188 EXPECT_FALSE(IsOSLion()); 189 EXPECT_FALSE(IsOSLionOrEarlier()); 190 EXPECT_TRUE(IsOSLionOrLater()); 191 EXPECT_FALSE(IsOSMountainLion()); 192 EXPECT_FALSE(IsOSMountainLionOrEarlier()); 193 EXPECT_TRUE(IsOSMountainLionOrLater()); 194 EXPECT_TRUE(IsOSMavericks()); 195 EXPECT_TRUE(IsOSMavericksOrEarlier()); 196 EXPECT_TRUE(IsOSMavericksOrLater()); 197 EXPECT_FALSE(IsOSYosemite()); 198 EXPECT_FALSE(IsOSYosemiteOrLater()); 199 EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis()); 200 } else if (minor == 10) { 201 EXPECT_FALSE(IsOSSnowLeopard()); 202 EXPECT_FALSE(IsOSLion()); 203 EXPECT_FALSE(IsOSLionOrEarlier()); 204 EXPECT_TRUE(IsOSLionOrLater()); 205 EXPECT_FALSE(IsOSMountainLion()); 206 EXPECT_FALSE(IsOSMountainLionOrEarlier()); 207 EXPECT_TRUE(IsOSMountainLionOrLater()); 208 EXPECT_FALSE(IsOSMavericks()); 209 EXPECT_FALSE(IsOSMavericksOrEarlier()); 210 EXPECT_TRUE(IsOSMavericksOrLater()); 211 EXPECT_TRUE(IsOSYosemite()); 212 EXPECT_TRUE(IsOSYosemiteOrLater()); 213 EXPECT_FALSE(IsOSLaterThanYosemite_DontCallThis()); 214 } else { 215 // Not six, seven, eight, nine, or ten. Ah, ah, ah. 216 EXPECT_TRUE(false); 217 } 218 } else { 219 // Not ten. What you gonna do? 220 EXPECT_FALSE(true); 221 } 222} 223 224TEST_F(MacUtilTest, ParseModelIdentifier) { 225 std::string model; 226 int32 major = 1, minor = 2; 227 228 EXPECT_FALSE(ParseModelIdentifier("", &model, &major, &minor)); 229 EXPECT_EQ(0U, model.length()); 230 EXPECT_EQ(1, major); 231 EXPECT_EQ(2, minor); 232 EXPECT_FALSE(ParseModelIdentifier("FooBar", &model, &major, &minor)); 233 234 EXPECT_TRUE(ParseModelIdentifier("MacPro4,1", &model, &major, &minor)); 235 EXPECT_EQ(model, "MacPro"); 236 EXPECT_EQ(4, major); 237 EXPECT_EQ(1, minor); 238 239 EXPECT_TRUE(ParseModelIdentifier("MacBookPro6,2", &model, &major, &minor)); 240 EXPECT_EQ(model, "MacBookPro"); 241 EXPECT_EQ(6, major); 242 EXPECT_EQ(2, minor); 243} 244 245TEST_F(MacUtilTest, TestRemoveQuarantineAttribute) { 246 ScopedTempDir temp_dir_; 247 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 248 FilePath dummy_folder_path = temp_dir_.path().Append("DummyFolder"); 249 ASSERT_TRUE(base::CreateDirectory(dummy_folder_path)); 250 const char* quarantine_str = "0000;4b392bb2;Chromium;|org.chromium.Chromium"; 251 const char* file_path_str = dummy_folder_path.value().c_str(); 252 EXPECT_EQ(0, setxattr(file_path_str, "com.apple.quarantine", 253 quarantine_str, strlen(quarantine_str), 0, 0)); 254 EXPECT_EQ(static_cast<long>(strlen(quarantine_str)), 255 getxattr(file_path_str, "com.apple.quarantine", 256 NULL, 0, 0, 0)); 257 EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path)); 258 EXPECT_EQ(-1, getxattr(file_path_str, "com.apple.quarantine", NULL, 0, 0, 0)); 259 EXPECT_EQ(ENOATTR, errno); 260} 261 262TEST_F(MacUtilTest, TestRemoveQuarantineAttributeTwice) { 263 ScopedTempDir temp_dir_; 264 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 265 FilePath dummy_folder_path = temp_dir_.path().Append("DummyFolder"); 266 const char* file_path_str = dummy_folder_path.value().c_str(); 267 ASSERT_TRUE(base::CreateDirectory(dummy_folder_path)); 268 EXPECT_EQ(-1, getxattr(file_path_str, "com.apple.quarantine", NULL, 0, 0, 0)); 269 // No quarantine attribute to begin with, but RemoveQuarantineAttribute still 270 // succeeds because in the end the folder still doesn't have the quarantine 271 // attribute set. 272 EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path)); 273 EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path)); 274 EXPECT_EQ(ENOATTR, errno); 275} 276 277TEST_F(MacUtilTest, TestRemoveQuarantineAttributeNonExistentPath) { 278 ScopedTempDir temp_dir_; 279 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); 280 FilePath non_existent_path = temp_dir_.path().Append("DummyPath"); 281 ASSERT_FALSE(PathExists(non_existent_path)); 282 EXPECT_FALSE(RemoveQuarantineAttribute(non_existent_path)); 283} 284 285} // namespace 286 287} // namespace mac 288} // namespace base 289