OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/chrome_content_browser_client.h" | 5 #include "chrome/browser/chrome_content_browser_client.h" |
6 | 6 |
| 7 #include <algorithm> |
7 #include <list> | 8 #include <list> |
8 #include <map> | 9 #include <map> |
9 #include <memory> | 10 #include <memory> |
10 | 11 |
11 #include "base/bind.h" | 12 #include "base/bind.h" |
12 #include "base/command_line.h" | 13 #include "base/command_line.h" |
13 #include "base/macros.h" | 14 #include "base/macros.h" |
14 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
15 #include "base/message_loop/message_loop.h" | 16 #include "base/message_loop/message_loop.h" |
16 #include "base/metrics/field_trial.h" | 17 #include "base/metrics/field_trial.h" |
17 #include "base/strings/stringprintf.h" | 18 #include "base/strings/stringprintf.h" |
18 #include "base/strings/utf_string_conversions.h" | 19 #include "base/strings/utf_string_conversions.h" |
19 #include "build/build_config.h" | 20 #include "build/build_config.h" |
20 #include "chrome/browser/browsing_data/browsing_data_helper.h" | 21 #include "chrome/browser/browsing_data/browsing_data_helper.h" |
21 #include "chrome/browser/browsing_data/browsing_data_remover_factory.h" | 22 #include "chrome/browser/browsing_data/browsing_data_remover_factory.h" |
22 #include "chrome/browser/browsing_data/browsing_data_remover_impl.h" | 23 #include "chrome/browser/browsing_data/browsing_data_remover_impl.h" |
| 24 #include "chrome/browser/browsing_data/chrome_browsing_data_types.h" |
23 #include "chrome/browser/search_engines/template_url_service_factory.h" | 25 #include "chrome/browser/search_engines/template_url_service_factory.h" |
24 #include "chrome/test/base/testing_profile.h" | 26 #include "chrome/test/base/testing_profile.h" |
25 #include "components/content_settings/core/browser/host_content_settings_map.h" | 27 #include "components/content_settings/core/browser/host_content_settings_map.h" |
26 #include "components/search_engines/template_url_service.h" | 28 #include "components/search_engines/template_url_service.h" |
27 #include "components/variations/entropy_provider.h" | 29 #include "components/variations/entropy_provider.h" |
28 #include "components/variations/variations_associated_data.h" | 30 #include "components/variations/variations_associated_data.h" |
29 #include "components/version_info/version_info.h" | 31 #include "components/version_info/version_info.h" |
30 #include "content/public/browser/browsing_data_filter_builder.h" | 32 #include "content/public/browser/browsing_data_filter_builder.h" |
31 #include "content/public/browser/navigation_controller.h" | 33 #include "content/public/browser/navigation_controller.h" |
32 #include "content/public/browser/navigation_entry.h" | 34 #include "content/public/browser/navigation_entry.h" |
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
351 class MockBrowsingDataRemover : public BrowsingDataRemoverImpl { | 353 class MockBrowsingDataRemover : public BrowsingDataRemoverImpl { |
352 public: | 354 public: |
353 explicit MockBrowsingDataRemover(content::BrowserContext* context) | 355 explicit MockBrowsingDataRemover(content::BrowserContext* context) |
354 : BrowsingDataRemoverImpl(context) {} | 356 : BrowsingDataRemoverImpl(context) {} |
355 | 357 |
356 ~MockBrowsingDataRemover() override { | 358 ~MockBrowsingDataRemover() override { |
357 DCHECK(!expected_calls_.size()) | 359 DCHECK(!expected_calls_.size()) |
358 << "Expectations were set but not verified."; | 360 << "Expectations were set but not verified."; |
359 } | 361 } |
360 | 362 |
361 void RemoveInternal(const base::Time& delete_begin, | 363 void RemoveInternal( |
362 const base::Time& delete_end, | 364 const base::Time& delete_begin, |
363 int remove_mask, | 365 const base::Time& delete_end, |
364 int origin_type_mask, | 366 const std::set<const content::BrowsingDataType*>& remove_mask, |
365 std::unique_ptr<BrowsingDataFilterBuilder> filter_builder, | 367 int origin_type_mask, |
366 BrowsingDataRemover::Observer* observer) override { | 368 std::unique_ptr<BrowsingDataFilterBuilder> filter_builder, |
| 369 BrowsingDataRemover::Observer* observer) override { |
367 actual_calls_.emplace_back(delete_begin, delete_end, remove_mask, | 370 actual_calls_.emplace_back(delete_begin, delete_end, remove_mask, |
368 origin_type_mask, std::move(filter_builder), | 371 origin_type_mask, std::move(filter_builder), |
369 true /* should_compare_filter */); | 372 true /* should_compare_filter */); |
370 | 373 |
371 // |observer| is not recorded in |actual_calls_| to be compared with | 374 // |observer| is not recorded in |actual_calls_| to be compared with |
372 // expectations, because it's created internally in ClearSiteData() and | 375 // expectations, because it's created internally in ClearSiteData() and |
373 // it's unknown to this. However, it is tested implicitly, because we use | 376 // it's unknown to this. However, it is tested implicitly, because we use |
374 // it for the completion callback, so an incorrect |observer| will fail | 377 // it for the completion callback, so an incorrect |observer| will fail |
375 // the test by waiting for the callback forever. | 378 // the test by waiting for the callback forever. |
376 DCHECK(observer); | 379 DCHECK(observer); |
377 observer->OnBrowsingDataRemoverDone(); | 380 observer->OnBrowsingDataRemoverDone(); |
378 } | 381 } |
379 | 382 |
380 void ExpectCall( | 383 void ExpectCall(const base::Time& delete_begin, |
381 const base::Time& delete_begin, | 384 const base::Time& delete_end, |
382 const base::Time& delete_end, | 385 const std::set<const content::BrowsingDataType*>& remove_mask, |
383 int remove_mask, | 386 int origin_type_mask, |
384 int origin_type_mask, | 387 std::unique_ptr<BrowsingDataFilterBuilder> filter_builder) { |
385 std::unique_ptr<BrowsingDataFilterBuilder> filter_builder) { | |
386 expected_calls_.emplace_back(delete_begin, delete_end, remove_mask, | 388 expected_calls_.emplace_back(delete_begin, delete_end, remove_mask, |
387 origin_type_mask, std::move(filter_builder), | 389 origin_type_mask, std::move(filter_builder), |
388 true /* should_compare_filter */); | 390 true /* should_compare_filter */); |
389 } | 391 } |
390 | 392 |
391 void ExpectCallDontCareAboutFilterBuilder(const base::Time& delete_begin, | 393 void ExpectCallDontCareAboutFilterBuilder( |
392 const base::Time& delete_end, | 394 const base::Time& delete_begin, |
393 int remove_mask, | 395 const base::Time& delete_end, |
394 int origin_type_mask) { | 396 const std::set<const content::BrowsingDataType*>& remove_mask, |
| 397 int origin_type_mask) { |
395 expected_calls_.emplace_back(delete_begin, delete_end, remove_mask, | 398 expected_calls_.emplace_back(delete_begin, delete_end, remove_mask, |
396 origin_type_mask, | 399 origin_type_mask, |
397 std::unique_ptr<BrowsingDataFilterBuilder>(), | 400 std::unique_ptr<BrowsingDataFilterBuilder>(), |
398 false /* should_compare_filter */); | 401 false /* should_compare_filter */); |
399 } | 402 } |
400 | 403 |
401 void VerifyAndClearExpectations() { | 404 void VerifyAndClearExpectations() { |
402 EXPECT_EQ(expected_calls_, actual_calls_); | 405 EXPECT_EQ(expected_calls_, actual_calls_); |
403 expected_calls_.clear(); | 406 expected_calls_.clear(); |
404 actual_calls_.clear(); | 407 actual_calls_.clear(); |
405 } | 408 } |
406 | 409 |
407 private: | 410 private: |
408 class CallParameters { | 411 class CallParameters { |
409 public: | 412 public: |
410 CallParameters(const base::Time& delete_begin, | 413 CallParameters( |
411 const base::Time& delete_end, | 414 const base::Time& delete_begin, |
412 int remove_mask, | 415 const base::Time& delete_end, |
413 int origin_type_mask, | 416 const std::set<const content::BrowsingDataType*>& remove_mask, |
414 std::unique_ptr<BrowsingDataFilterBuilder> filter_builder, | 417 int origin_type_mask, |
415 bool should_compare_filter) | 418 std::unique_ptr<BrowsingDataFilterBuilder> filter_builder, |
| 419 bool should_compare_filter) |
416 : delete_begin_(delete_begin), | 420 : delete_begin_(delete_begin), |
417 delete_end_(delete_end), | 421 delete_end_(delete_end), |
418 remove_mask_(remove_mask), | 422 remove_mask_(remove_mask), |
419 origin_type_mask_(origin_type_mask), | 423 origin_type_mask_(origin_type_mask), |
420 filter_builder_(std::move(filter_builder)), | 424 filter_builder_(std::move(filter_builder)), |
421 should_compare_filter_(should_compare_filter) {} | 425 should_compare_filter_(should_compare_filter) {} |
422 ~CallParameters() {} | 426 ~CallParameters() {} |
423 | 427 |
424 bool operator==(const CallParameters& other) const { | 428 bool operator==(const CallParameters& other) const { |
425 const CallParameters& a = *this; | 429 const CallParameters& a = *this; |
426 const CallParameters& b = other; | 430 const CallParameters& b = other; |
427 | 431 |
428 if (a.delete_begin_ != b.delete_begin_ || | 432 if (a.delete_begin_ != b.delete_begin_ || |
429 a.delete_end_ != b.delete_end_ || | 433 a.delete_end_ != b.delete_end_ || |
430 a.remove_mask_ != b.remove_mask_ || | 434 a.remove_mask_ != b.remove_mask_ || |
431 a.origin_type_mask_ != b.origin_type_mask_) { | 435 a.origin_type_mask_ != b.origin_type_mask_) { |
432 return false; | 436 return false; |
433 } | 437 } |
434 | 438 |
435 if (!a.should_compare_filter_ || !b.should_compare_filter_) | 439 if (!a.should_compare_filter_ || !b.should_compare_filter_) |
436 return true; | 440 return true; |
437 return *a.filter_builder_ == *b.filter_builder_; | 441 return *a.filter_builder_ == *b.filter_builder_; |
438 } | 442 } |
439 | 443 |
440 private: | 444 private: |
441 base::Time delete_begin_; | 445 base::Time delete_begin_; |
442 base::Time delete_end_; | 446 base::Time delete_end_; |
443 int remove_mask_; | 447 std::set<const content::BrowsingDataType*> remove_mask_; |
444 int origin_type_mask_; | 448 int origin_type_mask_; |
445 std::unique_ptr<BrowsingDataFilterBuilder> filter_builder_; | 449 std::unique_ptr<BrowsingDataFilterBuilder> filter_builder_; |
446 bool should_compare_filter_; | 450 bool should_compare_filter_; |
447 }; | 451 }; |
448 | 452 |
449 std::list<CallParameters> actual_calls_; | 453 std::list<CallParameters> actual_calls_; |
450 std::list<CallParameters> expected_calls_; | 454 std::list<CallParameters> expected_calls_; |
451 }; | 455 }; |
452 | 456 |
453 // Tests for ChromeContentBrowserClient::ClearSiteData(). | 457 // Tests for ChromeContentBrowserClient::ClearSiteData(). |
(...skipping 26 matching lines...) Expand all Loading... |
480 bool finished_; | 484 bool finished_; |
481 }; | 485 }; |
482 | 486 |
483 // Tests that the parameters to ClearBrowsingData() are translated to | 487 // Tests that the parameters to ClearBrowsingData() are translated to |
484 // the correct BrowsingDataRemover::RemoveInternal() operation. The fourth | 488 // the correct BrowsingDataRemover::RemoveInternal() operation. The fourth |
485 // parameter, |filter_builder|, is tested in detail in the RegistrableDomains | 489 // parameter, |filter_builder|, is tested in detail in the RegistrableDomains |
486 // test below. | 490 // test below. |
487 TEST_F(ChromeContentBrowserClientClearSiteDataTest, Parameters) { | 491 TEST_F(ChromeContentBrowserClientClearSiteDataTest, Parameters) { |
488 ChromeContentBrowserClient client; | 492 ChromeContentBrowserClient client; |
489 | 493 |
| 494 // no datatypes |
| 495 std::set<const content::BrowsingDataType*> empty_mask; |
| 496 |
| 497 // "cookies" |
| 498 const std::set<const content::BrowsingDataType*> domain_scoped_types = { |
| 499 &kBrowsingDataTypeCookies, &kBrowsingDataTypeChannelIDs, |
| 500 &kBrowsingDataTypePluginData, |
| 501 }; |
| 502 |
| 503 // "storage" |
| 504 std::set<const content::BrowsingDataType*> storage; |
| 505 std::set_difference(BrowsingDataTypeSetSiteData().begin(), |
| 506 BrowsingDataTypeSetSiteData().end(), |
| 507 domain_scoped_types.begin(), domain_scoped_types.end(), |
| 508 std::inserter(storage, storage.begin())); |
| 509 |
| 510 // "storage" + "cache" |
| 511 std::set<const content::BrowsingDataType*> storage_and_cache = storage; |
| 512 storage_and_cache.insert(&kBrowsingDataTypeCache); |
| 513 |
| 514 // "cookies" + "storage" + "cache" |
| 515 std::set<const content::BrowsingDataType*> all = |
| 516 BrowsingDataTypeSetSiteData(); |
| 517 all.insert(&kBrowsingDataTypeCache); |
| 518 |
490 struct TestCase { | 519 struct TestCase { |
491 bool cookies; | 520 bool cookies; |
492 bool storage; | 521 bool storage; |
493 bool cache; | 522 bool cache; |
494 int mask; | 523 const std::set<const content::BrowsingDataType*> mask; |
495 } test_cases[] = { | 524 } test_cases[] = { |
496 {false, false, false, 0}, | 525 {false, false, false, empty_mask}, |
497 {true, false, false, BrowsingDataRemover::REMOVE_COOKIES | | 526 {true, false, false, domain_scoped_types}, |
498 BrowsingDataRemover::REMOVE_CHANNEL_IDS | | 527 {false, true, false, storage}, |
499 BrowsingDataRemover::REMOVE_PLUGIN_DATA}, | 528 {false, false, true, {&kBrowsingDataTypeCache}}, |
500 {false, true, false, BrowsingDataRemover::REMOVE_SITE_DATA & | 529 {true, true, false, BrowsingDataTypeSetSiteData()}, |
501 ~BrowsingDataRemover::REMOVE_COOKIES & | 530 {true, |
502 ~BrowsingDataRemover::REMOVE_CHANNEL_IDS & | 531 false, |
503 ~BrowsingDataRemover::REMOVE_PLUGIN_DATA}, | 532 true, |
504 {false, false, true, BrowsingDataRemover::REMOVE_CACHE}, | 533 {&kBrowsingDataTypeCookies, &kBrowsingDataTypeChannelIDs, |
505 {true, true, false, BrowsingDataRemover::REMOVE_SITE_DATA}, | 534 &kBrowsingDataTypePluginData, &kBrowsingDataTypeCache}}, |
506 {true, false, true, BrowsingDataRemover::REMOVE_COOKIES | | 535 {false, true, true, storage_and_cache}, |
507 BrowsingDataRemover::REMOVE_CHANNEL_IDS | | 536 {true, true, true, all}, |
508 BrowsingDataRemover::REMOVE_PLUGIN_DATA | | |
509 BrowsingDataRemover::REMOVE_CACHE}, | |
510 {false, true, true, BrowsingDataRemover::REMOVE_CACHE | | |
511 (BrowsingDataRemover::REMOVE_SITE_DATA & | |
512 ~BrowsingDataRemover::REMOVE_COOKIES & | |
513 ~BrowsingDataRemover::REMOVE_CHANNEL_IDS & | |
514 ~BrowsingDataRemover::REMOVE_PLUGIN_DATA)}, | |
515 {true, true, true, BrowsingDataRemover::REMOVE_SITE_DATA | | |
516 BrowsingDataRemover::REMOVE_CACHE}, | |
517 }; | 537 }; |
518 | 538 |
519 for (unsigned int i = 0; i < arraysize(test_cases); ++i) { | 539 for (unsigned int i = 0; i < arraysize(test_cases); ++i) { |
520 SCOPED_TRACE(base::StringPrintf("Test case %d", i)); | 540 SCOPED_TRACE(base::StringPrintf("Test case %d", i)); |
521 const TestCase& test_case = test_cases[i]; | 541 const TestCase& test_case = test_cases[i]; |
522 | 542 |
523 // We always delete data for all time and all origin types. | 543 // We always delete data for all time and all origin types. |
524 BrowsingDataHelper::OriginTypeMask all_origin_types = | 544 BrowsingDataHelper::OriginTypeMask all_origin_types = |
525 BrowsingDataHelper::ALL; | 545 BrowsingDataHelper::ALL; |
526 | 546 |
527 // Some data are deleted for the origin and some for the registrable domain. | 547 // Some data are deleted for the origin and some for the registrable domain. |
528 // Depending on the chosen datatypes, this might result into one or two | 548 // Depending on the chosen datatypes, this might result into one or two |
529 // calls. In the latter case, the removal mask will be split into two | 549 // calls. In the latter case, the removal mask will be split into two |
530 // parts - one for the origin deletion and one for the registrable domain. | 550 // parts - one for the origin deletion and one for the registrable domain. |
531 const int domain_scoped_types = BrowsingDataRemover::REMOVE_COOKIES | | 551 std::set<const content::BrowsingDataType*> registrable_domain_deletion_mask; |
532 BrowsingDataRemover::REMOVE_CHANNEL_IDS | | 552 std::set_intersection( |
533 BrowsingDataRemover::REMOVE_PLUGIN_DATA; | 553 test_case.mask.begin(), test_case.mask.end(), |
534 int registrable_domain_deletion_mask = test_case.mask & domain_scoped_types; | 554 domain_scoped_types.begin(), domain_scoped_types.end(), |
535 int origin_deletion_mask = test_case.mask & ~domain_scoped_types; | 555 std::inserter(registrable_domain_deletion_mask, |
| 556 registrable_domain_deletion_mask.begin())); |
536 | 557 |
537 if (registrable_domain_deletion_mask) { | 558 std::set<const content::BrowsingDataType*> origin_deletion_mask; |
| 559 std::set_difference( |
| 560 test_case.mask.begin(), test_case.mask.end(), |
| 561 domain_scoped_types.begin(), domain_scoped_types.end(), |
| 562 std::inserter(origin_deletion_mask, origin_deletion_mask.begin())); |
| 563 |
| 564 if (!registrable_domain_deletion_mask.empty()) { |
538 remover()->ExpectCallDontCareAboutFilterBuilder( | 565 remover()->ExpectCallDontCareAboutFilterBuilder( |
539 base::Time(), base::Time::Max(), | 566 base::Time(), base::Time::Max(), |
540 registrable_domain_deletion_mask, all_origin_types); | 567 registrable_domain_deletion_mask, all_origin_types); |
541 } | 568 } |
542 | 569 |
543 if (origin_deletion_mask) { | 570 if (!origin_deletion_mask.empty()) { |
544 remover()->ExpectCallDontCareAboutFilterBuilder( | 571 remover()->ExpectCallDontCareAboutFilterBuilder( |
545 base::Time(), base::Time::Max(), | 572 base::Time(), base::Time::Max(), |
546 origin_deletion_mask, all_origin_types); | 573 origin_deletion_mask, all_origin_types); |
547 } | 574 } |
548 | 575 |
549 SetClearingFinished(false); | 576 SetClearingFinished(false); |
550 client.ClearSiteData( | 577 client.ClearSiteData( |
551 profile(), url::Origin(GURL("https://www.example.com")), | 578 profile(), url::Origin(GURL("https://www.example.com")), |
552 test_case.cookies, test_case.storage, test_case.cache, | 579 test_case.cookies, test_case.storage, test_case.cache, |
553 base::Bind( | 580 base::Bind( |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
605 for (const TestCase& test_case : test_cases) { | 632 for (const TestCase& test_case : test_cases) { |
606 SCOPED_TRACE(test_case.origin); | 633 SCOPED_TRACE(test_case.origin); |
607 | 634 |
608 std::unique_ptr<BrowsingDataFilterBuilder> | 635 std::unique_ptr<BrowsingDataFilterBuilder> |
609 registrable_domain_filter_builder(BrowsingDataFilterBuilder::Create( | 636 registrable_domain_filter_builder(BrowsingDataFilterBuilder::Create( |
610 BrowsingDataFilterBuilder::WHITELIST)); | 637 BrowsingDataFilterBuilder::WHITELIST)); |
611 registrable_domain_filter_builder->AddRegisterableDomain(test_case.domain); | 638 registrable_domain_filter_builder->AddRegisterableDomain(test_case.domain); |
612 | 639 |
613 remover()->ExpectCall( | 640 remover()->ExpectCall( |
614 base::Time(), base::Time::Max(), | 641 base::Time(), base::Time::Max(), |
615 BrowsingDataRemover::REMOVE_COOKIES | | 642 {&kBrowsingDataTypeCookies, &kBrowsingDataTypeChannelIDs, |
616 BrowsingDataRemover::REMOVE_CHANNEL_IDS | | 643 &kBrowsingDataTypePluginData}, |
617 BrowsingDataRemover::REMOVE_PLUGIN_DATA, | |
618 BrowsingDataHelper::ALL, std::move(registrable_domain_filter_builder)); | 644 BrowsingDataHelper::ALL, std::move(registrable_domain_filter_builder)); |
619 | 645 |
620 std::unique_ptr<BrowsingDataFilterBuilder> origin_filter_builder( | 646 std::unique_ptr<BrowsingDataFilterBuilder> origin_filter_builder( |
621 BrowsingDataFilterBuilder::Create( | 647 BrowsingDataFilterBuilder::Create( |
622 BrowsingDataFilterBuilder::WHITELIST)); | 648 BrowsingDataFilterBuilder::WHITELIST)); |
623 origin_filter_builder->AddOrigin(url::Origin(GURL(test_case.origin))); | 649 origin_filter_builder->AddOrigin(url::Origin(GURL(test_case.origin))); |
624 | 650 |
625 remover()->ExpectCall( | 651 remover()->ExpectCall(base::Time(), base::Time::Max(), |
626 base::Time(), base::Time::Max(), | 652 {&kBrowsingDataTypeCache}, BrowsingDataHelper::ALL, |
627 BrowsingDataRemover::REMOVE_CACHE, BrowsingDataHelper::ALL, | 653 std::move(origin_filter_builder)); |
628 std::move(origin_filter_builder)); | |
629 | 654 |
630 SetClearingFinished(false); | 655 SetClearingFinished(false); |
631 client.ClearSiteData( | 656 client.ClearSiteData( |
632 profile(), url::Origin(GURL(test_case.origin)), true /* cookies */, | 657 profile(), url::Origin(GURL(test_case.origin)), true /* cookies */, |
633 false /* storage */, true /* cache */, | 658 false /* storage */, true /* cache */, |
634 base::Bind( | 659 base::Bind( |
635 &ChromeContentBrowserClientClearSiteDataTest::SetClearingFinished, | 660 &ChromeContentBrowserClientClearSiteDataTest::SetClearingFinished, |
636 base::Unretained(this), true)); | 661 base::Unretained(this), true)); |
637 EXPECT_TRUE(IsClearingFinished()); | 662 EXPECT_TRUE(IsClearingFinished()); |
638 | 663 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
681 client.ClearSiteData( | 706 client.ClearSiteData( |
682 profile(), origin, true /* cookies */, false /* storage */, | 707 profile(), origin, true /* cookies */, false /* storage */, |
683 true /* cache */, | 708 true /* cache */, |
684 base::Bind( | 709 base::Bind( |
685 &ChromeContentBrowserClientClearSiteDataTest::SetClearingFinished, | 710 &ChromeContentBrowserClientClearSiteDataTest::SetClearingFinished, |
686 base::Unretained(this), true)); | 711 base::Unretained(this), true)); |
687 EXPECT_TRUE(IsClearingFinished()); | 712 EXPECT_TRUE(IsClearingFinished()); |
688 } | 713 } |
689 | 714 |
690 } // namespace | 715 } // namespace |
OLD | NEW |