web_data_service_unittest.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 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 <string> 6#include <vector> 7 8#include "base/basictypes.h" 9#include "base/file_util.h" 10#include "base/message_loop.h" 11#include "base/path_service.h" 12#include "base/ref_counted.h" 13#include "base/scoped_ptr.h" 14#include "base/scoped_vector.h" 15#include "base/stl_util-inl.h" 16#include "base/string16.h" 17#include "base/string_util.h" 18#include "base/time.h" 19#include "base/utf_string_conversions.h" 20#include "base/waitable_event.h" 21#include "chrome/browser/autofill/autofill_profile.h" 22#include "chrome/browser/autofill/credit_card.h" 23#include "chrome/browser/browser_thread.h" 24#include "chrome/browser/webdata/autofill_change.h" 25#include "chrome/browser/webdata/autofill_entry.h" 26#include "chrome/browser/webdata/web_data_service.h" 27#include "chrome/browser/webdata/web_data_service_test_util.h" 28#include "chrome/common/chrome_paths.h" 29#include "chrome/common/guid.h" 30#include "chrome/common/notification_details.h" 31#include "chrome/common/notification_service.h" 32#include "chrome/common/notification_type.h" 33#include "chrome/test/thread_observer_helper.h" 34#include "testing/gmock/include/gmock/gmock.h" 35#include "testing/gtest/include/gtest/gtest.h" 36#include "webkit/glue/form_field.h" 37 38using base::Time; 39using base::TimeDelta; 40using base::WaitableEvent; 41using testing::_; 42using testing::DoDefault; 43using testing::ElementsAreArray; 44using testing::Pointee; 45using testing::Property; 46 47typedef std::vector<AutofillChange> AutofillChangeList; 48 49static const int kWebDataServiceTimeoutSeconds = 8; 50 51ACTION_P(SignalEvent, event) { 52 event->Signal(); 53} 54 55class AutofillDBThreadObserverHelper : public DBThreadObserverHelper { 56 protected: 57 virtual void RegisterObservers() { 58 registrar_.Add(&observer_, 59 NotificationType::AUTOFILL_ENTRIES_CHANGED, 60 NotificationService::AllSources()); 61 registrar_.Add(&observer_, 62 NotificationType::AUTOFILL_PROFILE_CHANGED, 63 NotificationService::AllSources()); 64 registrar_.Add(&observer_, 65 NotificationType::AUTOFILL_PROFILE_CHANGED_GUID, 66 NotificationService::AllSources()); 67 registrar_.Add(&observer_, 68 NotificationType::AUTOFILL_CREDIT_CARD_CHANGED, 69 NotificationService::AllSources()); 70 registrar_.Add(&observer_, 71 NotificationType::AUTOFILL_CREDIT_CARD_CHANGED_GUID, 72 NotificationService::AllSources()); 73 } 74}; 75 76class WebDataServiceTest : public testing::Test { 77 public: 78 WebDataServiceTest() 79 : ui_thread_(BrowserThread::UI, &message_loop_), 80 db_thread_(BrowserThread::DB) {} 81 82 protected: 83 virtual void SetUp() { 84 db_thread_.Start(); 85 86 PathService::Get(chrome::DIR_TEST_DATA, &profile_dir_); 87 const std::string test_profile = "WebDataServiceTest"; 88 profile_dir_ = profile_dir_.AppendASCII(test_profile); 89 file_util::Delete(profile_dir_, true); 90 file_util::CreateDirectory(profile_dir_); 91 wds_ = new WebDataService(); 92 wds_->Init(profile_dir_); 93 } 94 95 virtual void TearDown() { 96 if (wds_.get()) 97 wds_->Shutdown(); 98 file_util::Delete(profile_dir_, true); 99 100 db_thread_.Stop(); 101 MessageLoop::current()->PostTask(FROM_HERE, new MessageLoop::QuitTask); 102 MessageLoop::current()->Run(); 103 } 104 105 MessageLoopForUI message_loop_; 106 BrowserThread ui_thread_; 107 BrowserThread db_thread_; 108 FilePath profile_dir_; 109 scoped_refptr<WebDataService> wds_; 110}; 111 112class WebDataServiceAutofillTest : public WebDataServiceTest { 113 public: 114 WebDataServiceAutofillTest() 115 : WebDataServiceTest(), 116 unique_id1_(1), 117 unique_id2_(2), 118 test_timeout_(TimeDelta::FromSeconds(kWebDataServiceTimeoutSeconds)), 119 done_event_(false, false) {} 120 121 protected: 122 virtual void SetUp() { 123 WebDataServiceTest::SetUp(); 124 name1_ = ASCIIToUTF16("name1"); 125 name2_ = ASCIIToUTF16("name2"); 126 value1_ = ASCIIToUTF16("value1"); 127 value2_ = ASCIIToUTF16("value2"); 128 observer_helper_ = new AutofillDBThreadObserverHelper(); 129 observer_helper_->Init(); 130 } 131 132 virtual void TearDown() { 133 // Release this first so it can get destructed on the db thread. 134 observer_helper_ = NULL; 135 WebDataServiceTest::TearDown(); 136 } 137 138 void AppendFormField(const string16& name, 139 const string16& value, 140 std::vector<webkit_glue::FormField>* form_fields) { 141 form_fields->push_back( 142 webkit_glue::FormField(string16(), 143 name, 144 value, 145 string16(), 146 0, 147 false)); 148 } 149 150 string16 name1_; 151 string16 name2_; 152 string16 value1_; 153 string16 value2_; 154 int unique_id1_, unique_id2_; 155 const TimeDelta test_timeout_; 156 scoped_refptr<AutofillDBThreadObserverHelper> observer_helper_; 157 WaitableEvent done_event_; 158}; 159 160TEST_F(WebDataServiceAutofillTest, FormFillAdd) { 161 const AutofillChange expected_changes[] = { 162 AutofillChange(AutofillChange::ADD, AutofillKey(name1_, value1_)), 163 AutofillChange(AutofillChange::ADD, AutofillKey(name2_, value2_)) 164 }; 165 166 // This will verify that the correct notification is triggered, 167 // passing the correct list of autofill keys in the details. 168 EXPECT_CALL( 169 *observer_helper_->observer(), 170 Observe(NotificationType(NotificationType::AUTOFILL_ENTRIES_CHANGED), 171 Source<WebDataService>(wds_.get()), 172 Property(&Details<const AutofillChangeList>::ptr, 173 Pointee(ElementsAreArray(expected_changes))))). 174 WillOnce(SignalEvent(&done_event_)); 175 176 std::vector<webkit_glue::FormField> form_fields; 177 AppendFormField(name1_, value1_, &form_fields); 178 AppendFormField(name2_, value2_, &form_fields); 179 wds_->AddFormFields(form_fields); 180 181 // The event will be signaled when the mock observer is notified. 182 done_event_.TimedWait(test_timeout_); 183 184 AutofillWebDataServiceConsumer<std::vector<string16> > consumer; 185 WebDataService::Handle handle; 186 static const int limit = 10; 187 handle = wds_->GetFormValuesForElementName( 188 name1_, string16(), limit, &consumer); 189 190 // The message loop will exit when the consumer is called. 191 MessageLoop::current()->Run(); 192 193 EXPECT_EQ(handle, consumer.handle()); 194 ASSERT_EQ(1U, consumer.result().size()); 195 EXPECT_EQ(value1_, consumer.result()[0]); 196} 197 198TEST_F(WebDataServiceAutofillTest, FormFillRemoveOne) { 199 // First add some values to autofill. 200 EXPECT_CALL(*observer_helper_->observer(), Observe(_, _, _)). 201 WillOnce(SignalEvent(&done_event_)); 202 std::vector<webkit_glue::FormField> form_fields; 203 AppendFormField(name1_, value1_, &form_fields); 204 wds_->AddFormFields(form_fields); 205 206 // The event will be signaled when the mock observer is notified. 207 done_event_.TimedWait(test_timeout_); 208 209 // This will verify that the correct notification is triggered, 210 // passing the correct list of autofill keys in the details. 211 const AutofillChange expected_changes[] = { 212 AutofillChange(AutofillChange::REMOVE, AutofillKey(name1_, value1_)) 213 }; 214 EXPECT_CALL( 215 *observer_helper_->observer(), 216 Observe(NotificationType(NotificationType::AUTOFILL_ENTRIES_CHANGED), 217 Source<WebDataService>(wds_.get()), 218 Property(&Details<const AutofillChangeList>::ptr, 219 Pointee(ElementsAreArray(expected_changes))))). 220 WillOnce(SignalEvent(&done_event_)); 221 wds_->RemoveFormValueForElementName(name1_, value1_); 222 223 // The event will be signaled when the mock observer is notified. 224 done_event_.TimedWait(test_timeout_); 225} 226 227TEST_F(WebDataServiceAutofillTest, FormFillRemoveMany) { 228 TimeDelta one_day(TimeDelta::FromDays(1)); 229 Time t = Time::Now(); 230 231 EXPECT_CALL(*observer_helper_->observer(), Observe(_, _, _)). 232 WillOnce(SignalEvent(&done_event_)); 233 std::vector<webkit_glue::FormField> form_fields; 234 AppendFormField(name1_, value1_, &form_fields); 235 AppendFormField(name2_, value2_, &form_fields); 236 wds_->AddFormFields(form_fields); 237 238 // The event will be signaled when the mock observer is notified. 239 done_event_.TimedWait(test_timeout_); 240 241 // This will verify that the correct notification is triggered, 242 // passing the correct list of autofill keys in the details. 243 const AutofillChange expected_changes[] = { 244 AutofillChange(AutofillChange::REMOVE, AutofillKey(name1_, value1_)), 245 AutofillChange(AutofillChange::REMOVE, AutofillKey(name2_, value2_)) 246 }; 247 EXPECT_CALL( 248 *observer_helper_->observer(), 249 Observe(NotificationType(NotificationType::AUTOFILL_ENTRIES_CHANGED), 250 Source<WebDataService>(wds_.get()), 251 Property(&Details<const AutofillChangeList>::ptr, 252 Pointee(ElementsAreArray(expected_changes))))). 253 WillOnce(SignalEvent(&done_event_)); 254 wds_->RemoveFormElementsAddedBetween(t, t + one_day); 255 256 // The event will be signaled when the mock observer is notified. 257 done_event_.TimedWait(test_timeout_); 258} 259 260TEST_F(WebDataServiceAutofillTest, ProfileAddGUID) { 261 AutoFillProfile profile; 262 263 // TODO(dhollowa): Remove this notification. http://crbug.com/58813 264 // Old Label-based notifications will be sent out until Sync can switch over 265 // to GUID-based notifications. 266 profile.set_label(name1_); 267 const AutofillProfileChange deprecated_expected_change( 268 AutofillProfileChange::ADD, name1_, &profile, string16()); 269 EXPECT_CALL( 270 *observer_helper_->observer(), 271 Observe(NotificationType(NotificationType::AUTOFILL_PROFILE_CHANGED), 272 Source<WebDataService>(wds_.get()), 273 Property(&Details<const AutofillProfileChange>::ptr, 274 Pointee(deprecated_expected_change)))). 275 WillOnce(SignalEvent(&done_event_)); 276 277 // Check that GUID-based notification was sent. 278 const AutofillProfileChangeGUID expected_change( 279 AutofillProfileChangeGUID::ADD, profile.guid(), &profile); 280 EXPECT_CALL( 281 *observer_helper_->observer(), 282 Observe(NotificationType(NotificationType::AUTOFILL_PROFILE_CHANGED_GUID), 283 Source<WebDataService>(wds_.get()), 284 Property(&Details<const AutofillProfileChangeGUID>::ptr, 285 Pointee(expected_change)))). 286 WillOnce(DoDefault()); 287 288 wds_->AddAutoFillProfileGUID(profile); 289 done_event_.TimedWait(test_timeout_); 290 291 // Check that it was added. 292 AutofillWebDataServiceConsumer<std::vector<AutoFillProfile*> > consumer; 293 WebDataService::Handle handle = wds_->GetAutoFillProfiles(&consumer); 294 MessageLoop::current()->Run(); 295 EXPECT_EQ(handle, consumer.handle()); 296 ASSERT_EQ(1U, consumer.result().size()); 297 EXPECT_EQ(profile, *consumer.result()[0]); 298 STLDeleteElements(&consumer.result()); 299} 300 301TEST_F(WebDataServiceAutofillTest, ProfileRemoveGUID) { 302 AutoFillProfile profile; 303 profile.set_label(name1_); 304 305 // Add a profile. 306 EXPECT_CALL(*observer_helper_->observer(), Observe(_, _, _)). 307 Times(2). 308 WillOnce(DoDefault()). 309 WillOnce(SignalEvent(&done_event_)); 310 wds_->AddAutoFillProfileGUID(profile); 311 done_event_.TimedWait(test_timeout_); 312 313 // Check that it was added. 314 AutofillWebDataServiceConsumer<std::vector<AutoFillProfile*> > consumer; 315 WebDataService::Handle handle = wds_->GetAutoFillProfiles(&consumer); 316 MessageLoop::current()->Run(); 317 EXPECT_EQ(handle, consumer.handle()); 318 ASSERT_EQ(1U, consumer.result().size()); 319 EXPECT_EQ(profile, *consumer.result()[0]); 320 STLDeleteElements(&consumer.result()); 321 322 // TODO(dhollowa): Remove this notification. http://crbug.com/58813 323 // Old Label-based notifications will be sent out until Sync can switch over 324 // to GUID-based notifications. 325 const AutofillProfileChange deprecated_expected_change( 326 AutofillProfileChange::REMOVE, name1_, NULL, string16()); 327 EXPECT_CALL( 328 *observer_helper_->observer(), 329 Observe(NotificationType(NotificationType::AUTOFILL_PROFILE_CHANGED), 330 Source<WebDataService>(wds_.get()), 331 Property(&Details<const AutofillProfileChange>::ptr, 332 Pointee(deprecated_expected_change)))). 333 WillOnce(SignalEvent(&done_event_)); 334 335 // Check that GUID-based notification was sent. 336 const AutofillProfileChangeGUID expected_change( 337 AutofillProfileChangeGUID::REMOVE, profile.guid(), NULL); 338 EXPECT_CALL( 339 *observer_helper_->observer(), 340 Observe(NotificationType(NotificationType::AUTOFILL_PROFILE_CHANGED_GUID), 341 Source<WebDataService>(wds_.get()), 342 Property(&Details<const AutofillProfileChangeGUID>::ptr, 343 Pointee(expected_change)))). 344 WillOnce(DoDefault()); 345 346 // Remove the profile. 347 wds_->RemoveAutoFillProfileGUID(profile.guid()); 348 done_event_.TimedWait(test_timeout_); 349 350 // Check that it was removed. 351 AutofillWebDataServiceConsumer<std::vector<AutoFillProfile*> > consumer2; 352 WebDataService::Handle handle2 = wds_->GetAutoFillProfiles(&consumer2); 353 MessageLoop::current()->Run(); 354 EXPECT_EQ(handle2, consumer2.handle()); 355 ASSERT_EQ(0U, consumer2.result().size()); 356} 357 358TEST_F(WebDataServiceAutofillTest, ProfileUpdateGUID) { 359 AutoFillProfile profile1; 360 profile1.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Abe")); 361 AutoFillProfile profile2; 362 profile2.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Alice")); 363 364 EXPECT_CALL(*observer_helper_->observer(), Observe(_, _, _)). 365 WillOnce(DoDefault()). 366 WillOnce(DoDefault()). 367 WillOnce(DoDefault()). 368 WillOnce(SignalEvent(&done_event_)); 369 wds_->AddAutoFillProfileGUID(profile1); 370 wds_->AddAutoFillProfileGUID(profile2); 371 done_event_.TimedWait(test_timeout_); 372 373 // Check that they were added. 374 AutofillWebDataServiceConsumer<std::vector<AutoFillProfile*> > consumer; 375 WebDataService::Handle handle = wds_->GetAutoFillProfiles(&consumer); 376 MessageLoop::current()->Run(); 377 EXPECT_EQ(handle, consumer.handle()); 378 ASSERT_EQ(2U, consumer.result().size()); 379 EXPECT_EQ(profile1, *consumer.result()[0]); 380 EXPECT_EQ(profile2, *consumer.result()[1]); 381 STLDeleteElements(&consumer.result()); 382 383 // TODO(dhollowa): Remove this notification. http://crbug.com/58813 384 // Old Label-based notifications will be sent out until Sync can switch over 385 // to GUID-based notifications. 386 AutoFillProfile deprecated_profile1_changed(profile1); 387 deprecated_profile1_changed.SetInfo(AutoFillType(NAME_FIRST), 388 ASCIIToUTF16("Bill")); 389 const AutofillProfileChangeGUID deprecated_expected_change( 390 AutofillProfileChangeGUID::UPDATE, profile1.guid(), 391 &deprecated_profile1_changed); 392 EXPECT_CALL( 393 *observer_helper_->observer(), 394 Observe(NotificationType(NotificationType::AUTOFILL_PROFILE_CHANGED), 395 Source<WebDataService>(wds_.get()), 396 Property(&Details<const AutofillProfileChangeGUID>::ptr, 397 Pointee(deprecated_expected_change)))). 398 WillOnce(SignalEvent(&done_event_)); 399 400 AutoFillProfile profile1_changed(profile1); 401 profile1_changed.SetInfo(AutoFillType(NAME_FIRST), ASCIIToUTF16("Bill")); 402 const AutofillProfileChangeGUID expected_change( 403 AutofillProfileChangeGUID::UPDATE, profile1.guid(), &profile1_changed); 404 405 EXPECT_CALL( 406 *observer_helper_->observer(), 407 Observe(NotificationType(NotificationType::AUTOFILL_PROFILE_CHANGED_GUID), 408 Source<WebDataService>(wds_.get()), 409 Property(&Details<const AutofillProfileChangeGUID>::ptr, 410 Pointee(expected_change)))). 411 WillOnce(DoDefault()); 412 413 // Update the profile. 414 wds_->UpdateAutoFillProfileGUID(profile1_changed); 415 done_event_.TimedWait(test_timeout_); 416 417 // Check that the updates were made. 418 AutofillWebDataServiceConsumer<std::vector<AutoFillProfile*> > consumer2; 419 WebDataService::Handle handle2 = wds_->GetAutoFillProfiles(&consumer2); 420 MessageLoop::current()->Run(); 421 EXPECT_EQ(handle2, consumer2.handle()); 422 ASSERT_EQ(2U, consumer2.result().size()); 423 EXPECT_NE(profile1, *consumer2.result()[0]); 424 EXPECT_EQ(profile1_changed, *consumer2.result()[0]); 425 EXPECT_EQ(profile2, *consumer2.result()[1]); 426 STLDeleteElements(&consumer2.result()); 427} 428 429TEST_F(WebDataServiceAutofillTest, CreditAddGUID) { 430 CreditCard card; 431 const AutofillCreditCardChangeGUID expected_change( 432 AutofillCreditCardChangeGUID::ADD, card.guid(), &card); 433 434 EXPECT_CALL( 435 *observer_helper_->observer(), 436 Observe( 437 NotificationType(NotificationType::AUTOFILL_CREDIT_CARD_CHANGED_GUID), 438 Source<WebDataService>(wds_.get()), 439 Property(&Details<const AutofillCreditCardChangeGUID>::ptr, 440 Pointee(expected_change)))). 441 WillOnce(SignalEvent(&done_event_)); 442 443 wds_->AddCreditCardGUID(card); 444 done_event_.TimedWait(test_timeout_); 445 446 // Check that it was added. 447 AutofillWebDataServiceConsumer<std::vector<CreditCard*> > consumer; 448 WebDataService::Handle handle = wds_->GetCreditCards(&consumer); 449 MessageLoop::current()->Run(); 450 EXPECT_EQ(handle, consumer.handle()); 451 ASSERT_EQ(1U, consumer.result().size()); 452 EXPECT_EQ(card, *consumer.result()[0]); 453 STLDeleteElements(&consumer.result()); 454} 455 456TEST_F(WebDataServiceAutofillTest, CreditCardRemoveGUID) { 457 CreditCard credit_card; 458 459 // Add a credit card. 460 EXPECT_CALL(*observer_helper_->observer(), Observe(_, _, _)). 461 WillOnce(SignalEvent(&done_event_)); 462 wds_->AddCreditCardGUID(credit_card); 463 done_event_.TimedWait(test_timeout_); 464 465 // Check that it was added. 466 AutofillWebDataServiceConsumer<std::vector<CreditCard*> > consumer; 467 WebDataService::Handle handle = wds_->GetCreditCards(&consumer); 468 MessageLoop::current()->Run(); 469 EXPECT_EQ(handle, consumer.handle()); 470 ASSERT_EQ(1U, consumer.result().size()); 471 EXPECT_EQ(credit_card, *consumer.result()[0]); 472 STLDeleteElements(&consumer.result()); 473 474 // Remove the credit card. 475 const AutofillCreditCardChangeGUID expected_change( 476 AutofillCreditCardChangeGUID::REMOVE, credit_card.guid(), NULL); 477 EXPECT_CALL( 478 *observer_helper_->observer(), 479 Observe( 480 NotificationType(NotificationType::AUTOFILL_CREDIT_CARD_CHANGED_GUID), 481 Source<WebDataService>(wds_.get()), 482 Property(&Details<const AutofillCreditCardChangeGUID>::ptr, 483 Pointee(expected_change)))). 484 WillOnce(SignalEvent(&done_event_)); 485 wds_->RemoveCreditCardGUID(credit_card.guid()); 486 done_event_.TimedWait(test_timeout_); 487 488 // Check that it was removed. 489 AutofillWebDataServiceConsumer<std::vector<CreditCard*> > consumer2; 490 WebDataService::Handle handle2 = wds_->GetCreditCards(&consumer2); 491 MessageLoop::current()->Run(); 492 EXPECT_EQ(handle2, consumer2.handle()); 493 ASSERT_EQ(0U, consumer2.result().size()); 494} 495 496TEST_F(WebDataServiceAutofillTest, CreditUpdateGUID) { 497 CreditCard card1; 498 card1.SetInfo(AutoFillType(CREDIT_CARD_NAME), ASCIIToUTF16("Abe")); 499 CreditCard card2; 500 card2.SetInfo(AutoFillType(CREDIT_CARD_NAME), ASCIIToUTF16("Alice")); 501 502 EXPECT_CALL(*observer_helper_->observer(), Observe(_, _, _)). 503 Times(2). 504 WillOnce(DoDefault()). 505 WillOnce(SignalEvent(&done_event_)); 506 wds_->AddCreditCardGUID(card1); 507 wds_->AddCreditCardGUID(card2); 508 done_event_.TimedWait(test_timeout_); 509 510 // Check that they got added. 511 AutofillWebDataServiceConsumer<std::vector<CreditCard*> > consumer; 512 WebDataService::Handle handle = wds_->GetCreditCards(&consumer); 513 MessageLoop::current()->Run(); 514 EXPECT_EQ(handle, consumer.handle()); 515 ASSERT_EQ(2U, consumer.result().size()); 516 EXPECT_EQ(card1, *consumer.result()[0]); 517 EXPECT_EQ(card2, *consumer.result()[1]); 518 STLDeleteElements(&consumer.result()); 519 520 CreditCard card1_changed(card1); 521 card1_changed.SetInfo(AutoFillType(CREDIT_CARD_NAME), ASCIIToUTF16("Bill")); 522 const AutofillCreditCardChangeGUID expected_change( 523 AutofillCreditCardChangeGUID::UPDATE, card1.guid(), &card1_changed); 524 525 EXPECT_CALL( 526 *observer_helper_->observer(), 527 Observe( 528 NotificationType(NotificationType::AUTOFILL_CREDIT_CARD_CHANGED_GUID), 529 Source<WebDataService>(wds_.get()), 530 Property(&Details<const AutofillCreditCardChangeGUID>::ptr, 531 Pointee(expected_change)))). 532 WillOnce(SignalEvent(&done_event_)); 533 534 wds_->UpdateCreditCardGUID(card1_changed); 535 done_event_.TimedWait(test_timeout_); 536 537 // Check that the updates were made. 538 AutofillWebDataServiceConsumer<std::vector<CreditCard*> > consumer2; 539 WebDataService::Handle handle2 = wds_->GetCreditCards(&consumer2); 540 MessageLoop::current()->Run(); 541 EXPECT_EQ(handle2, consumer2.handle()); 542 ASSERT_EQ(2U, consumer2.result().size()); 543 EXPECT_NE(card1, *consumer2.result()[0]); 544 EXPECT_EQ(card1_changed, *consumer2.result()[0]); 545 EXPECT_EQ(card2, *consumer2.result()[1]); 546 STLDeleteElements(&consumer2.result()); 547} 548