blob: dc05cc64b3953ddf65d0fbff6bb276933302c0b4 [file] [log] [blame]
// Copyright 2017 The Crashpad Authors. 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 "minidump/minidump_annotation_writer.h"
#include <memory>
#include "base/stl_util.h"
#include "gtest/gtest.h"
#include "minidump/minidump_extensions.h"
#include "minidump/test/minidump_byte_array_writer_test_util.h"
#include "minidump/test/minidump_string_writer_test_util.h"
#include "minidump/test/minidump_writable_test_util.h"
#include "util/file/string_file.h"
namespace crashpad {
namespace test {
namespace {
const MinidumpAnnotationList* MinidumpAnnotationListAtStart(
const std::string& file_contents,
uint32_t count) {
MINIDUMP_LOCATION_DESCRIPTOR location_descriptor;
location_descriptor.DataSize = static_cast<uint32_t>(
sizeof(MinidumpAnnotationList) + count * sizeof(MinidumpAnnotation));
location_descriptor.Rva = 0;
return MinidumpWritableAtLocationDescriptor<MinidumpAnnotationList>(
file_contents, location_descriptor);
}
TEST(MinidumpAnnotationWriter, EmptyList) {
StringFile string_file;
MinidumpAnnotationListWriter list_writer;
EXPECT_FALSE(list_writer.IsUseful());
EXPECT_TRUE(list_writer.WriteEverything(&string_file));
ASSERT_EQ(string_file.string().size(), sizeof(MinidumpAnnotationList));
auto* list = MinidumpAnnotationListAtStart(string_file.string(), 0);
ASSERT_TRUE(list);
EXPECT_EQ(list->count, 0u);
}
TEST(MinidumpAnnotationWriter, OneItem) {
StringFile string_file;
const char kName[] = "name";
const uint16_t kType = 0xFFFF;
const std::vector<uint8_t> kValue{'v', 'a', 'l', 'u', 'e', '\0'};
auto annotation_writer = std::make_unique<MinidumpAnnotationWriter>();
annotation_writer->InitializeWithData(kName, kType, kValue);
MinidumpAnnotationListWriter list_writer;
list_writer.AddObject(std::move(annotation_writer));
EXPECT_TRUE(list_writer.IsUseful());
EXPECT_TRUE(list_writer.WriteEverything(&string_file));
ASSERT_EQ(string_file.string().size(),
sizeof(MinidumpAnnotationList) + sizeof(MinidumpAnnotation) +
sizeof(MinidumpUTF8String) + sizeof(kName) +
sizeof(MinidumpByteArray) + kValue.size() +
3); // 3 for padding.
auto* list = MinidumpAnnotationListAtStart(string_file.string(), 1);
ASSERT_TRUE(list);
EXPECT_EQ(list->count, 1u);
EXPECT_EQ(MinidumpUTF8StringAtRVAAsString(string_file.string(),
list->objects[0].name),
kName);
EXPECT_EQ(list->objects[0].type, kType);
EXPECT_EQ(list->objects[0].reserved, 0u);
EXPECT_EQ(
MinidumpByteArrayAtRVA(string_file.string(), list->objects[0].value),
kValue);
}
TEST(MinidumpAnnotationWriter, ThreeItems) {
StringFile string_file;
const char* kNames[] = {
"~~FIRST~~", " second + ", "3",
};
const uint16_t kTypes[] = {
0x1, 0xABCD, 0x42,
};
const std::vector<uint8_t> kValues[] = {
{'\0'}, {0xB0, 0xA0, 0xD0, 0xD0, 0xD0}, {'T'},
};
MinidumpAnnotationListWriter list_writer;
for (size_t i = 0; i < base::size(kNames); ++i) {
auto annotation = std::make_unique<MinidumpAnnotationWriter>();
annotation->InitializeWithData(kNames[i], kTypes[i], kValues[i]);
list_writer.AddObject(std::move(annotation));
}
EXPECT_TRUE(list_writer.WriteEverything(&string_file));
ASSERT_EQ(string_file.string().size(),
sizeof(MinidumpAnnotationList) + 3 * sizeof(MinidumpAnnotation) +
3 * sizeof(MinidumpUTF8String) + 3 * sizeof(MinidumpByteArray) +
strlen(kNames[0]) + 1 + kValues[0].size() + 2 +
strlen(kNames[1]) + 1 + 3 + kValues[1].size() + 1 +
strlen(kNames[2]) + 1 + 3 + kValues[2].size() + 2);
auto* list = MinidumpAnnotationListAtStart(string_file.string(), 3);
ASSERT_TRUE(list);
EXPECT_EQ(list->count, 3u);
for (size_t i = 0; i < 3; ++i) {
EXPECT_EQ(MinidumpUTF8StringAtRVAAsString(string_file.string(),
list->objects[i].name),
kNames[i]);
EXPECT_EQ(list->objects[i].type, kTypes[i]);
EXPECT_EQ(list->objects[i].reserved, 0u);
EXPECT_EQ(
MinidumpByteArrayAtRVA(string_file.string(), list->objects[i].value),
kValues[i]);
}
}
TEST(MinidumpAnnotationWriter, DuplicateNames) {
StringFile string_file;
const char kName[] = "@@name!";
const uint16_t kType = 0x1;
const std::vector<uint8_t> kValue1{'r', 'e', 'd', '\0'};
const std::vector<uint8_t> kValue2{'m', 'a', 'g', 'e', 'n', 't', 'a', '\0'};
MinidumpAnnotationListWriter list_writer;
auto annotation = std::make_unique<MinidumpAnnotationWriter>();
annotation->InitializeWithData(kName, kType, kValue1);
list_writer.AddObject(std::move(annotation));
annotation = std::make_unique<MinidumpAnnotationWriter>();
annotation->InitializeWithData(kName, kType, kValue2);
list_writer.AddObject(std::move(annotation));
EXPECT_TRUE(list_writer.WriteEverything(&string_file));
ASSERT_EQ(string_file.string().size(),
sizeof(MinidumpAnnotationList) + 2 * sizeof(MinidumpAnnotation) +
2 * sizeof(MinidumpUTF8String) + 2 * sizeof(MinidumpByteArray) +
2 * sizeof(kName) + kValue1.size() + kValue2.size());
auto* list = MinidumpAnnotationListAtStart(string_file.string(), 2);
ASSERT_TRUE(list);
EXPECT_EQ(list->count, 2u);
EXPECT_EQ(MinidumpUTF8StringAtRVAAsString(string_file.string(),
list->objects[0].name),
kName);
EXPECT_EQ(list->objects[0].type, kType);
EXPECT_EQ(
MinidumpByteArrayAtRVA(string_file.string(), list->objects[0].value),
kValue1);
EXPECT_EQ(MinidumpUTF8StringAtRVAAsString(string_file.string(),
list->objects[1].name),
kName);
EXPECT_EQ(list->objects[1].type, kType);
EXPECT_EQ(
MinidumpByteArrayAtRVA(string_file.string(), list->objects[1].value),
kValue2);
}
} // namespace
} // namespace test
} // namespace crashpad