| // Copyright 2020 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 <gtest/gtest.h> |
| |
| #include "src/developer/debug/shared/zx_status_definitions.h" |
| #include "src/developer/debug/zxdb/client/mock_remote_api.h" |
| #include "src/developer/debug/zxdb/console/commands/breakpoint_command_test.h" |
| #include "src/developer/debug/zxdb/console/console_test.h" |
| |
| namespace zxdb { |
| |
| namespace { |
| |
| class VerbBreak : public BreakpointCommandTest {}; |
| |
| } // namespace |
| |
| TEST_F(VerbBreak, Break) { |
| // Process starts out as running. Make an expression breakpoint. |
| console().ProcessInputLine("break *0x1230 + 4"); |
| |
| // Validate the set request. |
| ASSERT_TRUE(breakpoint_remote_api()->last_request); |
| ASSERT_EQ(1u, breakpoint_remote_api()->last_request->breakpoint.locations.size()); |
| EXPECT_EQ(0x1234u, breakpoint_remote_api()->last_request->breakpoint.locations[0].address); |
| |
| // The breakpoint info should be immediately printed even though the backend has not replied. |
| auto event = console().GetOutputEvent(); |
| ASSERT_EQ(MockConsole::OutputEvent::Type::kOutput, event.type); |
| EXPECT_EQ("Created Breakpoint 1 @ 0x1234\n", event.output.AsString()); |
| |
| // Issue the success callback from the backend. Nothing should be printed. |
| ASSERT_TRUE(breakpoint_remote_api()->last_cb); |
| breakpoint_remote_api()->last_cb(Err(), debug_ipc::AddOrChangeBreakpointReply()); |
| EXPECT_FALSE(console().HasOutputEvent()); |
| |
| // Make a new process that's not running and then a breakpoint. |
| console().ProcessInputLine("process new"); |
| console().FlushOutputEvents(); |
| console().ProcessInputLine("break SomePendingFunc"); |
| |
| // It should give a pending message. |
| event = console().GetOutputEvent(); |
| ASSERT_EQ(MockConsole::OutputEvent::Type::kOutput, event.type); |
| EXPECT_EQ( |
| "Created Breakpoint 2 @ SomePendingFunc\n" |
| "Pending: No current matches for location. It will be matched against new\n" |
| " processes and shared libraries.\n", |
| event.output.AsString()); |
| } |
| |
| TEST_F(VerbBreak, WriteBreakpoint) { |
| // Creates a specifically-sized write breakpoint at a manual address. |
| console().ProcessInputLine("break -t write *(uint16_t*)0x1234"); |
| |
| // Validate the set request. It will have a 0 address but the range will be set to cover the |
| // 16-bit input value. |
| ASSERT_TRUE(breakpoint_remote_api()->last_request); |
| ASSERT_EQ(1u, breakpoint_remote_api()->last_request->breakpoint.locations.size()); |
| EXPECT_EQ(0u, breakpoint_remote_api()->last_request->breakpoint.locations[0].address); |
| EXPECT_EQ(0x1234u, |
| breakpoint_remote_api()->last_request->breakpoint.locations[0].address_range.begin()); |
| EXPECT_EQ(2u, |
| breakpoint_remote_api()->last_request->breakpoint.locations[0].address_range.size()); |
| |
| // The breakpoint info should be immediately printed even though the backend has not replied. |
| auto event = console().GetOutputEvent(); |
| ASSERT_EQ(MockConsole::OutputEvent::Type::kOutput, event.type); |
| EXPECT_EQ("Created Breakpoint 1 type=write size=2 @ 0x1234\n", event.output.AsString()); |
| |
| // Now do an explicitly-sized override. |
| console().ProcessInputLine("break -s 8 -t read-write *(uint16_t*)0x5678"); |
| ASSERT_TRUE(breakpoint_remote_api()->last_request); |
| EXPECT_EQ(0u, breakpoint_remote_api()->last_request->breakpoint.locations[0].address); |
| EXPECT_EQ(0x5678u, |
| breakpoint_remote_api()->last_request->breakpoint.locations[0].address_range.begin()); |
| EXPECT_EQ(8u, |
| breakpoint_remote_api()->last_request->breakpoint.locations[0].address_range.size()); |
| |
| // The breakpoint info should be immediately printed even though the backend has not replied. |
| event = console().GetOutputEvent(); |
| ASSERT_EQ(MockConsole::OutputEvent::Type::kOutput, event.type); |
| EXPECT_EQ("Created Breakpoint 2 type=read-write size=8 @ 0x5678\n", event.output.AsString()); |
| |
| // Untyped numeric inputs get a default size of 4. |
| console().ProcessInputLine("break -t read-write 0x9abc"); |
| ASSERT_TRUE(breakpoint_remote_api()->last_request); |
| EXPECT_EQ(0u, breakpoint_remote_api()->last_request->breakpoint.locations[0].address); |
| EXPECT_EQ(0x9abcu, |
| breakpoint_remote_api()->last_request->breakpoint.locations[0].address_range.begin()); |
| EXPECT_EQ(4u, |
| breakpoint_remote_api()->last_request->breakpoint.locations[0].address_range.size()); |
| } |
| |
| TEST_F(VerbBreak, ExpressionError) { |
| // This variable is not found. |
| console().ProcessInputLine("break -t write *&nonesitant_var"); |
| |
| // It might be nice if the error message mentioned the "break" command but the verb name isn't |
| // plumbed through to the error message currently so this is a generic "the command" error. |
| auto event = console().GetOutputEvent(); |
| ASSERT_EQ(MockConsole::OutputEvent::Type::kOutput, event.type); |
| EXPECT_EQ( |
| "Unable to evaluate the expression for the command. The result was:\n" |
| " No variable 'nonesitant_var' found.", |
| event.output.AsString()); |
| |
| // No breakpoint should have been created. |
| EXPECT_FALSE(breakpoint_remote_api()->last_request); |
| } |
| |
| // This is a more end-to-end-type test that tests that breakpoints that hit backend errors issue |
| // the proper notification and those notifications are caught and printed out on the screen. |
| TEST_F(VerbBreak, TransportError) { |
| // Create a breakpoint. |
| console().ProcessInputLine("break 0x1234"); |
| auto event = console().GetOutputEvent(); |
| ASSERT_EQ(MockConsole::OutputEvent::Type::kOutput, event.type); |
| EXPECT_EQ("Created Breakpoint 1 @ 0x1234\n", event.output.AsString()); |
| |
| // Issue the callback with a transport error. |
| ASSERT_TRUE(breakpoint_remote_api()->last_cb); |
| breakpoint_remote_api()->last_cb(Err("Some transport error."), |
| debug_ipc::AddOrChangeBreakpointReply()); |
| |
| // The ConsoleContext should have printed out the error. |
| event = console().GetOutputEvent(); |
| ASSERT_EQ(MockConsole::OutputEvent::Type::kOutput, event.type); |
| EXPECT_EQ( |
| "Error updating Breakpoint 1 @ 0x1234\n" |
| "Some transport error.", |
| event.output.AsString()); |
| } |
| |
| TEST_F(VerbBreak, BackendError) { |
| // Create a breakpoint. |
| console().ProcessInputLine("break 0x2345"); |
| auto event = console().GetOutputEvent(); |
| ASSERT_EQ(MockConsole::OutputEvent::Type::kOutput, event.type); |
| EXPECT_EQ("Created Breakpoint 1 @ 0x2345\n", event.output.AsString()); |
| |
| // Issue the callback with a backend error. |
| ASSERT_TRUE(breakpoint_remote_api()->last_cb); |
| debug_ipc::AddOrChangeBreakpointReply reply; |
| reply.status = debug::Status("Bad handle"); |
| breakpoint_remote_api()->last_cb(Err(), reply); |
| |
| // The ConsoleContext should have printed out the error. |
| event = console().GetOutputEvent(); |
| ASSERT_EQ(MockConsole::OutputEvent::Type::kOutput, event.type); |
| EXPECT_EQ( |
| "Error updating Breakpoint 1 @ 0x2345\n" |
| "Bad handle", |
| event.output.AsString()); |
| } |
| |
| } // namespace zxdb |