| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/chrome_cleaner/settings/settings.h" |
| |
| #include <algorithm> |
| #include <vector> |
| |
| #include "base/command_line.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h" |
| #include "chrome/chrome_cleaner/settings/engine_settings.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace chrome_cleaner { |
| |
| // Number high enough that it will never be a valid engine value. |
| constexpr int kInvalidEngineValue = 3141592; |
| static_assert(kInvalidEngineValue < Engine::Name_MIN || |
| kInvalidEngineValue > Engine::Name_MAX, |
| "kInvalidEngineValue is not an invalid value"); |
| |
| constexpr char kNonNumericValue[] = "foo"; |
| |
| class SettingsTest : public testing::Test { |
| protected: |
| Settings* ReinitializeSettings(const base::CommandLine& command_line) { |
| return ReinitializeSettings(command_line, GetTargetBinary()); |
| } |
| |
| Settings* ReinitializeSettings(const base::CommandLine& command_line, |
| TargetBinary target_binary) { |
| Settings* settings = Settings::GetInstance(); |
| settings->Initialize(command_line, target_binary); |
| return settings; |
| } |
| |
| void TestExecutionMode(const std::string& switch_value, |
| ExecutionMode expected_execution_mode) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| if (!switch_value.empty()) |
| command_line.AppendSwitchASCII(kExecutionModeSwitch, switch_value); |
| |
| Settings* settings = ReinitializeSettings(command_line); |
| EXPECT_EQ(expected_execution_mode, settings->execution_mode()); |
| } |
| }; |
| |
| TEST_F(SettingsTest, EngineDefaultValue) { |
| ASSERT_NE(GetDefaultEngine(), Engine::UNKNOWN); |
| ASSERT_NE(GetDefaultEngine(), Engine::DEPRECATED_URZA); |
| |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| Settings* settings = ReinitializeSettings(command_line); |
| EXPECT_EQ(GetDefaultEngine(), settings->engine()); |
| } |
| |
| TEST_F(SettingsTest, ValidEngines) { |
| for (int index = Engine::Name_MIN; index < Engine::Name_MAX; ++index) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(chrome_cleaner::kEngineSwitch, |
| base::NumberToString(index)); |
| Settings* settings = ReinitializeSettings(command_line); |
| if (index != Engine::UNKNOWN && index != Engine::DEPRECATED_URZA) { |
| EXPECT_EQ(static_cast<Engine::Name>(index), settings->engine()); |
| } else { |
| // Fall back to default. |
| EXPECT_EQ(GetDefaultEngine(), settings->engine()); |
| } |
| } |
| } |
| |
| TEST_F(SettingsTest, EngineInvalidNumericValue) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(chrome_cleaner::kEngineSwitch, |
| base::NumberToString(kInvalidEngineValue)); |
| Settings* settings = ReinitializeSettings(command_line); |
| EXPECT_EQ(GetDefaultEngine(), settings->engine()); |
| } |
| |
| TEST_F(SettingsTest, EngineNonNumericValue) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(chrome_cleaner::kEngineSwitch, |
| kNonNumericValue); |
| Settings* settings = ReinitializeSettings(command_line); |
| EXPECT_EQ(GetDefaultEngine(), settings->engine()); |
| } |
| |
| TEST_F(SettingsTest, CleanerRunId_Generated) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| Settings* settings = ReinitializeSettings(command_line); |
| // A non-empty cleanup id should be generated if switch --cleanup-id is not |
| // present. |
| EXPECT_FALSE(settings->cleanup_id().empty()); |
| |
| command_line.AppendSwitchASCII(chrome_cleaner::kCleanupIdSwitch, |
| std::string()); |
| settings = ReinitializeSettings(command_line); |
| // A non-empty cleanup id should be generated if switch --cleanup-id is |
| // present, but the corresponding value is empty. |
| EXPECT_FALSE(settings->cleanup_id().empty()); |
| } |
| |
| TEST_F(SettingsTest, CleanerRunId_Propagated) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| const std::string propagated_cleanup_id = "propagated-run-id"; |
| command_line.AppendSwitchASCII(chrome_cleaner::kCleanupIdSwitch, |
| propagated_cleanup_id); |
| Settings* settings = ReinitializeSettings(command_line); |
| EXPECT_EQ(propagated_cleanup_id, settings->cleanup_id()); |
| } |
| |
| TEST_F(SettingsTest, SBEREnabled) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| EXPECT_FALSE(ReinitializeSettings(command_line)->sber_enabled()); |
| |
| command_line.AppendSwitch(chrome_cleaner::kExtendedSafeBrowsingEnabledSwitch); |
| EXPECT_TRUE(ReinitializeSettings(command_line)->sber_enabled()); |
| } |
| |
| TEST_F(SettingsTest, ExecutionMode) { |
| const struct TestCase { |
| std::string switch_value; |
| ExecutionMode expected_execution_mode; |
| } test_cases[] = { |
| // Switch not present. |
| {"", ExecutionMode::kNone}, |
| // Valid values for execution mode. |
| {base::NumberToString(static_cast<int>(ExecutionMode::kScanning)), |
| ExecutionMode::kScanning}, |
| {base::NumberToString(static_cast<int>(ExecutionMode::kCleanup)), |
| ExecutionMode::kCleanup}, |
| // Unknown values for execution mode. |
| {base::NumberToString(static_cast<int>(ExecutionMode::kNumValues)), |
| ExecutionMode::kNone}, |
| {base::NumberToString(static_cast<int>(ExecutionMode::kNumValues) + 1), |
| ExecutionMode::kNone}, |
| {base::NumberToString(static_cast<int>(ExecutionMode::kNone) - 1), |
| ExecutionMode::kNone}, |
| {"invalid-value", ExecutionMode::kNone}, |
| }; |
| |
| for (auto t : test_cases) { |
| TestExecutionMode(t.switch_value, t.expected_execution_mode); |
| } |
| } |
| |
| TEST_F(SettingsTest, Timeouts) { |
| using OverrideAccessor = bool (Settings::*)() const; |
| using TimeoutAccessor = base::TimeDelta (Settings::*)() const; |
| |
| const struct TestCase { |
| std::string switch_value; |
| bool expected_timeout_overridden; |
| base::TimeDelta expected_timeout; |
| } test_cases[] = { |
| // Switch not present. |
| {"", false, base::TimeDelta()}, |
| // Valid number of minutes. |
| {"100", true, base::TimeDelta::FromMinutes(100)}, |
| // Disabled. |
| {"0", true, base::TimeDelta()}, |
| // Invalid values. |
| {"ten", false, base::TimeDelta()}, |
| {"1.5", false, base::TimeDelta()}, |
| {"-3", false, base::TimeDelta()}, |
| }; |
| |
| const struct SwitchesToTest { |
| std::string switch_name; |
| OverrideAccessor override_accessor; |
| TimeoutAccessor timeout_accessor; |
| } switches_to_test[] = { |
| {kCleaningTimeoutMinutesSwitch, &Settings::cleaning_timeout_overridden, |
| &Settings::cleaning_timeout}, |
| {kScanningTimeoutMinutesSwitch, &Settings::scanning_timeout_overridden, |
| &Settings::scanning_timeout}, |
| }; |
| |
| for (auto s : switches_to_test) { |
| SCOPED_TRACE(s.switch_name); |
| for (auto t : test_cases) { |
| SCOPED_TRACE(t.switch_value); |
| |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| if (!t.switch_value.empty()) |
| command_line.AppendSwitchASCII(s.switch_name, t.switch_value); |
| |
| Settings* settings = ReinitializeSettings(command_line); |
| |
| bool timeout_overridden = (settings->*(s.override_accessor))(); |
| base::TimeDelta timeout = (settings->*(s.timeout_accessor))(); |
| |
| EXPECT_EQ(t.expected_timeout_overridden, timeout_overridden); |
| EXPECT_EQ(t.expected_timeout, timeout); |
| } |
| } |
| } |
| |
| TEST_F(SettingsTest, NoLocationsToScanSpecified) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| Settings* settings = ReinitializeSettings(command_line); |
| // All valid scan locations should be specified, but let's not check the exact |
| // contents and size. It's bigger than 1 location for sure. |
| EXPECT_LT(1u, settings->locations_to_scan().size()); |
| EXPECT_TRUE(settings->scan_switches_correct()); |
| } |
| |
| TEST_F(SettingsTest, NoProgramFilesScanningOnReporter) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| Settings* cleaner_settings = |
| ReinitializeSettings(command_line, TargetBinary::kCleaner); |
| std::vector<UwS::TraceLocation> cleaner_locations = |
| cleaner_settings->locations_to_scan(); |
| EXPECT_NE(std::find(cleaner_locations.begin(), cleaner_locations.end(), |
| UwS::FOUND_IN_PROGRAMFILES), |
| cleaner_locations.end()); |
| |
| Settings* reporter_settings = |
| ReinitializeSettings(command_line, TargetBinary::kReporter); |
| std::vector<UwS::TraceLocation> reporter_locations = |
| reporter_settings->locations_to_scan(); |
| EXPECT_EQ(std::find(reporter_locations.begin(), reporter_locations.end(), |
| UwS::FOUND_IN_PROGRAMFILES), |
| reporter_locations.end()); |
| } |
| |
| TEST_F(SettingsTest, LimitsToSpecifiedLocations) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(kScanLocationsSwitch, "1,2,3"); |
| std::vector<UwS::TraceLocation> expected_locations = { |
| UwS::FOUND_IN_STARTUP, UwS::FOUND_IN_MEMORY, |
| UwS::FOUND_IN_UNINSTALLSTRING, |
| }; |
| |
| Settings* settings = ReinitializeSettings(command_line); |
| EXPECT_EQ(expected_locations, settings->locations_to_scan()); |
| EXPECT_TRUE(settings->scan_switches_correct()); |
| } |
| |
| TEST_F(SettingsTest, UsesOnlyValidSpecifiedLocations) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(kScanLocationsSwitch, "1,100,yada,-3"); |
| std::vector<UwS::TraceLocation> expected_locations = {UwS::FOUND_IN_STARTUP}; |
| |
| Settings* settings = ReinitializeSettings(command_line); |
| EXPECT_EQ(expected_locations, settings->locations_to_scan()); |
| EXPECT_FALSE(settings->scan_switches_correct()); |
| } |
| |
| TEST_F(SettingsTest, OnlyInvalidLocationsSpecified) { |
| const std::string test_cases[] = { |
| "", // empty flag value |
| "100,102,-3", // only invalid values specified |
| }; |
| for (const std::string& switch_value : test_cases) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(kScanLocationsSwitch, switch_value); |
| Settings* settings = ReinitializeSettings(command_line); |
| // All valid scan locations should be specified. |
| EXPECT_LT(1u, settings->locations_to_scan().size()); |
| EXPECT_FALSE(settings->scan_switches_correct()); |
| } |
| } |
| |
| TEST_F(SettingsTest, CorrectOpenFileSizeLimit) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(kFileSizeLimitSwitch, "1024"); |
| Settings* settings = |
| ReinitializeSettings(command_line, TargetBinary::kReporter); |
| EXPECT_EQ(1024, settings->open_file_size_limit()); |
| } |
| |
| TEST_F(SettingsTest, OpenFileSizeLimitInUnsupportedBinary) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| command_line.AppendSwitchASCII(kFileSizeLimitSwitch, "1024"); |
| |
| for (TargetBinary target : {TargetBinary::kCleaner, TargetBinary::kOther}) { |
| Settings* settings = ReinitializeSettings(command_line, target); |
| EXPECT_EQ(0, settings->open_file_size_limit()) |
| << "target binary: " << static_cast<int>(target); |
| } |
| } |
| |
| TEST_F(SettingsTest, IncorrectOpenFileSizeLimit) { |
| const struct TestCase { |
| bool file_size_switch_present; |
| std::string file_size_switch_value; |
| } test_cases[] = { |
| {false, ""}, // no switch present |
| {true, ""}, // switch is present, but the value is empty |
| {true, "0"}, // zero file size limit |
| {true, "-100"}, // negative file size limit should be ignored |
| {true, "abracadabra"}, // invalid file size limit, should be ignored. |
| }; |
| |
| for (const TestCase& test_case : test_cases) { |
| base::CommandLine command_line(base::CommandLine::NO_PROGRAM); |
| if (test_case.file_size_switch_present) { |
| command_line.AppendSwitchASCII(kFileSizeLimitSwitch, |
| test_case.file_size_switch_value); |
| } |
| Settings* settings = |
| ReinitializeSettings(command_line, TargetBinary::kReporter); |
| EXPECT_EQ(0, settings->open_file_size_limit()); |
| } |
| } |
| |
| } // namespace chrome_cleaner |