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