bloaty/tests/test.h
Go to the documentation of this file.
1 // Copyright 2016 Google Inc. All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef BLOATY_TESTS_TEST_H_
16 #define BLOATY_TESTS_TEST_H_
17 
18 #include <fstream>
19 #include <memory>
20 #include <string>
21 #include <unordered_set>
22 #include <tuple>
23 #include <vector>
24 #include "absl/strings/numbers.h"
25 #include "absl/strings/str_split.h"
26 #include "gmock/gmock.h"
27 #include "google/protobuf/text_format.h"
28 #include "gtest/gtest.h"
29 
30 #include "strarr.h"
31 #include "bloaty.h"
32 #include "bloaty.pb.h"
33 
34 #if defined(_MSC_VER)
35 #define PATH_MAX 4096
36 #endif
37 
38 inline bool GetFileSize(const std::string& filename, uint64_t* size) {
39  FILE* file = fopen(filename.c_str(), "rb");
40  if (!file) {
41  std::cerr << "Couldn't get file size for: " << filename << "\n";
42  return false;
43  }
44  fseek(file, 0L, SEEK_END);
45  *size = ftell(file);
46  fclose(file);
47  return true;
48 }
49 
51  char pathbuf[PATH_MAX];
52  if (!getcwd(pathbuf, sizeof(pathbuf))) {
53  return "";
54  }
55  std::string path(pathbuf);
56  size_t pos = path.rfind('/');
57  return path.substr(pos + 1);
58 }
59 
63  return ret;
64 }
65 
66 #define NONE_STRING "[None]"
67 
68 // Testing Bloaty requires a delicate balance. Bloaty's output is by its
69 // nature very compiler and platform dependent. So we want to verify correct
70 // operation without overspecifying how the platform should behave.
71 
72 class BloatyTest : public ::testing::Test {
73  protected:
74  void CheckConsistencyForRow(const bloaty::RollupRow& row, bool is_toplevel,
75  bool diff_mode, int* count) {
76  // If any children exist, they should sum up to this row's values.
77  // Also none of the children should have the same name.
78  std::unordered_set<std::string> names;
79 
80  if (row.sorted_children.size() > 0) {
81  uint64_t vmtotal = 0;
82  uint64_t filetotal = 0;
83  for (const auto& child : row.sorted_children) {
84  vmtotal += child.vmsize;
85  filetotal += child.filesize;
86  CheckConsistencyForRow(child, false, diff_mode, count);
87  ASSERT_TRUE(names.insert(child.name).second);
88  ASSERT_FALSE(child.vmsize == 0 && child.filesize == 0);
89  }
90 
91  if (!diff_mode) {
92  ASSERT_EQ(vmtotal, row.vmsize);
93  ASSERT_EQ(filetotal, row.filesize);
94  }
95  } else {
96  // Count leaf rows.
97  *count += 1;
98  }
99 
100  if (!is_toplevel && row.sorted_children.size() == 1) {
101  ASSERT_NE(NONE_STRING, row.sorted_children[0].name);
102  }
103  }
104 
105  void CheckCSVConsistency(int row_count) {
106  std::ostringstream stream;
108  options.output_format = bloaty::OutputFormat::kCSV;
109  output_->Print(options, &stream);
110  std::string csv_output = stream.str();
111 
112  std::vector<std::string> rows = absl::StrSplit(csv_output, '\n');
113  // Output ends with a final '\n', trim this.
114  ASSERT_EQ("", rows[rows.size() - 1]);
115  rows.pop_back();
116 
117  ASSERT_GT(rows.size(), 0); // There should be a header row.
118 
119  ASSERT_EQ(rows.size() - 1, row_count);
120  bool first = true;
121  for (const auto& row : rows) {
122  std::vector<std::string> cols = absl::StrSplit(row, ',');
123  if (first) {
124  // header row should be: header1,header2,...,vmsize,filesize
125  std::vector<std::string> expected_headers(output_->source_names());
126  expected_headers.push_back("vmsize");
127  expected_headers.push_back("filesize");
128  ASSERT_EQ(cols, expected_headers);
129  first = false;
130  } else {
131  // Final two columns should parse as integer.
132  int out;
133  ASSERT_EQ(output_->source_names().size() + 2, cols.size());
134  ASSERT_TRUE(absl::SimpleAtoi(cols[cols.size() - 1], &out));
135  ASSERT_TRUE(absl::SimpleAtoi(cols[cols.size() - 2], &out));
136  }
137  }
138  }
139 
140  void CheckConsistency(const bloaty::Options& options) {
141  ASSERT_EQ(options.base_filename_size() > 0, output_->diff_mode());
142 
143  if (!output_->diff_mode()) {
144  size_t total_input_size = 0;
145  for (const auto& filename : options.filename()) {
146  uint64_t size;
148  total_input_size += size;
149  }
150  ASSERT_EQ(top_row_->filesize, total_input_size);
151  }
152 
153  int rows = 0;
154  CheckConsistencyForRow(*top_row_, true, output_->diff_mode(), &rows);
155  CheckCSVConsistency(rows);
156  ASSERT_EQ("TOTAL", top_row_->name);
157  }
158 
159  std::string JoinStrings(const std::vector<std::string>& strings) {
160  std::string ret = strings[0];
161  for (size_t i = 1; i < strings.size(); i++) {
162  ret += " " + strings[i];
163  }
164  return ret;
165  }
166 
167  bool TryRunBloatyWithOptions(const bloaty::Options& options,
168  const bloaty::OutputOptions& output_options) {
169  output_.reset(new bloaty::RollupOutput);
170  top_row_ = &output_->toplevel_row();
173  if (bloaty::BloatyMain(options, factory, output_.get(), &error)) {
175  output_->Print(output_options, &std::cerr);
176  return true;
177  } else {
178  std::cerr << "Bloaty returned error:" << error << "\n";
179  return false;
180  }
181  }
182 
183  bool TryRunBloaty(const std::vector<std::string>& strings) {
184  bloaty::Options options;
185  bloaty::OutputOptions output_options;
187  StrArr str_arr(strings);
188  int argc = strings.size();
189  char** argv = str_arr.get();
190  bool ok = bloaty::ParseOptions(false, &argc, &argv, &options,
191  &output_options, &error);
192  if (!ok) {
193  std::cerr << "Error parsing options: " << error;
194  return false;
195  }
196 
197  return TryRunBloatyWithOptions(options, output_options);
198  }
199 
200  void RunBloaty(const std::vector<std::string>& strings) {
201  std::cerr << "Running bloaty: " << JoinStrings(strings) << "\n";
202  ASSERT_TRUE(TryRunBloaty(strings));
203  }
204 
205  void RunBloatyWithOptions(const bloaty::Options& options,
206  const bloaty::OutputOptions& output_options) {
207  std::cerr << "Running bloaty, options: " << DebugString(options) << "\n";
208  ASSERT_TRUE(TryRunBloatyWithOptions(options, output_options));
209  }
210 
211  void AssertBloatyFails(const std::vector<std::string>& strings,
212  const std::string& /*msg_regex*/) {
213  // TODO(haberman): verify msg_regex by making all errors logged to a
214  // standard place.
215  ASSERT_FALSE(TryRunBloaty(strings));
216  }
217 
218  // Special constants for asserting of children.
219  static constexpr int kUnknown = -1;
220  static constexpr int kSameAsVM = -2; // Only for file size.
221 
223  const bloaty::RollupRow& row,
224  const std::vector<std::tuple<std::string, int, int>>& children) {
225  size_t i = 0;
226  for (const auto& child : row.sorted_children) {
228  int expected_vm, expected_file;
229  std::tie(expected_name, expected_vm, expected_file) = children[i];
230 
231  // Excluding leading '_' is kind of a hack to exclude symbols
232  // automatically inserted by the compiler, like __x86.get_pc_thunk.bx
233  // for 32-bit x86 builds or _IO_stdin_used in binaries.
234  //
235  // Excluding leading '[' is for things like this:
236  //
237  // [None]
238  // [ELF Headers]
239  // [AR Headers]
240  // etc.
241  if (child.name[0] == '[' || child.name[0] == '_') {
242  continue;
243  }
245 
246  // <0 indicates that we don't know what the exact size should be (for
247  // example for functions).
248  if (expected_vm == kUnknown) {
249  // Always pass.
250  } else if (expected_vm > 0) {
251  EXPECT_GE(child.vmsize, expected_vm);
252  // Allow some overhead.
253  EXPECT_LE(child.vmsize, (expected_vm * 1.1) + 100);
254  } else {
255  ASSERT_TRUE(false);
256  }
257 
258  if (expected_file == kSameAsVM) {
259  expected_file = child.vmsize;
260  }
261 
262  if (expected_file != kUnknown) {
263  EXPECT_GE(child.filesize, expected_file);
264  // Allow some overhead.
265  EXPECT_LE(child.filesize, (expected_file * 1.2) + 180);
266  }
267 
268  if (++i == children.size()) {
269  // We allow the actual data to have excess elements.
270  break;
271  }
272  }
273 
274  // All expected elements must be present.
275  ASSERT_EQ(i, children.size());
276  }
277 
279  for (const auto& child : top_row_->sorted_children) {
280  if (child.name == name) {
281  return &child;
282  }
283  }
284  EXPECT_TRUE(false) << name;
285  return nullptr;
286  }
287 
288  std::unique_ptr<bloaty::RollupOutput> output_;
290 };
291 
292 constexpr int BloatyTest::kUnknown;
293 constexpr int BloatyTest::kSameAsVM;
294 
295 #endif // BLOATY_TESTS_TEST_H_
absl::StrSplit
strings_internal::Splitter< typename strings_internal::SelectDelimiter< Delimiter >::type, AllowEmpty, absl::string_view > StrSplit(strings_internal::ConvertibleToStringView text, Delimiter d)
Definition: abseil-cpp/absl/strings/str_split.h:499
GetTestDirectory
std::string GetTestDirectory()
Definition: bloaty/tests/test.h:50
BloatyTest::AssertBloatyFails
void AssertBloatyFails(const std::vector< std::string > &strings, const std::string &)
Definition: bloaty/tests/test.h:211
ASSERT_NE
#define ASSERT_NE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2060
filename
const char * filename
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:135
SEEK_END
#define SEEK_END
Definition: bloaty/third_party/zlib/contrib/minizip/zip.c:84
gen_build_yaml.out
dictionary out
Definition: src/benchmark/gen_build_yaml.py:24
pos
int pos
Definition: libuv/docs/code/tty-gravity/main.c:11
BloatyTest::TryRunBloaty
bool TryRunBloaty(const std::vector< std::string > &strings)
Definition: bloaty/tests/test.h:183
StrArr::get
char ** get() const
Definition: strarr.h:42
BloatyTest::CheckConsistencyForRow
void CheckConsistencyForRow(const bloaty::RollupRow &row, bool is_toplevel, bool diff_mode, int *count)
Definition: bloaty/tests/test.h:74
options
double_dict options[]
Definition: capstone_test.c:55
names
sub_type names
Definition: cxa_demangle.cpp:4905
DebugString
std::string DebugString(const google::protobuf::Message &message)
Definition: bloaty/tests/test.h:60
bloaty.h
testing::internal::string
::std::string string
Definition: bloaty/third_party/protobuf/third_party/googletest/googletest/include/gtest/internal/gtest-port.h:881
error
grpc_error_handle error
Definition: retry_filter.cc:499
bloaty::BloatyMain
bool BloatyMain(const Options &options, const InputFileFactory &file_factory, RollupOutput *output, std::string *error)
Definition: bloaty.cc:2196
file
Definition: bloaty/third_party/zlib/examples/gzappend.c:170
bloaty::RollupOutput
Definition: bloaty.h:376
setup.name
name
Definition: setup.py:542
BloatyTest::kSameAsVM
static constexpr int kSameAsVM
Definition: bloaty/tests/test.h:220
check_documentation.path
path
Definition: check_documentation.py:57
EXPECT_LE
#define EXPECT_LE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2030
message
char * message
Definition: libuv/docs/code/tty-gravity/main.c:12
BloatyTest::CheckCSVConsistency
void CheckCSVConsistency(int row_count)
Definition: bloaty/tests/test.h:105
testing::Test
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:402
bloaty::RollupRow::filesize
int64_t filesize
Definition: bloaty.h:339
EXPECT_EQ
#define EXPECT_EQ(a, b)
Definition: iomgr/time_averaged_stats_test.cc:27
absl::SimpleAtoi
ABSL_NAMESPACE_BEGIN ABSL_MUST_USE_RESULT bool SimpleAtoi(absl::string_view str, int_type *out)
Definition: abseil-cpp/absl/strings/numbers.h:271
BloatyTest::FindRow
const bloaty::RollupRow * FindRow(const std::string &name)
Definition: bloaty/tests/test.h:278
bloaty::OutputOptions
Definition: bloaty.h:370
bloaty::OutputFormat::kCSV
@ kCSV
BloatyTest
Definition: bloaty/tests/test.h:72
bloaty::ParseOptions
bool ParseOptions(bool skip_unknown, int *argc, char **argv[], Options *options, OutputOptions *output_options, std::string *error)
Definition: bloaty.cc:2138
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
BloatyTest::AssertChildren
void AssertChildren(const bloaty::RollupRow &row, const std::vector< std::tuple< std::string, int, int >> &children)
Definition: bloaty/tests/test.h:222
strarr.h
bloaty::RollupRow::sorted_children
std::vector< RollupRow > sorted_children
Definition: bloaty.h:346
googletest-filter-unittest.child
child
Definition: bloaty/third_party/googletest/googletest/test/googletest-filter-unittest.py:62
BloatyTest::kUnknown
static constexpr int kUnknown
Definition: bloaty/tests/test.h:219
BloatyTest::top_row_
const bloaty::RollupRow * top_row_
Definition: bloaty/tests/test.h:289
bloaty::RollupRow::name
std::string name
Definition: bloaty.h:337
bloaty::RollupRow::vmsize
int64_t vmsize
Definition: bloaty.h:338
BloatyTest::CheckConsistency
void CheckConsistency(const bloaty::Options &options)
Definition: bloaty/tests/test.h:140
google::protobuf::Message
Definition: bloaty/third_party/protobuf/src/google/protobuf/message.h:205
benchmark.FILE
FILE
Definition: benchmark.py:21
GetFileSize
bool GetFileSize(const std::string &filename, uint64_t *size)
Definition: bloaty/tests/test.h:38
count
int * count
Definition: bloaty/third_party/googletest/googlemock/test/gmock_stress_test.cc:96
grpc::fclose
fclose(creds_file)
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
google::protobuf::TextFormat::PrintToString
static bool PrintToString(const Message &message, std::string *output)
Definition: bloaty/third_party/protobuf/src/google/protobuf/text_format.cc:2395
BloatyTest::RunBloaty
void RunBloaty(const std::vector< std::string > &strings)
Definition: bloaty/tests/test.h:200
bloaty::MmapInputFileFactory
Definition: bloaty.h:96
L
lua_State * L
Definition: upb/upb/bindings/lua/main.c:35
first
StrT first
Definition: cxa_demangle.cpp:4884
ASSERT_TRUE
#define ASSERT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1973
ASSERT_FALSE
#define ASSERT_FALSE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1976
ok
bool ok
Definition: async_end2end_test.cc:197
check_package_name.expected_name
dictionary expected_name
Definition: check_package_name.py:67
EXPECT_GE
#define EXPECT_GE(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2034
EXPECT_TRUE
#define EXPECT_TRUE(condition)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:1967
BloatyTest::JoinStrings
std::string JoinStrings(const std::vector< std::string > &strings)
Definition: bloaty/tests/test.h:159
BloatyTest::TryRunBloatyWithOptions
bool TryRunBloatyWithOptions(const bloaty::Options &options, const bloaty::OutputOptions &output_options)
Definition: bloaty/tests/test.h:167
ASSERT_GT
#define ASSERT_GT(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2076
size
voidpf void uLong size
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136
bloaty::RollupRow
Definition: bloaty.h:334
NONE_STRING
#define NONE_STRING
Definition: bloaty/tests/test.h:66
BloatyTest::RunBloatyWithOptions
void RunBloatyWithOptions(const bloaty::Options &options, const bloaty::OutputOptions &output_options)
Definition: bloaty/tests/test.h:205
BloatyTest::output_
std::unique_ptr< bloaty::RollupOutput > output_
Definition: bloaty/tests/test.h:288
children
std::map< std::string, Node * > children
Definition: bloaty/third_party/protobuf/src/google/protobuf/util/field_mask_util.cc:257
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
ASSERT_EQ
#define ASSERT_EQ(val1, val2)
Definition: bloaty/third_party/googletest/googletest/include/gtest/gtest.h:2056
StrArr
Definition: strarr.h:24
stream
voidpf stream
Definition: bloaty/third_party/zlib/contrib/minizip/ioapi.h:136


grpc
Author(s):
autogenerated on Fri May 16 2025 03:00:27