/* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "persistent_properties.h" #include #include #include #include #include "util.h" using namespace std::string_literals; namespace android { namespace init { PersistentProperties VectorToPersistentProperties( const std::vector>& input_properties) { PersistentProperties persistent_properties; for (const auto& [name, value] : input_properties) { auto persistent_property_record = persistent_properties.add_properties(); persistent_property_record->set_name(name); persistent_property_record->set_value(value); } return persistent_properties; } void CheckPropertiesEqual(std::vector> expected, const PersistentProperties& persistent_properties) { for (const auto& persistent_property_record : persistent_properties.properties()) { auto it = std::find_if(expected.begin(), expected.end(), [persistent_property_record](const auto& entry) { return entry.first == persistent_property_record.name() && entry.second == persistent_property_record.value(); }); ASSERT_TRUE(it != expected.end()) << "Found unexpected property (" << persistent_property_record.name() << ", " << persistent_property_record.value() << ")"; expected.erase(it); } auto joiner = [](const std::vector>& vector) { std::string result; for (const auto& [name, value] : vector) { result += " (" + name + ", " + value + ")"; } return result; }; EXPECT_TRUE(expected.empty()) << "Did not find expected properties:" << joiner(expected); } TEST(persistent_properties, EndToEnd) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); persistent_property_filename = tf.path; std::vector> persistent_properties = { {"persist.sys.locale", "en-US"}, {"persist.sys.timezone", "America/Los_Angeles"}, {"persist.test.empty.value", ""}, {"persist.test.new.line", "abc\n\n\nabc"}, {"persist.test.numbers", "1234567890"}, {"persist.test.non.ascii", "\x00\x01\x02\xFF\xFE\xFD\x7F\x8F\x9F"}, // We don't currently allow for non-ascii names for system properties, but this is a policy // decision, not a technical limitation. {"persist.\x00\x01\x02\xFF\xFE\xFD\x7F\x8F\x9F", "non-ascii-name"}, }; ASSERT_TRUE(WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties))); auto read_back_properties = LoadPersistentProperties(); CheckPropertiesEqual(persistent_properties, read_back_properties); } TEST(persistent_properties, AddProperty) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); persistent_property_filename = tf.path; std::vector> persistent_properties = { {"persist.sys.timezone", "America/Los_Angeles"}, }; ASSERT_TRUE(WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties))); WritePersistentProperty("persist.sys.locale", "pt-BR"); std::vector> persistent_properties_expected = { {"persist.sys.timezone", "America/Los_Angeles"}, {"persist.sys.locale", "pt-BR"}, }; auto read_back_properties = LoadPersistentProperties(); CheckPropertiesEqual(persistent_properties_expected, read_back_properties); } TEST(persistent_properties, UpdateProperty) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); persistent_property_filename = tf.path; std::vector> persistent_properties = { {"persist.sys.locale", "en-US"}, {"persist.sys.timezone", "America/Los_Angeles"}, }; ASSERT_TRUE(WritePersistentPropertyFile(VectorToPersistentProperties(persistent_properties))); WritePersistentProperty("persist.sys.locale", "pt-BR"); std::vector> persistent_properties_expected = { {"persist.sys.locale", "pt-BR"}, {"persist.sys.timezone", "America/Los_Angeles"}, }; auto read_back_properties = LoadPersistentProperties(); CheckPropertiesEqual(persistent_properties_expected, read_back_properties); } TEST(persistent_properties, UpdatePropertyBadParse) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); persistent_property_filename = tf.path; ASSERT_TRUE(WriteFile(tf.path, "ab")); WritePersistentProperty("persist.sys.locale", "pt-BR"); auto read_back_properties = LoadPersistentProperties(); EXPECT_GT(read_back_properties.properties().size(), 0); auto it = std::find_if(read_back_properties.properties().begin(), read_back_properties.properties().end(), [](const auto& entry) { return entry.name() == "persist.sys.locale" && entry.value() == "pt-BR"; }); EXPECT_FALSE(it == read_back_properties.properties().end()); } } // namespace init } // namespace android