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/values.h"
19 : #include "base/files/scoped_temp_dir.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 : base::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 : base::FilePath does_not_exist(
91 E : temp_dir_.path().AppendASCII("does_not_exist.json"));
92 E : EXPECT_FALSE(serializer.LoadFromJson(does_not_exist, &entry_count_map));
93 :
94 : base::FilePath some_path(testing::GetExeTestDataRelativePath(
95 E : testing::kCoverageTraceFiles[0]));
96 E : EXPECT_FALSE(serializer.LoadFromJson(some_path, &entry_count_map));
97 E : }
98 :
99 E : TEST_F(BasicBlockEntryCountSerializerTest, PopulateFromJsonValueFails) {
100 E : ModuleEntryCountMap entry_count_map;
101 E : TestBasicBlockEntryCountSerializer serializer;
102 :
103 : // It should fail if the outermost JSON object is not a list.
104 E : scoped_ptr<Value> int_value(Value::CreateIntegerValue(7));
105 : ASSERT_FALSE(serializer.PopulateFromJsonValue(int_value.get(),
106 E : &entry_count_map));
107 :
108 : // It should fail if the outermost list does not contain dictionaries.
109 E : scoped_ptr<ListValue> list_value(new ListValue());
110 E : list_value->Append(Value::CreateBooleanValue(true));
111 : ASSERT_FALSE(serializer.PopulateFromJsonValue(list_value.get(),
112 E : &entry_count_map));
113 E : list_value->Clear();
114 :
115 : // It should fail if the list entry does not contain a metadata key.
116 E : DictionaryValue* dict_value = new DictionaryValue();
117 E : list_value->Append(dict_value);
118 : ASSERT_FALSE(serializer.PopulateFromJsonValue(list_value.get(),
119 E : &entry_count_map));
120 :
121 : // It should fail if the metadata value is not a dictionary.
122 E : dict_value->Set("metadata", Value::CreateStringValue("foo"));
123 : ASSERT_FALSE(serializer.PopulateFromJsonValue(list_value.get(),
124 E : &entry_count_map));
125 :
126 : // After adding the metadata value, it should still fail since there is no
127 : // entry_count_map key.
128 : static const char kMetadataStr[] =
129 : "{\n"
130 : " \"command_line\": \"foo.exe\",\n"
131 : " \"creation_time\": \"Wed, 19 Sep 2012 17:33:52 GMT\",\n"
132 : " \"toolchain_version\": {\n"
133 : " \"major\": 0,\n"
134 : " \"minor\": 2,\n"
135 : " \"build\": 7,\n"
136 : " \"patch\": 0,\n"
137 : " \"last_change\": \"0\"\n"
138 : " },\n"
139 : " \"module_signature\": {\n"
140 : " \"path\": \"C:\\\\foo\\\\bar.dll\",\n"
141 : " \"base_address\": 1904279552,\n"
142 : " \"module_size\": 180224,\n"
143 : " \"module_time_date_stamp\": \"0x46F7885059FE32\",\n"
144 : " \"module_checksum\": \"0x257AF\"\n"
145 : " }\n"
146 : "}\n";
147 E : std::string error_msg;
148 : scoped_ptr<Value> metadata(JSONReader().ReadAndReturnError(
149 E : kMetadataStr, true, NULL, &error_msg));
150 E : EXPECT_EQ(std::string(), error_msg);
151 E : ASSERT_TRUE(metadata.get() != NULL);
152 E : dict_value->Set("metadata", metadata.release());
153 : ASSERT_FALSE(serializer.PopulateFromJsonValue(list_value.get(),
154 E : &entry_count_map));
155 :
156 : // It should still fail since the entry_counts key has the wrong value type.
157 E : dict_value->Set("entry_counts", Value::CreateStringValue("foo"));
158 : ASSERT_FALSE(serializer.PopulateFromJsonValue(list_value.get(),
159 E : &entry_count_map));
160 :
161 : // It should still fail since the entry_counts list contains an invalid value.
162 E : ListValue* entry_counts = new ListValue();
163 E : dict_value->Set("entry_counts", entry_counts);
164 E : entry_counts->Append(Value::CreateStringValue("foo"));
165 : ASSERT_FALSE(serializer.PopulateFromJsonValue(list_value.get(),
166 E : &entry_count_map));
167 :
168 : // It should succeed once we start putting numbers into the entry_counts list.
169 E : EntryCountMap expected_values;
170 E : entry_counts->Clear();
171 E : for (size_t i = 0; i < expected_values.size(); ++i) {
172 i : scoped_ptr<ListValue> entry(new ListValue());
173 i : entry->Append(Value::CreateIntegerValue(i * i));
174 i : entry->Append(Value::CreateIntegerValue(100 * i));
175 i : expected_values[i * i] = 100 * i;
176 :
177 i : entry_counts->Append(entry.release());
178 i : }
179 :
180 : ASSERT_TRUE(serializer.PopulateFromJsonValue(list_value.get(),
181 E : &entry_count_map));
182 :
183 E : EXPECT_EQ(1U, entry_count_map.size());
184 : EXPECT_THAT(entry_count_map.begin()->second,
185 E : testing::ContainerEq(expected_values));
186 E : }
187 :
188 E : TEST_F(BasicBlockEntryCountSerializerTest, RoundTrip) {
189 E : ModuleInformation module_info;
190 E : ASSERT_NO_FATAL_FAILURE(InitModuleInfo(&module_info));
191 :
192 E : ModuleEntryCountMap entry_count_map;
193 E : EntryCountMap& counters = entry_count_map[module_info];
194 E : size_t num_basic_blocks = 100;
195 E : for (size_t i = 0; i < num_basic_blocks; ++i)
196 E : counters[i * i] = i + 1;
197 :
198 E : base::FilePath json_path(temp_dir_.path().AppendASCII("test.json"));
199 :
200 E : TestBasicBlockEntryCountSerializer serializer;
201 E : serializer.set_pretty_print(true);
202 E : ASSERT_TRUE(serializer.SaveAsJson(entry_count_map, json_path));
203 :
204 E : ModuleEntryCountMap new_entry_count_map;
205 E : serializer.LoadFromJson(json_path, &new_entry_count_map);
206 :
207 E : EXPECT_THAT(new_entry_count_map, ContainerEq(entry_count_map));
208 E : }
209 :
210 : } // namespace grinder
|