1 : // Copyright 2011 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/core/json_file_writer.h"
16 :
17 : #include "base/logging.h"
18 : #include "base/files/file_util.h"
19 : #include "base/files/scoped_temp_dir.h"
20 : #include "base/strings/utf_string_conversions.h"
21 : #include "gmock/gmock.h"
22 : #include "gtest/gtest.h"
23 : #include "syzygy/core/unittest_util.h"
24 :
25 : namespace core {
26 :
27 : namespace {
28 :
29 : class TestJSONFileWriter : public JSONFileWriter {
30 : public:
31 E : explicit TestJSONFileWriter(FILE* file, bool pretty_print)
32 : : JSONFileWriter(file, pretty_print) {}
33 :
34 : // Make the internal state functions public.
35 : using JSONFileWriter::FirstEntry;
36 : using JSONFileWriter::ReadyForKey;
37 : using JSONFileWriter::ReadyForValue;
38 : using JSONFileWriter::RequireKeyValue;
39 : using JSONFileWriter::CanClose;
40 :
41 : // Make the enumeration values public.
42 : using JSONFileWriter::kDict;
43 : using JSONFileWriter::kList;
44 : };
45 :
46 : class JSONFileWriterTest: public testing::Test {
47 : public:
48 E : virtual void SetUp() {
49 : // Initialize the temp directory for the first test.
50 E : if (temp_dir_.get() == NULL) {
51 E : temp_dir_.reset(new base::ScopedTempDir());
52 E : ASSERT_TRUE(temp_dir_->CreateUniqueTempDir());
53 : }
54 :
55 E : base::FilePath path;
56 : file_.reset(base::CreateAndOpenTemporaryFileInDir(temp_dir_->path(),
57 E : &path));
58 E : }
59 :
60 : // Returns the contents of the file, leaving the cursor at the end of the
61 : // file for further writing.
62 E : bool FileContents(std::string* contents) {
63 E : DCHECK(contents != NULL);
64 :
65 E : long length = ftell(file_.get());
66 E : if (length < 0)
67 i : return false;
68 :
69 E : contents->resize(length);
70 E : if (length == 0)
71 i : return true;
72 :
73 E : if (fseek(file_.get(), 0, SEEK_SET))
74 i : return false;
75 :
76 : if (fread(&(*contents)[0], 1, length, file_.get()) !=
77 E : static_cast<size_t>(length)) {
78 i : return false;
79 : }
80 :
81 E : if (fseek(file_.get(), 0, SEEK_END))
82 i : return false;
83 :
84 E : return true;
85 E : }
86 :
87 E : FILE* file() {
88 E : return file_.get();
89 E : }
90 :
91 : void ExpectFunctionGenerates(
92 : void (*GeneratorFunc)(TestJSONFileWriter* writer),
93 : const char* expected,
94 E : bool pretty_print) {
95 : // Use a new file each time.
96 E : base::FilePath path;
97 : file_.reset(base::CreateAndOpenTemporaryFileInDir(temp_dir_->path(),
98 E : &path));
99 :
100 E : TestJSONFileWriter json_file(file(), pretty_print);
101 E : ASSERT_NO_FATAL_FAILURE(GeneratorFunc(&json_file));
102 :
103 E : std::string s;
104 E : ASSERT_TRUE(FileContents(&s));
105 :
106 E : ASSERT_EQ(std::string(expected), s);
107 E : }
108 :
109 : private:
110 : // This is static so that a single temp directory is made for all of the
111 : // unittests, rather than one per instance.
112 : static scoped_ptr<base::ScopedTempDir> temp_dir_;
113 : base::ScopedFILE file_;
114 : };
115 :
116 E : scoped_ptr<base::ScopedTempDir> JSONFileWriterTest::temp_dir_;
117 :
118 : // A utility class that can convert a string literal to any of
119 : // * const char*,
120 : // * const wchar_t,
121 : // * const std::string&, or
122 : // * const std::wstring&
123 : // to allow coverage of all variants of methods taking StringPiece or
124 : // StringPiece16.
125 : template <typename StringType>
126 : class LiteralConvert {
127 : public:
128 E : LiteralConvert(const char* str) : str_(str) { // NOLINT
129 E : }
130 :
131 E : const StringType& str() { return str_; }
132 :
133 : private:
134 : std::string str_;
135 : };
136 :
137 : template <>
138 : class LiteralConvert<const char*> {
139 : public:
140 E : LiteralConvert(const char* str) : str_(str) { // NOLINT
141 E : }
142 :
143 E : const char* str() { return str_.c_str(); }
144 :
145 : private:
146 : std::string str_;
147 : };
148 :
149 : template <>
150 : class LiteralConvert<const wchar_t*> {
151 : public:
152 E : LiteralConvert(const char* str) : str_(base::UTF8ToWide(str)) { // NOLINT
153 E : }
154 :
155 E : const wchar_t* str() { return str_.c_str(); }
156 :
157 : private:
158 : std::wstring str_;
159 : };
160 :
161 : template <>
162 : class LiteralConvert<std::wstring> {
163 : public:
164 E : LiteralConvert(const char* str) : str_(base::UTF8ToWide(str)) { // NOLINT
165 E : }
166 :
167 E : const std::wstring& str() { return str_; }
168 :
169 : private:
170 : std::wstring str_;
171 : };
172 :
173 : template <typename StringType>
174 E : void CreateDict(TestJSONFileWriter* json_file) {
175 E : ASSERT_TRUE(json_file != NULL);
176 :
177 E : ASSERT_TRUE(json_file->FirstEntry());
178 E : ASSERT_TRUE(json_file->ReadyForValue());
179 E : ASSERT_FALSE(json_file->RequireKeyValue());
180 :
181 E : EXPECT_TRUE(json_file->OutputComment(
182 : LiteralConvert<StringType>("comment").str()));
183 E : EXPECT_TRUE(json_file->OpenDict());
184 E : ASSERT_TRUE(json_file->FirstEntry());
185 E : ASSERT_TRUE(json_file->ReadyForKey());
186 E : ASSERT_FALSE(json_file->RequireKeyValue());
187 E : ASSERT_TRUE(json_file->CanClose(TestJSONFileWriter::kDict));
188 :
189 E : EXPECT_TRUE(json_file->OutputComment(
190 : LiteralConvert<StringType>("comment").str()));
191 E : EXPECT_TRUE(json_file->OutputKey(
192 : LiteralConvert<StringType>("sample key 1").str()));
193 E : ASSERT_FALSE(json_file->ReadyForKey());
194 E : ASSERT_TRUE(json_file->RequireKeyValue());
195 :
196 : // We shouldn't be able to write a comment in the middle of a key/value pair,
197 : // nor should we be able to close the dictionary.
198 E : EXPECT_FALSE(json_file->OutputComment(
199 : LiteralConvert<StringType>("comment").str()));
200 E : ASSERT_FALSE(json_file->CanClose(TestJSONFileWriter::kDict));
201 :
202 E : EXPECT_TRUE(json_file->OutputString(
203 : LiteralConvert<StringType>("sample value").str()));
204 E : ASSERT_FALSE(json_file->FirstEntry());
205 E : ASSERT_TRUE(json_file->ReadyForKey());
206 E : ASSERT_FALSE(json_file->RequireKeyValue());
207 E : ASSERT_TRUE(json_file->CanClose(TestJSONFileWriter::kDict));
208 :
209 E : EXPECT_TRUE(json_file->OutputKey(
210 : LiteralConvert<StringType>("sample key 2").str()));
211 E : ASSERT_FALSE(json_file->ReadyForKey());
212 E : ASSERT_TRUE(json_file->RequireKeyValue());
213 E : ASSERT_FALSE(json_file->CanClose(TestJSONFileWriter::kDict));
214 :
215 E : EXPECT_TRUE(json_file->OutputInteger(5));
216 E : ASSERT_FALSE(json_file->FirstEntry());
217 E : ASSERT_TRUE(json_file->ReadyForKey());
218 E : ASSERT_FALSE(json_file->RequireKeyValue());
219 E : ASSERT_TRUE(json_file->CanClose(TestJSONFileWriter::kDict));
220 :
221 E : EXPECT_TRUE(json_file->OutputTrailingComment(
222 : LiteralConvert<StringType>("trailing comment").str()));
223 E : EXPECT_FALSE(json_file->OutputTrailingComment(
224 : LiteralConvert<StringType>("foo").str()));
225 :
226 E : EXPECT_TRUE(json_file->OutputComment(
227 : LiteralConvert<StringType>("comment").str()));
228 :
229 E : EXPECT_TRUE(json_file->CloseDict());
230 E : ASSERT_TRUE(json_file->Finished());
231 E : }
232 :
233 : template <typename StringType>
234 E : void CreateList(TestJSONFileWriter* json_file) {
235 E : ASSERT_TRUE(json_file != NULL);
236 :
237 E : ASSERT_TRUE(json_file->FirstEntry());
238 E : ASSERT_TRUE(json_file->ReadyForValue());
239 E : ASSERT_FALSE(json_file->RequireKeyValue());
240 :
241 E : EXPECT_TRUE(json_file->OpenList());
242 E : ASSERT_TRUE(json_file->FirstEntry());
243 E : ASSERT_FALSE(json_file->RequireKeyValue());
244 E : ASSERT_TRUE(json_file->CanClose(TestJSONFileWriter::kList));
245 :
246 E : EXPECT_TRUE(json_file->OutputString(
247 : LiteralConvert<StringType>("sample value").str()));
248 E : ASSERT_FALSE(json_file->FirstEntry());
249 E : ASSERT_FALSE(json_file->RequireKeyValue());
250 E : ASSERT_TRUE(json_file->CanClose(TestJSONFileWriter::kList));
251 :
252 E : EXPECT_TRUE(json_file->OutputComment(
253 : LiteralConvert<StringType>("comment").str()));
254 :
255 E : EXPECT_TRUE(json_file->OutputDouble(4.5));
256 E : ASSERT_FALSE(json_file->FirstEntry());
257 E : ASSERT_FALSE(json_file->RequireKeyValue());
258 E : ASSERT_TRUE(json_file->CanClose(TestJSONFileWriter::kList));
259 :
260 E : EXPECT_TRUE(json_file->OutputBoolean(false));
261 E : ASSERT_FALSE(json_file->FirstEntry());
262 E : ASSERT_FALSE(json_file->RequireKeyValue());
263 E : ASSERT_TRUE(json_file->CanClose(TestJSONFileWriter::kList));
264 :
265 E : EXPECT_TRUE(json_file->OutputTrailingComment(
266 : LiteralConvert<StringType>("trailing comment").str()));
267 E : EXPECT_FALSE(json_file->OutputTrailingComment(
268 : LiteralConvert<StringType>("foo").str()));
269 :
270 E : EXPECT_TRUE(json_file->OutputComment(
271 : LiteralConvert<StringType>("comment").str()));
272 :
273 E : EXPECT_TRUE(json_file->CloseList());
274 E : ASSERT_TRUE(json_file->Finished());
275 :
276 E : EXPECT_TRUE(json_file->OutputComment(
277 : LiteralConvert<StringType>("comment").str()));
278 E : }
279 :
280 : template <typename StringType>
281 E : void CreateNested(TestJSONFileWriter* json_file) {
282 E : ASSERT_TRUE(json_file != NULL);
283 :
284 E : ASSERT_TRUE(json_file->FirstEntry());
285 E : ASSERT_TRUE(json_file->ReadyForValue());
286 E : ASSERT_FALSE(json_file->RequireKeyValue());
287 :
288 E : EXPECT_TRUE(json_file->OpenDict());
289 E : ASSERT_FALSE(json_file->ReadyForValue());
290 E : ASSERT_FALSE(json_file->RequireKeyValue());
291 :
292 E : EXPECT_TRUE(json_file->OutputComment(
293 : LiteralConvert<StringType>("comment").str()));
294 :
295 E : EXPECT_TRUE(json_file->OutputKey(LiteralConvert<StringType>("key").str()));
296 E : ASSERT_TRUE(json_file->ReadyForValue());
297 E : ASSERT_TRUE(json_file->RequireKeyValue());
298 :
299 E : EXPECT_TRUE(json_file->OpenList());
300 E : ASSERT_TRUE(json_file->ReadyForValue());
301 E : ASSERT_FALSE(json_file->RequireKeyValue());
302 :
303 E : EXPECT_TRUE(json_file->OutputNull());
304 E : ASSERT_TRUE(json_file->ReadyForValue());
305 E : ASSERT_FALSE(json_file->RequireKeyValue());
306 :
307 E : EXPECT_TRUE(json_file->OutputTrailingComment(
308 : LiteralConvert<StringType>("trailing comment").str()));
309 E : EXPECT_FALSE(json_file->OutputTrailingComment(
310 : LiteralConvert<StringType>("foo").str()));
311 :
312 E : EXPECT_TRUE(json_file->Flush());
313 E : EXPECT_TRUE(json_file->Finished());
314 :
315 E : EXPECT_TRUE(json_file->OutputComment(
316 : LiteralConvert<StringType>("comment").str()));
317 E : }
318 :
319 : } // namespace
320 :
321 E : TEST_F(JSONFileWriterTest, OutputBoolean) {
322 E : TestJSONFileWriter json_file(file(), false);
323 E : ASSERT_TRUE(json_file.FirstEntry());
324 E : ASSERT_TRUE(json_file.ReadyForValue());
325 E : ASSERT_FALSE(json_file.RequireKeyValue());
326 :
327 E : EXPECT_TRUE(json_file.OutputBoolean(true));
328 E : ASSERT_TRUE(json_file.Finished());
329 :
330 E : std::string s;
331 E : ASSERT_TRUE(FileContents(&s));
332 E : ASSERT_EQ("true", s);
333 E : }
334 :
335 E : TEST_F(JSONFileWriterTest, OutputInteger) {
336 E : TestJSONFileWriter json_file(file(), false);
337 E : ASSERT_TRUE(json_file.FirstEntry());
338 E : ASSERT_TRUE(json_file.ReadyForValue());
339 E : ASSERT_FALSE(json_file.RequireKeyValue());
340 :
341 E : EXPECT_TRUE(json_file.OutputInteger(11));
342 E : ASSERT_TRUE(json_file.Finished());
343 :
344 E : std::string s;
345 E : ASSERT_TRUE(FileContents(&s));
346 E : ASSERT_EQ("11", s);
347 E : }
348 :
349 E : TEST_F(JSONFileWriterTest, OutputDouble) {
350 E : TestJSONFileWriter json_file(file(), false);
351 E : ASSERT_TRUE(json_file.FirstEntry());
352 E : ASSERT_TRUE(json_file.ReadyForValue());
353 E : ASSERT_FALSE(json_file.RequireKeyValue());
354 :
355 E : EXPECT_TRUE(json_file.OutputDouble(4.5));
356 E : ASSERT_TRUE(json_file.Finished());
357 :
358 E : std::string s;
359 E : ASSERT_TRUE(FileContents(&s));
360 E : ASSERT_EQ("4.5", s);
361 E : }
362 :
363 E : TEST_F(JSONFileWriterTest, OutputString) {
364 E : TestJSONFileWriter json_file(file(), false);
365 E : ASSERT_TRUE(json_file.FirstEntry());
366 E : ASSERT_TRUE(json_file.ReadyForValue());
367 E : ASSERT_FALSE(json_file.RequireKeyValue());
368 :
369 E : EXPECT_TRUE(json_file.OutputString("sample string"));
370 E : ASSERT_TRUE(json_file.Finished());
371 :
372 E : std::string s;
373 E : ASSERT_TRUE(FileContents(&s));
374 E : ASSERT_EQ("\"sample string\"", s);
375 E : }
376 :
377 E : TEST_F(JSONFileWriterTest, OutputWstring) {
378 E : TestJSONFileWriter json_file(file(), false);
379 E : ASSERT_TRUE(json_file.FirstEntry());
380 E : ASSERT_TRUE(json_file.ReadyForValue());
381 E : ASSERT_FALSE(json_file.RequireKeyValue());
382 :
383 E : EXPECT_TRUE(json_file.OutputString(L"sample string"));
384 E : ASSERT_TRUE(json_file.Finished());
385 :
386 E : std::string s;
387 E : ASSERT_TRUE(FileContents(&s));
388 E : ASSERT_EQ("\"sample string\"", s);
389 E : }
390 :
391 E : TEST_F(JSONFileWriterTest, OutputNull) {
392 E : TestJSONFileWriter json_file(file(), false);
393 E : ASSERT_TRUE(json_file.FirstEntry());
394 E : ASSERT_TRUE(json_file.ReadyForValue());
395 E : ASSERT_FALSE(json_file.RequireKeyValue());
396 :
397 E : EXPECT_TRUE(json_file.OutputNull());
398 E : ASSERT_TRUE(json_file.Finished());
399 :
400 E : std::string s;
401 E : ASSERT_TRUE(FileContents(&s));
402 E : ASSERT_EQ("null", s);
403 E : }
404 :
405 E : TEST_F(JSONFileWriterTest, DestructorAutoFlushes) {
406 : {
407 E : TestJSONFileWriter json_file(file(), false);
408 E : EXPECT_TRUE(json_file.OpenList());
409 E : EXPECT_TRUE(json_file.OpenDict());
410 E : }
411 :
412 E : std::string s;
413 E : ASSERT_TRUE(FileContents(&s));
414 :
415 E : std::string expected = "[{}]";
416 :
417 E : ASSERT_EQ(expected, s);
418 E : }
419 :
420 E : TEST_F(JSONFileWriterTest, OutputDict) {
421 : const char* kExpected = "{\"sample key 1\":\"sample value\","
422 E : "\"sample key 2\":5}";
423 :
424 E : ExpectFunctionGenerates(CreateDict<const char*>, kExpected, false);
425 E : ExpectFunctionGenerates(CreateDict<const wchar_t*>, kExpected, false);
426 E : ExpectFunctionGenerates(CreateDict<std::string>, kExpected, false);
427 E : ExpectFunctionGenerates(CreateDict<std::wstring>, kExpected, false);
428 E : }
429 :
430 E : TEST_F(JSONFileWriterTest, OutputDictPrettyPrint) {
431 : const char* kExpected =
432 : "// comment\n"
433 : "{\n"
434 : " // comment\n"
435 : " \"sample key 1\": \"sample value\",\n"
436 : " \"sample key 2\": 5 // trailing comment\n"
437 : " // comment\n"
438 E : "}";
439 :
440 E : ExpectFunctionGenerates(CreateDict<const char*>, kExpected, true);
441 E : ExpectFunctionGenerates(CreateDict<const wchar_t*>, kExpected, true);
442 E : ExpectFunctionGenerates(CreateDict<std::string>, kExpected, true);
443 E : ExpectFunctionGenerates(CreateDict<std::wstring>, kExpected, true);
444 E : }
445 :
446 E : TEST_F(JSONFileWriterTest, OutputList) {
447 E : const char* kExpected = "[\"sample value\",4.5,false]";
448 :
449 E : ExpectFunctionGenerates(CreateList<const char*>, kExpected, false);
450 E : ExpectFunctionGenerates(CreateList<const wchar_t*>, kExpected, false);
451 E : ExpectFunctionGenerates(CreateList<std::string>, kExpected, false);
452 E : ExpectFunctionGenerates(CreateList<std::wstring>, kExpected, false);
453 E : }
454 :
455 E : TEST_F(JSONFileWriterTest, OutputListPrettyPrint) {
456 : const char* kExpected =
457 : "[\n"
458 : " \"sample value\",\n"
459 : " // comment\n"
460 : " 4.5,\n"
461 : " false // trailing comment\n"
462 : " // comment\n"
463 : "]\n"
464 E : "// comment";
465 :
466 E : ExpectFunctionGenerates(CreateList<const char*>, kExpected, true);
467 E : ExpectFunctionGenerates(CreateList<const wchar_t*>, kExpected, true);
468 E : ExpectFunctionGenerates(CreateList<std::string>, kExpected, true);
469 E : ExpectFunctionGenerates(CreateList<std::wstring>, kExpected, true);
470 E : }
471 :
472 E : TEST_F(JSONFileWriterTest, Nested) {
473 E : const char* kExpected = "{\"key\":[null]}";
474 :
475 E : ExpectFunctionGenerates(CreateNested<const char*>, kExpected, false);
476 E : ExpectFunctionGenerates(CreateNested<const wchar_t*>, kExpected, false);
477 E : ExpectFunctionGenerates(CreateNested<std::string>, kExpected, false);
478 E : ExpectFunctionGenerates(CreateNested<std::wstring>, kExpected, false);
479 E : }
480 :
481 E : TEST_F(JSONFileWriterTest, NestedPrettyPrint) {
482 : const char* kExpected =
483 : "{\n"
484 : " // comment\n"
485 : " \"key\": [\n"
486 : " null // trailing comment\n"
487 : " ]\n"
488 : "}\n"
489 E : "// comment";
490 :
491 E : ExpectFunctionGenerates(CreateNested<const char*>, kExpected, true);
492 E : ExpectFunctionGenerates(CreateNested<const wchar_t*>, kExpected, true);
493 E : ExpectFunctionGenerates(CreateNested<std::string>, kExpected, true);
494 E : ExpectFunctionGenerates(CreateNested<std::wstring>, kExpected, true);
495 E : }
496 :
497 E : TEST_F(JSONFileWriterTest, MismatchedDictionaryCausesError) {
498 E : TestJSONFileWriter json_file(file(), false);
499 E : EXPECT_TRUE(json_file.OpenDict());
500 E : EXPECT_FALSE(json_file.CloseList());
501 E : }
502 :
503 E : TEST_F(JSONFileWriterTest, MissingDictionaryKeyCausesError) {
504 E : TestJSONFileWriter json_file(file(), false);
505 E : EXPECT_TRUE(json_file.OpenDict());
506 E : EXPECT_FALSE(json_file.OutputBoolean(false));
507 E : }
508 :
509 E : TEST_F(JSONFileWriterTest, MissingDictionaryValueCausesError) {
510 E : TestJSONFileWriter json_file(file(), false);
511 E : EXPECT_TRUE(json_file.OpenDict());
512 E : EXPECT_TRUE(json_file.OutputKey("key1"));
513 E : EXPECT_FALSE(json_file.OutputKey("key2"));
514 E : }
515 :
516 E : TEST_F(JSONFileWriterTest, MismatchedListCausesError) {
517 E : TestJSONFileWriter json_file(file(), false);
518 E : EXPECT_TRUE(json_file.OpenList());
519 E : EXPECT_FALSE(json_file.CloseDict());
520 E : }
521 :
522 E : TEST_F(JSONFileWriterTest, TrailingCommentSingleValue) {
523 E : TestJSONFileWriter json_file(file(), true);
524 E : ASSERT_TRUE(json_file.ReadyForValue());
525 E : ASSERT_FALSE(json_file.Finished());
526 :
527 E : EXPECT_TRUE(json_file.OutputInteger(2));
528 E : ASSERT_FALSE(json_file.ReadyForValue());
529 E : ASSERT_TRUE(json_file.Finished());
530 :
531 E : EXPECT_TRUE(json_file.OutputTrailingComment("trailing comment"));
532 :
533 E : std::string s;
534 E : ASSERT_TRUE(FileContents(&s));
535 :
536 E : std::string expected = "2 // trailing comment";
537 :
538 E : ASSERT_EQ(expected, s);
539 E : }
540 :
541 : } // namespace core
|