1 : // Copyright 2012 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/grinder/basic_block_entry_count_serializer.h"
16 :
17 : #include "base/file_util.h"
18 : #include "base/scoped_temp_dir.h"
19 : #include "base/values.h"
20 : #include "base/json/json_reader.h"
21 : #include "gmock/gmock.h"
22 : #include "gtest/gtest.h"
23 : #include "syzygy/core/unittest_util.h"
24 : #include "syzygy/pe/metadata.h"
25 : #include "syzygy/pe/unittest_util.h"
26 :
27 : namespace grinder {
28 :
29 : namespace {
30 :
31 : using base::DictionaryValue;
32 : using base::FundamentalValue;
33 : using base::JSONReader;
34 : using base::ListValue;
35 : using base::Value;
36 : using basic_block_util::EntryCountMap;
37 : using basic_block_util::EntryCountType;
38 : using basic_block_util::ModuleEntryCountMap;
39 : using basic_block_util::ModuleInformation;
40 : using testing::ContainerEq;
41 :
42 : const wchar_t kImageFileName[] = L"foo.dll";
43 : const uint32 kBaseAddress = 0xDEADBEEF;
44 : const uint32 kModuleSize = 0x1000;
45 : const uint32 kImageChecksum = 0xCAFEBABE;
46 : const uint32 kTimeDateStamp = 0xBABECAFE;
47 :
48 : class TestBasicBlockEntryCountSerializer
49 : : public BasicBlockEntryCountSerializer {
50 : public:
51 : using BasicBlockEntryCountSerializer::PopulateFromJsonValue;
52 : using BasicBlockEntryCountSerializer::pretty_print_;
53 : };
54 :
55 : class BasicBlockEntryCountSerializerTest : public testing::PELibUnitTest {
56 : public:
57 : typedef testing::PELibUnitTest Super;
58 :
59 E : virtual void SetUp() OVERRIDE {
60 E : Super::SetUp();
61 E : ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
62 E : }
63 :
64 E : void InitModuleInfo(ModuleInformation* module_info) {
65 E : ASSERT_TRUE(module_info != NULL);
66 E : module_info->image_file_name = kImageFileName;
67 E : module_info->base_address = kBaseAddress;
68 E : module_info->module_size = kModuleSize;
69 E : module_info->image_checksum = kImageChecksum;
70 E : module_info->time_date_stamp = kTimeDateStamp;
71 E : }
72 : protected:
73 : ScopedTempDir temp_dir_;
74 : };
75 :
76 : } // namespace
77 :
78 E : TEST_F(BasicBlockEntryCountSerializerTest, Accessors) {
79 E : TestBasicBlockEntryCountSerializer serializer;
80 E : EXPECT_FALSE(serializer.pretty_print_);
81 :
82 E : serializer.set_pretty_print(true);
83 E : EXPECT_TRUE(serializer.pretty_print_);
84 E : }
85 :
86 E : TEST_F(BasicBlockEntryCountSerializerTest, LoadFromJsonFails) {
87 E : TestBasicBlockEntryCountSerializer serializer;
88 E : ModuleEntryCountMap entry_count_map;
89 :
90 E : FilePath does_not_exist(temp_dir_.path().AppendASCII("does_not_exist.json"));
91 E : EXPECT_FALSE(serializer.LoadFromJson(does_not_exist, &entry_count_map));
92 :
93 : FilePath some_path(testing::GetExeTestDataRelativePath(
94 E : testing::kCoverageTraceFiles[0]));
95 E : EXPECT_FALSE(serializer.LoadFromJson(some_path, &entry_count_map));
96 E : }
97 :
98 E : TEST_F(BasicBlockEntryCountSerializerTest, PopulateFromJsonValueFails) {
99 E : ModuleEntryCountMap entry_count_map;
100 E : TestBasicBlockEntryCountSerializer serializer;
101 :
102 : // It should fail if the outermost JSON object is not a list.
103 E : scoped_ptr<Value> int_value(Value::CreateIntegerValue(7));
104 : ASSERT_FALSE(serializer.PopulateFromJsonValue(int_value.get(),
105 E : &entry_count_map));
106 :
107 : // It should fail if the outermost list does not contain dictionaries.
108 E : scoped_ptr<ListValue> list_value(new ListValue());
109 E : list_value->Append(Value::CreateBooleanValue(true));
110 : ASSERT_FALSE(serializer.PopulateFromJsonValue(list_value.get(),
111 E : &entry_count_map));
112 E : list_value->Clear();
113 :
114 : // It should fail if the list entry does not contain a metadata key.
115 E : DictionaryValue* dict_value = new DictionaryValue();
116 E : list_value->Append(dict_value);
117 : ASSERT_FALSE(serializer.PopulateFromJsonValue(list_value.get(),
118 E : &entry_count_map));
119 :
120 : // It should fail if the metadata value is not a dictionary.
121 E : dict_value->Set("metadata", Value::CreateStringValue("foo"));
122 : ASSERT_FALSE(serializer.PopulateFromJsonValue(list_value.get(),
123 E : &entry_count_map));
124 :
125 : // After adding the metadata value, it should still fail since there is no
126 : // entry_count_map key.
127 : static const char kMetadataStr[] =
128 : "{\n"
129 : " \"command_line\": \"foo.exe\",\n"
130 : " \"creation_time\": \"Wed, 19 Sep 2012 17:33:52 GMT\",\n"
131 : " \"toolchain_version\": {\n"
132 : " \"major\": 0,\n"
133 : " \"minor\": 2,\n"
134 : " \"build\": 7,\n"
135 : " \"patch\": 0,\n"
136 : " \"last_change\": \"0\"\n"
137 : " },\n"
138 : " \"module_signature\": {\n"
139 : " \"path\": \"C:\\\\foo\\\\bar.dll\",\n"
140 : " \"base_address\": 1904279552,\n"
141 : " \"module_size\": 180224,\n"
142 : " \"module_time_date_stamp\": \"0x46F7885059FE32\",\n"
143 : " \"module_checksum\": \"0x257AF\"\n"
144 : " }\n"
145 : "}\n";
146 E : std::string error_msg;
147 : scoped_ptr<Value> metadata(JSONReader().ReadAndReturnError(
148 E : kMetadataStr, true, NULL, &error_msg));
149 E : EXPECT_EQ(std::string(), error_msg);
150 E : ASSERT_TRUE(metadata.get() != NULL);
151 E : dict_value->Set("metadata", metadata.release());
152 : ASSERT_FALSE(serializer.PopulateFromJsonValue(list_value.get(),
153 E : &entry_count_map));
154 :
155 : // It should still fail since the entry_counts key has the wrong value type.
156 E : dict_value->Set("entry_counts", Value::CreateStringValue("foo"));
157 : ASSERT_FALSE(serializer.PopulateFromJsonValue(list_value.get(),
158 E : &entry_count_map));
159 :
160 : // It should still fail since the entry_counts list contains an invalid value.
161 E : ListValue* entry_counts = new ListValue();
162 E : dict_value->Set("entry_counts", entry_counts);
163 E : entry_counts->Append(Value::CreateStringValue("foo"));
164 : ASSERT_FALSE(serializer.PopulateFromJsonValue(list_value.get(),
165 E : &entry_count_map));
166 :
167 : // It should succeed once we start putting numbers into the entry_counts list.
168 E : EntryCountMap expected_values;
169 E : entry_counts->Clear();
170 E : for (size_t i = 0; i < expected_values.size(); ++i) {
171 i : scoped_ptr<ListValue> entry(new ListValue());
172 i : entry->Append(Value::CreateIntegerValue(i * i));
173 i : entry->Append(Value::CreateIntegerValue(100 * i));
174 i : expected_values[i * i] = 100 * i;
175 :
176 i : entry_counts->Append(entry.release());
177 i : }
178 :
179 : ASSERT_TRUE(serializer.PopulateFromJsonValue(list_value.get(),
180 E : &entry_count_map));
181 :
182 E : EXPECT_EQ(1U, entry_count_map.size());
183 : EXPECT_THAT(entry_count_map.begin()->second,
184 E : testing::ContainerEq(expected_values));
185 E : }
186 :
187 E : TEST_F(BasicBlockEntryCountSerializerTest, RoundTrip) {
188 E : ModuleInformation module_info;
189 E : ASSERT_NO_FATAL_FAILURE(InitModuleInfo(&module_info));
190 :
191 E : ModuleEntryCountMap entry_count_map;
192 E : EntryCountMap& counters = entry_count_map[module_info];
193 E : size_t num_basic_blocks = 100;
194 E : for (size_t i = 0; i < num_basic_blocks; ++i)
195 E : counters[i * i] = i + 1;
196 :
197 E : FilePath json_path(temp_dir_.path().AppendASCII("test.json"));
198 :
199 E : TestBasicBlockEntryCountSerializer serializer;
200 E : serializer.set_pretty_print(true);
201 E : ASSERT_TRUE(serializer.SaveAsJson(entry_count_map, json_path));
202 :
203 E : ModuleEntryCountMap new_entry_count_map;
204 E : serializer.LoadFromJson(json_path, &new_entry_count_map);
205 :
206 E : EXPECT_THAT(new_entry_count_map, ContainerEq(entry_count_map));
207 E : }
208 :
209 : } // namespace grinder
|