blob: b77f0d5d695ab3989eccc0b2912e3a79d5df2db3 [file] [log] [blame]
// Copyright 2015 Google Inc. All Rights Reserved.
//
// 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 "syzygy/crashdata/json.h"
#include "gtest/gtest.h"
namespace crashdata {
namespace {
void TestConversion(bool pretty_print,
const Value& value,
const char* expected_json) {
std::string json;
EXPECT_TRUE(ToJson(pretty_print, &value, &json));
EXPECT_EQ(json, expected_json);
}
} // namespace
TEST(CrashDataJsonTest, BadValueFails) {
Value value;
std::string json;
for (size_t i = Value_Type_Type_MIN; i <= Value_Type_Type_MAX; ++i) {
value.set_type(static_cast<Value_Type>(i));
EXPECT_FALSE(ToJson(true, &value, &json));
EXPECT_TRUE(json.empty());
}
}
TEST(CrashDataJsonTest, BadLeafFails) {
Value value;
Leaf* leaf = ValueGetLeaf(&value);
std::string json;
for (size_t i = Leaf_Type_Type_MIN; i <= Leaf_Type_Type_MAX; ++i) {
leaf->set_type(static_cast<Leaf_Type>(i));
EXPECT_FALSE(ToJson(true, &value, &json));
EXPECT_TRUE(json.empty());
}
}
TEST(CrashDataJsonTest, BadKeyValue) {
Value value;
value.set_type(Value_Type_DICTIONARY);
Dictionary* dict = value.mutable_dictionary();
KeyValue* kv = dict->add_values();
std::string json;
// No key and no value should fail.
EXPECT_FALSE(ToJson(true, &value, &json));
EXPECT_TRUE(json.empty());
// A key and no value should fail.
kv->set_key("key");
EXPECT_FALSE(ToJson(true, &value, &json));
EXPECT_TRUE(json.empty());
// No key and a valid value should fail.
kv->clear_key();
Value* value2 = kv->mutable_value();
Leaf* leaf = ValueGetLeaf(value2);
leaf->set_type(Leaf_Type_INTEGER);
leaf->set_integer(42);
EXPECT_FALSE(ToJson(true, &value, &json));
EXPECT_TRUE(json.empty());
}
TEST(CrashDataJsonTest, ValueLeafInteger) {
Value value;
LeafSetInt(-48, ValueGetLeaf(&value));
const char kExpected[] = "-48";
TestConversion(true, value, kExpected);
TestConversion(false, value, kExpected);;
}
TEST(CrashDataJsonTest, ValueLeafUnsignedInteger) {
Value value;
LeafSetUInt(653, ValueGetLeaf(&value));
const char kExpected[] = "653";
TestConversion(true, value, kExpected);
TestConversion(false, value, kExpected);;
}
TEST(CrashDataJsonTest, ValueLeafReal) {
Value value;
LeafSetReal(2.0e99, ValueGetLeaf(&value));
const char kExpected[] = "1.9999999999999999E+99";
TestConversion(true, value, kExpected);
TestConversion(false, value, kExpected);
}
TEST(CrashDataJsonTest, ValueLeafString) {
Value value;
*LeafGetString(ValueGetLeaf(&value)) = "foo \"\\ bar";
const char kExpected[] = "\"foo \\\"\\\\ bar\"";
TestConversion(true, value, kExpected);
TestConversion(false, value, kExpected);
}
TEST(CrashDataJsonTest, ValueLeafAddress) {
Value value;
LeafGetAddress(ValueGetLeaf(&value))->set_address(0xBADBEEF);
const char kExpected[] = "\"0x0BADBEEF\"";
TestConversion(true, value, kExpected);
TestConversion(false, value, kExpected);;
}
TEST(CrashDataJsonTest, ValueLeafStackTrace) {
Value value;
StackTrace* stack = LeafGetStackTrace(ValueGetLeaf(&value));
stack->add_frames(0xDEADBEEF);
stack->add_frames(0xBADF00D);
stack->add_frames(0x10000000);
stack->add_frames(0x20000000);
stack->add_frames(0x30000000);
stack->add_frames(0x40000000);
const char kExpectedPretty[] =
"[\n"
" \"0xDEADBEEF\", \"0x0BADF00D\", \"0x10000000\", \"0x20000000\",\n"
" \"0x30000000\", \"0x40000000\"\n"
"]";
TestConversion(true, value, kExpectedPretty);
const char kExpectedCompact[] = "[\"0xDEADBEEF\",\"0x0BADF00D\","
"\"0x10000000\",\"0x20000000\",\"0x30000000\",\"0x40000000\"]";
TestConversion(false, value, kExpectedCompact);
}
TEST(CrashDataJsonTest, ValueLeafBlob) {
Value value;
Blob* blob = LeafGetBlob(ValueGetLeaf(&value));
blob->mutable_address()->set_address(0xF00);
std::string* data = blob->mutable_data();
for (size_t i = 0; i < 3; ++i) {
data->push_back(static_cast<unsigned char>(0xDE));
data->push_back(static_cast<unsigned char>(0xAD));
data->push_back(static_cast<unsigned char>(0xBE));
data->push_back(static_cast<unsigned char>(0xEF));
}
const char kExpectedPretty[] =
"{\n"
" \"type\": \"blob\",\n"
" \"address\": \"0x00000F00\",\n"
" \"size\": null,\n"
" \"data\": [\n"
" \"0xDE\", \"0xAD\", \"0xBE\", \"0xEF\", \"0xDE\", \"0xAD\","
" \"0xBE\", \"0xEF\",\n"
" \"0xDE\", \"0xAD\", \"0xBE\", \"0xEF\"\n"
" ]\n"
"}";
TestConversion(true, value, kExpectedPretty);
const char kExpectedCompact[] =
"{\"type\":\"blob\",\"address\":\"0x00000F00\",\"size\":null,"
"\"data\":[\"0xDE\",\"0xAD\",\"0xBE\",\"0xEF\",\"0xDE\",\"0xAD\","
"\"0xBE\",\"0xEF\",\"0xDE\",\"0xAD\",\"0xBE\",\"0xEF\"]}";
TestConversion(false, value, kExpectedCompact);
}
TEST(CrashDataJsonTest, ValueList) {
Value value;
ValueList* list = ValueGetValueList(&value);
LeafGetAddress(ValueGetLeaf(list->add_values()))->set_address(0xDEADF00D);
LeafSetInt(42, ValueGetLeaf(list->add_values()));
const char kExpectedPretty[] =
"[\n"
" \"0xDEADF00D\",\n"
" 42\n"
"]";
TestConversion(true, value, kExpectedPretty);
const char kExpectedCompact[] = "[\"0xDEADF00D\",42]";
TestConversion(false, value, kExpectedCompact);
}
TEST(CrashDataJsonTest, ValueDict) {
Value value;
Dictionary* dict = ValueGetDict(&value);
LeafGetAddress(ValueGetLeaf(DictAddValue("key1", dict)))->set_address(
0xDEADF00D);
LeafSetInt(42, ValueGetLeaf(DictAddValue("key2", dict)));
const char kExpectedPretty[] =
"{\n"
" \"key1\": \"0xDEADF00D\",\n"
" \"key2\": 42\n"
"}";
TestConversion(true, value, kExpectedPretty);
const char kExpectedCompact[] = "{\"key1\":\"0xDEADF00D\",\"key2\":42}";
TestConversion(false, value, kExpectedCompact);
}
TEST(CrashDataJsonTest, AllTypes) {
Value value;
value.set_type(Value_Type_DICTIONARY);
Dictionary* dict = value.mutable_dictionary();
// One of each type of leaf.
LeafSetInt(-42, ValueGetLeaf(DictAddValue("int", dict)));
LeafSetUInt(42, ValueGetLeaf(DictAddValue("uint", dict)));
LeafSetReal(2.0e99, ValueGetLeaf(DictAddValue("real", dict)));
*LeafGetString(ValueGetLeaf(DictAddValue("string", dict))) = "foobar";
LeafGetAddress(ValueGetLeaf(DictAddValue("address", dict)))->set_address(
0xDEADF00D);
LeafGetStackTrace(ValueGetLeaf(DictAddValue("stack-trace", dict)))
->add_frames(0xBAADBEEF);
LeafGetBlob(ValueGetLeaf(DictAddValue("blob", dict)))->mutable_data()
->append("hey");
// Nested dictionary with a single element.
LeafSetInt(100, ValueGetLeaf(DictAddValue("INT", ValueGetDict(
DictAddValue("dict", dict)))));
// Nested list with a single element
ValueList* list = ValueGetValueList(DictAddValue("list", dict));
LeafSetInt(200, ValueGetLeaf(list->add_values()));
const char kExpectedPretty[] =
"{\n"
" \"int\": -42,\n"
" \"uint\": 42,\n"
" \"real\": 1.9999999999999999E+99,\n"
" \"string\": \"foobar\",\n"
" \"address\": \"0xDEADF00D\",\n"
" \"stack-trace\": [\n"
" \"0xBAADBEEF\"\n"
" ],\n"
" \"blob\": {\n"
" \"type\": \"blob\",\n"
" \"address\": null,\n"
" \"size\": null,\n"
" \"data\": [\n"
" \"0x68\", \"0x65\", \"0x79\"\n"
" ]\n"
" },\n"
" \"dict\": {\n"
" \"INT\": 100\n"
" },\n"
" \"list\": [\n"
" 200\n"
" ]\n"
"}";
TestConversion(true, value, kExpectedPretty);
const char kExpectedCompact[] =
"{"
"\"int\":-42,"
"\"uint\":42,"
"\"real\":1.9999999999999999E+99,"
"\"string\":\"foobar\","
"\"address\":\"0xDEADF00D\","
"\"stack-trace\":[\"0xBAADBEEF\"],"
"\"blob\":{"
"\"type\":\"blob\","
"\"address\":null,"
"\"size\":null,"
"\"data\":[\"0x68\",\"0x65\",\"0x79\"]"
"},"
"\"dict\":{"
"\"INT\":100"
"},"
"\"list\":["
"200"
"]"
"}";
TestConversion(false, value, kExpectedCompact);
}
} // namespace crashdata