simpleperf: port cmd_report_test to nonlinux.

And fix one build_id bug introduced by previous patch.

Bug: 26962895

Change-Id: Ibb8bd6ec77ee862bb01c26342d3b3024468e75b2
(cherry picked from commit 6e51bef9aa101307523946df301ca90215d0ee82)
diff --git a/simpleperf/Android.mk b/simpleperf/Android.mk
index 5c5642b..36372e9 100644
--- a/simpleperf/Android.mk
+++ b/simpleperf/Android.mk
@@ -176,6 +176,7 @@
 # simpleperf_unit_test
 # =========================================================
 simpleperf_unit_test_src_files := \
+  cmd_report_test.cpp \
   command_test.cpp \
   gtest_main.cpp \
   read_apk_test.cpp \
@@ -187,7 +188,6 @@
   cmd_dumprecord_test.cpp \
   cmd_list_test.cpp \
   cmd_record_test.cpp \
-  cmd_report_test.cpp \
   cmd_stat_test.cpp \
   environment_test.cpp \
   record_file_test.cpp \
diff --git a/simpleperf/cmd_dumprecord_test.cpp b/simpleperf/cmd_dumprecord_test.cpp
index f23ae16..574fb2a 100644
--- a/simpleperf/cmd_dumprecord_test.cpp
+++ b/simpleperf/cmd_dumprecord_test.cpp
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 
 #include "command.h"
+#include "test_util.h"
 
 class DumpRecordCommandTest : public ::testing::Test {
  protected:
@@ -32,11 +33,11 @@
 };
 
 TEST_F(DumpRecordCommandTest, no_options) {
-  ASSERT_TRUE(record_cmd->Run({"-a", "sleep", "1"}));
+  ASSERT_TRUE(record_cmd->Run({"-a", "sleep", SLEEP_SEC}));
   ASSERT_TRUE(dumprecord_cmd->Run({}));
 }
 
 TEST_F(DumpRecordCommandTest, record_file_option) {
-  ASSERT_TRUE(record_cmd->Run({"-a", "-o", "perf2.data", "sleep", "1"}));
+  ASSERT_TRUE(record_cmd->Run({"-a", "-o", "perf2.data", "sleep", SLEEP_SEC}));
   ASSERT_TRUE(dumprecord_cmd->Run({"perf2.data"}));
 }
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index ca38a05..6f54fc6 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -32,32 +32,32 @@
 }
 
 TEST(record_cmd, no_options) {
-  ASSERT_TRUE(RecordCmd()->Run({"sleep", "1"}));
+  ASSERT_TRUE(RecordCmd()->Run({"sleep", SLEEP_SEC}));
 }
 
 TEST(record_cmd, system_wide_option) {
-  ASSERT_TRUE(RecordCmd()->Run({"-a", "sleep", "1"}));
+  ASSERT_TRUE(RecordCmd()->Run({"-a", "sleep", SLEEP_SEC}));
 }
 
 TEST(record_cmd, sample_period_option) {
-  ASSERT_TRUE(RecordCmd()->Run({"-c", "100000", "sleep", "1"}));
+  ASSERT_TRUE(RecordCmd()->Run({"-c", "100000", "sleep", SLEEP_SEC}));
 }
 
 TEST(record_cmd, event_option) {
-  ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-clock", "sleep", "1"}));
+  ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-clock", "sleep", SLEEP_SEC}));
 }
 
 TEST(record_cmd, freq_option) {
-  ASSERT_TRUE(RecordCmd()->Run({"-f", "99", "sleep", "1"}));
-  ASSERT_TRUE(RecordCmd()->Run({"-F", "99", "sleep", "1"}));
+  ASSERT_TRUE(RecordCmd()->Run({"-f", "99", "sleep", SLEEP_SEC}));
+  ASSERT_TRUE(RecordCmd()->Run({"-F", "99", "sleep", SLEEP_SEC}));
 }
 
 TEST(record_cmd, output_file_option) {
-  ASSERT_TRUE(RecordCmd()->Run({"-o", "perf2.data", "sleep", "1"}));
+  ASSERT_TRUE(RecordCmd()->Run({"-o", "perf2.data", "sleep", SLEEP_SEC}));
 }
 
 TEST(record_cmd, dump_kernel_mmap) {
-  ASSERT_TRUE(RecordCmd()->Run({"sleep", "1"}));
+  ASSERT_TRUE(RecordCmd()->Run({"sleep", SLEEP_SEC}));
   std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance("perf.data");
   ASSERT_TRUE(reader != nullptr);
   std::vector<std::unique_ptr<Record>> records = reader->DataSection();
@@ -76,7 +76,7 @@
 }
 
 TEST(record_cmd, dump_build_id_feature) {
-  ASSERT_TRUE(RecordCmd()->Run({"sleep", "1"}));
+  ASSERT_TRUE(RecordCmd()->Run({"sleep", SLEEP_SEC}));
   std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance("perf.data");
   ASSERT_TRUE(reader != nullptr);
   const FileHeader& file_header = reader->FileHeader();
@@ -85,16 +85,16 @@
 }
 
 TEST(record_cmd, tracepoint_event) {
-  ASSERT_TRUE(RecordCmd()->Run({"-a", "-e", "sched:sched_switch", "sleep", "1"}));
+  ASSERT_TRUE(RecordCmd()->Run({"-a", "-e", "sched:sched_switch", "sleep", SLEEP_SEC}));
 }
 
 TEST(record_cmd, branch_sampling) {
   if (IsBranchSamplingSupported()) {
-    ASSERT_TRUE(RecordCmd()->Run({"-a", "-b", "sleep", "1"}));
-    ASSERT_TRUE(RecordCmd()->Run({"-j", "any,any_call,any_ret,ind_call", "sleep", "1"}));
-    ASSERT_TRUE(RecordCmd()->Run({"-j", "any,k", "sleep", "1"}));
-    ASSERT_TRUE(RecordCmd()->Run({"-j", "any,u", "sleep", "1"}));
-    ASSERT_FALSE(RecordCmd()->Run({"-j", "u", "sleep", "1"}));
+    ASSERT_TRUE(RecordCmd()->Run({"-a", "-b", "sleep", SLEEP_SEC}));
+    ASSERT_TRUE(RecordCmd()->Run({"-j", "any,any_call,any_ret,ind_call", "sleep", SLEEP_SEC}));
+    ASSERT_TRUE(RecordCmd()->Run({"-j", "any,k", "sleep", SLEEP_SEC}));
+    ASSERT_TRUE(RecordCmd()->Run({"-j", "any,u", "sleep", SLEEP_SEC}));
+    ASSERT_FALSE(RecordCmd()->Run({"-j", "u", "sleep", SLEEP_SEC}));
   } else {
     GTEST_LOG_(INFO)
         << "This test does nothing as branch stack sampling is not supported on this device.";
@@ -102,18 +102,18 @@
 }
 
 TEST(record_cmd, event_modifier) {
-  ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-cycles:u", "sleep", "1"}));
+  ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-cycles:u", "sleep", SLEEP_SEC}));
 }
 
 TEST(record_cmd, fp_callchain_sampling) {
-  ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "fp", "sleep", "1"}));
+  ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "fp", "sleep", SLEEP_SEC}));
 }
 
 TEST(record_cmd, dwarf_callchain_sampling) {
   if (IsDwarfCallChainSamplingSupported()) {
-    ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf", "sleep", "1"}));
-    ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf,16384", "sleep", "1"}));
-    ASSERT_TRUE(RecordCmd()->Run({"-g", "sleep", "1"}));
+    ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf", "sleep", SLEEP_SEC}));
+    ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf,16384", "sleep", SLEEP_SEC}));
+    ASSERT_TRUE(RecordCmd()->Run({"-g", "sleep", SLEEP_SEC}));
   } else {
     GTEST_LOG_(INFO)
         << "This test does nothing as dwarf callchain sampling is not supported on this device.";
@@ -122,24 +122,24 @@
 
 TEST(record_cmd, no_unwind_option) {
   if (IsDwarfCallChainSamplingSupported()) {
-    ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf", "--no-unwind", "sleep", "1"}));
+    ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf", "--no-unwind", "sleep", SLEEP_SEC}));
   } else {
     GTEST_LOG_(INFO)
         << "This test does nothing as dwarf callchain sampling is not supported on this device.";
   }
-  ASSERT_FALSE(RecordCmd()->Run({"--no-unwind", "sleep", "1"}));
+  ASSERT_FALSE(RecordCmd()->Run({"--no-unwind", "sleep", SLEEP_SEC}));
 }
 
 TEST(record_cmd, post_unwind_option) {
   if (IsDwarfCallChainSamplingSupported()) {
-    ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf", "--post-unwind", "sleep", "1"}));
+    ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf", "--post-unwind", "sleep", SLEEP_SEC}));
   } else {
     GTEST_LOG_(INFO)
         << "This test does nothing as dwarf callchain sampling is not supported on this device.";
   }
-  ASSERT_FALSE(RecordCmd()->Run({"--post-unwind", "sleep", "1"}));
+  ASSERT_FALSE(RecordCmd()->Run({"--post-unwind", "sleep", SLEEP_SEC}));
   ASSERT_FALSE(
-      RecordCmd()->Run({"--call-graph", "dwarf", "--no-unwind", "--post-unwind", "sleep", "1"}));
+      RecordCmd()->Run({"--call-graph", "dwarf", "--no-unwind", "--post-unwind", "sleep", SLEEP_SEC}));
 }
 
 TEST(record_cmd, existing_processes) {
@@ -164,17 +164,17 @@
 }
 
 TEST(record_cmd, more_than_one_event_types) {
-  ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-cycles,cpu-clock", "sleep", "1"}));
-  ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-cycles", "-e", "cpu-clock", "sleep", "1"}));
+  ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-cycles,cpu-clock", "sleep", SLEEP_SEC}));
+  ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-cycles", "-e", "cpu-clock", "sleep", SLEEP_SEC}));
 }
 
 TEST(record_cmd, cpu_option) {
-  ASSERT_TRUE(RecordCmd()->Run({"--cpu", "0", "sleep", "1"}));
-  ASSERT_TRUE(RecordCmd()->Run({"--cpu", "0", "-a", "sleep", "1"}));
+  ASSERT_TRUE(RecordCmd()->Run({"--cpu", "0", "sleep", SLEEP_SEC}));
+  ASSERT_TRUE(RecordCmd()->Run({"--cpu", "0", "-a", "sleep", SLEEP_SEC}));
 }
 
 TEST(record_cmd, mmap_page_option) {
-  ASSERT_TRUE(RecordCmd()->Run({"-m", "1", "sleep", "1"}));
-  ASSERT_FALSE(RecordCmd()->Run({"-m", "0", "sleep", "1"}));
-  ASSERT_FALSE(RecordCmd()->Run({"-m", "7", "sleep", "1"}));
+  ASSERT_TRUE(RecordCmd()->Run({"-m", "1", "sleep", SLEEP_SEC}));
+  ASSERT_FALSE(RecordCmd()->Run({"-m", "0", "sleep", SLEEP_SEC}));
+  ASSERT_FALSE(RecordCmd()->Run({"-m", "7", "sleep", SLEEP_SEC}));
 }
diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp
index afdd9fd..a5ece01 100644
--- a/simpleperf/cmd_report_test.cpp
+++ b/simpleperf/cmd_report_test.cpp
@@ -16,17 +16,17 @@
 
 #include <gtest/gtest.h>
 
+#include <set>
+#include <unordered_map>
+
 #include <android-base/file.h>
+#include <android-base/strings.h>
 #include <android-base/test_utils.h>
 
 #include "command.h"
-#include "event_selection_set.h"
 #include "get_test_data.h"
 #include "read_apk.h"
-
-static std::unique_ptr<Command> RecordCmd() {
-  return CreateCommandInstance("record");
-}
+#include "test_util.h"
 
 static std::unique_ptr<Command> ReportCmd() {
   return CreateCommandInstance("report");
@@ -34,86 +34,242 @@
 
 class ReportCommandTest : public ::testing::Test {
  protected:
-  static void SetUpTestCase() {
-    ASSERT_TRUE(RecordCmd()->Run({"-a", "sleep", "1"}));
-    ASSERT_TRUE(RecordCmd()->Run({"-a", "-o", "perf2.data", "sleep", "1"}));
-    ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "fp", "-o", "perf_g.data", "sleep", "1"}));
+  void Report(const std::string perf_data,
+              const std::vector<std::string>& add_args = std::vector<std::string>()) {
+    ReportRaw(GetTestData(perf_data), add_args);
   }
+
+  void ReportRaw(const std::string perf_data,
+                 const std::vector<std::string>& add_args = std::vector<std::string>()) {
+    success = false;
+    std::vector<std::string> args = {"-i", perf_data,
+        "--symfs", GetTestDataDir(), "-o", tmp_file.path};
+    args.insert(args.end(), add_args.begin(), add_args.end());
+    ASSERT_TRUE(ReportCmd()->Run(args));
+    ASSERT_TRUE(android::base::ReadFileToString(tmp_file.path, &content));
+    ASSERT_TRUE(!content.empty());
+    std::vector<std::string> raw_lines = android::base::Split(content, "\n");
+    lines.clear();
+    for (const auto& line : raw_lines) {
+      std::string s = android::base::Trim(line);
+      if (!s.empty()) {
+        lines.push_back(s);
+      }
+    }
+    ASSERT_GE(lines.size(), 2u);
+    success = true;
+  }
+
+  TemporaryFile tmp_file;
+  std::string content;
+  std::vector<std::string> lines;
+  bool success;
 };
 
-TEST_F(ReportCommandTest, no_options) {
-  ASSERT_TRUE(ReportCmd()->Run({}));
-}
-
-TEST_F(ReportCommandTest, input_file_option) {
-  ASSERT_TRUE(ReportCmd()->Run({"-i", "perf2.data"}));
+TEST_F(ReportCommandTest, no_option) {
+  Report(PERF_DATA);
+  ASSERT_TRUE(success);
+  ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
 }
 
 TEST_F(ReportCommandTest, sort_option_pid) {
-  ASSERT_TRUE(ReportCmd()->Run({"--sort", "pid"}));
+  Report(PERF_DATA, {"--sort", "pid"});
+  ASSERT_TRUE(success);
+  size_t line_index = 0;
+  while (line_index < lines.size() && lines[line_index].find("Pid") == std::string::npos) {
+    line_index++;
+  }
+  ASSERT_LT(line_index + 2, lines.size());
 }
 
-TEST_F(ReportCommandTest, sort_option_all) {
-  ASSERT_TRUE(ReportCmd()->Run({"--sort", "comm,pid,dso,symbol"}));
+TEST_F(ReportCommandTest, sort_option_more_than_one) {
+  Report(PERF_DATA, {"--sort", "comm,pid,dso,symbol"});
+  ASSERT_TRUE(success);
+  size_t line_index = 0;
+  while (line_index < lines.size() && lines[line_index].find("Overhead") == std::string::npos) {
+    line_index++;
+  }
+  ASSERT_LT(line_index + 1, lines.size());
+  ASSERT_NE(lines[line_index].find("Command"), std::string::npos);
+  ASSERT_NE(lines[line_index].find("Pid"), std::string::npos);
+  ASSERT_NE(lines[line_index].find("Shared Object"), std::string::npos);
+  ASSERT_NE(lines[line_index].find("Symbol"), std::string::npos);
+  ASSERT_EQ(lines[line_index].find("Tid"), std::string::npos);
 }
 
 TEST_F(ReportCommandTest, children_option) {
-  ASSERT_TRUE(ReportCmd()->Run({"--children", "-i", "perf_g.data"}));
+  Report(CALLGRAPH_FP_PERF_DATA, {"--children", "--sort", "symbol"});
+  ASSERT_TRUE(success);
+  std::unordered_map<std::string, std::pair<double, double>> map;
+  for (size_t i = 0; i < lines.size(); ++i) {
+    char name[1024];
+    std::pair<double, double> pair;
+    if (sscanf(lines[i].c_str(), "%lf%%%lf%%%s", &pair.first, &pair.second, name) == 3) {
+      map.insert(std::make_pair(name, pair));
+    }
+  }
+  ASSERT_NE(map.find("GlobalFunc"), map.end());
+  ASSERT_NE(map.find("main"), map.end());
+  auto func_pair = map["GlobalFunc"];
+  auto main_pair = map["main"];
+  ASSERT_GE(main_pair.first, func_pair.first);
+  ASSERT_GE(func_pair.first, func_pair.second);
+  ASSERT_GE(func_pair.second, main_pair.second);
+}
+
+static bool CheckCalleeMode(std::vector<std::string>& lines) {
+  bool found = false;
+  for (size_t i = 0; i + 2 < lines.size(); ++i) {
+    if (lines[i].find("GlobalFunc") != std::string::npos &&
+        lines[i + 1].find("|") != std::string::npos &&
+        lines[i + 2].find("main") != std::string::npos) {
+      found = true;
+      break;
+    }
+  }
+  return found;
+}
+
+static bool CheckCallerMode(std::vector<std::string>& lines) {
+  bool found = false;
+  for (size_t i = 0; i + 2 < lines.size(); ++i) {
+    if (lines[i].find("main") != std::string::npos &&
+        lines[i + 1].find("|") != std::string::npos &&
+        lines[i + 2].find("GlobalFunc") != std::string::npos) {
+      found = true;
+      break;
+    }
+  }
+  return found;
 }
 
 TEST_F(ReportCommandTest, callgraph_option) {
-  ASSERT_TRUE(ReportCmd()->Run({"-g", "-i", "perf_g.data"}));
-  ASSERT_TRUE(ReportCmd()->Run({"-g", "callee", "-i", "perf_g.data"}));
-  ASSERT_TRUE(ReportCmd()->Run({"-g", "caller", "-i", "perf_g.data"}));
+  Report(CALLGRAPH_FP_PERF_DATA, {"-g"});
+  ASSERT_TRUE(success);
+  ASSERT_TRUE(CheckCalleeMode(lines));
+  Report(CALLGRAPH_FP_PERF_DATA, {"-g", "callee"});
+  ASSERT_TRUE(success);
+  ASSERT_TRUE(CheckCalleeMode(lines));
+  Report(CALLGRAPH_FP_PERF_DATA, {"-g", "caller"});
+  ASSERT_TRUE(success);
+  ASSERT_TRUE(CheckCallerMode(lines));
+}
+
+static bool AllItemsWithString(std::vector<std::string>& lines, const std::vector<std::string>& strs) {
+  size_t line_index = 0;
+  while (line_index < lines.size() && lines[line_index].find("Overhead") == std::string::npos) {
+    line_index++;
+  }
+  if (line_index == lines.size() || line_index + 1 == lines.size()) {
+    return false;
+  }
+  line_index++;
+  for (; line_index < lines.size(); ++line_index) {
+    bool exist = false;
+    for (auto& s : strs) {
+      if (lines[line_index].find(s) != std::string::npos) {
+        exist = true;
+        break;
+      }
+    }
+    if (!exist) {
+      return false;
+    }
+  }
+  return true;
 }
 
 TEST_F(ReportCommandTest, pid_filter_option) {
-  ASSERT_TRUE(ReportCmd()->Run({"--pids", "0"}));
-  ASSERT_TRUE(ReportCmd()->Run({"--pids", "0,1"}));
+  Report(PERF_DATA);
+  ASSERT_TRUE("success");
+  ASSERT_FALSE(AllItemsWithString(lines, {"26083"}));
+  ASSERT_FALSE(AllItemsWithString(lines, {"26083", "26090"}));
+  Report(PERF_DATA, {"--pids", "26083"});
+  ASSERT_TRUE(success);
+  ASSERT_TRUE(AllItemsWithString(lines, {"26083"}));
+  Report(PERF_DATA, {"--pids", "26083,26090"});
+  ASSERT_TRUE(success);
+  ASSERT_TRUE(AllItemsWithString(lines, {"26083", "26090"}));
 }
 
 TEST_F(ReportCommandTest, tid_filter_option) {
-  ASSERT_TRUE(ReportCmd()->Run({"--tids", "0"}));
-  ASSERT_TRUE(ReportCmd()->Run({"--tids", "0,1"}));
+  Report(PERF_DATA);
+  ASSERT_TRUE("success");
+  ASSERT_FALSE(AllItemsWithString(lines, {"26083"}));
+  ASSERT_FALSE(AllItemsWithString(lines, {"26083", "26090"}));
+  Report(PERF_DATA, {"--tids", "26083"});
+  ASSERT_TRUE(success);
+  ASSERT_TRUE(AllItemsWithString(lines, {"26083"}));
+  Report(PERF_DATA, {"--tids", "26083,26090"});
+  ASSERT_TRUE(success);
+  ASSERT_TRUE(AllItemsWithString(lines, {"26083", "26090"}));
 }
 
 TEST_F(ReportCommandTest, comm_filter_option) {
-  ASSERT_TRUE(ReportCmd()->Run({"--comms", "swapper"}));
-  ASSERT_TRUE(ReportCmd()->Run({"--comms", "swapper,simpleperf"}));
+  Report(PERF_DATA, {"--sort", "comm"});
+  ASSERT_TRUE(success);
+  ASSERT_FALSE(AllItemsWithString(lines, {"t1"}));
+  ASSERT_FALSE(AllItemsWithString(lines, {"t1", "t2"}));
+  Report(PERF_DATA, {"--sort", "comm", "--comms", "t1"});
+  ASSERT_TRUE(success);
+  ASSERT_TRUE(AllItemsWithString(lines, {"t1"}));
+  Report(PERF_DATA, {"--sort", "comm", "--comms", "t1,t2"});
+  ASSERT_TRUE(success);
+  ASSERT_TRUE(AllItemsWithString(lines, {"t1", "t2"}));
 }
 
 TEST_F(ReportCommandTest, dso_filter_option) {
-  ASSERT_TRUE(ReportCmd()->Run({"--dsos", "[kernel.kallsyms]"}));
-  ASSERT_TRUE(ReportCmd()->Run({"--dsos", "[kernel.kallsyms],/init"}));
+  Report(PERF_DATA, {"--sort", "dso"});
+  ASSERT_TRUE(success);
+  ASSERT_FALSE(AllItemsWithString(lines, {"/t1"}));
+  ASSERT_FALSE(AllItemsWithString(lines, {"/t1", "/t2"}));
+  Report(PERF_DATA, {"--sort", "dso", "--dsos", "/t1"});
+  ASSERT_TRUE(success);
+  ASSERT_TRUE(AllItemsWithString(lines, {"/t1"}));
+  Report(PERF_DATA, {"--sort", "dso", "--dsos", "/t1,/t2"});
+  ASSERT_TRUE(success);
+  ASSERT_TRUE(AllItemsWithString(lines, {"/t1", "/t2"}));
 }
 
-TEST(report_cmd, use_branch_address) {
-  if (IsBranchSamplingSupported()) {
-    ASSERT_TRUE(RecordCmd()->Run({"-b", "sleep", "1"}));
-    ASSERT_TRUE(
-        ReportCmd()->Run({"-b", "--sort", "comm,pid,dso_from,symbol_from,dso_to,symbol_to"}));
-  } else {
-    GTEST_LOG_(INFO)
-        << "This test does nothing as branch stack sampling is not supported on this device.";
+TEST_F(ReportCommandTest, use_branch_address) {
+  Report(BRANCH_PERF_DATA, {"-b", "--sort", "symbol_from,symbol_to"});
+  std::set<std::pair<std::string, std::string>> hit_set;
+  bool after_overhead = false;
+  for (const auto& line : lines) {
+    if (!after_overhead && line.find("Overhead") != std::string::npos) {
+      after_overhead = true;
+    } else if (after_overhead) {
+      char from[80];
+      char to[80];
+      if (sscanf(line.c_str(), "%*f%%%s%s", from, to) == 2) {
+        hit_set.insert(std::make_pair<std::string, std::string>(from, to));
+      }
+    }
   }
+  ASSERT_NE(hit_set.find(std::make_pair<std::string, std::string>("GlobalFunc", "CalledFunc")),
+            hit_set.end());
+  ASSERT_NE(hit_set.find(std::make_pair<std::string, std::string>("CalledFunc", "GlobalFunc")),
+            hit_set.end());
 }
 
-TEST(report_cmd, dwarf_callgraph) {
-  if (IsDwarfCallChainSamplingSupported()) {
-    ASSERT_TRUE(RecordCmd()->Run({"-g", "-o", "perf_dwarf.data", "sleep", "1"}));
-    ASSERT_TRUE(ReportCmd()->Run({"-g", "-i", "perf_dwarf.data"}));
-  } else {
-    GTEST_LOG_(INFO)
-        << "This test does nothing as dwarf callchain sampling is not supported on this device.";
-  }
+#if defined(__ANDROID__) || defined(__linux__)
+
+static std::unique_ptr<Command> RecordCmd() {
+  return CreateCommandInstance("record");
 }
 
-TEST(report_cmd, report_symbols_of_nativelib_in_apk) {
+TEST_F(ReportCommandTest, dwarf_callgraph) {
   TemporaryFile tmp_file;
-  ASSERT_TRUE(ReportCmd()->Run({"-i", GetTestData(NATIVELIB_IN_APK_PERF_DATA),
-                                "--symfs", GetTestDataDir(), "-o", tmp_file.path}));
-  std::string content;
-  ASSERT_TRUE(android::base::ReadFileToString(tmp_file.path, &content));
+  ASSERT_TRUE(RecordCmd()->Run({"-g", "-o", tmp_file.path, "sleep", SLEEP_SEC}));
+  ReportRaw(tmp_file.path, {"-g"});
+  ASSERT_TRUE(success);
+}
+
+#endif
+
+TEST_F(ReportCommandTest, report_symbols_of_nativelib_in_apk) {
+  Report(NATIVELIB_IN_APK_PERF_DATA);
+  ASSERT_TRUE(success);
   ASSERT_NE(content.find(GetUrlInApk(APK_FILE, NATIVELIB_IN_APK)), std::string::npos);
   ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
 }
diff --git a/simpleperf/get_test_data.h b/simpleperf/get_test_data.h
index bceedc0..00d1a0b 100644
--- a/simpleperf/get_test_data.h
+++ b/simpleperf/get_test_data.h
@@ -24,6 +24,12 @@
 std::string GetTestData(const std::string& filename);
 const std::string& GetTestDataDir();
 
+static const std::string PERF_DATA = "perf.data";
+static const std::string CALLGRAPH_FP_PERF_DATA = "perf_g_fp.data";
+static const std::string BRANCH_PERF_DATA = "perf_b.data";
+
+static const std::string ELF_FILE = "elf";
+
 static const std::string APK_FILE = "data/app/com.example.hellojni-1/base.apk";
 static const std::string NATIVELIB_IN_APK = "lib/arm64-v8a/libhello-jni.so";
 static const std::string NATIVELIB_IN_APK_PERF_DATA = "has_embedded_native_libs_apk_perf.data";
@@ -31,7 +37,7 @@
 constexpr size_t NATIVELIB_OFFSET_IN_APK = 0x8000;
 constexpr size_t NATIVELIB_SIZE_IN_APK = 0x15d8;
 
-static BuildId elf_file_build_id("7600329e31058e12b145d153ef27cd40e1a5f7b9");
+static BuildId elf_file_build_id("0b12a384a9f4a3f3659b7171ca615dbec3a81f71");
 
 static BuildId native_lib_build_id("b46f51cb9c4b71fb08a2fdbefc2c187894f14008");
 
diff --git a/simpleperf/read_apk_test.cpp b/simpleperf/read_apk_test.cpp
index aeedbbe..e983a25 100644
--- a/simpleperf/read_apk_test.cpp
+++ b/simpleperf/read_apk_test.cpp
@@ -23,7 +23,7 @@
 
 TEST(read_apk, IsValidApkPath) {
   ASSERT_FALSE(IsValidApkPath("/dev/zero"));
-  ASSERT_FALSE(IsValidApkPath(GetTestData("elf_file")));
+  ASSERT_FALSE(IsValidApkPath(GetTestData(ELF_FILE)));
   ASSERT_TRUE(IsValidApkPath(GetTestData(APK_FILE)));
 }
 
diff --git a/simpleperf/read_elf.cpp b/simpleperf/read_elf.cpp
index e66e68e..6551629 100644
--- a/simpleperf/read_elf.cpp
+++ b/simpleperf/read_elf.cpp
@@ -184,7 +184,9 @@
   if (!IsValidElfPath(filename)) {
     return false;
   }
-  return GetBuildIdFromEmbeddedElfFile(filename, 0, 0, build_id);
+  bool result = GetBuildIdFromEmbeddedElfFile(filename, 0, 0, build_id);
+  LOG(VERBOSE) << "GetBuildIdFromElfFile(" << filename << ") => " << build_id->ToString();
+  return result;
 }
 
 bool GetBuildIdFromEmbeddedElfFile(const std::string& filename, uint64_t file_offset,
diff --git a/simpleperf/read_elf_test.cpp b/simpleperf/read_elf_test.cpp
index 920da27..929540f 100644
--- a/simpleperf/read_elf_test.cpp
+++ b/simpleperf/read_elf_test.cpp
@@ -23,7 +23,7 @@
 
 TEST(read_elf, GetBuildIdFromElfFile) {
   BuildId build_id;
-  ASSERT_TRUE(GetBuildIdFromElfFile(GetTestData("elf_file"), &build_id));
+  ASSERT_TRUE(GetBuildIdFromElfFile(GetTestData(ELF_FILE), &build_id));
   ASSERT_EQ(build_id, BuildId(elf_file_build_id));
 }
 
@@ -50,14 +50,14 @@
 
 TEST(read_elf, parse_symbols_from_elf_file_with_correct_build_id) {
   std::map<std::string, ElfFileSymbol> symbols;
-  ASSERT_TRUE(ParseSymbolsFromElfFile(GetTestData("elf_file"), elf_file_build_id,
+  ASSERT_TRUE(ParseSymbolsFromElfFile(GetTestData(ELF_FILE), elf_file_build_id,
                                       std::bind(ParseSymbol, std::placeholders::_1, &symbols)));
   CheckElfFileSymbols(symbols);
 }
 
 TEST(read_elf, parse_symbols_from_elf_file_without_build_id) {
   std::map<std::string, ElfFileSymbol> symbols;
-  ASSERT_TRUE(ParseSymbolsFromElfFile(GetTestData("elf_file"), BuildId(),
+  ASSERT_TRUE(ParseSymbolsFromElfFile(GetTestData(ELF_FILE), BuildId(),
                                       std::bind(ParseSymbol, std::placeholders::_1, &symbols)));
   CheckElfFileSymbols(symbols);
 }
@@ -65,7 +65,7 @@
 TEST(read_elf, parse_symbols_from_elf_file_with_wrong_build_id) {
   BuildId build_id("01010101010101010101");
   std::map<std::string, ElfFileSymbol> symbols;
-  ASSERT_FALSE(ParseSymbolsFromElfFile(GetTestData("elf_file"), build_id,
+  ASSERT_FALSE(ParseSymbolsFromElfFile(GetTestData(ELF_FILE), build_id,
                                        std::bind(ParseSymbol, std::placeholders::_1, &symbols)));
 }
 
@@ -87,5 +87,5 @@
 TEST(read_elf, IsValidElfPath) {
   ASSERT_FALSE(IsValidElfPath("/dev/zero"));
   ASSERT_FALSE(IsValidElfPath("/sys/devices/system/cpu/online"));
-  ASSERT_TRUE(IsValidElfPath(GetTestData("elf_file")));
+  ASSERT_TRUE(IsValidElfPath(GetTestData(ELF_FILE)));
 }
diff --git a/simpleperf/record.cpp b/simpleperf/record.cpp
index 660634c..5c048fb 100644
--- a/simpleperf/record.cpp
+++ b/simpleperf/record.cpp
@@ -534,7 +534,7 @@
   const char* p = reinterpret_cast<const char*>(pheader + 1);
   const char* end = reinterpret_cast<const char*>(pheader) + pheader->size;
   MoveFromBinaryFormat(pid, p);
-  build_id = BuildId(p);
+  build_id = BuildId(p, BUILD_ID_SIZE);
   p += ALIGN(build_id.Size(), 8);
   filename = p;
   p += ALIGN(filename.size() + 1, 64);
diff --git a/simpleperf/test_util.h b/simpleperf/test_util.h
index 734a48b..cfbe493 100644
--- a/simpleperf/test_util.h
+++ b/simpleperf/test_util.h
@@ -15,10 +15,13 @@
  */
 
 #include <map>
+#include <string>
 
 #include "read_elf.h"
 #include "workload.h"
 
+static const std::string SLEEP_SEC = "0.001";
+
 void CreateProcesses(size_t count, std::vector<std::unique_ptr<Workload>>* workloads);
 
 void ParseSymbol(const ElfFileSymbol& symbol, std::map<std::string, ElfFileSymbol>* symbols);
diff --git a/simpleperf/testdata/elf b/simpleperf/testdata/elf
new file mode 100644
index 0000000..f63c25c
--- /dev/null
+++ b/simpleperf/testdata/elf
Binary files differ
diff --git a/simpleperf/testdata/elf_file b/simpleperf/testdata/elf_file
deleted file mode 100644
index 53b589a..0000000
--- a/simpleperf/testdata/elf_file
+++ /dev/null
Binary files differ
diff --git a/simpleperf/testdata/elf_file_source.cpp b/simpleperf/testdata/elf_file_source.cpp
new file mode 100644
index 0000000..3cfd00b
--- /dev/null
+++ b/simpleperf/testdata/elf_file_source.cpp
@@ -0,0 +1,20 @@
+#include <pthread.h>
+
+volatile int GlobalVar;
+
+extern "C" void CalledFunc() {
+  GlobalVar++;
+}
+
+extern "C" void GlobalFunc() {
+  for (int i = 0; i < 1000000; ++i) {
+    CalledFunc();
+  }
+}
+
+int main() {
+  while (true) {
+    GlobalFunc();
+  }
+  return 0;
+}
diff --git a/simpleperf/testdata/perf.data b/simpleperf/testdata/perf.data
new file mode 100644
index 0000000..64a59da
--- /dev/null
+++ b/simpleperf/testdata/perf.data
Binary files differ
diff --git a/simpleperf/testdata/perf_b.data b/simpleperf/testdata/perf_b.data
new file mode 100644
index 0000000..e514944
--- /dev/null
+++ b/simpleperf/testdata/perf_b.data
Binary files differ
diff --git a/simpleperf/testdata/perf_g_fp.data b/simpleperf/testdata/perf_g_fp.data
new file mode 100644
index 0000000..de9cf53
--- /dev/null
+++ b/simpleperf/testdata/perf_g_fp.data
Binary files differ