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
3// found in the LICENSE file.
4
5#include "components/policy/core/common/policy_test_utils.h"
6
7#include <string>
8
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/callback.h"
12#include "base/json/json_writer.h"
13#include "base/logging.h"
14#include "base/strings/sys_string_conversions.h"
15#include "base/values.h"
16#include "components/policy/core/common/policy_bundle.h"
17
18#if defined(OS_IOS) || defined(OS_MACOSX)
19#include <CoreFoundation/CoreFoundation.h>
20
21#include "base/mac/scoped_cftyperef.h"
22#endif
23
24namespace policy {
25
26PolicyDetailsMap::PolicyDetailsMap() {}
27
28PolicyDetailsMap::~PolicyDetailsMap() {}
29
30GetChromePolicyDetailsCallback PolicyDetailsMap::GetCallback() const {
31  return base::Bind(&PolicyDetailsMap::Lookup, base::Unretained(this));
32}
33
34void PolicyDetailsMap::SetDetails(const std::string& policy,
35                                  const PolicyDetails* details) {
36  map_[policy] = details;
37}
38
39const PolicyDetails* PolicyDetailsMap::Lookup(const std::string& policy) const {
40  PolicyDetailsMapping::const_iterator it = map_.find(policy);
41  return it == map_.end() ? NULL : it->second;
42}
43
44bool PolicyServiceIsEmpty(const PolicyService* service) {
45  const PolicyMap& map = service->GetPolicies(
46      PolicyNamespace(POLICY_DOMAIN_CHROME, std::string()));
47  if (!map.empty()) {
48    base::DictionaryValue dict;
49    for (PolicyMap::const_iterator it = map.begin(); it != map.end(); ++it)
50      dict.SetWithoutPathExpansion(it->first, it->second.value->DeepCopy());
51    LOG(WARNING) << "There are pre-existing policies in this machine: " << dict;
52  }
53  return map.empty();
54}
55
56#if defined(OS_IOS) || defined(OS_MACOSX)
57CFPropertyListRef ValueToProperty(const base::Value* value) {
58  switch (value->GetType()) {
59    case base::Value::TYPE_NULL:
60      return kCFNull;
61
62    case base::Value::TYPE_BOOLEAN: {
63      bool bool_value;
64      if (value->GetAsBoolean(&bool_value))
65        return bool_value ? kCFBooleanTrue : kCFBooleanFalse;
66      break;
67    }
68
69    case base::Value::TYPE_INTEGER: {
70      int int_value;
71      if (value->GetAsInteger(&int_value)) {
72        return CFNumberCreate(
73            kCFAllocatorDefault, kCFNumberIntType, &int_value);
74      }
75      break;
76    }
77
78    case base::Value::TYPE_DOUBLE: {
79      double double_value;
80      if (value->GetAsDouble(&double_value)) {
81        return CFNumberCreate(
82            kCFAllocatorDefault, kCFNumberDoubleType, &double_value);
83      }
84      break;
85    }
86
87    case base::Value::TYPE_STRING: {
88      std::string string_value;
89      if (value->GetAsString(&string_value))
90        return base::SysUTF8ToCFStringRef(string_value);
91      break;
92    }
93
94    case base::Value::TYPE_DICTIONARY: {
95      const base::DictionaryValue* dict_value;
96      if (value->GetAsDictionary(&dict_value)) {
97        // |dict| is owned by the caller.
98        CFMutableDictionaryRef dict =
99            CFDictionaryCreateMutable(kCFAllocatorDefault,
100                                      dict_value->size(),
101                                      &kCFTypeDictionaryKeyCallBacks,
102                                      &kCFTypeDictionaryValueCallBacks);
103        for (base::DictionaryValue::Iterator iterator(*dict_value);
104             !iterator.IsAtEnd(); iterator.Advance()) {
105          // CFDictionaryAddValue() retains both |key| and |value|, so make sure
106          // the references are balanced.
107          base::ScopedCFTypeRef<CFStringRef> key(
108              base::SysUTF8ToCFStringRef(iterator.key()));
109          base::ScopedCFTypeRef<CFPropertyListRef> cf_value(
110              ValueToProperty(&iterator.value()));
111          if (cf_value)
112            CFDictionaryAddValue(dict, key, cf_value);
113        }
114        return dict;
115      }
116      break;
117    }
118
119    case base::Value::TYPE_LIST: {
120      const base::ListValue* list;
121      if (value->GetAsList(&list)) {
122        CFMutableArrayRef array =
123            CFArrayCreateMutable(NULL, list->GetSize(), &kCFTypeArrayCallBacks);
124        for (base::ListValue::const_iterator it(list->begin());
125             it != list->end(); ++it) {
126          // CFArrayAppendValue() retains |value|, so make sure the reference
127          // created by ValueToProperty() is released.
128          base::ScopedCFTypeRef<CFPropertyListRef> cf_value(
129              ValueToProperty(*it));
130          if (cf_value)
131            CFArrayAppendValue(array, cf_value);
132        }
133        return array;
134      }
135      break;
136    }
137
138    case base::Value::TYPE_BINARY:
139      // This type isn't converted (though it can be represented as CFData)
140      // because there's no equivalent JSON type, and policy values can only
141      // take valid JSON values.
142      break;
143  }
144
145  return NULL;
146}
147#endif  // defined(OS_IOS) || defined(OS_MACOSX)
148
149}  // namespace policy
150
151std::ostream& operator<<(std::ostream& os,
152                         const policy::PolicyBundle& bundle) {
153  os << "{" << std::endl;
154  for (policy::PolicyBundle::const_iterator iter = bundle.begin();
155       iter != bundle.end(); ++iter) {
156    os << "  \"" << iter->first << "\": " << *iter->second << "," << std::endl;
157  }
158  os << "}";
159  return os;
160}
161
162std::ostream& operator<<(std::ostream& os, policy::PolicyScope scope) {
163  switch (scope) {
164    case policy::POLICY_SCOPE_USER: {
165      os << "POLICY_SCOPE_USER";
166      break;
167    }
168    case policy::POLICY_SCOPE_MACHINE: {
169      os << "POLICY_SCOPE_MACHINE";
170      break;
171    }
172    default: {
173      os << "POLICY_SCOPE_UNKNOWN(" << int(scope) << ")";
174    }
175  }
176  return os;
177}
178
179std::ostream& operator<<(std::ostream& os, policy::PolicyLevel level) {
180  switch (level) {
181    case policy::POLICY_LEVEL_RECOMMENDED: {
182      os << "POLICY_LEVEL_RECOMMENDED";
183      break;
184    }
185    case policy::POLICY_LEVEL_MANDATORY: {
186      os << "POLICY_LEVEL_MANDATORY";
187      break;
188    }
189    default: {
190      os << "POLICY_LEVEL_UNKNOWN(" << int(level) << ")";
191    }
192  }
193  return os;
194}
195
196std::ostream& operator<<(std::ostream& os, policy::PolicyDomain domain) {
197  switch (domain) {
198    case policy::POLICY_DOMAIN_CHROME: {
199      os << "POLICY_DOMAIN_CHROME";
200      break;
201    }
202    case policy::POLICY_DOMAIN_EXTENSIONS: {
203      os << "POLICY_DOMAIN_EXTENSIONS";
204      break;
205    }
206    default: {
207      os << "POLICY_DOMAIN_UNKNOWN(" << int(domain) << ")";
208    }
209  }
210  return os;
211}
212
213std::ostream& operator<<(std::ostream& os, const policy::PolicyMap& policies) {
214  os << "{" << std::endl;
215  for (policy::PolicyMap::const_iterator iter = policies.begin();
216       iter != policies.end(); ++iter) {
217    os << "  \"" << iter->first << "\": " << iter->second << "," << std::endl;
218  }
219  os << "}";
220  return os;
221}
222
223std::ostream& operator<<(std::ostream& os, const policy::PolicyMap::Entry& e) {
224  std::string value;
225  base::JSONWriter::WriteWithOptions(e.value,
226                                     base::JSONWriter::OPTIONS_PRETTY_PRINT,
227                                     &value);
228  os << "{" << std::endl
229     << "  \"level\": " << e.level << "," << std::endl
230     << "  \"scope\": " << e.scope << "," << std::endl
231     << "  \"value\": " << value
232     << "}";
233  return os;
234}
235
236std::ostream& operator<<(std::ostream& os, const policy::PolicyNamespace& ns) {
237  os << ns.domain << "/" << ns.component_id;
238  return os;
239}
240