Commit 557ea2b7 authored by rodmartin's avatar rodmartin Committed by Commit Bot

Added an initial version of plist_writer

Writer for Priority List. Write a base::Value() in a string with PLIST
format. The decisions were all as pretty print format and kept only the
types that we need for policies. The implemented types are Boolean,
string, integer, list and dictionary.

Bug: 
Change-Id: If43041a2e5dd2e97014a266f35b176019fffb2ff
Reviewed-on: https://chromium-review.googlesource.com/986912
Commit-Queue: Martin Rodriguez <rodmartin@google.com>
Reviewed-by: default avatarJulian Pastarmov <pastarmovj@chromium.org>
Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarGeorges Khalil <georgesak@chromium.org>
Cr-Commit-Position: refs/heads/master@{#553703}
parent f7f8d201
......@@ -91,6 +91,8 @@ source_set("internal") {
"external_data_fetcher.cc",
"external_data_fetcher.h",
"external_data_manager.h",
"plist_writer.cc",
"plist_writer.h",
"policy_bundle.cc",
"policy_bundle.h",
"policy_details.h",
......@@ -156,6 +158,7 @@ source_set("internal") {
"//extensions/buildflags",
"//google_apis",
"//net",
"//third_party/libxml",
"//third_party/re2",
"//url",
]
......@@ -306,6 +309,7 @@ source_set("unit_tests") {
"cloud/policy_header_service_unittest.cc",
"cloud/user_info_fetcher_unittest.cc",
"generate_policy_source_unittest.cc",
"plist_writer_unittest.cc",
"policy_bundle_unittest.cc",
"policy_loader_ios_unittest.mm",
"policy_loader_mac_unittest.cc",
......@@ -375,6 +379,7 @@ source_set("unit_tests") {
"//net:test_support",
"//testing/gmock",
"//testing/gtest",
"//third_party/libxml",
]
}
......
......@@ -4,4 +4,5 @@ include_rules = [
"+components/data_use_measurement/core",
"+components/signin/core/account_id",
"+extensions/buildflags",
"+third_party/libxml",
]
// 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 "components/policy/core/common/plist_writer.h"
#include "base/strings/string_number_conversions.h"
#include "build/build_config.h"
#include "third_party/libxml/chromium/libxml_utils.h"
namespace policy {
namespace {
// Called recursively to build the Plist xml. When completed,
// |plist_writer| will contain the Plist. Return true on success and false on
// failure.
bool BuildPlistString(const base::Value& node, XmlWriter& plist_writer) {
switch (node.type()) {
case base::Value::Type::BOOLEAN: {
bool value = node.GetBool();
plist_writer.StartElement(value ? "true" : "false");
plist_writer.EndElement();
return true;
}
case base::Value::Type::INTEGER: {
int value = node.GetInt();
plist_writer.WriteElement("integer", base::IntToString(value));
return true;
}
case base::Value::Type::STRING: {
std::string value = node.GetString();
plist_writer.WriteElement("string", value);
return true;
}
case base::Value::Type::LIST: {
plist_writer.StartElement("array");
for (const auto& value : node.GetList()) {
if (!BuildPlistString(value, plist_writer))
return false;
}
plist_writer.EndElement();
return true;
}
case base::Value::Type::DICTIONARY: {
plist_writer.StartElement("dict");
const base::DictionaryValue* dict = nullptr;
bool result = node.GetAsDictionary(&dict);
DCHECK(result);
for (base::DictionaryValue::Iterator itr(*dict); !itr.IsAtEnd();
itr.Advance()) {
plist_writer.WriteElement("key", itr.key());
if (!BuildPlistString(itr.value(), plist_writer))
result = false;
}
plist_writer.EndElement();
return result;
}
default:
NOTREACHED();
return false;
}
}
} // namespace
bool PlistWrite(const base::Value& node, std::string* plist) {
// Where we write Plist data as we generate it.
XmlWriter plist_writer;
plist_writer.StartWriting();
plist_writer.StartIndenting();
plist_writer.StartElement("plist");
bool result = BuildPlistString(node, plist_writer);
plist_writer.EndElement();
plist_writer.StopWriting();
*plist = plist_writer.GetWrittenString();
return result;
}
} // namespace policy
// 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.
#ifndef COMPONENTS_POLICY_CORE_COMMON_PLIST_WRITER_H_
#define COMPONENTS_POLICY_CORE_COMMON_PLIST_WRITER_H_
#include <stddef.h>
#include <string>
#include "base/values.h"
#include "components/policy/policy_export.h"
namespace policy {
// Given a root node, generates a Plist string and puts it into |plist|.
// The output string is overwritten and not appended.
// Return true on success and false on failure.
// TODO(rodmartin): Should we generate plist if it would be invalid plist
// (e.g., |node| is not a DictionaryValue/ListValue or if there are inf/-inf
// float values)?
POLICY_EXPORT bool PlistWrite(const base::Value& node, std::string* plist);
} // namespace policy
#endif // COMPONENTS_POLICY_CORE_COMMON_Plist_WRITER_H_
\ No newline at end of file
// 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 "components/policy/core/common/plist_writer.h"
#include "base/memory/ptr_util.h"
#include "base/strings/strcat.h"
#include "base/values.h"
#include "build/build_config.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace policy {
namespace {
const char kPlistHeaderXML[] = "<?xml version=\"1.0\"?>";
const char kPlistHeaderVersion[] = "<plist>";
const char kPlistFooter[] = "</plist>\n";
#define PLIST_NEWLINE "\n"
} // namespace
class PlistWriterTest : public testing::Test {
public:
PlistWriterTest();
~PlistWriterTest() override;
void SetUp() override;
std::string header_;
private:
DISALLOW_COPY_AND_ASSIGN(PlistWriterTest);
};
PlistWriterTest::PlistWriterTest() {}
PlistWriterTest::~PlistWriterTest() {}
void PlistWriterTest::SetUp() {
header_ = base::StrCat(
{kPlistHeaderXML, PLIST_NEWLINE, kPlistHeaderVersion, PLIST_NEWLINE});
}
TEST_F(PlistWriterTest, BasicTypes) {
std::string output_plist;
// Test empty dict.
EXPECT_TRUE(PlistWrite(base::DictionaryValue(), &output_plist));
EXPECT_EQ(base::StrCat({header_, " <dict/>", PLIST_NEWLINE, kPlistFooter}),
output_plist);
// Test empty list.
EXPECT_TRUE(PlistWrite(base::ListValue(), &output_plist));
EXPECT_EQ(base::StrCat({header_, " <array/>", PLIST_NEWLINE, kPlistFooter}),
output_plist);
// Test integer values.
EXPECT_TRUE(PlistWrite(base::Value(42), &output_plist));
EXPECT_EQ(base::StrCat({header_, " <integer>42</integer>", PLIST_NEWLINE,
kPlistFooter}),
output_plist);
// Test boolean values.
EXPECT_TRUE(PlistWrite(base::Value(true), &output_plist));
EXPECT_EQ(base::StrCat({header_, " <true/>", PLIST_NEWLINE, kPlistFooter}),
output_plist);
// Test string values.
EXPECT_TRUE(PlistWrite(base::Value("foo"), &output_plist));
EXPECT_EQ(base::StrCat({header_, " <string>foo</string>", PLIST_NEWLINE,
kPlistFooter}),
output_plist);
}
TEST_F(PlistWriterTest, NestedTypes) {
std::string output_plist;
// Writer unittests like empty list/dict nesting,
// list list nesting, etc.
base::DictionaryValue root_dict;
std::unique_ptr<base::ListValue> list(new base::ListValue());
std::unique_ptr<base::DictionaryValue> inner_dict(
new base::DictionaryValue());
inner_dict->SetInteger("inner int", 10);
list->Append(std::move(inner_dict));
list->Append(std::make_unique<base::ListValue>());
list->AppendBoolean(false);
root_dict.Set("list", std::move(list));
EXPECT_TRUE(PlistWrite(root_dict, &output_plist));
EXPECT_EQ(base::StrCat({header_, " <dict>",
PLIST_NEWLINE, " <key>list</key>",
PLIST_NEWLINE, " <array>",
PLIST_NEWLINE, " <dict>",
PLIST_NEWLINE, " <key>inner int</key>",
PLIST_NEWLINE, " <integer>10</integer>",
PLIST_NEWLINE, " </dict>",
PLIST_NEWLINE, " <array/>",
PLIST_NEWLINE, " <false/>",
PLIST_NEWLINE, " </array>",
PLIST_NEWLINE, " </dict>",
PLIST_NEWLINE, kPlistFooter}),
output_plist);
}
TEST_F(PlistWriterTest, KeysWithPeriods) {
std::string output_plist;
base::DictionaryValue period_dict;
period_dict.SetKey("a.b", base::Value(3));
period_dict.SetKey("c", base::Value(2));
std::unique_ptr<base::DictionaryValue> period_dict2(
new base::DictionaryValue());
period_dict2->SetKey("g.h.i.j", base::Value(1));
period_dict.SetWithoutPathExpansion("d.e.f", std::move(period_dict2));
EXPECT_TRUE(PlistWrite(period_dict, &output_plist));
EXPECT_EQ(base::StrCat({header_, " <dict>",
PLIST_NEWLINE, " <key>a.b</key>",
PLIST_NEWLINE, " <integer>3</integer>",
PLIST_NEWLINE, " <key>c</key>",
PLIST_NEWLINE, " <integer>2</integer>",
PLIST_NEWLINE, " <key>d.e.f</key>",
PLIST_NEWLINE, " <dict>",
PLIST_NEWLINE, " <key>g.h.i.j</key>",
PLIST_NEWLINE, " <integer>1</integer>",
PLIST_NEWLINE, " </dict>",
PLIST_NEWLINE, " </dict>",
PLIST_NEWLINE, kPlistFooter}),
output_plist);
}
} // namespace policy
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment