| // Copyright 2012 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chromeos/components/onc/onc_test_utils.h" |
| |
| #include <utility> |
| |
| #include "base/check.h" |
| #include "base/files/file_path.h" |
| #include "base/files/file_util.h" |
| #include "base/json/json_file_value_serializer.h" |
| #include "base/json/json_reader.h" |
| #include "base/json/json_writer.h" |
| #include "base/logging.h" |
| #include "base/notreached.h" |
| #include "base/path_service.h" |
| #include "base/threading/thread_restrictions.h" |
| #include "base/values.h" |
| #include "components/onc/onc_constants.h" |
| |
| namespace chromeos::onc::test_utils { |
| |
| namespace { |
| |
| bool GetTestDataPath(const std::string& filename, base::FilePath* result_path) { |
| base::ScopedAllowBlockingForTesting allow_io; |
| |
| base::FilePath path; |
| if (!base::PathService::Get(base::DIR_SRC_TEST_DATA_ROOT, &path)) { |
| LOG(FATAL) << "Failed to get the path to root for " << filename; |
| } |
| path = path.Append(FILE_PATH_LITERAL("chromeos")); |
| path = path.Append(FILE_PATH_LITERAL("components")); |
| path = path.Append(FILE_PATH_LITERAL("test")); |
| path = path.Append(FILE_PATH_LITERAL("data")); |
| path = path.Append(FILE_PATH_LITERAL("onc")); |
| path = path.Append(FILE_PATH_LITERAL(filename)); |
| if (!base::PathExists(path)) { // We don't want to create this. |
| LOG(FATAL) << "The file doesn't exist: " << path; |
| } |
| |
| *result_path = path; |
| return true; |
| } |
| |
| } // namespace |
| |
| std::string ReadTestData(const std::string& filename) { |
| base::ScopedAllowBlockingForTesting allow_io; |
| base::FilePath path; |
| if (!GetTestDataPath(filename, &path)) { |
| return ""; |
| } |
| std::string result; |
| base::ReadFileToString(path, &result); |
| return result; |
| } |
| |
| namespace { |
| |
| base::Value ReadTestJson(const std::string& filename) { |
| base::FilePath path; |
| if (!GetTestDataPath(filename, &path)) { |
| LOG(FATAL) << "Unable to get test file path for: " << filename; |
| } |
| JSONFileValueDeserializer deserializer( |
| path, |
| base::JSON_PARSE_CHROMIUM_EXTENSIONS | base::JSON_ALLOW_TRAILING_COMMAS); |
| std::string error_message; |
| std::unique_ptr<base::Value> result = |
| deserializer.Deserialize(nullptr, &error_message); |
| CHECK(result != nullptr) << "Couldn't json-deserialize file: " << filename |
| << ": " << error_message; |
| return std::move(*result); |
| } |
| |
| } // namespace |
| |
| base::Value::Dict ReadTestDictionary(const std::string& filename) { |
| base::Value content = ReadTestJson(filename); |
| CHECK(content.is_dict()) |
| << "File '" << filename |
| << "' does not contain a dictionary as expected, but type " |
| << content.type(); |
| return std::move(content.GetDict()); |
| } |
| |
| base::Value::List ReadTestList(const std::string& filename) { |
| base::Value content = ReadTestJson(filename); |
| CHECK(content.is_list()) << "File '" << filename |
| << "' does not contain a list as expected, but type " |
| << content.type(); |
| return std::move(content.GetList()); |
| } |
| |
| ::testing::AssertionResult Equals(const base::Value::Dict* expected, |
| const base::Value::Dict* actual) { |
| CHECK(expected != nullptr); |
| if (actual == nullptr) { |
| return ::testing::AssertionFailure() << "Actual value pointer is nullptr"; |
| } |
| |
| if (*expected == *actual) { |
| return ::testing::AssertionSuccess() << "Values are equal"; |
| } |
| |
| return ::testing::AssertionFailure() << "Values are unequal.\n" |
| << "Expected value:\n" |
| << *expected << "Actual value:\n" |
| << *actual; |
| } |
| |
| namespace { |
| |
| base::Value::List ConvertToBaseValueList( |
| const std::vector<std::string>& string_vector) { |
| base::Value::List result; |
| for (const std::string& str : string_vector) { |
| result.Append(str); |
| } |
| return result; |
| } |
| |
| } // namespace |
| |
| TestToplevelApnData::TestToplevelApnData( |
| std::optional<std::string> id, |
| std::optional<std::string> access_point_name, |
| std::optional<std::string> ip_type, |
| std::optional<std::vector<std::string>> apn_types, |
| std::optional<std::vector<std::string>> admin_apn_list_ids, |
| std::optional<std::vector<std::string>> psim_admin_assigned_apn_ids, |
| std::optional<std::vector<std::string>> admin_assigned_apn_ids) |
| : id(id), |
| access_point_name(access_point_name), |
| ip_type(ip_type), |
| apn_types(apn_types), |
| admin_apn_list_ids(admin_apn_list_ids), |
| psim_admin_assigned_apn_ids(psim_admin_assigned_apn_ids), |
| admin_assigned_apn_ids(admin_assigned_apn_ids) {} |
| |
| TestToplevelApnData::~TestToplevelApnData() = default; |
| |
| TestToplevelApnData::TestToplevelApnData(const TestToplevelApnData& other) |
| : id(other.id), |
| access_point_name(other.access_point_name), |
| ip_type(other.ip_type), |
| apn_types(other.apn_types), |
| admin_apn_list_ids(other.admin_apn_list_ids), |
| psim_admin_assigned_apn_ids(other.psim_admin_assigned_apn_ids), |
| admin_assigned_apn_ids(other.admin_assigned_apn_ids) {} |
| |
| // Helper function to build an individual APN dictionary |
| base::Value::Dict BuildApnDict(TestToplevelApnData apn_data) { |
| base::Value::Dict apn_dict; |
| |
| auto maybe_set_string = [&](const char* key, |
| const std::optional<std::string>& value) { |
| if (value.has_value()) { |
| apn_dict.Set(key, *value); |
| } |
| }; |
| |
| maybe_set_string(::onc::cellular_apn::kId, apn_data.id); |
| maybe_set_string(::onc::cellular_apn::kAccessPointName, |
| apn_data.access_point_name); |
| maybe_set_string(::onc::cellular_apn::kIpType, apn_data.ip_type); |
| |
| if (apn_data.apn_types) { |
| apn_dict.Set(::onc::cellular_apn::kApnTypes, |
| ConvertToBaseValueList(apn_data.apn_types.value())); |
| } |
| |
| return apn_dict; |
| } |
| |
| const std::string GenerateTopLevelWithCellularWithAPNAsJSON( |
| TestToplevelApnData apn_data) { |
| base::Value::Dict top_level_dict = |
| test_utils::ReadTestDictionary("toplevel_cellular_no_apn.onc"); |
| |
| // Locate the Cellular config within the top-level dictionary |
| base::Value::List* network_configs = |
| top_level_dict.FindList(::onc::toplevel_config::kNetworkConfigurations); |
| DCHECK(network_configs); |
| base::Value::Dict* cellular_network_config_dict = |
| network_configs->front().GetIfDict(); |
| DCHECK(cellular_network_config_dict); |
| base::Value::Dict* cellular_dict = |
| cellular_network_config_dict->FindDict(::onc::network_config::kCellular); |
| DCHECK(cellular_dict); |
| cellular_dict->Set(::onc::cellular::kAPN, BuildApnDict(apn_data)); |
| if (apn_data.admin_assigned_apn_ids.has_value()) { |
| cellular_dict->Set( |
| ::onc::cellular::kAdminAssignedAPNIds, |
| ConvertToBaseValueList(apn_data.admin_assigned_apn_ids.value())); |
| } |
| |
| if (apn_data.admin_apn_list_ids.has_value()) { |
| base::Value::List admin_apn_list; |
| |
| for (const std::string& apn_id : apn_data.admin_apn_list_ids.value()) { |
| // Use BuildApnDict with the apn_id and optional values as null |
| TestToplevelApnData admin_apn_data; |
| admin_apn_data.id = apn_id; |
| admin_apn_data.access_point_name = "test-access-point-name"; |
| admin_apn_list.Append(BuildApnDict(admin_apn_data)); |
| } |
| top_level_dict.Set(::onc::toplevel_config::kAdminAPNList, |
| std::move(admin_apn_list)); |
| } |
| |
| if (apn_data.psim_admin_assigned_apn_ids.has_value()) { |
| // Locate the Global network config within the top-level dictionary |
| base::Value::Dict* global_network_config = top_level_dict.FindDict( |
| ::onc::toplevel_config::kGlobalNetworkConfiguration); |
| DCHECK(global_network_config); |
| global_network_config->Set( |
| ::onc::global_network_config::kPSIMAdminAssignedAPNIds, |
| ConvertToBaseValueList(apn_data.psim_admin_assigned_apn_ids.value())); |
| } |
| |
| // Serialize to JSON string |
| std::string json_output; |
| if (!base::JSONWriter::WriteWithOptions( |
| top_level_dict, base::JSONWriter::OPTIONS_PRETTY_PRINT, |
| &json_output)) { |
| LOG(ERROR) << "JSON serialization failed"; |
| } |
| return json_output; |
| } |
| |
| } // namespace chromeos::onc::test_utils |