1 // Copyright (c) 2012 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 <stddef.h>
6 #include <stdint.h>
7 
8 #include <vector>
9 
10 #include "base/stl_util.h"
11 #include "chrome/test/logging/win/mof_data_parser.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 // A test fixture for Mof parser tests.
15 class MofDataParserTest : public ::testing::Test {
16  protected:
17   EVENT_TRACE* MakeEventWithDataOfSize(size_t size);
MakeEventWithBlittedValue(T value)18   template<typename T> EVENT_TRACE* MakeEventWithBlittedValue(T value) {
19     EVENT_TRACE* event = MakeEventWithDataOfSize(sizeof(value));
20     *reinterpret_cast<T*>(event->MofData) = value;
21     return event;
22   }
23   EVENT_TRACE* MakeEventWithDWORD(DWORD value);
24   EVENT_TRACE* MakeEventWithPointerArray(const void* const* pointers,
25                                          DWORD size);
26   EVENT_TRACE* MakeEventWithString(const char* a_string, size_t length);
27 
28   std::vector<uint8_t> buffer_;
29 };
30 
MakeEventWithDataOfSize(size_t size)31 EVENT_TRACE* MofDataParserTest::MakeEventWithDataOfSize(size_t size) {
32   buffer_.assign(sizeof(EVENT_TRACE) + size, 0);
33   EVENT_TRACE* event = reinterpret_cast<EVENT_TRACE*>(&buffer_[0]);
34   event->MofLength = size;
35   event->MofData = &buffer_[sizeof(EVENT_TRACE)];
36   return event;
37 }
38 
MakeEventWithDWORD(DWORD value)39 EVENT_TRACE* MofDataParserTest::MakeEventWithDWORD(DWORD value) {
40   return MakeEventWithBlittedValue(value);
41 }
42 
MakeEventWithPointerArray(const void * const * pointers,DWORD size)43 EVENT_TRACE* MofDataParserTest::MakeEventWithPointerArray(
44     const void* const* pointers,
45     DWORD size) {
46   EVENT_TRACE* event =
47       MakeEventWithDataOfSize(sizeof(DWORD) + sizeof(*pointers) * size);
48   *reinterpret_cast<DWORD*>(event->MofData) = size;
49   ::memcpy(reinterpret_cast<DWORD*>(event->MofData) + 1, pointers,
50            sizeof(*pointers) * size);
51   return event;
52 }
53 
54 // |length| is the number of bytes to put in (i.e., include the terminator if
55 // you want one).
MakeEventWithString(const char * a_string,size_t length)56 EVENT_TRACE* MofDataParserTest::MakeEventWithString(const char* a_string,
57                                                     size_t length) {
58   EVENT_TRACE* event = MakeEventWithDataOfSize(length);
59   ::memcpy(event->MofData, a_string, length);
60   return event;
61 }
62 
63 // Tests reading a primitive value.  ReadDWORD, ReadInt, and ReadPointer share
64 // the same implementation, so this test covers all three.
TEST_F(MofDataParserTest,ReadPrimitive)65 TEST_F(MofDataParserTest, ReadPrimitive) {
66 
67   // Read a valid DWORD.
68   EVENT_TRACE* event = MakeEventWithDWORD(5);
69   {
70     DWORD value = 0;
71     logging_win::MofDataParser parser(event);
72     EXPECT_FALSE(parser.empty());
73     EXPECT_TRUE(parser.ReadDWORD(&value));
74     EXPECT_EQ(5UL, value);
75     EXPECT_TRUE(parser.empty());
76   }
77 
78   // Try again if there's insufficient data.
79   --(event->MofLength);
80   {
81     DWORD value = 0;
82     logging_win::MofDataParser parser(event);
83     EXPECT_FALSE(parser.empty());
84     EXPECT_FALSE(parser.ReadDWORD(&value));
85     EXPECT_EQ(0UL, value);
86   }
87 }
88 
89 // Tests reading an array of pointer-sized values.  These arrays are encoded by
90 // writing a DWORD item count followed by the items.
TEST_F(MofDataParserTest,ReadPointerArray)91 TEST_F(MofDataParserTest, ReadPointerArray) {
92   const void* const pointers[] = { this, &buffer_ };
93   const DWORD array_size = base::size(pointers);
94 
95   // Read a valid array of two pointers.
96   EVENT_TRACE* event = MakeEventWithPointerArray(&pointers[0], array_size);
97   {
98     DWORD size = 0;
99     const intptr_t* values = NULL;
100 
101     logging_win::MofDataParser parser(event);
102     EXPECT_FALSE(parser.empty());
103     EXPECT_TRUE(parser.ReadDWORD(&size));
104     EXPECT_EQ(array_size, size);
105     EXPECT_TRUE(parser.ReadPointerArray(size, &values));
106     EXPECT_EQ(0, ::memcmp(&pointers[0], values, sizeof(*values) * size));
107     EXPECT_TRUE(parser.empty());
108   }
109 
110   // Try again if there's insufficient data.
111   --(event->MofLength);
112   {
113     DWORD size = 0;
114     const intptr_t* values = NULL;
115 
116     logging_win::MofDataParser parser(event);
117     EXPECT_FALSE(parser.empty());
118     EXPECT_TRUE(parser.ReadDWORD(&size));
119     EXPECT_EQ(array_size, size);
120     EXPECT_FALSE(parser.ReadPointerArray(size, &values));
121     EXPECT_FALSE(parser.empty());
122   }
123 }
124 
125 // Tests reading a structure.
TEST_F(MofDataParserTest,ReadStructure)126 TEST_F(MofDataParserTest, ReadStructure) {
127   struct Spam {
128     int blorf;
129     char spiffy;
130   };
131   const Spam canned_meat = { 47, 'Y' };
132 
133   // Read a pointer to a structure.
134   EVENT_TRACE* event = MakeEventWithBlittedValue(canned_meat);
135   {
136     const Spam* value = NULL;
137     logging_win::MofDataParser parser(event);
138     EXPECT_FALSE(parser.empty());
139     EXPECT_TRUE(parser.ReadStructure(&value));
140     EXPECT_EQ(canned_meat.blorf, value->blorf);
141     EXPECT_EQ(canned_meat.spiffy, value->spiffy);
142     EXPECT_TRUE(parser.empty());
143   }
144 
145   // Try again if there's insufficient data.
146   --(event->MofLength);
147   {
148     const Spam* value = NULL;
149     logging_win::MofDataParser parser(event);
150     EXPECT_FALSE(parser.empty());
151     EXPECT_FALSE(parser.ReadStructure(&value));
152     EXPECT_FALSE(parser.empty());
153   }
154 }
155 
156 // Tests reading null-terminated string.
TEST_F(MofDataParserTest,ReadString)157 TEST_F(MofDataParserTest, ReadString) {
158   const char a_string_nl[] = "sometimes i get lost in my own thoughts.\n";
159   const char a_string[] = "sometimes i get lost in my own thoughts.";
160 
161   // Read a string with a trailing newline.
162   EVENT_TRACE* event =
163       MakeEventWithString(a_string_nl, base::size(a_string_nl));
164   {
165     base::StringPiece value;
166     logging_win::MofDataParser parser(event);
167     EXPECT_FALSE(parser.empty());
168     EXPECT_TRUE(parser.ReadString(&value));
169     EXPECT_EQ(base::StringPiece(&a_string_nl[0], base::size(a_string_nl) - 2),
170               value);
171     EXPECT_TRUE(parser.empty());
172   }
173 
174   // Read a string without a trailing newline.
175   event = MakeEventWithString(a_string, base::size(a_string));
176   {
177     base::StringPiece value;
178     logging_win::MofDataParser parser(event);
179     EXPECT_FALSE(parser.empty());
180     EXPECT_TRUE(parser.ReadString(&value));
181     EXPECT_EQ(base::StringPiece(&a_string[0], base::size(a_string) - 1), value);
182     EXPECT_TRUE(parser.empty());
183   }
184 
185   // Try a string that isn't terminated.
186   event = MakeEventWithString(a_string, base::size(a_string) - 1);
187   {
188     base::StringPiece value;
189     logging_win::MofDataParser parser(event);
190     EXPECT_FALSE(parser.empty());
191     EXPECT_FALSE(parser.ReadString(&value));
192     EXPECT_FALSE(parser.empty());
193   }
194 }
195