OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2009 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 "chrome/browser/sync/syncable/syncable.h" |
| 6 |
| 7 #include <sys/types.h> |
| 8 |
| 9 #include <iostream> |
| 10 #include <limits> |
| 11 #include <string> |
| 12 |
| 13 // TODO(ncarter): Winnow down the OS-specific includes from the test |
| 14 // file. |
| 15 #if defined(OS_WINDOWS) |
| 16 #include <tchar.h> |
| 17 #include <atlbase.h> |
| 18 #include <process.h> |
| 19 #endif // defined(OS_WINDOWS) |
| 20 |
| 21 #if !defined(OS_WINDOWS) |
| 22 #define MAX_PATH PATH_MAX |
| 23 #include <strstream> |
| 24 #include <ostream> |
| 25 #include <stdio.h> |
| 26 #include <sys/ipc.h> |
| 27 #include <sys/sem.h> |
| 28 #include <sys/times.h> |
| 29 #endif // !defined(OS_WINDOWS) |
| 30 |
| 31 #include "base/at_exit.h" |
| 32 #include "base/logging.h" |
| 33 #include "base/scoped_ptr.h" |
| 34 #include "chrome/browser/sync/syncable/directory_backing_store.h" |
| 35 #include "chrome/browser/sync/syncable/directory_manager.h" |
| 36 #include "chrome/browser/sync/util/character_set_converters.h" |
| 37 #include "chrome/browser/sync/util/closure.h" |
| 38 #include "chrome/browser/sync/util/compat-file.h" |
| 39 #include "chrome/browser/sync/util/event_sys-inl.h" |
| 40 #include "chrome/browser/sync/util/path_helpers.h" |
| 41 #include "chrome/browser/sync/util/pthread_helpers.h" |
| 42 #include "chrome/browser/sync/util/query_helpers.h" |
| 43 #include "chrome/test/sync/engine/test_id_factory.h" |
| 44 #include "testing/gtest/include/gtest/gtest.h" |
| 45 #include "third_party/sqlite/preprocessed/sqlite3.h" |
| 46 |
| 47 using browser_sync::TestIdFactory; |
| 48 using std::cout; |
| 49 using std::endl; |
| 50 using std::string; |
| 51 |
| 52 namespace syncable { |
| 53 |
| 54 // A lot of these tests were written expecting to be able to read and |
| 55 // write object data on entries. However, the design has changed. |
| 56 void PutDataAsExtendedAttribute(WriteTransaction *wtrans, |
| 57 MutableEntry* e, |
| 58 const char* bytes, |
| 59 size_t bytes_length) { |
| 60 ExtendedAttributeKey key(e->Get(META_HANDLE), PSTR("DATA")); |
| 61 MutableExtendedAttribute attr(wtrans, CREATE, key); |
| 62 Blob bytes_blob(bytes, bytes + bytes_length); |
| 63 attr.mutable_value()->swap(bytes_blob); |
| 64 } |
| 65 |
| 66 void ExpectDataFromExtendedAttributeEquals(BaseTransaction *trans, |
| 67 Entry* e, |
| 68 const char* bytes, |
| 69 size_t bytes_length) { |
| 70 Blob expected_value(bytes, bytes + bytes_length); |
| 71 ExtendedAttributeKey key(e->Get(META_HANDLE), PSTR("DATA")); |
| 72 ExtendedAttribute attr(trans, GET_BY_HANDLE, key); |
| 73 EXPECT_FALSE(attr.is_deleted()); |
| 74 EXPECT_EQ(expected_value, attr.value()); |
| 75 } |
| 76 |
| 77 |
| 78 TEST(Syncable, General) { |
| 79 remove("SimpleTest.sqlite3"); |
| 80 Directory dir; |
| 81 dir.Open(PSTR("SimpleTest.sqlite3"), PSTR("SimpleTest")); |
| 82 bool entry_exists = false; |
| 83 int64 metahandle; |
| 84 const Id id = TestIdFactory::FromNumber(99); |
| 85 // Test simple read operations. |
| 86 { |
| 87 ReadTransaction rtrans(&dir, __FILE__, __LINE__); |
| 88 Entry e(&rtrans, GET_BY_ID, id); |
| 89 if (e.good()) { |
| 90 entry_exists = true; |
| 91 metahandle = e.Get(META_HANDLE); |
| 92 } |
| 93 Directory::ChildHandles child_handles; |
| 94 dir.GetChildHandles(&rtrans, rtrans.root_id(), &child_handles); |
| 95 for (Directory::ChildHandles::iterator i = child_handles.begin(); |
| 96 i != child_handles.end(); ++i) |
| 97 cout << *i << endl; |
| 98 |
| 99 Entry e2(&rtrans, GET_BY_PATH, PSTR("/Hello\\World/")); |
| 100 } |
| 101 |
| 102 // Test creating a new meta entry. |
| 103 { |
| 104 WriteTransaction wtrans(&dir, UNITTEST, __FILE__, __LINE__); |
| 105 MutableEntry me(&wtrans, CREATE, wtrans.root_id(), PSTR("Jeff")); |
| 106 ASSERT_TRUE(entry_exists ? !me.good() : me.good()); |
| 107 if (me.good()) { |
| 108 me.Put(ID, id); |
| 109 me.Put(BASE_VERSION, 1); |
| 110 metahandle = me.Get(META_HANDLE); |
| 111 } |
| 112 } |
| 113 |
| 114 // Test writing data to an entity. |
| 115 static const char s[] = "Hello World."; |
| 116 { |
| 117 WriteTransaction trans(&dir, UNITTEST, __FILE__, __LINE__); |
| 118 MutableEntry e(&trans, GET_BY_PATH, |
| 119 PathString(kPathSeparator) + PSTR("Jeff")); |
| 120 ASSERT_TRUE(e.good()); |
| 121 PutDataAsExtendedAttribute(&trans, &e, s, sizeof(s)); |
| 122 } |
| 123 |
| 124 // Test reading back the name contents that we just wrote. |
| 125 { |
| 126 WriteTransaction trans(&dir, UNITTEST, __FILE__, __LINE__); |
| 127 MutableEntry e(&trans, GET_BY_PATH, |
| 128 PathString(kPathSeparator) + PSTR("Jeff")); |
| 129 ASSERT_TRUE(e.good()); |
| 130 ExpectDataFromExtendedAttributeEquals(&trans, &e, s, sizeof(s)); |
| 131 } |
| 132 |
| 133 // Now delete it. |
| 134 { |
| 135 WriteTransaction trans(&dir, UNITTEST, __FILE__, __LINE__); |
| 136 MutableEntry e(&trans, CREATE, trans.root_id(), PSTR("New File")); |
| 137 e.Put(IS_DEL, true); |
| 138 } |
| 139 |
| 140 dir.SaveChanges(); |
| 141 } |
| 142 |
| 143 TEST(Syncable, NameClassTest) { |
| 144 const PathString foo(PSTR("foo")); |
| 145 const PathString bar(PSTR("bar")); |
| 146 |
| 147 Name name1(foo); |
| 148 EXPECT_EQ(name1.value(), foo); |
| 149 EXPECT_EQ(name1.db_value(), foo); |
| 150 EXPECT_FALSE(name1.HasBeenSanitized()); |
| 151 EXPECT_TRUE(name1.GetUnsanitizedName().empty()); |
| 152 |
| 153 Name name2(foo, foo); |
| 154 EXPECT_EQ(name2.value(), foo); |
| 155 EXPECT_EQ(name2.db_value(), foo); |
| 156 EXPECT_FALSE(name2.HasBeenSanitized()); |
| 157 EXPECT_TRUE(name2.GetUnsanitizedName().empty()); |
| 158 |
| 159 Name name3(foo, bar); |
| 160 EXPECT_EQ(name3.value(), bar); |
| 161 EXPECT_EQ(name3.db_value(), foo); |
| 162 EXPECT_TRUE(name3.HasBeenSanitized()); |
| 163 EXPECT_EQ(name3.GetUnsanitizedName(), bar); |
| 164 |
| 165 EXPECT_TRUE(name1 == name2); |
| 166 EXPECT_FALSE(name1 != name2); |
| 167 EXPECT_FALSE(name2 == name3); |
| 168 EXPECT_TRUE(name2 != name3); |
| 169 } |
| 170 |
| 171 namespace { |
| 172 |
| 173 // A Directory whose backing store always fails SaveChanges by returning false. |
| 174 class TestUnsaveableDirectory : public Directory { |
| 175 public: |
| 176 class UnsaveableBackingStore : public DirectoryBackingStore { |
| 177 public: |
| 178 UnsaveableBackingStore(const PathString& dir_name, |
| 179 const PathString& backing_filepath) |
| 180 : DirectoryBackingStore(dir_name, backing_filepath) { } |
| 181 virtual bool SaveChanges(const Directory::SaveChangesSnapshot& snapshot) { |
| 182 return false; |
| 183 } |
| 184 }; |
| 185 virtual DirectoryBackingStore* CreateBackingStore( |
| 186 const PathString& dir_name, const PathString& backing_filepath) { |
| 187 return new UnsaveableBackingStore(dir_name, backing_filepath); |
| 188 } |
| 189 }; |
| 190 |
| 191 // Test suite for syncable::Directory. |
| 192 class SyncableDirectoryTest : public testing::Test { |
| 193 protected: |
| 194 static const PathString kFilePath; |
| 195 static const PathString kName; |
| 196 static const PathChar *kSqlite3File; |
| 197 static const Id kId; |
| 198 |
| 199 // SetUp() is called before each test case is run. |
| 200 // The sqlite3 DB is deleted before each test is run. |
| 201 virtual void SetUp() { |
| 202 PathRemove(PathString(kSqlite3File)); |
| 203 dir_.reset(new Directory()); |
| 204 ASSERT_TRUE(dir_.get()); |
| 205 ASSERT_EQ(OPENED, dir_->Open(kFilePath, kName)); |
| 206 ASSERT_TRUE(dir_->good()); |
| 207 } |
| 208 |
| 209 virtual void TearDown() { |
| 210 // This also closes file handles. |
| 211 dir_->SaveChanges(); |
| 212 dir_.reset(); |
| 213 PathRemove(PathString(kSqlite3File)); |
| 214 } |
| 215 |
| 216 scoped_ptr<Directory> dir_; |
| 217 |
| 218 // Creates an empty entry and sets the ID field to the default kId. |
| 219 void CreateEntry(const PathString &entryname) { |
| 220 CreateEntry(entryname, kId); |
| 221 } |
| 222 |
| 223 // Creates an empty entry and sets the ID field to id. |
| 224 void CreateEntry(const PathString &entryname, const int id) { |
| 225 CreateEntry(entryname, TestIdFactory::FromNumber(id)); |
| 226 } |
| 227 void CreateEntry(const PathString &entryname, Id id) { |
| 228 WriteTransaction wtrans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 229 MutableEntry me(&wtrans, CREATE, wtrans.root_id(), entryname); |
| 230 ASSERT_TRUE(me.good()); |
| 231 me.Put(ID, id); |
| 232 me.Put(IS_UNSYNCED, true); |
| 233 } |
| 234 |
| 235 void ValidateEntry(BaseTransaction *trans, int64 id, bool check_name, |
| 236 PathString name, int64 base_version, int64 server_version, bool is_del); |
| 237 void CreateAndCheck(WriteTransaction *trans, int64 parent_id, int64 id, |
| 238 PathString name, PathString server_name, int64 version, |
| 239 bool set_server_fields, bool is_dir, bool add_to_lru, int64 *meta_handle); |
| 240 }; |
| 241 |
| 242 const PathString SyncableDirectoryTest::kFilePath(PSTR("Test.sqlite3")); |
| 243 const PathChar* SyncableDirectoryTest::kSqlite3File(PSTR("Test.sqlite3")); |
| 244 const PathString SyncableDirectoryTest::kName(PSTR("Foo")); |
| 245 const Id SyncableDirectoryTest::kId(TestIdFactory::FromNumber(-99)); |
| 246 |
| 247 TEST_F(SyncableDirectoryTest, TestBasicLookupNonExistantID) { |
| 248 ReadTransaction rtrans(dir_.get(), __FILE__, __LINE__); |
| 249 Entry e(&rtrans, GET_BY_ID, kId); |
| 250 ASSERT_FALSE(e.good()); |
| 251 } |
| 252 |
| 253 TEST_F(SyncableDirectoryTest, TestBasicLookupValidID) { |
| 254 CreateEntry(PSTR("rtc")); |
| 255 ReadTransaction rtrans(dir_.get(), __FILE__, __LINE__); |
| 256 Entry e(&rtrans, GET_BY_ID, kId); |
| 257 ASSERT_TRUE(e.good()); |
| 258 } |
| 259 |
| 260 TEST_F(SyncableDirectoryTest, TestBasicCaseSensitivity) { |
| 261 PathString name = PSTR("RYAN"); |
| 262 PathString conflicting_name = PSTR("ryan"); |
| 263 CreateEntry(name); |
| 264 |
| 265 WriteTransaction wtrans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 266 MutableEntry me(&wtrans, CREATE, wtrans.root_id(), conflicting_name); |
| 267 ASSERT_FALSE(me.good()); |
| 268 } |
| 269 |
| 270 TEST_F(SyncableDirectoryTest, TestDelete) { |
| 271 PathString name = PSTR("peanut butter jelly time"); |
| 272 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 273 MutableEntry e1(&trans, CREATE, trans.root_id(), name); |
| 274 ASSERT_TRUE(e1.good()); |
| 275 ASSERT_TRUE(e1.Put(IS_DEL, true)); |
| 276 MutableEntry e2(&trans, CREATE, trans.root_id(), name); |
| 277 ASSERT_TRUE(e2.good()); |
| 278 ASSERT_TRUE(e2.Put(IS_DEL, true)); |
| 279 MutableEntry e3(&trans, CREATE, trans.root_id(), name); |
| 280 ASSERT_TRUE(e3.good()); |
| 281 ASSERT_TRUE(e3.Put(IS_DEL, true)); |
| 282 |
| 283 ASSERT_TRUE(e3.Put(IS_DEL, false)); |
| 284 ASSERT_FALSE(e1.Put(IS_DEL, false)); |
| 285 ASSERT_FALSE(e2.Put(IS_DEL, false)); |
| 286 ASSERT_TRUE(e3.Put(IS_DEL, true)); |
| 287 |
| 288 ASSERT_TRUE(e1.Put(IS_DEL, false)); |
| 289 ASSERT_FALSE(e2.Put(IS_DEL, false)); |
| 290 ASSERT_FALSE(e3.Put(IS_DEL, false)); |
| 291 ASSERT_TRUE(e1.Put(IS_DEL, true)); |
| 292 } |
| 293 |
| 294 TEST_F(SyncableDirectoryTest, TestGetFullPathNeverCrashes) { |
| 295 PathString dirname = PSTR("honey"), |
| 296 childname = PSTR("jelly"); |
| 297 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 298 MutableEntry e1(&trans, CREATE, trans.root_id(), dirname); |
| 299 ASSERT_TRUE(e1.good()); |
| 300 ASSERT_TRUE(e1.Put(IS_DIR, true)); |
| 301 MutableEntry e2(&trans, CREATE, e1.Get(ID), childname); |
| 302 ASSERT_TRUE(e2.good()); |
| 303 PathString path = GetFullPath(&trans, e2); |
| 304 ASSERT_FALSE(path.empty()); |
| 305 // Give the child a parent that doesn't exist. |
| 306 e2.Put(PARENT_ID, TestIdFactory::FromNumber(42)); |
| 307 path = GetFullPath(&trans, e2); |
| 308 ASSERT_TRUE(path.empty()); |
| 309 // Done testing, make sure CheckTreeInvariants doesn't choke. |
| 310 e2.Put(PARENT_ID, e1.Get(ID)); |
| 311 e2.Put(IS_DEL, true); |
| 312 e1.Put(IS_DEL, true); |
| 313 } |
| 314 |
| 315 TEST_F(SyncableDirectoryTest, TestGetUnsynced) { |
| 316 Directory::UnsyncedMetaHandles handles; |
| 317 int64 handle1, handle2; |
| 318 { |
| 319 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 320 |
| 321 dir_->GetUnsyncedMetaHandles(&trans, &handles); |
| 322 ASSERT_EQ(0, handles.size()); |
| 323 |
| 324 MutableEntry e1(&trans, CREATE, trans.root_id(), PSTR("abba")); |
| 325 ASSERT_TRUE(e1.good()); |
| 326 handle1 = e1.Get(META_HANDLE); |
| 327 e1.Put(BASE_VERSION, 1); |
| 328 e1.Put(IS_DIR, true); |
| 329 e1.Put(ID, TestIdFactory::FromNumber(101)); |
| 330 |
| 331 MutableEntry e2(&trans, CREATE, e1.Get(ID), PSTR("bread")); |
| 332 ASSERT_TRUE(e2.good()); |
| 333 handle2 = e2.Get(META_HANDLE); |
| 334 e2.Put(BASE_VERSION, 1); |
| 335 e2.Put(ID, TestIdFactory::FromNumber(102)); |
| 336 } |
| 337 dir_->SaveChanges(); |
| 338 { |
| 339 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 340 |
| 341 dir_->GetUnsyncedMetaHandles(&trans, &handles); |
| 342 ASSERT_EQ(0, handles.size()); |
| 343 |
| 344 MutableEntry e3(&trans, GET_BY_HANDLE, handle1); |
| 345 ASSERT_TRUE(e3.good()); |
| 346 e3.Put(IS_UNSYNCED, true); |
| 347 } |
| 348 dir_->SaveChanges(); |
| 349 { |
| 350 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 351 dir_->GetUnsyncedMetaHandles(&trans, &handles); |
| 352 ASSERT_EQ(1, handles.size()); |
| 353 ASSERT_TRUE(handle1 == handles[0]); |
| 354 |
| 355 MutableEntry e4(&trans, GET_BY_HANDLE, handle2); |
| 356 ASSERT_TRUE(e4.good()); |
| 357 e4.Put(IS_UNSYNCED, true); |
| 358 } |
| 359 dir_->SaveChanges(); |
| 360 { |
| 361 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 362 dir_->GetUnsyncedMetaHandles(&trans, &handles); |
| 363 ASSERT_EQ(2, handles.size()); |
| 364 if (handle1 == handles[0]) { |
| 365 ASSERT_TRUE(handle2 == handles[1]); |
| 366 } else { |
| 367 ASSERT_TRUE(handle2 == handles[0]); |
| 368 ASSERT_TRUE(handle1 == handles[1]); |
| 369 } |
| 370 |
| 371 MutableEntry e5(&trans, GET_BY_HANDLE, handle1); |
| 372 ASSERT_TRUE(e5.good()); |
| 373 ASSERT_TRUE(e5.Get(IS_UNSYNCED)); |
| 374 ASSERT_TRUE(e5.Put(IS_UNSYNCED, false)); |
| 375 ASSERT_FALSE(e5.Get(IS_UNSYNCED)); |
| 376 } |
| 377 dir_->SaveChanges(); |
| 378 { |
| 379 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 380 dir_->GetUnsyncedMetaHandles(&trans, &handles); |
| 381 ASSERT_EQ(1, handles.size()); |
| 382 ASSERT_TRUE(handle2 == handles[0]); |
| 383 } |
| 384 } |
| 385 |
| 386 TEST_F(SyncableDirectoryTest, TestGetUnappliedUpdates) { |
| 387 Directory::UnappliedUpdateMetaHandles handles; |
| 388 int64 handle1, handle2; |
| 389 { |
| 390 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 391 |
| 392 dir_->GetUnappliedUpdateMetaHandles(&trans, &handles); |
| 393 ASSERT_EQ(0, handles.size()); |
| 394 |
| 395 MutableEntry e1(&trans, CREATE, trans.root_id(), PSTR("abba")); |
| 396 ASSERT_TRUE(e1.good()); |
| 397 handle1 = e1.Get(META_HANDLE); |
| 398 e1.Put(IS_UNAPPLIED_UPDATE, false); |
| 399 e1.Put(BASE_VERSION, 1); |
| 400 e1.Put(ID, TestIdFactory::FromNumber(101)); |
| 401 e1.Put(IS_DIR, true); |
| 402 |
| 403 MutableEntry e2(&trans, CREATE, e1.Get(ID), PSTR("bread")); |
| 404 ASSERT_TRUE(e2.good()); |
| 405 handle2 = e2.Get(META_HANDLE); |
| 406 e2.Put(IS_UNAPPLIED_UPDATE, false); |
| 407 e2.Put(BASE_VERSION, 1); |
| 408 e2.Put(ID, TestIdFactory::FromNumber(102)); |
| 409 } |
| 410 dir_->SaveChanges(); |
| 411 { |
| 412 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 413 |
| 414 dir_->GetUnappliedUpdateMetaHandles(&trans, &handles); |
| 415 ASSERT_EQ(0, handles.size()); |
| 416 |
| 417 MutableEntry e3(&trans, GET_BY_HANDLE, handle1); |
| 418 ASSERT_TRUE(e3.good()); |
| 419 e3.Put(IS_UNAPPLIED_UPDATE, true); |
| 420 } |
| 421 dir_->SaveChanges(); |
| 422 { |
| 423 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 424 dir_->GetUnappliedUpdateMetaHandles(&trans, &handles); |
| 425 ASSERT_EQ(1, handles.size()); |
| 426 ASSERT_TRUE(handle1 == handles[0]); |
| 427 |
| 428 MutableEntry e4(&trans, GET_BY_HANDLE, handle2); |
| 429 ASSERT_TRUE(e4.good()); |
| 430 e4.Put(IS_UNAPPLIED_UPDATE, true); |
| 431 } |
| 432 dir_->SaveChanges(); |
| 433 { |
| 434 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 435 dir_->GetUnappliedUpdateMetaHandles(&trans, &handles); |
| 436 ASSERT_EQ(2, handles.size()); |
| 437 if (handle1 == handles[0]) { |
| 438 ASSERT_TRUE(handle2 == handles[1]); |
| 439 } else { |
| 440 ASSERT_TRUE(handle2 == handles[0]); |
| 441 ASSERT_TRUE(handle1 == handles[1]); |
| 442 } |
| 443 |
| 444 MutableEntry e5(&trans, GET_BY_HANDLE, handle1); |
| 445 ASSERT_TRUE(e5.good()); |
| 446 e5.Put(IS_UNAPPLIED_UPDATE, false); |
| 447 } |
| 448 dir_->SaveChanges(); |
| 449 { |
| 450 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 451 dir_->GetUnappliedUpdateMetaHandles(&trans, &handles); |
| 452 ASSERT_EQ(1, handles.size()); |
| 453 ASSERT_TRUE(handle2 == handles[0]); |
| 454 } |
| 455 } |
| 456 |
| 457 |
| 458 TEST_F(SyncableDirectoryTest, DeleteBug_531383) { |
| 459 // Try to evoke a check failure... |
| 460 TestIdFactory id_factory; |
| 461 int64 grandchild_handle, twin_handle; |
| 462 { |
| 463 WriteTransaction wtrans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 464 MutableEntry parent(&wtrans, CREATE, id_factory.root(), PSTR("Bob")); |
| 465 ASSERT_TRUE(parent.good()); |
| 466 parent.Put(IS_DIR, true); |
| 467 parent.Put(ID, id_factory.NewServerId()); |
| 468 parent.Put(BASE_VERSION, 1); |
| 469 MutableEntry child(&wtrans, CREATE, parent.Get(ID), PSTR("Bob")); |
| 470 ASSERT_TRUE(child.good()); |
| 471 child.Put(IS_DIR, true); |
| 472 child.Put(ID, id_factory.NewServerId()); |
| 473 child.Put(BASE_VERSION, 1); |
| 474 MutableEntry grandchild(&wtrans, CREATE, child.Get(ID), PSTR("Bob")); |
| 475 ASSERT_TRUE(grandchild.good()); |
| 476 grandchild.Put(ID, id_factory.NewServerId()); |
| 477 grandchild.Put(BASE_VERSION, 1); |
| 478 ASSERT_TRUE(grandchild.Put(IS_DEL, true)); |
| 479 MutableEntry twin(&wtrans, CREATE, child.Get(ID), PSTR("Bob")); |
| 480 ASSERT_TRUE(twin.good()); |
| 481 ASSERT_TRUE(twin.Put(IS_DEL, true)); |
| 482 ASSERT_TRUE(grandchild.Put(IS_DEL, false)); |
| 483 ASSERT_FALSE(twin.Put(IS_DEL, false)); |
| 484 grandchild_handle = grandchild.Get(META_HANDLE); |
| 485 twin_handle = twin.Get(META_HANDLE); |
| 486 } |
| 487 dir_->SaveChanges(); |
| 488 { |
| 489 WriteTransaction wtrans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 490 MutableEntry grandchild(&wtrans, GET_BY_HANDLE, grandchild_handle); |
| 491 grandchild.Put(IS_DEL, true); // Used to CHECK fail here. |
| 492 } |
| 493 } |
| 494 |
| 495 static inline bool IsLegalNewParent(const Entry& a, const Entry& b) { |
| 496 return IsLegalNewParent(a.trans(), a.Get(ID), b.Get(ID)); |
| 497 } |
| 498 |
| 499 TEST_F(SyncableDirectoryTest, TestIsLegalNewParent) { |
| 500 TestIdFactory id_factory; |
| 501 WriteTransaction wtrans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 502 Entry root(&wtrans, GET_BY_ID, id_factory.root()); |
| 503 ASSERT_TRUE(root.good()); |
| 504 MutableEntry parent(&wtrans, CREATE, root.Get(ID), PSTR("Bob")); |
| 505 ASSERT_TRUE(parent.good()); |
| 506 parent.Put(IS_DIR, true); |
| 507 parent.Put(ID, id_factory.NewServerId()); |
| 508 parent.Put(BASE_VERSION, 1); |
| 509 MutableEntry child(&wtrans, CREATE, parent.Get(ID), PSTR("Bob")); |
| 510 ASSERT_TRUE(child.good()); |
| 511 child.Put(IS_DIR, true); |
| 512 child.Put(ID, id_factory.NewServerId()); |
| 513 child.Put(BASE_VERSION, 1); |
| 514 MutableEntry grandchild(&wtrans, CREATE, child.Get(ID), PSTR("Bob")); |
| 515 ASSERT_TRUE(grandchild.good()); |
| 516 grandchild.Put(ID, id_factory.NewServerId()); |
| 517 grandchild.Put(BASE_VERSION, 1); |
| 518 |
| 519 MutableEntry parent2(&wtrans, CREATE, root.Get(ID), PSTR("Pete")); |
| 520 ASSERT_TRUE(parent2.good()); |
| 521 parent2.Put(IS_DIR, true); |
| 522 parent2.Put(ID, id_factory.NewServerId()); |
| 523 parent2.Put(BASE_VERSION, 1); |
| 524 MutableEntry child2(&wtrans, CREATE, parent2.Get(ID), PSTR("Pete")); |
| 525 ASSERT_TRUE(child2.good()); |
| 526 child2.Put(IS_DIR, true); |
| 527 child2.Put(ID, id_factory.NewServerId()); |
| 528 child2.Put(BASE_VERSION, 1); |
| 529 MutableEntry grandchild2(&wtrans, CREATE, child2.Get(ID), PSTR("Pete")); |
| 530 ASSERT_TRUE(grandchild2.good()); |
| 531 grandchild2.Put(ID, id_factory.NewServerId()); |
| 532 grandchild2.Put(BASE_VERSION, 1); |
| 533 // resulting tree |
| 534 // root |
| 535 // / \ |
| 536 // parent parent2 |
| 537 // | | |
| 538 // child child2 |
| 539 // | | |
| 540 // grandchild grandchild2 |
| 541 ASSERT_TRUE(IsLegalNewParent(child, root)); |
| 542 ASSERT_TRUE(IsLegalNewParent(child, parent)); |
| 543 ASSERT_FALSE(IsLegalNewParent(child, child)); |
| 544 ASSERT_FALSE(IsLegalNewParent(child, grandchild)); |
| 545 ASSERT_TRUE(IsLegalNewParent(child, parent2)); |
| 546 ASSERT_TRUE(IsLegalNewParent(child, grandchild2)); |
| 547 ASSERT_FALSE(IsLegalNewParent(parent, grandchild)); |
| 548 ASSERT_FALSE(IsLegalNewParent(root, grandchild)); |
| 549 ASSERT_FALSE(IsLegalNewParent(parent, grandchild)); |
| 550 } |
| 551 |
| 552 TEST_F(SyncableDirectoryTest, TestFindEntryInFolder) { |
| 553 // Create a subdir and an entry. |
| 554 int64 entry_handle; |
| 555 { |
| 556 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 557 MutableEntry folder(&trans, CREATE, trans.root_id(), PSTR("folder")); |
| 558 ASSERT_TRUE(folder.good()); |
| 559 EXPECT_TRUE(folder.Put(IS_DIR, true)); |
| 560 EXPECT_TRUE(folder.Put(IS_UNSYNCED, true)); |
| 561 MutableEntry entry(&trans, CREATE, folder.Get(ID), PSTR("entry")); |
| 562 ASSERT_TRUE(entry.good()); |
| 563 entry_handle = entry.Get(META_HANDLE); |
| 564 entry.Put(IS_UNSYNCED, true); |
| 565 } |
| 566 |
| 567 // Make sure we can find the entry in the folder. |
| 568 { |
| 569 ReadTransaction trans(dir_.get(), __FILE__, __LINE__); |
| 570 Entry entry(&trans, GET_BY_PATH, PathString(kPathSeparator) + |
| 571 PSTR("folder") + |
| 572 kPathSeparator + PSTR("entry")); |
| 573 ASSERT_TRUE(entry.good()); |
| 574 ASSERT_EQ(entry.Get(META_HANDLE), entry_handle); |
| 575 } |
| 576 } |
| 577 |
| 578 TEST_F(SyncableDirectoryTest, TestGetByParentIdAndName) { |
| 579 PathString name = PSTR("Bob"); |
| 580 Id id = TestIdFactory::MakeServer("ID for Bob"); |
| 581 { |
| 582 WriteTransaction wtrans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 583 MutableEntry entry(&wtrans, CREATE, wtrans.root_id() /*entry id*/, name); |
| 584 ASSERT_TRUE(entry.good()); |
| 585 entry.Put(IS_DIR, true); |
| 586 entry.Put(ID, id); |
| 587 entry.Put(BASE_VERSION, 1); |
| 588 entry.Put(IS_UNSYNCED, true); |
| 589 } |
| 590 { |
| 591 WriteTransaction wtrans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 592 MutableEntry entry(&wtrans, GET_BY_PARENTID_AND_NAME, wtrans.root_id(), |
| 593 name); |
| 594 ASSERT_TRUE(entry.good()); |
| 595 ASSERT_EQ(id, entry.Get(ID)); |
| 596 } |
| 597 { |
| 598 ReadTransaction trans(dir_.get(), __FILE__, __LINE__); |
| 599 Entry entry(&trans, GET_BY_PARENTID_AND_NAME, trans.root_id(), name); |
| 600 ASSERT_TRUE(entry.good()); |
| 601 ASSERT_EQ(id, entry.Get(ID)); |
| 602 } |
| 603 } |
| 604 |
| 605 TEST_F(SyncableDirectoryTest, TestParentIDIndexUpdate) { |
| 606 WriteTransaction wt(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 607 MutableEntry folder(&wt, CREATE, wt.root_id(), PSTR("oldname")); |
| 608 folder.Put(NAME, PSTR("newname")); |
| 609 folder.Put(IS_UNSYNCED, true); |
| 610 Entry entry(&wt, GET_BY_PATH, PSTR("newname")); |
| 611 ASSERT_TRUE(entry.good()); |
| 612 } |
| 613 |
| 614 TEST_F(SyncableDirectoryTest, TestNoReindexDeletedItems) { |
| 615 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 616 MutableEntry folder(&trans, CREATE, trans.root_id(), PSTR("folder")); |
| 617 ASSERT_TRUE(folder.good()); |
| 618 ASSERT_TRUE(folder.Put(IS_DIR, true)); |
| 619 ASSERT_TRUE(folder.Put(IS_DEL, true)); |
| 620 Entry gone(&trans, GET_BY_PARENTID_AND_NAME, trans.root_id(), PSTR("folder")); |
| 621 ASSERT_FALSE(gone.good()); |
| 622 ASSERT_TRUE(folder.PutParentIdAndName(trans.root_id(), |
| 623 Name(PSTR("new_name")))); |
| 624 } |
| 625 |
| 626 TEST_F(SyncableDirectoryTest, TestCaseChangeRename) { |
| 627 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 628 MutableEntry folder(&trans, CREATE, trans.root_id(), PSTR("CaseChange")); |
| 629 ASSERT_TRUE(folder.good()); |
| 630 EXPECT_TRUE(folder.PutParentIdAndName(trans.root_id(), |
| 631 Name(PSTR("CASECHANGE")))); |
| 632 EXPECT_TRUE(folder.Put(IS_DEL, true)); |
| 633 } |
| 634 |
| 635 TEST_F(SyncableDirectoryTest, TestShareInfo) { |
| 636 dir_->set_last_sync_timestamp(100); |
| 637 dir_->set_store_birthday("Jan 31st"); |
| 638 { |
| 639 ReadTransaction trans(dir_.get(), __FILE__, __LINE__); |
| 640 EXPECT_EQ(100, dir_->last_sync_timestamp()); |
| 641 EXPECT_EQ("Jan 31st", dir_->store_birthday()); |
| 642 } |
| 643 dir_->set_last_sync_timestamp(200); |
| 644 dir_->set_store_birthday("April 10th"); |
| 645 dir_->SaveChanges(); |
| 646 { |
| 647 ReadTransaction trans(dir_.get(), __FILE__, __LINE__); |
| 648 EXPECT_EQ(200, dir_->last_sync_timestamp()); |
| 649 EXPECT_EQ("April 10th", dir_->store_birthday()); |
| 650 } |
| 651 } |
| 652 |
| 653 TEST_F(SyncableDirectoryTest, TestSimpleFieldsPreservedDuringSaveChanges) { |
| 654 Id id = TestIdFactory::FromNumber(1); |
| 655 EntryKernel create_pre_save, update_pre_save; |
| 656 EntryKernel create_post_save, update_post_save; |
| 657 { |
| 658 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 659 MutableEntry create(&trans, CREATE, trans.root_id(), PSTR("Create")); |
| 660 MutableEntry update(&trans, CREATE_NEW_UPDATE_ITEM, id); |
| 661 create.Put(IS_UNSYNCED, true); |
| 662 update.Put(IS_UNAPPLIED_UPDATE, true); |
| 663 create_pre_save = create.GetKernelCopy(); |
| 664 update_pre_save = update.GetKernelCopy(); |
| 665 } |
| 666 dir_->SaveChanges(); |
| 667 { |
| 668 ReadTransaction trans(dir_.get(), __FILE__, __LINE__); |
| 669 Entry create(&trans, GET_BY_PARENTID_AND_NAME, trans.root_id(), |
| 670 PSTR("Create")); |
| 671 Entry update(&trans, GET_BY_ID, id); |
| 672 create_post_save = create.GetKernelCopy(); |
| 673 update_post_save = update.GetKernelCopy(); |
| 674 } |
| 675 int i = BEGIN_FIELDS; |
| 676 for ( ; i < INT64_FIELDS_END ; ++i) { |
| 677 EXPECT_EQ(create_pre_save.ref((Int64Field)i), |
| 678 create_post_save.ref((Int64Field)i)) |
| 679 << "int64 field #" << i << " changed during save/load"; |
| 680 EXPECT_EQ(update_pre_save.ref((Int64Field)i), |
| 681 update_post_save.ref((Int64Field)i)) |
| 682 << "int64 field #" << i << " changed during save/load"; |
| 683 } |
| 684 for ( ; i < ID_FIELDS_END ; ++i) { |
| 685 EXPECT_EQ(create_pre_save.ref((IdField)i), |
| 686 create_post_save.ref((IdField)i)) |
| 687 << "id field #" << i << " changed during save/load"; |
| 688 EXPECT_EQ(update_pre_save.ref((IdField)i), |
| 689 update_pre_save.ref((IdField)i)) |
| 690 << "id field #" << i << " changed during save/load"; |
| 691 } |
| 692 for ( ; i < BIT_FIELDS_END ; ++i) { |
| 693 EXPECT_EQ(create_pre_save.ref((BitField)i), |
| 694 create_post_save.ref((BitField)i)) |
| 695 << "Bit field #" << i << " changed during save/load"; |
| 696 EXPECT_EQ(update_pre_save.ref((BitField)i), |
| 697 update_post_save.ref((BitField)i)) |
| 698 << "Bit field #" << i << " changed during save/load"; |
| 699 } |
| 700 for ( ; i < STRING_FIELDS_END ; ++i) { |
| 701 EXPECT_EQ(create_pre_save.ref((StringField)i), |
| 702 create_post_save.ref((StringField)i)) |
| 703 << "String field #" << i << " changed during save/load"; |
| 704 EXPECT_EQ(update_pre_save.ref((StringField)i), |
| 705 update_post_save.ref((StringField)i)) |
| 706 << "String field #" << i << " changed during save/load"; |
| 707 } |
| 708 } |
| 709 |
| 710 TEST_F(SyncableDirectoryTest, TestSaveChangesFailure) { |
| 711 int64 handle1 = 0; |
| 712 { |
| 713 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 714 |
| 715 MutableEntry e1(&trans, CREATE, trans.root_id(), PSTR("aguilera")); |
| 716 ASSERT_TRUE(e1.good()); |
| 717 handle1 = e1.Get(META_HANDLE); |
| 718 e1.Put(BASE_VERSION, 1); |
| 719 e1.Put(IS_DIR, true); |
| 720 e1.Put(ID, TestIdFactory::FromNumber(101)); |
| 721 } |
| 722 ASSERT_TRUE(dir_->SaveChanges()); |
| 723 |
| 724 dir_.reset(new TestUnsaveableDirectory()); |
| 725 ASSERT_TRUE(dir_.get()); |
| 726 ASSERT_EQ(OPENED, dir_->Open(kFilePath, kName)); |
| 727 ASSERT_TRUE(dir_->good()); |
| 728 int64 handle2 = 0; |
| 729 { |
| 730 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 731 |
| 732 MutableEntry aguilera(&trans, GET_BY_HANDLE, handle1); |
| 733 ASSERT_TRUE(aguilera.good()); |
| 734 aguilera.Put(NAME, PSTR("christina")); |
| 735 ASSERT_TRUE(aguilera.GetKernelCopy().dirty[NAME]); |
| 736 |
| 737 MutableEntry kids_on_block(&trans, CREATE, trans.root_id(), PSTR("kids")); |
| 738 ASSERT_TRUE(kids_on_block.good()); |
| 739 handle2 = kids_on_block.Get(META_HANDLE); |
| 740 kids_on_block.Put(BASE_VERSION, 1); |
| 741 kids_on_block.Put(IS_DIR, true); |
| 742 kids_on_block.Put(ID, TestIdFactory::FromNumber(102)); |
| 743 EXPECT_TRUE(kids_on_block.Get(IS_NEW)); |
| 744 } |
| 745 |
| 746 // We are using an unsaveable directory, so this can't succeed. However, |
| 747 // the HandleSaveChangesFailure code path should have been triggered. |
| 748 ASSERT_FALSE(dir_->SaveChanges()); |
| 749 |
| 750 // Make sure things were rolled back and the world is as it was before call. |
| 751 { |
| 752 ReadTransaction trans(dir_.get(), __FILE__, __LINE__); |
| 753 Entry e1(&trans, GET_BY_HANDLE, handle1); |
| 754 ASSERT_TRUE(e1.good()); |
| 755 const EntryKernel& aguilera = e1.GetKernelCopy(); |
| 756 Entry kids_on_block(&trans, GET_BY_HANDLE, handle2); |
| 757 ASSERT_TRUE(kids_on_block.good()); |
| 758 |
| 759 EXPECT_TRUE(aguilera.dirty[NAME]); |
| 760 EXPECT_TRUE(kids_on_block.Get(IS_NEW)); |
| 761 } |
| 762 } |
| 763 |
| 764 |
| 765 void SyncableDirectoryTest::ValidateEntry(BaseTransaction *trans, int64 id, |
| 766 bool check_name, PathString name, int64 base_version, int64 server_version, |
| 767 bool is_del) { |
| 768 Entry e(trans, GET_BY_ID, TestIdFactory::FromNumber(id)); |
| 769 ASSERT_TRUE(e.good()); |
| 770 if (check_name) |
| 771 ASSERT_EQ(name, e.Get(NAME)); |
| 772 ASSERT_EQ(base_version, e.Get(BASE_VERSION)); |
| 773 ASSERT_EQ(server_version, e.Get(SERVER_VERSION)); |
| 774 ASSERT_EQ(is_del, e.Get(IS_DEL)); |
| 775 } |
| 776 |
| 777 TEST(SyncableDirectoryManager, TestFileRelease) { |
| 778 DirectoryManager dm(PSTR(".")); |
| 779 ASSERT_TRUE(dm.Open(PSTR("ScopeTest"))); |
| 780 { |
| 781 ScopedDirLookup(&dm, PSTR("ScopeTest")); |
| 782 } |
| 783 dm.Close(PSTR("ScopeTest")); |
| 784 ASSERT_EQ(0, PathRemove(dm.GetSyncDataDatabasePath())); |
| 785 } |
| 786 |
| 787 static void* OpenTestThreadMain(void* arg) { |
| 788 DirectoryManager* const dm = reinterpret_cast<DirectoryManager*>(arg); |
| 789 CHECK(dm->Open(PSTR("Open"))); |
| 790 return 0; |
| 791 } |
| 792 |
| 793 TEST(SyncableDirectoryManager, ThreadOpenTest) { |
| 794 DirectoryManager dm(PSTR(".")); |
| 795 pthread_t thread; |
| 796 ASSERT_EQ(0, pthread_create(&thread, 0, OpenTestThreadMain, &dm)); |
| 797 void* result; |
| 798 ASSERT_EQ(0, pthread_join(thread, &result)); |
| 799 { |
| 800 ScopedDirLookup dir(&dm, PSTR("Open")); |
| 801 ASSERT_TRUE(dir.good()); |
| 802 } |
| 803 dm.Close(PSTR("Open")); |
| 804 ScopedDirLookup dir(&dm, PSTR("Open")); |
| 805 ASSERT_FALSE(dir.good()); |
| 806 } |
| 807 |
| 808 namespace ThreadBug1 { |
| 809 struct Step { |
| 810 PThreadMutex mutex; |
| 811 PThreadCondVar condvar; |
| 812 int number; |
| 813 int64 metahandle; |
| 814 }; |
| 815 struct ThreadArg { |
| 816 int role; // 0 or 1, meaning this thread does the odd or event steps. |
| 817 Step* step; |
| 818 DirectoryManager* dirman; |
| 819 }; |
| 820 |
| 821 void* ThreadMain(void* arg) { |
| 822 ThreadArg* const args = reinterpret_cast<ThreadArg*>(arg); |
| 823 const int role = args->role; |
| 824 Step* const step = args->step; |
| 825 DirectoryManager* const dirman = args->dirman; |
| 826 const PathString dirname = PSTR("ThreadBug1"); |
| 827 PThreadScopedLock<PThreadMutex> lock(&step->mutex); |
| 828 while (step->number < 3) { |
| 829 while (step->number % 2 != role) |
| 830 pthread_cond_wait(&step->condvar.condvar_, &step->mutex.mutex_); |
| 831 switch (step->number) { |
| 832 case 0: |
| 833 dirman->Open(dirname); |
| 834 break; |
| 835 case 1: |
| 836 { |
| 837 dirman->Close(dirname); |
| 838 dirman->Open(dirname); |
| 839 ScopedDirLookup dir(dirman, dirname); |
| 840 CHECK(dir.good()); |
| 841 WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__); |
| 842 MutableEntry me(&trans, CREATE, trans.root_id(), PSTR("Jeff")); |
| 843 step->metahandle = me.Get(META_HANDLE); |
| 844 me.Put(IS_UNSYNCED, true); |
| 845 } |
| 846 break; |
| 847 case 2: |
| 848 { |
| 849 ScopedDirLookup dir(dirman, dirname); |
| 850 CHECK(dir.good()); |
| 851 ReadTransaction trans(dir, __FILE__, __LINE__); |
| 852 Entry e(&trans, GET_BY_HANDLE, step->metahandle); |
| 853 CHECK(e.good()); // Failed due to ThreadBug1 |
| 854 } |
| 855 dirman->Close(dirname); |
| 856 break; |
| 857 } |
| 858 step->number += 1; |
| 859 pthread_cond_signal(&step->condvar.condvar_); |
| 860 } |
| 861 return 0; |
| 862 } |
| 863 } |
| 864 |
| 865 TEST(SyncableDirectoryManager, ThreadBug1) { |
| 866 using ThreadBug1::Step; |
| 867 using ThreadBug1::ThreadArg; |
| 868 using ThreadBug1::ThreadMain; |
| 869 |
| 870 Step step; |
| 871 step.number = 0; |
| 872 DirectoryManager dirman(PSTR(".")); |
| 873 ThreadArg arg1 = { 0, &step, &dirman }; |
| 874 ThreadArg arg2 = { 1, &step, &dirman }; |
| 875 pthread_t thread1, thread2; |
| 876 ASSERT_EQ(0, pthread_create(&thread1, NULL, &ThreadMain, &arg1)); |
| 877 ASSERT_EQ(0, pthread_create(&thread2, NULL, &ThreadMain, &arg2)); |
| 878 void* retval; |
| 879 ASSERT_EQ(0, pthread_join(thread1, &retval)); |
| 880 ASSERT_EQ(0, pthread_join(thread2, &retval)); |
| 881 } |
| 882 |
| 883 namespace DirectoryKernelStalenessBug { |
| 884 // The in-memory information would get out of sync because a |
| 885 // directory would be closed and re-opened, and then an old |
| 886 // Directory::Kernel with stale information would get saved to the db. |
| 887 typedef ThreadBug1::Step Step; |
| 888 typedef ThreadBug1::ThreadArg ThreadArg; |
| 889 |
| 890 void* ThreadMain(void* arg) { |
| 891 const char test_bytes[] = "test data"; |
| 892 ThreadArg* const args = reinterpret_cast<ThreadArg*>(arg); |
| 893 const int role = args->role; |
| 894 Step* const step = args->step; |
| 895 DirectoryManager* const dirman = args->dirman; |
| 896 const PathString dirname = PSTR("DirectoryKernelStalenessBug"); |
| 897 PThreadScopedLock<PThreadMutex> lock(&step->mutex); |
| 898 while (step->number < 4) { |
| 899 while (step->number % 2 != role) |
| 900 pthread_cond_wait(&step->condvar.condvar_, &step->mutex.mutex_); |
| 901 switch (step->number) { |
| 902 case 0: |
| 903 { |
| 904 // Clean up remnants of earlier test runs. |
| 905 PathRemove(dirman->GetSyncDataDatabasePath()); |
| 906 // Test. |
| 907 dirman->Open(dirname); |
| 908 ScopedDirLookup dir(dirman, dirname); |
| 909 CHECK(dir.good()); |
| 910 WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__); |
| 911 MutableEntry me(&trans, CREATE, trans.root_id(), PSTR("Jeff")); |
| 912 me.Put(BASE_VERSION, 1); |
| 913 me.Put(ID, TestIdFactory::FromNumber(100)); |
| 914 PutDataAsExtendedAttribute(&trans, &me, test_bytes, |
| 915 sizeof(test_bytes)); |
| 916 } |
| 917 { |
| 918 ScopedDirLookup dir(dirman, dirname); |
| 919 CHECK(dir.good()); |
| 920 dir->SaveChanges(); |
| 921 } |
| 922 dirman->CloseAllDirectories(); |
| 923 break; |
| 924 case 1: |
| 925 { |
| 926 dirman->Open(dirname); |
| 927 ScopedDirLookup dir(dirman, dirname); |
| 928 CHECK(dir.good()); |
| 929 } |
| 930 break; |
| 931 case 2: |
| 932 { |
| 933 ScopedDirLookup dir(dirman, dirname); |
| 934 CHECK(dir.good()); |
| 935 } |
| 936 break; |
| 937 case 3: |
| 938 { |
| 939 ScopedDirLookup dir(dirman, dirname); |
| 940 CHECK(dir.good()); |
| 941 ReadTransaction trans(dir, __FILE__, __LINE__); |
| 942 Entry e(&trans, GET_BY_PATH, PSTR("Jeff")); |
| 943 ExpectDataFromExtendedAttributeEquals(&trans, &e, test_bytes, |
| 944 sizeof(test_bytes)); |
| 945 } |
| 946 // Same result as CloseAllDirectories, but more code coverage. |
| 947 dirman->Close(dirname); |
| 948 break; |
| 949 } |
| 950 step->number += 1; |
| 951 pthread_cond_signal(&step->condvar.condvar_); |
| 952 } |
| 953 return 0; |
| 954 } |
| 955 } |
| 956 |
| 957 TEST(SyncableDirectoryManager, DirectoryKernelStalenessBug) { |
| 958 using DirectoryKernelStalenessBug::Step; |
| 959 using DirectoryKernelStalenessBug::ThreadArg; |
| 960 using DirectoryKernelStalenessBug::ThreadMain; |
| 961 |
| 962 Step step; |
| 963 step.number = 0; |
| 964 DirectoryManager dirman(PSTR(".")); |
| 965 ThreadArg arg1 = { 0, &step, &dirman }; |
| 966 ThreadArg arg2 = { 1, &step, &dirman }; |
| 967 pthread_t thread1, thread2; |
| 968 ASSERT_EQ(0, pthread_create(&thread1, NULL, &ThreadMain, &arg1)); |
| 969 ASSERT_EQ(0, pthread_create(&thread2, NULL, &ThreadMain, &arg2)); |
| 970 void* retval; |
| 971 ASSERT_EQ(0, pthread_join(thread1, &retval)); |
| 972 ASSERT_EQ(0, pthread_join(thread2, &retval)); |
| 973 } |
| 974 |
| 975 timespec operator + (const timespec& a, const timespec& b) { |
| 976 const long nanos = a.tv_nsec + b.tv_nsec; |
| 977 static const long nanos_per_second = 1000000000; |
| 978 timespec r = { a.tv_sec + b.tv_sec + (nanos / nanos_per_second), |
| 979 nanos % nanos_per_second }; |
| 980 return r; |
| 981 } |
| 982 |
| 983 void SleepMs(int milliseconds) { |
| 984 #ifdef OS_WINDOWS |
| 985 Sleep(milliseconds); |
| 986 #else |
| 987 usleep(milliseconds * 1000); |
| 988 #endif |
| 989 } |
| 990 |
| 991 namespace StressTransaction { |
| 992 struct Globals { |
| 993 DirectoryManager* dirman; |
| 994 PathString dirname; |
| 995 }; |
| 996 |
| 997 struct ThreadArg { |
| 998 Globals* globals; |
| 999 int thread_number; |
| 1000 }; |
| 1001 |
| 1002 void* ThreadMain(void* arg) { |
| 1003 ThreadArg* const args = reinterpret_cast<ThreadArg*>(arg); |
| 1004 Globals* const globals = args->globals; |
| 1005 ScopedDirLookup dir(globals->dirman, globals->dirname); |
| 1006 CHECK(dir.good()); |
| 1007 int entry_count = 0; |
| 1008 PathString path_name; |
| 1009 for (int i = 0; i < 20; ++i) { |
| 1010 const int rand_action = rand() % 10; |
| 1011 if (rand_action < 4 && !path_name.empty()) { |
| 1012 ReadTransaction trans(dir, __FILE__, __LINE__); |
| 1013 Entry e(&trans, GET_BY_PARENTID_AND_NAME, trans.root_id(), path_name); |
| 1014 SleepMs(rand() % 10); |
| 1015 CHECK(e.good()); |
| 1016 } else { |
| 1017 string unique_name = StringPrintf("%d.%d", args->thread_number, |
| 1018 entry_count++); |
| 1019 path_name.assign(unique_name.begin(), unique_name.end()); |
| 1020 WriteTransaction trans(dir, UNITTEST, __FILE__, __LINE__); |
| 1021 MutableEntry e(&trans, CREATE, trans.root_id(), path_name); |
| 1022 CHECK(e.good()); |
| 1023 SleepMs(rand() % 20); |
| 1024 e.Put(IS_UNSYNCED, true); |
| 1025 if (e.Put(ID, TestIdFactory::FromNumber(rand())) && |
| 1026 e.Get(ID).ServerKnows() && !e.Get(ID).IsRoot()) |
| 1027 e.Put(BASE_VERSION, 1); |
| 1028 } |
| 1029 } |
| 1030 return 0; |
| 1031 } |
| 1032 } |
| 1033 |
| 1034 TEST(SyncableDirectory, StressTransactions) { |
| 1035 using StressTransaction::Globals; |
| 1036 using StressTransaction::ThreadArg; |
| 1037 using StressTransaction::ThreadMain; |
| 1038 |
| 1039 DirectoryManager dirman(PSTR(".")); |
| 1040 Globals globals; |
| 1041 globals.dirname = PSTR("stress"); |
| 1042 globals.dirman = &dirman; |
| 1043 PathRemove(dirman.GetSyncDataDatabasePath()); |
| 1044 dirman.Open(globals.dirname); |
| 1045 const int kThreadCount = 7; |
| 1046 pthread_t threads[kThreadCount]; |
| 1047 ThreadArg thread_args[kThreadCount]; |
| 1048 for (int i = 0; i < kThreadCount; ++i) { |
| 1049 thread_args[i].thread_number = i; |
| 1050 thread_args[i].globals = &globals; |
| 1051 ASSERT_EQ(0, pthread_create(threads + i, NULL, &ThreadMain, |
| 1052 thread_args + i)); |
| 1053 } |
| 1054 void* retval; |
| 1055 for (pthread_t* i = threads; i < threads + kThreadCount; ++i) |
| 1056 ASSERT_EQ(0, pthread_join(*i, &retval)); |
| 1057 dirman.Close(globals.dirname); |
| 1058 PathRemove(dirman.GetSyncDataDatabasePath()); |
| 1059 } |
| 1060 |
| 1061 static PathString UTF8ToPathStringQuick(const char *str) { |
| 1062 PathString ret; |
| 1063 CHECK(browser_sync::UTF8ToPathString(str, strlen(str), &ret)); |
| 1064 return ret; |
| 1065 } |
| 1066 |
| 1067 // returns number of chars used. max possible is 4 |
| 1068 // This algorithm was coded from the table at |
| 1069 // http://en.wikipedia.org/w/index.php?title=UTF-8&oldid=153391259 |
| 1070 // there are no endian issues. |
| 1071 static int UTF32ToUTF8(uint32 incode, unsigned char *out) { |
| 1072 if (incode <= 0x7f) { |
| 1073 out[0] = incode; |
| 1074 return 1; |
| 1075 } |
| 1076 if (incode <= 0x7ff) { |
| 1077 out[0] = 0xC0; |
| 1078 out[0] |= (incode >> 6); |
| 1079 out[1] = 0x80; |
| 1080 out[1] |= (incode & 0x3F); |
| 1081 return 2; |
| 1082 } |
| 1083 if (incode <= 0xFFFF) { |
| 1084 if ((incode > 0xD7FF) && (incode < 0xE000)) |
| 1085 return 0; |
| 1086 out[0] = 0xE0; |
| 1087 out[0] |= (incode >> 12); |
| 1088 out[1] = 0x80; |
| 1089 out[1] |= (incode >> 6) & 0x3F; |
| 1090 out[2] = 0x80; |
| 1091 out[2] |= incode & 0x3F; |
| 1092 return 3; |
| 1093 } |
| 1094 if (incode <= 0x10FFFF) { |
| 1095 out[0] = 0xF0; |
| 1096 out[0] |= incode >> 18; |
| 1097 out[1] = 0x80; |
| 1098 out[1] |= (incode >> 12) & 0x3F; |
| 1099 out[2] = 0x80; |
| 1100 out[2] |= (incode >> 6) & 0x3F; |
| 1101 out[3] = 0x80; |
| 1102 out[3] |= incode & 0x3F; |
| 1103 return 4; |
| 1104 } |
| 1105 return 0; |
| 1106 } |
| 1107 |
| 1108 TEST(Syncable, ComparePathNames) { |
| 1109 struct { |
| 1110 char a; |
| 1111 char b; |
| 1112 int expected_result; |
| 1113 } tests[] = { |
| 1114 { 'A', 'A', 0 }, |
| 1115 { 'A', 'a', 0 }, |
| 1116 { 'a', 'A', 0 }, |
| 1117 { 'a', 'a', 0 }, |
| 1118 { 'A', 'B', -1 }, |
| 1119 { 'A', 'b', -1 }, |
| 1120 { 'a', 'B', -1 }, |
| 1121 { 'a', 'b', -1 }, |
| 1122 { 'B', 'A', 1 }, |
| 1123 { 'B', 'a', 1 }, |
| 1124 { 'b', 'A', 1 }, |
| 1125 { 'b', 'a', 1 } }; |
| 1126 for (int i = 0; i < ARRAYSIZE(tests); ++i) { |
| 1127 PathString a(1, tests[i].a); |
| 1128 PathString b(1, tests[i].b); |
| 1129 const int result = ComparePathNames(a, b); |
| 1130 if (result != tests[i].expected_result) { |
| 1131 ADD_FAILURE() << "ComparePathNames(" << tests[i].a << ", " << tests[i].b |
| 1132 << ") returned " << result << "; expected " |
| 1133 << tests[i].expected_result; |
| 1134 } |
| 1135 } |
| 1136 |
| 1137 #ifndef OS_WINDOWS |
| 1138 // This table lists (to the best of my knowledge) every pair of characters |
| 1139 // in unicode such that: |
| 1140 // for all i: tolower(kUpperToLowerMap[i].upper) = kUpperToLowerMap[i].lower |
| 1141 // This is then used to test that case-insensitive comparison of each pair |
| 1142 // returns 0 (that, that they are equal). After running the test on Mac OS X |
| 1143 // with the CFString API for comparision, the failing cases were commented |
| 1144 // out. |
| 1145 // |
| 1146 // Map of upper to lower case characters taken from |
| 1147 // ftp://ftp.unicode.org/Public/UNIDATA/UnicodeData.txt |
| 1148 typedef struct { |
| 1149 uint32 upper; // the upper case character |
| 1150 uint32 lower; // the lower case character that upper maps to |
| 1151 } UpperToLowerMapEntry; |
| 1152 static const UpperToLowerMapEntry kUpperToLowerMap[] = { |
| 1153 // { UPPER, lower }, { UPPER, lower }, etc... |
| 1154 // some of these are commented out because they fail on some OS. |
| 1155 { 0x00041, 0x00061 }, { 0x00042, 0x00062 }, { 0x00043, 0x00063 }, |
| 1156 { 0x00044, 0x00064 }, { 0x00045, 0x00065 }, { 0x00046, 0x00066 }, |
| 1157 { 0x00047, 0x00067 }, { 0x00048, 0x00068 }, { 0x00049, 0x00069 }, |
| 1158 { 0x0004A, 0x0006A }, { 0x0004B, 0x0006B }, { 0x0004C, 0x0006C }, |
| 1159 { 0x0004D, 0x0006D }, { 0x0004E, 0x0006E }, { 0x0004F, 0x0006F }, |
| 1160 { 0x00050, 0x00070 }, { 0x00051, 0x00071 }, { 0x00052, 0x00072 }, |
| 1161 { 0x00053, 0x00073 }, { 0x00054, 0x00074 }, { 0x00055, 0x00075 }, |
| 1162 { 0x00056, 0x00076 }, { 0x00057, 0x00077 }, { 0x00058, 0x00078 }, |
| 1163 { 0x00059, 0x00079 }, { 0x0005A, 0x0007A }, { 0x000C0, 0x000E0 }, |
| 1164 { 0x000C1, 0x000E1 }, { 0x000C2, 0x000E2 }, { 0x000C3, 0x000E3 }, |
| 1165 { 0x000C4, 0x000E4 }, { 0x000C5, 0x000E5 }, { 0x000C6, 0x000E6 }, |
| 1166 { 0x000C7, 0x000E7 }, { 0x000C8, 0x000E8 }, { 0x000C9, 0x000E9 }, |
| 1167 { 0x000CA, 0x000EA }, { 0x000CB, 0x000EB }, { 0x000CC, 0x000EC }, |
| 1168 { 0x000CD, 0x000ED }, { 0x000CE, 0x000EE }, { 0x000CF, 0x000EF }, |
| 1169 { 0x000D0, 0x000F0 }, { 0x000D1, 0x000F1 }, { 0x000D2, 0x000F2 }, |
| 1170 { 0x000D3, 0x000F3 }, { 0x000D4, 0x000F4 }, { 0x000D5, 0x000F5 }, |
| 1171 { 0x000D6, 0x000F6 }, { 0x000D8, 0x000F8 }, { 0x000D9, 0x000F9 }, |
| 1172 { 0x000DA, 0x000FA }, { 0x000DB, 0x000FB }, { 0x000DC, 0x000FC }, |
| 1173 { 0x000DD, 0x000FD }, { 0x000DE, 0x000FE }, |
| 1174 { 0x00100, 0x00101 }, { 0x00102, 0x00103 }, { 0x00104, 0x00105 }, |
| 1175 { 0x00106, 0x00107 }, { 0x00108, 0x00109 }, { 0x0010A, 0x0010B }, |
| 1176 { 0x0010C, 0x0010D }, { 0x0010E, 0x0010F }, { 0x00110, 0x00111 }, |
| 1177 { 0x00112, 0x00113 }, { 0x00114, 0x00115 }, { 0x00116, 0x00117 }, |
| 1178 { 0x00118, 0x00119 }, { 0x0011A, 0x0011B }, { 0x0011C, 0x0011D }, |
| 1179 { 0x0011E, 0x0011F }, { 0x00120, 0x00121 }, { 0x00122, 0x00123 }, |
| 1180 { 0x00124, 0x00125 }, { 0x00126, 0x00127 }, { 0x00128, 0x00129 }, |
| 1181 { 0x0012A, 0x0012B }, { 0x0012C, 0x0012D }, { 0x0012E, 0x0012F }, |
| 1182 /*{ 0x00130, 0x00069 },*/ { 0x00132, 0x00133 }, { 0x00134, 0x00135 }, |
| 1183 { 0x00136, 0x00137 }, { 0x00139, 0x0013A }, { 0x0013B, 0x0013C }, |
| 1184 { 0x0013D, 0x0013E }, { 0x0013F, 0x00140 }, { 0x00141, 0x00142 }, |
| 1185 { 0x00143, 0x00144 }, { 0x00145, 0x00146 }, { 0x00147, 0x00148 }, |
| 1186 { 0x0014A, 0x0014B }, { 0x0014C, 0x0014D }, { 0x0014E, 0x0014F }, |
| 1187 { 0x00150, 0x00151 }, { 0x00152, 0x00153 }, { 0x00154, 0x00155 }, |
| 1188 { 0x00156, 0x00157 }, { 0x00158, 0x00159 }, { 0x0015A, 0x0015B }, |
| 1189 { 0x0015C, 0x0015D }, { 0x0015E, 0x0015F }, { 0x00160, 0x00161 }, |
| 1190 { 0x00162, 0x00163 }, { 0x00164, 0x00165 }, { 0x00166, 0x00167 }, |
| 1191 { 0x00168, 0x00169 }, { 0x0016A, 0x0016B }, { 0x0016C, 0x0016D }, |
| 1192 { 0x0016E, 0x0016F }, { 0x00170, 0x00171 }, { 0x00172, 0x00173 }, |
| 1193 { 0x00174, 0x00175 }, { 0x00176, 0x00177 }, { 0x00178, 0x000FF }, |
| 1194 { 0x00179, 0x0017A }, { 0x0017B, 0x0017C }, { 0x0017D, 0x0017E }, |
| 1195 { 0x00181, 0x00253 }, { 0x00182, 0x00183 }, { 0x00184, 0x00185 }, |
| 1196 { 0x00186, 0x00254 }, { 0x00187, 0x00188 }, { 0x00189, 0x00256 }, |
| 1197 { 0x0018A, 0x00257 }, { 0x0018B, 0x0018C }, { 0x0018E, 0x001DD }, |
| 1198 { 0x0018F, 0x00259 }, { 0x00190, 0x0025B }, { 0x00191, 0x00192 }, |
| 1199 { 0x00193, 0x00260 }, { 0x00194, 0x00263 }, { 0x00196, 0x00269 }, |
| 1200 { 0x00197, 0x00268 }, { 0x00198, 0x00199 }, { 0x0019C, 0x0026F }, |
| 1201 { 0x0019D, 0x00272 }, { 0x0019F, 0x00275 }, { 0x001A0, 0x001A1 }, |
| 1202 { 0x001A2, 0x001A3 }, { 0x001A4, 0x001A5 }, { 0x001A6, 0x00280 }, |
| 1203 { 0x001A7, 0x001A8 }, { 0x001A9, 0x00283 }, { 0x001AC, 0x001AD }, |
| 1204 { 0x001AE, 0x00288 }, { 0x001AF, 0x001B0 }, { 0x001B1, 0x0028A }, |
| 1205 { 0x001B2, 0x0028B }, { 0x001B3, 0x001B4 }, { 0x001B5, 0x001B6 }, |
| 1206 { 0x001B7, 0x00292 }, { 0x001B8, 0x001B9 }, { 0x001BC, 0x001BD }, |
| 1207 { 0x001C4, 0x001C6 }, { 0x001C7, 0x001C9 }, { 0x001CA, 0x001CC }, |
| 1208 { 0x001CD, 0x001CE }, { 0x001CF, 0x001D0 }, { 0x001D1, 0x001D2 }, |
| 1209 { 0x001D3, 0x001D4 }, { 0x001D5, 0x001D6 }, { 0x001D7, 0x001D8 }, |
| 1210 { 0x001D9, 0x001DA }, { 0x001DB, 0x001DC }, { 0x001DE, 0x001DF }, |
| 1211 { 0x001E0, 0x001E1 }, { 0x001E2, 0x001E3 }, { 0x001E4, 0x001E5 }, |
| 1212 { 0x001E6, 0x001E7 }, { 0x001E8, 0x001E9 }, { 0x001EA, 0x001EB }, |
| 1213 { 0x001EC, 0x001ED }, { 0x001EE, 0x001EF }, { 0x001F1, 0x001F3 }, |
| 1214 { 0x001F4, 0x001F5 }, { 0x001F6, 0x00195 }, { 0x001F7, 0x001BF }, |
| 1215 { 0x001F8, 0x001F9 }, { 0x001FA, 0x001FB }, { 0x001FC, 0x001FD }, |
| 1216 { 0x001FE, 0x001FF }, { 0x00200, 0x00201 }, { 0x00202, 0x00203 }, |
| 1217 { 0x00204, 0x00205 }, { 0x00206, 0x00207 }, { 0x00208, 0x00209 }, |
| 1218 { 0x0020A, 0x0020B }, { 0x0020C, 0x0020D }, { 0x0020E, 0x0020F }, |
| 1219 { 0x00210, 0x00211 }, { 0x00212, 0x00213 }, { 0x00214, 0x00215 }, |
| 1220 { 0x00216, 0x00217 }, { 0x00218, 0x00219 }, { 0x0021A, 0x0021B }, |
| 1221 { 0x0021C, 0x0021D }, { 0x0021E, 0x0021F }, { 0x00220, 0x0019E }, |
| 1222 { 0x00222, 0x00223 }, { 0x00224, 0x00225 }, { 0x00226, 0x00227 }, |
| 1223 { 0x00228, 0x00229 }, { 0x0022A, 0x0022B }, { 0x0022C, 0x0022D }, |
| 1224 { 0x0022E, 0x0022F }, { 0x00230, 0x00231 }, { 0x00232, 0x00233 }, |
| 1225 /*{ 0x0023B, 0x0023C }, { 0x0023D, 0x0019A }, { 0x00241, 0x00294 }, */ |
| 1226 { 0x00386, 0x003AC }, { 0x00388, 0x003AD }, { 0x00389, 0x003AE }, |
| 1227 { 0x0038A, 0x003AF }, { 0x0038C, 0x003CC }, { 0x0038E, 0x003CD }, |
| 1228 { 0x0038F, 0x003CE }, { 0x00391, 0x003B1 }, { 0x00392, 0x003B2 }, |
| 1229 { 0x00393, 0x003B3 }, { 0x00394, 0x003B4 }, { 0x00395, 0x003B5 }, |
| 1230 { 0x00396, 0x003B6 }, { 0x00397, 0x003B7 }, { 0x00398, 0x003B8 }, |
| 1231 { 0x00399, 0x003B9 }, { 0x0039A, 0x003BA }, { 0x0039B, 0x003BB }, |
| 1232 { 0x0039C, 0x003BC }, { 0x0039D, 0x003BD }, { 0x0039E, 0x003BE }, |
| 1233 { 0x0039F, 0x003BF }, { 0x003A0, 0x003C0 }, { 0x003A1, 0x003C1 }, |
| 1234 { 0x003A3, 0x003C3 }, { 0x003A4, 0x003C4 }, { 0x003A5, 0x003C5 }, |
| 1235 { 0x003A6, 0x003C6 }, { 0x003A7, 0x003C7 }, { 0x003A8, 0x003C8 }, |
| 1236 { 0x003A9, 0x003C9 }, { 0x003AA, 0x003CA }, { 0x003AB, 0x003CB }, |
| 1237 { 0x003D8, 0x003D9 }, { 0x003DA, 0x003DB }, { 0x003DC, 0x003DD }, |
| 1238 { 0x003DE, 0x003DF }, { 0x003E0, 0x003E1 }, { 0x003E2, 0x003E3 }, |
| 1239 { 0x003E4, 0x003E5 }, { 0x003E6, 0x003E7 }, { 0x003E8, 0x003E9 }, |
| 1240 { 0x003EA, 0x003EB }, { 0x003EC, 0x003ED }, { 0x003EE, 0x003EF }, |
| 1241 { 0x003F4, 0x003B8 }, { 0x003F7, 0x003F8 }, { 0x003F9, 0x003F2 }, |
| 1242 { 0x003FA, 0x003FB }, { 0x00400, 0x00450 }, { 0x00401, 0x00451 }, |
| 1243 { 0x00402, 0x00452 }, { 0x00403, 0x00453 }, { 0x00404, 0x00454 }, |
| 1244 { 0x00405, 0x00455 }, { 0x00406, 0x00456 }, { 0x00407, 0x00457 }, |
| 1245 { 0x00408, 0x00458 }, { 0x00409, 0x00459 }, { 0x0040A, 0x0045A }, |
| 1246 { 0x0040B, 0x0045B }, { 0x0040C, 0x0045C }, { 0x0040D, 0x0045D }, |
| 1247 { 0x0040E, 0x0045E }, { 0x0040F, 0x0045F }, { 0x00410, 0x00430 }, |
| 1248 { 0x00411, 0x00431 }, { 0x00412, 0x00432 }, { 0x00413, 0x00433 }, |
| 1249 { 0x00414, 0x00434 }, { 0x00415, 0x00435 }, { 0x00416, 0x00436 }, |
| 1250 { 0x00417, 0x00437 }, { 0x00418, 0x00438 }, { 0x00419, 0x00439 }, |
| 1251 { 0x0041A, 0x0043A }, { 0x0041B, 0x0043B }, { 0x0041C, 0x0043C }, |
| 1252 { 0x0041D, 0x0043D }, { 0x0041E, 0x0043E }, { 0x0041F, 0x0043F }, |
| 1253 { 0x00420, 0x00440 }, { 0x00421, 0x00441 }, { 0x00422, 0x00442 }, |
| 1254 { 0x00423, 0x00443 }, { 0x00424, 0x00444 }, { 0x00425, 0x00445 }, |
| 1255 { 0x00426, 0x00446 }, { 0x00427, 0x00447 }, { 0x00428, 0x00448 }, |
| 1256 { 0x00429, 0x00449 }, { 0x0042A, 0x0044A }, { 0x0042B, 0x0044B }, |
| 1257 { 0x0042C, 0x0044C }, { 0x0042D, 0x0044D }, { 0x0042E, 0x0044E }, |
| 1258 { 0x0042F, 0x0044F }, { 0x00460, 0x00461 }, { 0x00462, 0x00463 }, |
| 1259 { 0x00464, 0x00465 }, { 0x00466, 0x00467 }, { 0x00468, 0x00469 }, |
| 1260 { 0x0046A, 0x0046B }, { 0x0046C, 0x0046D }, { 0x0046E, 0x0046F }, |
| 1261 { 0x00470, 0x00471 }, { 0x00472, 0x00473 }, { 0x00474, 0x00475 }, |
| 1262 { 0x00476, 0x00477 }, { 0x00478, 0x00479 }, { 0x0047A, 0x0047B }, |
| 1263 { 0x0047C, 0x0047D }, { 0x0047E, 0x0047F }, { 0x00480, 0x00481 }, |
| 1264 { 0x0048A, 0x0048B }, { 0x0048C, 0x0048D }, { 0x0048E, 0x0048F }, |
| 1265 { 0x00490, 0x00491 }, { 0x00492, 0x00493 }, { 0x00494, 0x00495 }, |
| 1266 { 0x00496, 0x00497 }, { 0x00498, 0x00499 }, { 0x0049A, 0x0049B }, |
| 1267 { 0x0049C, 0x0049D }, { 0x0049E, 0x0049F }, { 0x004A0, 0x004A1 }, |
| 1268 { 0x004A2, 0x004A3 }, { 0x004A4, 0x004A5 }, { 0x004A6, 0x004A7 }, |
| 1269 { 0x004A8, 0x004A9 }, { 0x004AA, 0x004AB }, { 0x004AC, 0x004AD }, |
| 1270 { 0x004AE, 0x004AF }, { 0x004B0, 0x004B1 }, { 0x004B2, 0x004B3 }, |
| 1271 { 0x004B4, 0x004B5 }, { 0x004B6, 0x004B7 }, { 0x004B8, 0x004B9 }, |
| 1272 { 0x004BA, 0x004BB }, { 0x004BC, 0x004BD }, { 0x004BE, 0x004BF }, |
| 1273 { 0x004C1, 0x004C2 }, { 0x004C3, 0x004C4 }, { 0x004C5, 0x004C6 }, |
| 1274 { 0x004C7, 0x004C8 }, { 0x004C9, 0x004CA }, { 0x004CB, 0x004CC }, |
| 1275 { 0x004CD, 0x004CE }, { 0x004D0, 0x004D1 }, { 0x004D2, 0x004D3 }, |
| 1276 { 0x004D4, 0x004D5 }, { 0x004D6, 0x004D7 }, { 0x004D8, 0x004D9 }, |
| 1277 { 0x004DA, 0x004DB }, { 0x004DC, 0x004DD }, { 0x004DE, 0x004DF }, |
| 1278 { 0x004E0, 0x004E1 }, { 0x004E2, 0x004E3 }, { 0x004E4, 0x004E5 }, |
| 1279 { 0x004E6, 0x004E7 }, { 0x004E8, 0x004E9 }, { 0x004EA, 0x004EB }, |
| 1280 { 0x004EC, 0x004ED }, { 0x004EE, 0x004EF }, { 0x004F0, 0x004F1 }, |
| 1281 { 0x004F2, 0x004F3 }, { 0x004F4, 0x004F5 }, /*{ 0x004F6, 0x004F7 }, */ |
| 1282 { 0x004F8, 0x004F9 }, { 0x00500, 0x00501 }, { 0x00502, 0x00503 }, |
| 1283 { 0x00504, 0x00505 }, { 0x00506, 0x00507 }, { 0x00508, 0x00509 }, |
| 1284 { 0x0050A, 0x0050B }, { 0x0050C, 0x0050D }, { 0x0050E, 0x0050F }, |
| 1285 { 0x00531, 0x00561 }, { 0x00532, 0x00562 }, { 0x00533, 0x00563 }, |
| 1286 { 0x00534, 0x00564 }, { 0x00535, 0x00565 }, { 0x00536, 0x00566 }, |
| 1287 { 0x00537, 0x00567 }, { 0x00538, 0x00568 }, { 0x00539, 0x00569 }, |
| 1288 { 0x0053A, 0x0056A }, { 0x0053B, 0x0056B }, { 0x0053C, 0x0056C }, |
| 1289 { 0x0053D, 0x0056D }, { 0x0053E, 0x0056E }, { 0x0053F, 0x0056F }, |
| 1290 { 0x00540, 0x00570 }, { 0x00541, 0x00571 }, { 0x00542, 0x00572 }, |
| 1291 { 0x00543, 0x00573 }, { 0x00544, 0x00574 }, { 0x00545, 0x00575 }, |
| 1292 { 0x00546, 0x00576 }, { 0x00547, 0x00577 }, { 0x00548, 0x00578 }, |
| 1293 { 0x00549, 0x00579 }, { 0x0054A, 0x0057A }, { 0x0054B, 0x0057B }, |
| 1294 { 0x0054C, 0x0057C }, { 0x0054D, 0x0057D }, { 0x0054E, 0x0057E }, |
| 1295 { 0x0054F, 0x0057F }, { 0x00550, 0x00580 }, { 0x00551, 0x00581 }, |
| 1296 { 0x00552, 0x00582 }, { 0x00553, 0x00583 }, { 0x00554, 0x00584 }, |
| 1297 { 0x00555, 0x00585 }, { 0x00556, 0x00586 }, /*{ 0x010A0, 0x02D00 }, |
| 1298 { 0x010A1, 0x02D01 }, { 0x010A2, 0x02D02 }, { 0x010A3, 0x02D03 }, |
| 1299 { 0x010A4, 0x02D04 }, { 0x010A5, 0x02D05 }, { 0x010A6, 0x02D06 }, |
| 1300 { 0x010A7, 0x02D07 }, { 0x010A8, 0x02D08 }, { 0x010A9, 0x02D09 }, |
| 1301 { 0x010AA, 0x02D0A }, { 0x010AB, 0x02D0B }, { 0x010AC, 0x02D0C }, |
| 1302 { 0x010AD, 0x02D0D }, { 0x010AE, 0x02D0E }, { 0x010AF, 0x02D0F }, |
| 1303 { 0x010B0, 0x02D10 }, { 0x010B1, 0x02D11 }, { 0x010B2, 0x02D12 }, |
| 1304 { 0x010B3, 0x02D13 }, { 0x010B4, 0x02D14 }, { 0x010B5, 0x02D15 }, |
| 1305 { 0x010B6, 0x02D16 }, { 0x010B7, 0x02D17 }, { 0x010B8, 0x02D18 }, |
| 1306 { 0x010B9, 0x02D19 }, { 0x010BA, 0x02D1A }, { 0x010BB, 0x02D1B }, |
| 1307 { 0x010BC, 0x02D1C }, { 0x010BD, 0x02D1D }, { 0x010BE, 0x02D1E }, |
| 1308 { 0x010BF, 0x02D1F }, { 0x010C0, 0x02D20 }, { 0x010C1, 0x02D21 }, |
| 1309 { 0x010C2, 0x02D22 }, { 0x010C3, 0x02D23 }, { 0x010C4, 0x02D24 }, |
| 1310 { 0x010C5, 0x02D25 },*/ { 0x01E00, 0x01E01 }, { 0x01E02, 0x01E03 }, |
| 1311 { 0x01E04, 0x01E05 }, { 0x01E06, 0x01E07 }, { 0x01E08, 0x01E09 }, |
| 1312 { 0x01E0A, 0x01E0B }, { 0x01E0C, 0x01E0D }, { 0x01E0E, 0x01E0F }, |
| 1313 { 0x01E10, 0x01E11 }, { 0x01E12, 0x01E13 }, { 0x01E14, 0x01E15 }, |
| 1314 { 0x01E16, 0x01E17 }, { 0x01E18, 0x01E19 }, { 0x01E1A, 0x01E1B }, |
| 1315 { 0x01E1C, 0x01E1D }, { 0x01E1E, 0x01E1F }, { 0x01E20, 0x01E21 }, |
| 1316 { 0x01E22, 0x01E23 }, { 0x01E24, 0x01E25 }, { 0x01E26, 0x01E27 }, |
| 1317 { 0x01E28, 0x01E29 }, { 0x01E2A, 0x01E2B }, { 0x01E2C, 0x01E2D }, |
| 1318 { 0x01E2E, 0x01E2F }, { 0x01E30, 0x01E31 }, { 0x01E32, 0x01E33 }, |
| 1319 { 0x01E34, 0x01E35 }, { 0x01E36, 0x01E37 }, { 0x01E38, 0x01E39 }, |
| 1320 { 0x01E3A, 0x01E3B }, { 0x01E3C, 0x01E3D }, { 0x01E3E, 0x01E3F }, |
| 1321 { 0x01E40, 0x01E41 }, { 0x01E42, 0x01E43 }, { 0x01E44, 0x01E45 }, |
| 1322 { 0x01E46, 0x01E47 }, { 0x01E48, 0x01E49 }, { 0x01E4A, 0x01E4B }, |
| 1323 { 0x01E4C, 0x01E4D }, { 0x01E4E, 0x01E4F }, { 0x01E50, 0x01E51 }, |
| 1324 { 0x01E52, 0x01E53 }, { 0x01E54, 0x01E55 }, { 0x01E56, 0x01E57 }, |
| 1325 { 0x01E58, 0x01E59 }, { 0x01E5A, 0x01E5B }, { 0x01E5C, 0x01E5D }, |
| 1326 { 0x01E5E, 0x01E5F }, { 0x01E60, 0x01E61 }, { 0x01E62, 0x01E63 }, |
| 1327 { 0x01E64, 0x01E65 }, { 0x01E66, 0x01E67 }, { 0x01E68, 0x01E69 }, |
| 1328 { 0x01E6A, 0x01E6B }, { 0x01E6C, 0x01E6D }, { 0x01E6E, 0x01E6F }, |
| 1329 { 0x01E70, 0x01E71 }, { 0x01E72, 0x01E73 }, { 0x01E74, 0x01E75 }, |
| 1330 { 0x01E76, 0x01E77 }, { 0x01E78, 0x01E79 }, { 0x01E7A, 0x01E7B }, |
| 1331 { 0x01E7C, 0x01E7D }, { 0x01E7E, 0x01E7F }, { 0x01E80, 0x01E81 }, |
| 1332 { 0x01E82, 0x01E83 }, { 0x01E84, 0x01E85 }, { 0x01E86, 0x01E87 }, |
| 1333 { 0x01E88, 0x01E89 }, { 0x01E8A, 0x01E8B }, { 0x01E8C, 0x01E8D }, |
| 1334 { 0x01E8E, 0x01E8F }, { 0x01E90, 0x01E91 }, { 0x01E92, 0x01E93 }, |
| 1335 { 0x01E94, 0x01E95 }, { 0x01EA0, 0x01EA1 }, { 0x01EA2, 0x01EA3 }, |
| 1336 { 0x01EA4, 0x01EA5 }, { 0x01EA6, 0x01EA7 }, { 0x01EA8, 0x01EA9 }, |
| 1337 { 0x01EAA, 0x01EAB }, { 0x01EAC, 0x01EAD }, { 0x01EAE, 0x01EAF }, |
| 1338 { 0x01EB0, 0x01EB1 }, { 0x01EB2, 0x01EB3 }, { 0x01EB4, 0x01EB5 }, |
| 1339 { 0x01EB6, 0x01EB7 }, { 0x01EB8, 0x01EB9 }, { 0x01EBA, 0x01EBB }, |
| 1340 { 0x01EBC, 0x01EBD }, { 0x01EBE, 0x01EBF }, { 0x01EC0, 0x01EC1 }, |
| 1341 { 0x01EC2, 0x01EC3 }, { 0x01EC4, 0x01EC5 }, { 0x01EC6, 0x01EC7 }, |
| 1342 { 0x01EC8, 0x01EC9 }, { 0x01ECA, 0x01ECB }, { 0x01ECC, 0x01ECD }, |
| 1343 { 0x01ECE, 0x01ECF }, { 0x01ED0, 0x01ED1 }, { 0x01ED2, 0x01ED3 }, |
| 1344 { 0x01ED4, 0x01ED5 }, { 0x01ED6, 0x01ED7 }, { 0x01ED8, 0x01ED9 }, |
| 1345 { 0x01EDA, 0x01EDB }, { 0x01EDC, 0x01EDD }, { 0x01EDE, 0x01EDF }, |
| 1346 { 0x01EE0, 0x01EE1 }, { 0x01EE2, 0x01EE3 }, { 0x01EE4, 0x01EE5 }, |
| 1347 { 0x01EE6, 0x01EE7 }, { 0x01EE8, 0x01EE9 }, { 0x01EEA, 0x01EEB }, |
| 1348 { 0x01EEC, 0x01EED }, { 0x01EEE, 0x01EEF }, { 0x01EF0, 0x01EF1 }, |
| 1349 { 0x01EF2, 0x01EF3 }, { 0x01EF4, 0x01EF5 }, { 0x01EF6, 0x01EF7 }, |
| 1350 { 0x01EF8, 0x01EF9 }, { 0x01F08, 0x01F00 }, { 0x01F09, 0x01F01 }, |
| 1351 { 0x01F0A, 0x01F02 }, { 0x01F0B, 0x01F03 }, { 0x01F0C, 0x01F04 }, |
| 1352 { 0x01F0D, 0x01F05 }, { 0x01F0E, 0x01F06 }, { 0x01F0F, 0x01F07 }, |
| 1353 { 0x01F18, 0x01F10 }, { 0x01F19, 0x01F11 }, { 0x01F1A, 0x01F12 }, |
| 1354 { 0x01F1B, 0x01F13 }, { 0x01F1C, 0x01F14 }, { 0x01F1D, 0x01F15 }, |
| 1355 { 0x01F28, 0x01F20 }, { 0x01F29, 0x01F21 }, { 0x01F2A, 0x01F22 }, |
| 1356 { 0x01F2B, 0x01F23 }, { 0x01F2C, 0x01F24 }, { 0x01F2D, 0x01F25 }, |
| 1357 { 0x01F2E, 0x01F26 }, { 0x01F2F, 0x01F27 }, { 0x01F38, 0x01F30 }, |
| 1358 { 0x01F39, 0x01F31 }, { 0x01F3A, 0x01F32 }, { 0x01F3B, 0x01F33 }, |
| 1359 { 0x01F3C, 0x01F34 }, { 0x01F3D, 0x01F35 }, { 0x01F3E, 0x01F36 }, |
| 1360 { 0x01F3F, 0x01F37 }, { 0x01F48, 0x01F40 }, { 0x01F49, 0x01F41 }, |
| 1361 { 0x01F4A, 0x01F42 }, { 0x01F4B, 0x01F43 }, { 0x01F4C, 0x01F44 }, |
| 1362 { 0x01F4D, 0x01F45 }, { 0x01F59, 0x01F51 }, { 0x01F5B, 0x01F53 }, |
| 1363 { 0x01F5D, 0x01F55 }, { 0x01F5F, 0x01F57 }, { 0x01F68, 0x01F60 }, |
| 1364 { 0x01F69, 0x01F61 }, { 0x01F6A, 0x01F62 }, { 0x01F6B, 0x01F63 }, |
| 1365 { 0x01F6C, 0x01F64 }, { 0x01F6D, 0x01F65 }, { 0x01F6E, 0x01F66 }, |
| 1366 { 0x01F6F, 0x01F67 }, { 0x01F88, 0x01F80 }, { 0x01F89, 0x01F81 }, |
| 1367 { 0x01F8A, 0x01F82 }, { 0x01F8B, 0x01F83 }, { 0x01F8C, 0x01F84 }, |
| 1368 { 0x01F8D, 0x01F85 }, { 0x01F8E, 0x01F86 }, { 0x01F8F, 0x01F87 }, |
| 1369 { 0x01F98, 0x01F90 }, { 0x01F99, 0x01F91 }, { 0x01F9A, 0x01F92 }, |
| 1370 { 0x01F9B, 0x01F93 }, { 0x01F9C, 0x01F94 }, { 0x01F9D, 0x01F95 }, |
| 1371 { 0x01F9E, 0x01F96 }, { 0x01F9F, 0x01F97 }, { 0x01FA8, 0x01FA0 }, |
| 1372 { 0x01FA9, 0x01FA1 }, { 0x01FAA, 0x01FA2 }, { 0x01FAB, 0x01FA3 }, |
| 1373 { 0x01FAC, 0x01FA4 }, { 0x01FAD, 0x01FA5 }, { 0x01FAE, 0x01FA6 }, |
| 1374 { 0x01FAF, 0x01FA7 }, { 0x01FB8, 0x01FB0 }, { 0x01FB9, 0x01FB1 }, |
| 1375 { 0x01FBA, 0x01F70 }, { 0x01FBB, 0x01F71 }, { 0x01FBC, 0x01FB3 }, |
| 1376 { 0x01FC8, 0x01F72 }, { 0x01FC9, 0x01F73 }, { 0x01FCA, 0x01F74 }, |
| 1377 { 0x01FCB, 0x01F75 }, { 0x01FCC, 0x01FC3 }, { 0x01FD8, 0x01FD0 }, |
| 1378 { 0x01FD9, 0x01FD1 }, { 0x01FDA, 0x01F76 }, { 0x01FDB, 0x01F77 }, |
| 1379 { 0x01FE8, 0x01FE0 }, { 0x01FE9, 0x01FE1 }, { 0x01FEA, 0x01F7A }, |
| 1380 { 0x01FEB, 0x01F7B }, { 0x01FEC, 0x01FE5 }, { 0x01FF8, 0x01F78 }, |
| 1381 { 0x01FF9, 0x01F79 }, { 0x01FFA, 0x01F7C }, { 0x01FFB, 0x01F7D }, |
| 1382 { 0x01FFC, 0x01FF3 }, { 0x02126, 0x003C9 }, { 0x0212A, 0x0006B }, |
| 1383 { 0x0212B, 0x000E5 }, { 0x02160, 0x02170 }, { 0x02161, 0x02171 }, |
| 1384 { 0x02162, 0x02172 }, { 0x02163, 0x02173 }, { 0x02164, 0x02174 }, |
| 1385 { 0x02165, 0x02175 }, { 0x02166, 0x02176 }, { 0x02167, 0x02177 }, |
| 1386 { 0x02168, 0x02178 }, { 0x02169, 0x02179 }, { 0x0216A, 0x0217A }, |
| 1387 { 0x0216B, 0x0217B }, { 0x0216C, 0x0217C }, { 0x0216D, 0x0217D }, |
| 1388 { 0x0216E, 0x0217E }, { 0x0216F, 0x0217F }, { 0x024B6, 0x024D0 }, |
| 1389 { 0x024B7, 0x024D1 }, { 0x024B8, 0x024D2 }, { 0x024B9, 0x024D3 }, |
| 1390 { 0x024BA, 0x024D4 }, { 0x024BB, 0x024D5 }, { 0x024BC, 0x024D6 }, |
| 1391 { 0x024BD, 0x024D7 }, { 0x024BE, 0x024D8 }, { 0x024BF, 0x024D9 }, |
| 1392 { 0x024C0, 0x024DA }, { 0x024C1, 0x024DB }, { 0x024C2, 0x024DC }, |
| 1393 { 0x024C3, 0x024DD }, { 0x024C4, 0x024DE }, { 0x024C5, 0x024DF }, |
| 1394 { 0x024C6, 0x024E0 }, { 0x024C7, 0x024E1 }, { 0x024C8, 0x024E2 }, |
| 1395 { 0x024C9, 0x024E3 }, { 0x024CA, 0x024E4 }, { 0x024CB, 0x024E5 }, |
| 1396 { 0x024CC, 0x024E6 }, { 0x024CD, 0x024E7 }, { 0x024CE, 0x024E8 }, |
| 1397 { 0x024CF, 0x024E9 }, /*{ 0x02C00, 0x02C30 }, { 0x02C01, 0x02C31 }, |
| 1398 { 0x02C02, 0x02C32 }, { 0x02C03, 0x02C33 }, { 0x02C04, 0x02C34 }, |
| 1399 { 0x02C05, 0x02C35 }, { 0x02C06, 0x02C36 }, { 0x02C07, 0x02C37 }, |
| 1400 { 0x02C08, 0x02C38 }, { 0x02C09, 0x02C39 }, { 0x02C0A, 0x02C3A }, |
| 1401 { 0x02C0B, 0x02C3B }, { 0x02C0C, 0x02C3C }, { 0x02C0D, 0x02C3D }, |
| 1402 { 0x02C0E, 0x02C3E }, { 0x02C0F, 0x02C3F }, { 0x02C10, 0x02C40 }, |
| 1403 { 0x02C11, 0x02C41 }, { 0x02C12, 0x02C42 }, { 0x02C13, 0x02C43 }, |
| 1404 { 0x02C14, 0x02C44 }, { 0x02C15, 0x02C45 }, { 0x02C16, 0x02C46 }, |
| 1405 { 0x02C17, 0x02C47 }, { 0x02C18, 0x02C48 }, { 0x02C19, 0x02C49 }, |
| 1406 { 0x02C1A, 0x02C4A }, { 0x02C1B, 0x02C4B }, { 0x02C1C, 0x02C4C }, |
| 1407 { 0x02C1D, 0x02C4D }, { 0x02C1E, 0x02C4E }, { 0x02C1F, 0x02C4F }, |
| 1408 { 0x02C20, 0x02C50 }, { 0x02C21, 0x02C51 }, { 0x02C22, 0x02C52 }, |
| 1409 { 0x02C23, 0x02C53 }, { 0x02C24, 0x02C54 }, { 0x02C25, 0x02C55 }, |
| 1410 { 0x02C26, 0x02C56 }, { 0x02C27, 0x02C57 }, { 0x02C28, 0x02C58 }, |
| 1411 { 0x02C29, 0x02C59 }, { 0x02C2A, 0x02C5A }, { 0x02C2B, 0x02C5B }, |
| 1412 { 0x02C2C, 0x02C5C }, { 0x02C2D, 0x02C5D }, { 0x02C2E, 0x02C5E }, |
| 1413 { 0x02C80, 0x02C81 }, { 0x02C82, 0x02C83 }, { 0x02C84, 0x02C85 }, |
| 1414 { 0x02C86, 0x02C87 }, { 0x02C88, 0x02C89 }, { 0x02C8A, 0x02C8B }, |
| 1415 { 0x02C8C, 0x02C8D }, { 0x02C8E, 0x02C8F }, { 0x02C90, 0x02C91 }, |
| 1416 { 0x02C92, 0x02C93 }, { 0x02C94, 0x02C95 }, { 0x02C96, 0x02C97 }, |
| 1417 { 0x02C98, 0x02C99 }, { 0x02C9A, 0x02C9B }, { 0x02C9C, 0x02C9D }, |
| 1418 { 0x02C9E, 0x02C9F }, { 0x02CA0, 0x02CA1 }, { 0x02CA2, 0x02CA3 }, |
| 1419 { 0x02CA4, 0x02CA5 }, { 0x02CA6, 0x02CA7 }, { 0x02CA8, 0x02CA9 }, |
| 1420 { 0x02CAA, 0x02CAB }, { 0x02CAC, 0x02CAD }, { 0x02CAE, 0x02CAF }, |
| 1421 { 0x02CB0, 0x02CB1 }, { 0x02CB2, 0x02CB3 }, { 0x02CB4, 0x02CB5 }, |
| 1422 { 0x02CB6, 0x02CB7 }, { 0x02CB8, 0x02CB9 }, { 0x02CBA, 0x02CBB }, |
| 1423 { 0x02CBC, 0x02CBD }, { 0x02CBE, 0x02CBF }, { 0x02CC0, 0x02CC1 }, |
| 1424 { 0x02CC2, 0x02CC3 }, { 0x02CC4, 0x02CC5 }, { 0x02CC6, 0x02CC7 }, |
| 1425 { 0x02CC8, 0x02CC9 }, { 0x02CCA, 0x02CCB }, { 0x02CCC, 0x02CCD }, |
| 1426 { 0x02CCE, 0x02CCF }, { 0x02CD0, 0x02CD1 }, { 0x02CD2, 0x02CD3 }, |
| 1427 { 0x02CD4, 0x02CD5 }, { 0x02CD6, 0x02CD7 }, { 0x02CD8, 0x02CD9 }, |
| 1428 { 0x02CDA, 0x02CDB }, { 0x02CDC, 0x02CDD }, { 0x02CDE, 0x02CDF }, |
| 1429 { 0x02CE0, 0x02CE1 }, { 0x02CE2, 0x02CE3 },*/ { 0x0FF21, 0x0FF41 }, |
| 1430 { 0x0FF22, 0x0FF42 }, { 0x0FF23, 0x0FF43 }, { 0x0FF24, 0x0FF44 }, |
| 1431 { 0x0FF25, 0x0FF45 }, { 0x0FF26, 0x0FF46 }, { 0x0FF27, 0x0FF47 }, |
| 1432 { 0x0FF28, 0x0FF48 }, { 0x0FF29, 0x0FF49 }, { 0x0FF2A, 0x0FF4A }, |
| 1433 { 0x0FF2B, 0x0FF4B }, { 0x0FF2C, 0x0FF4C }, { 0x0FF2D, 0x0FF4D }, |
| 1434 { 0x0FF2E, 0x0FF4E }, { 0x0FF2F, 0x0FF4F }, { 0x0FF30, 0x0FF50 }, |
| 1435 { 0x0FF31, 0x0FF51 }, { 0x0FF32, 0x0FF52 }, { 0x0FF33, 0x0FF53 }, |
| 1436 { 0x0FF34, 0x0FF54 }, { 0x0FF35, 0x0FF55 }, { 0x0FF36, 0x0FF56 }, |
| 1437 { 0x0FF37, 0x0FF57 }, { 0x0FF38, 0x0FF58 }, { 0x0FF39, 0x0FF59 }, |
| 1438 // the following commented out ones fail on OS X 10.5 Leopard |
| 1439 { 0x0FF3A, 0x0FF5A }/*, { 0x10400, 0x10428 }, { 0x10401, 0x10429 }, |
| 1440 { 0x10402, 0x1042A }, { 0x10403, 0x1042B }, { 0x10404, 0x1042C }, |
| 1441 { 0x10405, 0x1042D }, { 0x10406, 0x1042E }, { 0x10407, 0x1042F }, |
| 1442 { 0x10408, 0x10430 }, { 0x10409, 0x10431 }, { 0x1040A, 0x10432 }, |
| 1443 { 0x1040B, 0x10433 }, { 0x1040C, 0x10434 }, { 0x1040D, 0x10435 }, |
| 1444 { 0x1040E, 0x10436 }, { 0x1040F, 0x10437 }, { 0x10410, 0x10438 }, |
| 1445 { 0x10411, 0x10439 }, { 0x10412, 0x1043A }, { 0x10413, 0x1043B }, |
| 1446 { 0x10414, 0x1043C }, { 0x10415, 0x1043D }, { 0x10416, 0x1043E }, |
| 1447 { 0x10417, 0x1043F }, { 0x10418, 0x10440 }, { 0x10419, 0x10441 }, |
| 1448 { 0x1041A, 0x10442 }, { 0x1041B, 0x10443 }, { 0x1041C, 0x10444 }, |
| 1449 { 0x1041D, 0x10445 }, { 0x1041E, 0x10446 }, { 0x1041F, 0x10447 }, |
| 1450 { 0x10420, 0x10448 }, { 0x10421, 0x10449 }, { 0x10422, 0x1044A }, |
| 1451 { 0x10423, 0x1044B }, { 0x10424, 0x1044C }, { 0x10425, 0x1044D }, |
| 1452 { 0x10426, 0x1044E }, { 0x10427, 0x1044F } */ |
| 1453 }; |
| 1454 unsigned char utf8str_upper[5]; |
| 1455 unsigned char utf8str_lower[5]; |
| 1456 for (int i = 0; i < ARRAYSIZE(kUpperToLowerMap); i++) { |
| 1457 int len; |
| 1458 len = UTF32ToUTF8(kUpperToLowerMap[i].upper, utf8str_upper); |
| 1459 CHECK_NE(0, len); |
| 1460 utf8str_upper[len] = '\0'; |
| 1461 len = UTF32ToUTF8(kUpperToLowerMap[i].lower, utf8str_lower); |
| 1462 CHECK_NE(0, len); |
| 1463 utf8str_lower[len] = '\0'; |
| 1464 int result = ComparePathNames( |
| 1465 UTF8ToPathStringQuick(reinterpret_cast<char*>(utf8str_upper)), |
| 1466 UTF8ToPathStringQuick(reinterpret_cast<char*>(utf8str_lower))); |
| 1467 if (0 != result) { |
| 1468 // This ugly strstream works around an issue where using << hex on the |
| 1469 // stream for ADD_FAILURE produces "true" and "false" in the output. |
| 1470 strstream msg; |
| 1471 msg << "ComparePathNames(0x" << hex << kUpperToLowerMap[i].upper |
| 1472 << ", 0x" << hex << kUpperToLowerMap[i].lower |
| 1473 << ") returned " << dec << result << "; expected 0" << '\0'; |
| 1474 ADD_FAILURE() << msg.str(); |
| 1475 } |
| 1476 } |
| 1477 #endif // not defined OS_WINDOWS |
| 1478 } |
| 1479 |
| 1480 #ifdef OS_WINDOWS |
| 1481 TEST(Syncable, PathNameMatch) { |
| 1482 // basic stuff, not too many otherwise we're testing the os. |
| 1483 EXPECT_TRUE(PathNameMatch(PSTR("bob"), PSTR("bob"))); |
| 1484 EXPECT_FALSE(PathNameMatch(PSTR("bob"), PSTR("fred"))); |
| 1485 // Test our ; extension. |
| 1486 EXPECT_TRUE(PathNameMatch(PSTR("bo;b"), PSTR("bo;b"))); |
| 1487 EXPECT_TRUE(PathNameMatch(PSTR("bo;b"), PSTR("bo*"))); |
| 1488 EXPECT_FALSE(PathNameMatch(PSTR("bo;b"), PSTR("co;b"))); |
| 1489 EXPECT_FALSE(PathNameMatch(PSTR("bo;b"), PSTR("co*"))); |
| 1490 // Test our fixes for prepended spaces. |
| 1491 EXPECT_TRUE(PathNameMatch(PSTR(" bob"), PSTR(" bo*"))); |
| 1492 EXPECT_TRUE(PathNameMatch(PSTR(" bob"), PSTR(" bob"))); |
| 1493 EXPECT_FALSE(PathNameMatch(PSTR("bob"), PSTR(" bob"))); |
| 1494 EXPECT_FALSE(PathNameMatch(PSTR(" bob"), PSTR("bob"))); |
| 1495 // Combo test |
| 1496 EXPECT_TRUE(PathNameMatch(PSTR(" b;ob"), PSTR(" b;o*"))); |
| 1497 EXPECT_TRUE(PathNameMatch(PSTR(" b;ob"), PSTR(" b;ob"))); |
| 1498 EXPECT_FALSE(PathNameMatch(PSTR("b;ob"), PSTR(" b;ob"))); |
| 1499 EXPECT_FALSE(PathNameMatch(PSTR(" b;ob"), PSTR("b;ob"))); |
| 1500 // other whitespace should give no matches. |
| 1501 EXPECT_FALSE(PathNameMatch(PSTR("bob"), PSTR("\tbob"))); |
| 1502 } |
| 1503 #endif // OS_WINDOWS |
| 1504 |
| 1505 } // namespace |
| 1506 |
| 1507 void FakeSync(MutableEntry* e, const char* fake_id) { |
| 1508 e->Put(IS_UNSYNCED, false); |
| 1509 e->Put(BASE_VERSION, 2); |
| 1510 e->Put(ID, Id::CreateFromServerId(fake_id)); |
| 1511 } |
| 1512 |
| 1513 TEST_F(SyncableDirectoryTest, Bug1509232) { |
| 1514 const PathString a = PSTR("alpha"); |
| 1515 |
| 1516 CreateEntry(a, dir_.get()->NextId()); |
| 1517 { |
| 1518 WriteTransaction trans(dir_.get(), UNITTEST, __FILE__, __LINE__); |
| 1519 MutableEntry e(&trans, GET_BY_PATH, a); |
| 1520 ASSERT_TRUE(e.good()); |
| 1521 ExtendedAttributeKey key(e.Get(META_HANDLE), PSTR("resourcefork")); |
| 1522 MutableExtendedAttribute ext(&trans, CREATE, key); |
| 1523 ASSERT_TRUE(ext.good()); |
| 1524 const char value[] = "stuff"; |
| 1525 Blob value_blob(value, value + ARRAYSIZE(value)); |
| 1526 ext.mutable_value()->swap(value_blob); |
| 1527 ext.delete_attribute(); |
| 1528 } |
| 1529 // This call to SaveChanges used to CHECK fail. |
| 1530 dir_.get()->SaveChanges(); |
| 1531 } |
| 1532 |
| 1533 } // namespace syncable |
| 1534 |
| 1535 #ifdef OS_WINDOWS |
| 1536 class LocalModule : public CAtlExeModuleT<LocalModule> { }; |
| 1537 LocalModule module_; |
| 1538 |
| 1539 int main(int argc, char* argv[]) { |
| 1540 testing::InitGoogleTest(&argc, argv); |
| 1541 |
| 1542 // TODO(chron) Add method to change random seed. |
| 1543 const int32 test_random_seed = time(NULL); |
| 1544 cout << "Random seed: " << test_random_seed << endl; |
| 1545 LOG(INFO) << "Random seed: " << test_random_seed << endl; |
| 1546 srand(test_random_seed); |
| 1547 |
| 1548 // Necessary for NewCallback, scoped to main |
| 1549 base::AtExitManager at_exit_manager; |
| 1550 |
| 1551 int result = RUN_ALL_TESTS(); |
| 1552 return result; |
| 1553 } |
| 1554 #endif |
OLD | NEW |