blob: e5fd95bc63174a30b85208194e6665fbe3734a28 [file] [log] [blame]
// Copyright 2018 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 "third_party/googletest/custom/gtest/internal/custom/stack_trace_getter.h"
#include <algorithm>
#include <iterator>
#include "base/logging.h"
std::string StackTraceGetter::CurrentStackTrace(int max_depth, int skip_count) {
DCHECK(stack_trace_upon_leaving_gtest_)
<< "Missing call to UponLeavingGTest. Are you using GoogleTest's "
"RUN_ALL_TESTS()?";
base::debug::StackTrace stack_trace;
size_t departure_frame_count = 0;
const void* const* departure_addresses =
stack_trace_upon_leaving_gtest_->Addresses(&departure_frame_count);
size_t current_frame_count = 0;
const void* const* current_addresses =
stack_trace.Addresses(&current_frame_count);
// Ignore the frames at the root of the current trace that match those of the
// point of departure from GTest. These frames all relate to thread start and
// test setup, and are irrelevant for diagnosing a failure in a given test.
// Also ignore the very first mismatch, as this identifies two instructions
// within the GTest function that called UponLeavingGTest, and is irrelevant
// as well.
{
auto departure_rbegin =
std::make_reverse_iterator(departure_addresses + departure_frame_count);
auto departure_rend = std::make_reverse_iterator(departure_addresses);
auto current_rbegin =
std::make_reverse_iterator(current_addresses + current_frame_count);
auto current_rend = std::make_reverse_iterator(current_addresses);
auto mismatch_pair = std::mismatch(departure_rbegin, departure_rend,
current_rbegin, current_rend);
if (mismatch_pair.second != current_rend)
current_frame_count -= (mismatch_pair.second - current_rbegin) + 1;
}
// Ignore the frames at the leaf of the current trace that match those of the
// point of departure from GTest. These frames are the call(s) into
// StackTrace's constructor, which are irrelevant. Also ignore the very first
// mismatch, as it identifies two instructions within current function.
{
auto mismatch_pair = std::mismatch(
departure_addresses, departure_addresses + departure_frame_count,
current_addresses, current_addresses + current_frame_count);
if (mismatch_pair.second != current_addresses + current_frame_count) {
auto match_size = (mismatch_pair.second - current_addresses) + 1;
current_frame_count -= match_size;
current_addresses += match_size;
}
}
// Ignore frames that the caller wishes to skip.
if (skip_count >= 0 &&
static_cast<size_t>(skip_count) < current_frame_count) {
current_frame_count -= skip_count;
current_addresses += skip_count;
}
// Only return as many as requested.
if (max_depth >= 0 && static_cast<size_t>(max_depth) < current_frame_count)
current_frame_count = static_cast<size_t>(max_depth);
return base::debug::StackTrace(current_addresses, current_frame_count)
.ToString();
}
void StackTraceGetter::UponLeavingGTest() {
// Remember the callstack as GTest is left.
stack_trace_upon_leaving_gtest_.emplace();
}