// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include "base/basictypes.h" #include "chrome/test/logging/win/mof_data_parser.h" #include "testing/gtest/include/gtest/gtest.h" // A test fixture for Mof parser tests. class MofDataParserTest : public ::testing::Test { protected: EVENT_TRACE* MakeEventWithDataOfSize(size_t size); template EVENT_TRACE* MakeEventWithBlittedValue(T value) { EVENT_TRACE* event = MakeEventWithDataOfSize(sizeof(value)); *reinterpret_cast(event->MofData) = value; return event; } EVENT_TRACE* MakeEventWithDWORD(DWORD value); EVENT_TRACE* MakeEventWithPointerArray(const void* const* pointers, DWORD size); EVENT_TRACE* MakeEventWithString(const char* a_string, size_t length); std::vector buffer_; }; EVENT_TRACE* MofDataParserTest::MakeEventWithDataOfSize(size_t size) { buffer_.assign(sizeof(EVENT_TRACE) + size, 0); EVENT_TRACE* event = reinterpret_cast(&buffer_[0]); event->MofLength = size; event->MofData = &buffer_[sizeof(EVENT_TRACE)]; return event; } EVENT_TRACE* MofDataParserTest::MakeEventWithDWORD(DWORD value) { return MakeEventWithBlittedValue(value); } EVENT_TRACE* MofDataParserTest::MakeEventWithPointerArray( const void* const* pointers, DWORD size) { EVENT_TRACE* event = MakeEventWithDataOfSize(sizeof(DWORD) + sizeof(*pointers) * size); *reinterpret_cast(event->MofData) = size; ::memcpy(reinterpret_cast(event->MofData) + 1, pointers, sizeof(*pointers) * size); return event; } // |length| is the number of bytes to put in (i.e., include the terminator if // you want one). EVENT_TRACE* MofDataParserTest::MakeEventWithString(const char* a_string, size_t length) { EVENT_TRACE* event = MakeEventWithDataOfSize(length); ::memcpy(event->MofData, a_string, length); return event; } // Tests reading a primitive value. ReadDWORD, ReadInt, and ReadPointer share // the same implementation, so this test covers all three. TEST_F(MofDataParserTest, ReadPrimitive) { // Read a valid DWORD. EVENT_TRACE* event = MakeEventWithDWORD(5); { DWORD value = 0; logging_win::MofDataParser parser(event); EXPECT_FALSE(parser.empty()); EXPECT_TRUE(parser.ReadDWORD(&value)); EXPECT_EQ(5UL, value); EXPECT_TRUE(parser.empty()); } // Try again if there's insufficient data. --(event->MofLength); { DWORD value = 0; logging_win::MofDataParser parser(event); EXPECT_FALSE(parser.empty()); EXPECT_FALSE(parser.ReadDWORD(&value)); EXPECT_EQ(0UL, value); } } // Tests reading an array of pointer-sized values. These arrays are encoded by // writing a DWORD item count followed by the items. TEST_F(MofDataParserTest, ReadPointerArray) { const void* const pointers[] = { this, &buffer_ }; const DWORD array_size = arraysize(pointers); // Read a valid array of two pointers. EVENT_TRACE* event = MakeEventWithPointerArray(&pointers[0], array_size); { DWORD size = 0; const intptr_t* values = NULL; logging_win::MofDataParser parser(event); EXPECT_FALSE(parser.empty()); EXPECT_TRUE(parser.ReadDWORD(&size)); EXPECT_EQ(array_size, size); EXPECT_TRUE(parser.ReadPointerArray(size, &values)); EXPECT_EQ(0, ::memcmp(&pointers[0], values, sizeof(*values) * size)); EXPECT_TRUE(parser.empty()); } // Try again if there's insufficient data. --(event->MofLength); { DWORD size = 0; const intptr_t* values = NULL; logging_win::MofDataParser parser(event); EXPECT_FALSE(parser.empty()); EXPECT_TRUE(parser.ReadDWORD(&size)); EXPECT_EQ(array_size, size); EXPECT_FALSE(parser.ReadPointerArray(size, &values)); EXPECT_FALSE(parser.empty()); } } // Tests reading a structure. TEST_F(MofDataParserTest, ReadStructure) { struct Spam { int blorf; char spiffy; }; const Spam canned_meat = { 47, 'Y' }; // Read a pointer to a structure. EVENT_TRACE* event = MakeEventWithBlittedValue(canned_meat); { const Spam* value = NULL; logging_win::MofDataParser parser(event); EXPECT_FALSE(parser.empty()); EXPECT_TRUE(parser.ReadStructure(&value)); EXPECT_EQ(canned_meat.blorf, value->blorf); EXPECT_EQ(canned_meat.spiffy, value->spiffy); EXPECT_TRUE(parser.empty()); } // Try again if there's insufficient data. --(event->MofLength); { const Spam* value = NULL; logging_win::MofDataParser parser(event); EXPECT_FALSE(parser.empty()); EXPECT_FALSE(parser.ReadStructure(&value)); EXPECT_FALSE(parser.empty()); } } // Tests reading null-terminated string. TEST_F(MofDataParserTest, ReadString) { const char a_string_nl[] = "sometimes i get lost in my own thoughts.\n"; const char a_string[] = "sometimes i get lost in my own thoughts."; // Read a string with a trailing newline. EVENT_TRACE* event = MakeEventWithString(a_string_nl, arraysize(a_string_nl)); { base::StringPiece value; logging_win::MofDataParser parser(event); EXPECT_FALSE(parser.empty()); EXPECT_TRUE(parser.ReadString(&value)); EXPECT_EQ(base::StringPiece(&a_string_nl[0], arraysize(a_string_nl) - 2), value); EXPECT_TRUE(parser.empty()); } // Read a string without a trailing newline. event = MakeEventWithString(a_string, arraysize(a_string)); { base::StringPiece value; logging_win::MofDataParser parser(event); EXPECT_FALSE(parser.empty()); EXPECT_TRUE(parser.ReadString(&value)); EXPECT_EQ(base::StringPiece(&a_string[0], arraysize(a_string) - 1), value); EXPECT_TRUE(parser.empty()); } // Try a string that isn't terminated. event = MakeEventWithString(a_string, arraysize(a_string) - 1); { base::StringPiece value; logging_win::MofDataParser parser(event); EXPECT_FALSE(parser.empty()); EXPECT_FALSE(parser.ReadString(&value)); EXPECT_FALSE(parser.empty()); } }