Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add assert locals to protocol tests #559

Merged
merged 5 commits into from
Mar 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,14 @@ Passes if result of `expression` is equal to `expected`.

Passes if `expected` is equal to the location where debugger stops.

- assert_locals_result(expected)

Passes if all of `expected` local variable entries match the ones returned by debugger.

An variable entry looks like this: `{ name: "bar", value: "nil", type: "NilClass" }`.

Please note that both `value` and `type` need to be strings.


## To Update README

Expand Down
23 changes: 19 additions & 4 deletions test/protocol/break_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,30 @@ class BreakTest1 < TestCase
8| bar = Bar.new
9| end
RUBY

def test_break_stops_at_correct_place
run_protocol_scenario PROGRAM do
req_add_breakpoint 5
req_continue
assert_line_num 5
req_add_breakpoint 8

assert_locals_result(
[
{ name: "%self", value: "Foo::Bar", type: "Class" },
{ name: "_return", value: "hello", type: "String" }
]
)

req_add_breakpoint 9
req_continue
assert_line_num 8
assert_line_num 9

assert_locals_result(
[
{ name: "%self", value: "Foo", type: "Module" },
{ name: "bar", value: /#<Foo::Bar/, type: "Foo::Bar" }
]
)
req_terminate_debuggee
end
end
Expand Down Expand Up @@ -52,7 +67,7 @@ def bar2
end
RUBY
end

def test_break_stops_at_the_extra_file
with_extra_tempfile do |extra_file|
run_protocol_scenario(program(extra_file.path), cdp: false) do
Expand Down
29 changes: 28 additions & 1 deletion test/protocol/next_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,44 @@ class NextTest < TestCase
8| bar = Bar.new
9| end
RUBY

def test_next_goes_to_the_next_statement
run_protocol_scenario PROGRAM do
req_next
assert_line_num 2

assert_locals_result(
[
{ name: "%self", value: "Foo", type: "Module" },
{ name: "bar", value: "nil", type: "NilClass" }
]
)
req_next
assert_line_num 3

assert_locals_result(
[
{ name: "%self", value: "Foo::Bar", type: "Class" },
]
)
req_next
assert_line_num 7

assert_locals_result(
[
{ name: "%self", value: "Foo", type: "Module" },
{ name: "bar", value: "nil", type: "NilClass" }
]
)
req_next
assert_line_num 8

assert_locals_result(
[
{ name: "%self", value: "Foo", type: "Module" },
{ name: "bar", value: "nil", type: "NilClass" }
]
)
req_terminate_debuggee
end
end
Expand Down
19 changes: 17 additions & 2 deletions test/protocol/step_back_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ module DEBUGGER__
class StepBackTest < TestCase
PROGRAM = <<~RUBY
1| binding.b do: 'record on'
2|
2|
3| module Foo
4| class Bar
5| def self.a
Expand All @@ -17,17 +17,32 @@ class StepBackTest < TestCase
10| bar = Bar.new
11| end
RUBY

def test_step_back_goes_back_to_the_previous_statement
run_protocol_scenario PROGRAM, cdp: false do
req_add_breakpoint 9
req_continue
req_step_back
assert_line_num 9
assert_locals_result(
[
{ name: "%self", value: "Foo", type: "Module" },
{ name: "bar", value: "nil", type: "NilClass" }
]
)
req_step_back
assert_line_num 5
assert_locals_result([
{ name: "%self", value: "Foo::Bar", type: "Class" }
])
req_step_back
assert_line_num 4
assert_locals_result(
[
{ name: "%self", value: "Foo", type: "Module" },
{ name: "bar", value: "nil", type: "NilClass" }
]
)
req_terminate_debuggee
end
end
Expand Down
65 changes: 65 additions & 0 deletions test/support/protocol_utils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,71 @@ def assert_reattach
end
end

def assert_locals_result expected, frame_idx: 0
case ENV['RUBY_DEBUG_TEST_UI']
when 'vscode'
# get frameId
send_request 'stackTrace',
threadId: 1,
startFrame: 0,
levels: 20
res = find_crt_dap_response
f_id = res.dig(:body, :stackFrames, frame_idx, :id)

# get variablesReference
send_request 'scopes', frameId: f_id
res = find_crt_dap_response
assert_dap_response :ScopesResponse, res

locals_scope = res.dig(:body, :scopes).find { |d| d[:presentationHint] == "locals" }
locals_reference = locals_scope[:variablesReference]

# get variables
send_request 'variables', variablesReference: locals_reference
res = find_crt_dap_response
assert_dap_response :VariablesResponse, res

expected.each do |exp|
if exp[:type] == "String"
exp[:value] = exp[:value].inspect
end
end

actual_locals = res.dig(:body, :variables).map { |loc| { name: loc[:name], value: loc[:value], type: loc[:type] } }
when 'chrome'
current_frame = @crt_frames.first
locals_scope = current_frame[:scopeChain].find { |f| f[:type] == "local" }
object_id = locals_scope.dig(:object, :objectId)

send_request "Runtime.getProperties", objectId: object_id
res = find_crt_cdp_response
assert_cdp_response 'Runtime.getProperties', res

actual_locals = res.dig(:result, :result).map do |loc|
type = loc.dig(:value, :className) || loc.dig(:value, :type).capitalize # TODO: sync this with get_ruby_type
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I noticed that this is incorrect. We can't use :type as Ruby class.
I'll fix it later.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That'd be great, thank you.


{ name: loc[:name], value: loc.dig(:value, :description), type: type }
end
end

failure_msg = FailureMessage.new{create_protocol_message "result:\n#{JSON.pretty_generate res}"}

actual_locals = actual_locals.sort_by { |h| h[:name] }
expected = expected.sort_by { |h| h[:name] }

expected.each_with_index do |expect, index|
actual = actual_locals[index]
assert_equal(expect[:name], actual[:name], failure_msg)
assert_equal(expect[:type], actual[:type], failure_msg)

if expect[:value].is_a?(Regexp)
assert_match(expect[:value], actual[:value], failure_msg)
else
assert_equal(expect[:value], actual[:value], failure_msg)
end
end
end

def assert_hover_result expected, expression: nil, frame_idx: 0
case ENV['RUBY_DEBUG_TEST_UI']
when 'vscode'
Expand Down