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 "sync/internal_api/public/change_record.h" 6 7 #include "base/memory/scoped_ptr.h" 8 #include "base/strings/string_number_conversions.h" 9 #include "base/test/values_test_util.h" 10 #include "base/values.h" 11 #include "sync/protocol/extension_specifics.pb.h" 12 #include "sync/protocol/proto_value_conversions.h" 13 #include "sync/protocol/sync.pb.h" 14 #include "testing/gmock/include/gmock/gmock.h" 15 #include "testing/gtest/include/gtest/gtest.h" 16 17 namespace syncer { 18 namespace { 19 20 using base::ExpectDictDictionaryValue; 21 using base::ExpectDictStringValue; 22 using testing::Invoke; 23 using testing::StrictMock; 24 25 class ChangeRecordTest : public testing::Test {}; 26 27 void ExpectChangeRecordActionValue(ChangeRecord::Action expected_value, 28 const base::DictionaryValue& value, 29 const std::string& key) { 30 std::string str_value; 31 EXPECT_TRUE(value.GetString(key, &str_value)); 32 switch (expected_value) { 33 case ChangeRecord::ACTION_ADD: 34 EXPECT_EQ("Add", str_value); 35 break; 36 case ChangeRecord::ACTION_UPDATE: 37 EXPECT_EQ("Update", str_value); 38 break; 39 case ChangeRecord::ACTION_DELETE: 40 EXPECT_EQ("Delete", str_value); 41 break; 42 default: 43 NOTREACHED(); 44 break; 45 } 46 } 47 48 void CheckChangeRecordValue( 49 const ChangeRecord& record, 50 const base::DictionaryValue& value) { 51 ExpectChangeRecordActionValue(record.action, value, "action"); 52 ExpectDictStringValue(base::Int64ToString(record.id), value, "id"); 53 if (record.action == ChangeRecord::ACTION_DELETE) { 54 scoped_ptr<base::DictionaryValue> expected_extra_value; 55 if (record.extra.get()) { 56 expected_extra_value.reset(record.extra->ToValue()); 57 } 58 const base::Value* extra_value = NULL; 59 EXPECT_EQ(record.extra.get() != NULL, 60 value.Get("extra", &extra_value)); 61 EXPECT_TRUE(base::Value::Equals(extra_value, expected_extra_value.get())); 62 63 scoped_ptr<base::DictionaryValue> expected_specifics_value( 64 EntitySpecificsToValue(record.specifics)); 65 ExpectDictDictionaryValue(*expected_specifics_value, 66 value, "specifics"); 67 } 68 } 69 70 class MockExtraChangeRecordData 71 : public ExtraPasswordChangeRecordData { 72 public: 73 MOCK_CONST_METHOD0(ToValue, base::DictionaryValue*()); 74 }; 75 76 TEST_F(ChangeRecordTest, ChangeRecordToValue) { 77 sync_pb::EntitySpecifics old_specifics; 78 old_specifics.mutable_extension()->set_id("old"); 79 sync_pb::EntitySpecifics new_specifics; 80 old_specifics.mutable_extension()->set_id("new"); 81 82 const int64 kTestId = 5; 83 84 // Add 85 { 86 ChangeRecord record; 87 record.action = ChangeRecord::ACTION_ADD; 88 record.id = kTestId; 89 record.specifics = old_specifics; 90 record.extra.reset(new StrictMock<MockExtraChangeRecordData>()); 91 scoped_ptr<base::DictionaryValue> value(record.ToValue()); 92 CheckChangeRecordValue(record, *value); 93 } 94 95 // Update 96 { 97 ChangeRecord record; 98 record.action = ChangeRecord::ACTION_UPDATE; 99 record.id = kTestId; 100 record.specifics = old_specifics; 101 record.extra.reset(new StrictMock<MockExtraChangeRecordData>()); 102 scoped_ptr<base::DictionaryValue> value(record.ToValue()); 103 CheckChangeRecordValue(record, *value); 104 } 105 106 // Delete (no extra) 107 { 108 ChangeRecord record; 109 record.action = ChangeRecord::ACTION_DELETE; 110 record.id = kTestId; 111 record.specifics = old_specifics; 112 scoped_ptr<base::DictionaryValue> value(record.ToValue()); 113 CheckChangeRecordValue(record, *value); 114 } 115 116 // Delete (with extra) 117 { 118 ChangeRecord record; 119 record.action = ChangeRecord::ACTION_DELETE; 120 record.id = kTestId; 121 record.specifics = old_specifics; 122 123 base::DictionaryValue extra_value; 124 extra_value.SetString("foo", "bar"); 125 scoped_ptr<StrictMock<MockExtraChangeRecordData> > extra( 126 new StrictMock<MockExtraChangeRecordData>()); 127 EXPECT_CALL(*extra, ToValue()).Times(2).WillRepeatedly( 128 Invoke(&extra_value, &base::DictionaryValue::DeepCopy)); 129 130 record.extra.reset(extra.release()); 131 scoped_ptr<base::DictionaryValue> value(record.ToValue()); 132 CheckChangeRecordValue(record, *value); 133 } 134 } 135 136 } // namespace 137 } // namespace syncer 138