1 // Copyright 2018 The Chromium Authors
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 "third_party/googletest/custom/gtest/internal/custom/stack_trace_getter.h"
6
7 #include <algorithm>
8 #include <iterator>
9
10 #include "base/containers/adapters.h"
11 #include "base/containers/span.h"
12 #include "base/ranges/algorithm.h"
13
CurrentStackTrace(int max_depth,int skip_count)14 std::string StackTraceGetter::CurrentStackTrace(int max_depth, int skip_count) {
15 base::debug::StackTrace stack_trace;
16
17 base::span<const void* const> departure;
18 if (stack_trace_upon_leaving_gtest_.has_value()) {
19 departure = stack_trace_upon_leaving_gtest_->addresses();
20 }
21
22 base::span<const void* const> current = stack_trace.addresses();
23
24 // Ignore the frames at the root of the current trace that match those of the
25 // point of departure from GTest. These frames all relate to thread start and
26 // test setup, and are irrelevant for diagnosing a failure in a given test.
27 // Also ignore the very first mismatch, as this identifies two instructions
28 // within the GTest function that called UponLeavingGTest, and is irrelevant
29 // as well.
30 {
31 auto mismatch_pair = std::mismatch(departure.rbegin(), departure.rend(),
32 current.rbegin(), current.rend());
33 if (mismatch_pair.second != current.rend()) {
34 current = current.subspan(
35 0, current.size() - (mismatch_pair.second - current.rbegin() + 1));
36 }
37 }
38
39 // Ignore the frames at the leaf of the current trace that match those of the
40 // point of departure from GTest. These frames are the call(s) into
41 // StackTrace's constructor, which are irrelevant. Also ignore the very first
42 // mismatch, as it identifies two instructions within current function.
43 {
44 auto mismatch_pair = std::mismatch(departure.begin(), departure.end(),
45 current.begin(), current.end());
46 if (mismatch_pair.second != current.end()) {
47 auto match_size = (mismatch_pair.second - current.begin()) + 1;
48 current = current.subspan(match_size);
49 }
50 }
51
52 // Ignore frames that the caller wishes to skip.
53 if (skip_count >= 0 && static_cast<size_t>(skip_count) < current.size()) {
54 current = current.subspan(skip_count);
55 }
56
57 // Only return as many as requested.
58 if (max_depth >= 0 && static_cast<size_t>(max_depth) < current.size()) {
59 current = current.subspan(0, static_cast<size_t>(max_depth));
60 }
61
62 return base::debug::StackTrace(current.data(), current.size()).ToString();
63 }
64
UponLeavingGTest()65 void StackTraceGetter::UponLeavingGTest() {
66 // Remember the callstack as GTest is left.
67 stack_trace_upon_leaving_gtest_.emplace();
68 }
69