xref: /aosp_15_r20/external/cronet/third_party/googletest/custom/gtest/internal/custom/stack_trace_getter.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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