// Copyright 2021 The Fuchsia 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 "src/developer/debug/zxdb/debug_adapter/handlers/request_stacktrace.h"

#include <gtest/gtest.h>

#include "src/developer/debug/zxdb/client/mock_frame.h"
#include "src/developer/debug/zxdb/client/mock_remote_api.h"
#include "src/developer/debug/zxdb/common/scoped_temp_file.h"
#include "src/developer/debug/zxdb/debug_adapter/context_test.h"
#include "src/developer/debug/zxdb/symbols/function.h"
#include "src/developer/debug/zxdb/symbols/mock_module_symbols.h"

namespace zxdb {

namespace {

using RequestStackTraceTest = DebugAdapterContextTest;

}  // namespace

TEST_F(RequestStackTraceTest, FullFrameAvailable) {
  InitializeDebugging();

  InjectProcess(kProcessKoid);
  // Run client to receive process started event.
  RunClient();
  auto thread = InjectThread(kProcessKoid, kThreadKoid);
  // Run client to receive threads started event.
  RunClient();

  // Insert mock frames
  // Top frame has a valid source location
  ScopedTempFile temp_file;
  fxl::RefPtr<Function> function1(fxl::MakeRefCounted<Function>(DwarfTag::kSubprogram));
  function1->set_assigned_name("test_func1");
  function1->set_code_ranges(AddressRanges(AddressRange(0x10000, 0x10020)));
  auto location1 = Location(0x10010, FileLine(temp_file.name(), 23), 10,
                            SymbolContext::ForRelativeAddresses(), function1);

  // The source of this frame cannot be found and will not be reported in response.
  fxl::RefPtr<Function> function2(fxl::MakeRefCounted<Function>(DwarfTag::kSubprogram));
  function2->set_assigned_name("test_func2");
  function2->set_code_ranges(AddressRanges(AddressRange(0x10024, 0x10060)));
  auto location2 = Location(0x10040, FileLine("not_found.cc", 55), 12,
                            SymbolContext::ForRelativeAddresses(), function2);

  std::vector<std::unique_ptr<Frame>> frames;
  frames.push_back(std::make_unique<MockFrame>(&session(), thread, location1, 0x2000));
  frames.push_back(std::make_unique<MockFrame>(&session(), thread, location2, 0x2020));
  InjectExceptionWithStack(kProcessKoid, kThreadKoid, debug_ipc::ExceptionType::kSingleStep,
                           std::move(frames), true);

  // Receive thread stopped event in client.
  RunClient();

  // Send request from the client.
  dap::StackTraceRequest request = {};
  request.threadId = kThreadKoid;
  auto response = client().send(request);

  // Read request and process it in server.
  context().OnStreamReadable();
  loop().RunUntilNoTasks();

  // Run client to receive response.
  RunClient();
  auto got = response.get();
  EXPECT_FALSE(got.error);
  EXPECT_EQ(got.response.totalFrames.value(), 2);
  EXPECT_EQ(got.response.stackFrames[0].column, location1.column());
  EXPECT_EQ(got.response.stackFrames[0].line, location1.file_line().line());
  EXPECT_EQ(got.response.stackFrames[0].name, function1->GetAssignedName());
  EXPECT_EQ(got.response.stackFrames[0].source.value().path.value(), temp_file.name());
  EXPECT_EQ(got.response.stackFrames[1].column, location2.column());
  EXPECT_EQ(got.response.stackFrames[1].line, location2.file_line().line());
  EXPECT_EQ(got.response.stackFrames[1].name, function2->GetAssignedName());
  EXPECT_FALSE(got.response.stackFrames[1].source);
}

TEST_F(RequestStackTraceTest, SyncFramesRequired) {
  InitializeDebugging();

  auto process = InjectProcess(kProcessKoid);
  // Run client to receive process started event.
  RunClient();
  InjectThread(kProcessKoid, kThreadKoid);
  // Run client to receive threads started event.
  RunClient();

  constexpr uint64_t kAddress[] = {0x10010, 0x10040, 0x9000};
  constexpr uint64_t kStack[] = {0x3000, 0x3020, 0x3050};
  constexpr size_t kStackSize = 3;

  // Set up symbol resolution for stack frames.
  auto mock_module = InjectMockModule(process);
  ScopedTempFile temp_file;
  std::vector<fxl::RefPtr<Function>> function;
  std::vector<Location> location;

  for (size_t i = 0; i < kStackSize; i++) {
    function.push_back(fxl::MakeRefCounted<Function>(DwarfTag::kSubprogram));
    function[i]->set_assigned_name(std::string("test_func_") + std::to_string(i));
    function[i]->set_code_ranges(
        AddressRanges(AddressRange(kAddress[i] - 0x10, kAddress[i] + 0x10)));
    location.push_back(Location(kAddress[i], FileLine(temp_file.name(), 23 + i), 10 + i,
                                SymbolContext::ForRelativeAddresses(), function[i]));
    mock_module->AddSymbolLocations(kAddress[i], {location[i]});
  }

  // Notify of thread stop and push expected stack frames.
  debug_ipc::NotifyException break_notification;
  break_notification.type = debug_ipc::ExceptionType::kSoftwareBreakpoint;
  break_notification.thread.process_koid = kProcessKoid;
  break_notification.thread.thread_koid = kThreadKoid;
  break_notification.thread.state = debug_ipc::ThreadRecord::State::kBlocked;
  InjectException(break_notification);

  debug_ipc::ThreadStatusReply expected_reply;
  expected_reply.record = break_notification.thread;
  expected_reply.record.stack_amount = debug_ipc::ThreadRecord::StackAmount::kFull;
  for (size_t i = 0; i < kStackSize; i++) {
    debug_ipc::StackFrame frame(kAddress[i], kStack[i]);
    expected_reply.record.frames.push_back(frame);
  }
  mock_remote_api()->set_thread_status_reply(expected_reply);

  // Receive thread stopped event in client.
  RunClient();

  // Send request from the client.
  dap::StackTraceRequest request = {};
  request.threadId = kThreadKoid;
  auto response = client().send(request);

  // Read request and process it in server.
  context().OnStreamReadable();
  loop().RunUntilNoTasks();

  // Run client to receive response.
  RunClient();
  auto got = response.get();
  EXPECT_FALSE(got.error);
  EXPECT_EQ(static_cast<size_t>(got.response.totalFrames.value()), kStackSize);
  for (size_t i = 0; i < kStackSize; i++) {
    EXPECT_EQ(got.response.stackFrames[i].column, location[i].column());
    EXPECT_EQ(got.response.stackFrames[i].line, location[i].file_line().line());
    EXPECT_EQ(got.response.stackFrames[i].name, function[i]->GetAssignedName());
    EXPECT_EQ(got.response.stackFrames[i].source.value().path.value(), temp_file.name());
  }
}

}  // namespace zxdb
