OLD | NEW |
| (Empty) |
1 // Copyright (c) 2009 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 "chrome/browser/extensions/extension_message_bundle.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/scoped_ptr.h" | |
10 #include "base/string_util.h" | |
11 #include "base/values.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 | |
14 namespace { | |
15 | |
16 // Helper method for dictionary building. | |
17 void SetDictionary(const std::wstring name, | |
18 DictionaryValue* target, | |
19 DictionaryValue* subtree) { | |
20 target->Set(name, static_cast<Value*>(subtree)); | |
21 } | |
22 | |
23 void CreateContentTree(const std::wstring& name, | |
24 const std::string content, | |
25 DictionaryValue* dict) { | |
26 DictionaryValue* content_tree = new DictionaryValue; | |
27 content_tree->SetString(ExtensionMessageBundle::kContentKey, content); | |
28 SetDictionary(name, dict, content_tree); | |
29 } | |
30 | |
31 void CreatePlaceholdersTree(DictionaryValue* dict) { | |
32 DictionaryValue* placeholders_tree = new DictionaryValue; | |
33 CreateContentTree(L"a", "A", placeholders_tree); | |
34 CreateContentTree(L"b", "B", placeholders_tree); | |
35 CreateContentTree(L"c", "C", placeholders_tree); | |
36 SetDictionary(ExtensionMessageBundle::kPlaceholdersKey, | |
37 dict, | |
38 placeholders_tree); | |
39 } | |
40 | |
41 void CreateMessageTree(const std::wstring& name, | |
42 const std::string& message, | |
43 bool create_placeholder_subtree, | |
44 DictionaryValue* dict) { | |
45 DictionaryValue* message_tree = new DictionaryValue; | |
46 if (create_placeholder_subtree) | |
47 CreatePlaceholdersTree(message_tree); | |
48 message_tree->SetString(ExtensionMessageBundle::kMessageKey, message); | |
49 SetDictionary(name, dict, message_tree); | |
50 } | |
51 | |
52 void CreateGoodDictionary(DictionaryValue* dict) { | |
53 dict->Clear(); | |
54 CreateMessageTree(L"n1", "message1 $a$ $b$", true, dict); | |
55 CreateMessageTree(L"n2", "message2 $c$", true, dict); | |
56 CreateMessageTree(L"n3", "message3", false, dict); | |
57 } | |
58 | |
59 enum BadDictionary { | |
60 INVALID_NAME, | |
61 NAME_NOT_A_TREE, | |
62 EMPTY_NAME_TREE, | |
63 MISSING_MESSAGE, | |
64 PLACEHOLDER_NOT_A_TREE, | |
65 EMPTY_PLACEHOLDER_TREE, | |
66 CONTENT_MISSING, | |
67 MESSAGE_PLACEHOLDER_DOESNT_MATCH, | |
68 }; | |
69 | |
70 void CreateBadDictionary(DictionaryValue* dict, | |
71 enum BadDictionary what_is_bad) { | |
72 CreateGoodDictionary(dict); | |
73 // Now remove/break things. | |
74 switch (what_is_bad) { | |
75 case INVALID_NAME: | |
76 CreateMessageTree(L"n 5", "nevermind", false, dict); | |
77 break; | |
78 case NAME_NOT_A_TREE: | |
79 dict->SetString(L"n4", "whatever"); | |
80 break; | |
81 case EMPTY_NAME_TREE: { | |
82 DictionaryValue* empty_tree = new DictionaryValue; | |
83 SetDictionary(L"n4", dict, empty_tree); | |
84 } | |
85 break; | |
86 case MISSING_MESSAGE: | |
87 dict->Remove(L"n1.message", NULL); | |
88 break; | |
89 case PLACEHOLDER_NOT_A_TREE: | |
90 dict->SetString(L"n1.placeholders", "whatever"); | |
91 break; | |
92 case EMPTY_PLACEHOLDER_TREE: { | |
93 DictionaryValue* empty_tree = new DictionaryValue; | |
94 SetDictionary(L"n1.placeholders", dict, empty_tree); | |
95 } | |
96 break; | |
97 case CONTENT_MISSING: | |
98 dict->Remove(L"n1.placeholders.a.content", NULL); | |
99 break; | |
100 case MESSAGE_PLACEHOLDER_DOESNT_MATCH: | |
101 DictionaryValue* value; | |
102 dict->Remove(L"n1.placeholders.a", NULL); | |
103 dict->GetDictionary(L"n1.placeholders", &value); | |
104 CreateContentTree(L"x", "X", value); | |
105 break; | |
106 } | |
107 } | |
108 | |
109 TEST(ExtensionMessageBundle, InitEmptyDictionaries) { | |
110 DictionaryValue default_dict; | |
111 DictionaryValue app_dict; | |
112 std::string error; | |
113 scoped_ptr<ExtensionMessageBundle> handler( | |
114 ExtensionMessageBundle::Create(default_dict, app_dict, &error)); | |
115 | |
116 EXPECT_TRUE(handler.get() != NULL); | |
117 EXPECT_EQ(0U, handler->size()); | |
118 } | |
119 | |
120 TEST(ExtensionMessageBundle, InitGoodDefaultDictEmptyAppDict) { | |
121 DictionaryValue default_dict; | |
122 DictionaryValue app_dict; | |
123 std::string error; | |
124 | |
125 CreateGoodDictionary(&default_dict); | |
126 scoped_ptr<ExtensionMessageBundle> handler( | |
127 ExtensionMessageBundle::Create(default_dict, app_dict, &error)); | |
128 | |
129 EXPECT_TRUE(handler.get() != NULL); | |
130 EXPECT_EQ(3U, handler->size()); | |
131 | |
132 EXPECT_EQ("message1 A B", handler->GetL10nMessage("n1")); | |
133 EXPECT_EQ("message2 C", handler->GetL10nMessage("n2")); | |
134 EXPECT_EQ("message3", handler->GetL10nMessage("n3")); | |
135 } | |
136 | |
137 TEST(ExtensionMessageBundle, InitAppDictConsultedFirst) { | |
138 DictionaryValue default_dict; | |
139 DictionaryValue app_dict; | |
140 std::string error; | |
141 | |
142 CreateGoodDictionary(&default_dict); | |
143 CreateGoodDictionary(&app_dict); | |
144 // Flip placeholders in message of n1 tree. | |
145 app_dict.SetString(L"n1.message", "message1 $b$ $a$"); | |
146 // Remove one message from app dict. | |
147 app_dict.Remove(L"n2", NULL); | |
148 // Replace n3 with N3. | |
149 app_dict.Remove(L"n3", NULL); | |
150 CreateMessageTree(L"N3", "message3_app_dict", false, &app_dict); | |
151 | |
152 scoped_ptr<ExtensionMessageBundle> handler( | |
153 ExtensionMessageBundle::Create(default_dict, app_dict, &error)); | |
154 | |
155 EXPECT_TRUE(handler.get() != NULL); | |
156 EXPECT_EQ(3U, handler->size()); | |
157 | |
158 EXPECT_EQ("message1 B A", handler->GetL10nMessage("n1")); | |
159 EXPECT_EQ("message2 C", handler->GetL10nMessage("n2")); | |
160 EXPECT_EQ("message3_app_dict", handler->GetL10nMessage("n3")); | |
161 } | |
162 | |
163 TEST(ExtensionMessageBundle, InitBadAppDict) { | |
164 DictionaryValue default_dict; | |
165 DictionaryValue app_dict; | |
166 std::string error; | |
167 | |
168 CreateBadDictionary(&app_dict, INVALID_NAME); | |
169 scoped_ptr<ExtensionMessageBundle> handler( | |
170 ExtensionMessageBundle::Create(default_dict, app_dict, &error)); | |
171 | |
172 EXPECT_TRUE(handler.get() == NULL); | |
173 EXPECT_EQ("Name of a key \"n 5\" is invalid. Only ASCII [a-z], " | |
174 "[A-Z], [0-9] and \"_\" are allowed.", error); | |
175 | |
176 CreateBadDictionary(&app_dict, NAME_NOT_A_TREE); | |
177 handler.reset(ExtensionMessageBundle::Create(default_dict, app_dict, &error)); | |
178 EXPECT_TRUE(handler.get() == NULL); | |
179 EXPECT_EQ("Not a valid tree for key n4.", error); | |
180 | |
181 CreateBadDictionary(&app_dict, EMPTY_NAME_TREE); | |
182 handler.reset(ExtensionMessageBundle::Create(default_dict, app_dict, &error)); | |
183 EXPECT_TRUE(handler.get() == NULL); | |
184 EXPECT_EQ("There is no \"message\" element for key n4.", error); | |
185 | |
186 CreateBadDictionary(&app_dict, MISSING_MESSAGE); | |
187 handler.reset(ExtensionMessageBundle::Create(default_dict, app_dict, &error)); | |
188 EXPECT_TRUE(handler.get() == NULL); | |
189 EXPECT_EQ("There is no \"message\" element for key n1.", error); | |
190 | |
191 CreateBadDictionary(&app_dict, PLACEHOLDER_NOT_A_TREE); | |
192 handler.reset(ExtensionMessageBundle::Create(default_dict, app_dict, &error)); | |
193 EXPECT_TRUE(handler.get() == NULL); | |
194 EXPECT_EQ("Not a valid \"placeholders\" element for key n1.", error); | |
195 | |
196 CreateBadDictionary(&app_dict, EMPTY_PLACEHOLDER_TREE); | |
197 handler.reset(ExtensionMessageBundle::Create(default_dict, app_dict, &error)); | |
198 EXPECT_TRUE(handler.get() == NULL); | |
199 EXPECT_EQ("Variable $a$ used but not defined.", error); | |
200 | |
201 CreateBadDictionary(&app_dict, CONTENT_MISSING); | |
202 handler.reset(ExtensionMessageBundle::Create(default_dict, app_dict, &error)); | |
203 EXPECT_TRUE(handler.get() == NULL); | |
204 EXPECT_EQ("Invalid \"content\" element for key n1.", error); | |
205 | |
206 CreateBadDictionary(&app_dict, MESSAGE_PLACEHOLDER_DOESNT_MATCH); | |
207 handler.reset(ExtensionMessageBundle::Create(default_dict, app_dict, &error)); | |
208 EXPECT_TRUE(handler.get() == NULL); | |
209 EXPECT_EQ("Variable $a$ used but not defined.", error); | |
210 } | |
211 | |
212 struct ReplaceVariables { | |
213 const char* original; | |
214 const char* result; | |
215 const char* error; | |
216 const char* begin_delimiter; | |
217 const char* end_delimiter; | |
218 bool pass; | |
219 }; | |
220 | |
221 TEST(ExtensionMessageBundle, ReplaceMessagesInText) { | |
222 const char* kMessageBegin = ExtensionMessageBundle::kMessageBegin; | |
223 const char* kMessageEnd = ExtensionMessageBundle::kMessageEnd; | |
224 const char* kPlaceholderBegin = ExtensionMessageBundle::kPlaceholderBegin; | |
225 const char* kPlaceholderEnd = ExtensionMessageBundle::kPlaceholderEnd; | |
226 | |
227 static ReplaceVariables test_cases[] = { | |
228 // Message replacement. | |
229 { "This is __MSG_siMPle__ message", "This is simple message", | |
230 "", kMessageBegin, kMessageEnd, true }, | |
231 { "This is __MSG_", "This is __MSG_", | |
232 "", kMessageBegin, kMessageEnd, true }, | |
233 { "This is __MSG__simple__ message", "This is __MSG__simple__ message", | |
234 "Variable __MSG__simple__ used but not defined.", | |
235 kMessageBegin, kMessageEnd, false }, | |
236 { "__MSG_LoNg__", "A pretty long replacement", | |
237 "", kMessageBegin, kMessageEnd, true }, | |
238 { "A __MSG_SimpLE__MSG_ a", "A simpleMSG_ a", | |
239 "", kMessageBegin, kMessageEnd, true }, | |
240 { "A __MSG_simple__MSG_long__", "A simpleMSG_long__", | |
241 "", kMessageBegin, kMessageEnd, true }, | |
242 { "A __MSG_simple____MSG_long__", "A simpleA pretty long replacement", | |
243 "", kMessageBegin, kMessageEnd, true }, | |
244 { "__MSG_d1g1ts_are_ok__", "I are d1g1t", | |
245 "", kMessageBegin, kMessageEnd, true }, | |
246 // Placeholder replacement. | |
247 { "This is $sImpLe$ message", "This is simple message", | |
248 "", kPlaceholderBegin, kPlaceholderEnd, true }, | |
249 { "This is $", "This is $", | |
250 "", kPlaceholderBegin, kPlaceholderEnd, true }, | |
251 { "This is $$sIMPle$ message", "This is $simple message", | |
252 "", kPlaceholderBegin, kPlaceholderEnd, true }, | |
253 { "$LONG_V$", "A pretty long replacement", | |
254 "", kPlaceholderBegin, kPlaceholderEnd, true }, | |
255 { "A $simple$$ a", "A simple$ a", | |
256 "", kPlaceholderBegin, kPlaceholderEnd, true }, | |
257 { "A $simple$long_v$", "A simplelong_v$", | |
258 "", kPlaceholderBegin, kPlaceholderEnd, true }, | |
259 { "A $simple$$long_v$", "A simpleA pretty long replacement", | |
260 "", kPlaceholderBegin, kPlaceholderEnd, true }, | |
261 { "This is $bad name$", "This is $bad name$", | |
262 "", kPlaceholderBegin, kPlaceholderEnd, true }, | |
263 { "This is $missing$", "This is $missing$", | |
264 "Variable $missing$ used but not defined.", | |
265 kPlaceholderBegin, kPlaceholderEnd, false }, | |
266 }; | |
267 | |
268 ExtensionMessageBundle::SubstitutionMap messages; | |
269 messages.insert(std::make_pair("simple", "simple")); | |
270 messages.insert(std::make_pair("long", "A pretty long replacement")); | |
271 messages.insert(std::make_pair("long_v", "A pretty long replacement")); | |
272 messages.insert(std::make_pair("bad name", "Doesn't matter")); | |
273 messages.insert(std::make_pair("d1g1ts_are_ok", "I are d1g1t")); | |
274 | |
275 for (size_t i = 0; i < arraysize(test_cases); ++i) { | |
276 std::string text = test_cases[i].original; | |
277 std::string error; | |
278 EXPECT_EQ(test_cases[i].pass, | |
279 ExtensionMessageBundle::ReplaceVariables(messages, | |
280 test_cases[i].begin_delimiter, | |
281 test_cases[i].end_delimiter, | |
282 &text, | |
283 &error)); | |
284 EXPECT_EQ(test_cases[i].result, text); | |
285 } | |
286 } | |
287 | |
288 } // namespace | |
OLD | NEW |