Skip to content
Closed
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
2 changes: 1 addition & 1 deletion Gemfile
Original file line numberDiff line numberDiff line change
Expand Up@@ -4,4 +4,4 @@ gemspec

gem "rake"
gem "rake-compiler"
gem "minitest", "~> 5.0"
gem "test-unit", "~> 3.0"
6 changes: 6 additions & 0 deletions bin/minitest
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require_relative '../test/minitest_runner'

DEBUGGER__::MinitestRunner.new.run
9 changes: 9 additions & 0 deletions bin/test-unit.rb
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
base_dir = File.expand_path(File.join(File.dirname(__FILE__), ".."))
lib_dir = File.join(base_dir, "lib")
test_dir = File.join(base_dir, "test")

$LOAD_PATH.unshift(lib_dir)

require 'test/unit'

exit Test::Unit::AutoRunner.run(true, test_dir)
21 changes: 18 additions & 3 deletions lib/debug/session.rb
Original file line numberDiff line numberDiff line change
Expand Up@@ -55,6 +55,12 @@ def last_line

module DEBUGGER__
class Session
class << self
attr_accessor :ui_console
end

attr_accessor :tp_load_script, :tp_thread_begin, :q_evt, :th_clients

def initialize ui
@ui = ui
@sr = SourceRepository.new
Expand All@@ -73,7 +79,8 @@ def initialize ui

@tp_load_script = TracePoint.new(:script_compiled){|tp|
ThreadClient.current.on_load tp.instruction_sequence, tp.eval_script
}.enable
}
@tp_load_script.enable

@session_server = Thread.new do
Thread.current.abort_on_exception = true
Expand DownExpand Up@@ -149,7 +156,8 @@ def initialize ui

@tp_thread_begin = TracePoint.new(:thread_begin){|tp|
ThreadClient.current.on_thread_begin Thread.current
}.enable
}
@tp_thread_begin.enable
end

def add_initial_commands cmds
Expand DownExpand Up@@ -193,6 +201,9 @@ def wait_command
@ui.puts "(rdbg:init) #{line}"
end

# This code is for test
return :retry if line.nil?

if line.empty?
if @repl_prev_line
line = @repl_prev_line
Expand DownExpand Up@@ -934,8 +945,12 @@ def self.require_location
nil
end

def self.call_console
Session.ui_console || UI_Console.new
end

def self.console
initialize_session UI_Console.new
initialize_session call_console

@prev_handler = trap(:SIGINT){
ThreadClient.current.on_trap :SIGINT
Expand Down
44 changes: 44 additions & 0 deletions lib/debug/test_console.rb
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
# frozen_string_literal: true

require_relative 'console'

module DEBUGGER__
#
# Custom interface for easier associations
#
class TestUI_Console < UI_Console
attr_accessor :queue, :test_block

def quit _n
SESSION.q_evt.close
SESSION.tp_load_script.disable
SESSION.tp_thread_begin.disable
end

def initialize
@mutex = Mutex.new
@assertion_cv = ConditionVariable.new
@counter = 0
@queue = Queue.new
end

def ask _prompt
''
end

def readline
readline_body
end

def readline_body
test_block&.call
self.test_block = nil
cmd = queue.pop
if cmd.is_a?(Proc)
cmd.call
return nil
end
cmd
end
end
end
2 changes: 1 addition & 1 deletion lib/debug/thread_client.rb
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,7 @@ def self.current
end
end

attr_reader :location, :thread, :mode, :id
attr_reader :location, :thread, :mode, :id, :target_frames

def initialize id, q_evt, q_cmd, thr = Thread.current
@id = id
Expand Down
93 changes: 93 additions & 0 deletions test/debug/step_test.rb
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
# frozen_string_literal: true

require 'test_helper'
require 'socket'

require_relative '../support/assertions'

module DEBUGGER__

# Test basic stepping behaviour.

class BasicSteppingTest < TestCase
def program
strip_line_numbers <<-RUBY
1: require 'debug/session'
2: DEBUGGER__.console
3: module DEBUGGER__
4: #
5: # Toy class to test stepping
6: #
7: class #{example_class}
8: def self.add_four(num)
9: num += 4
10: num
11: end
12: end
13:
14: res = #{example_class}.add_four(7)
15:
16: res + 1
17: end
RUBY
end

def test_step_goes_to_the_next_statement
debug_code(program) do
enter "step"
assertion 7
enter "quit"
end
end

def test_s_goes_to_the_next_statement
debug_code(program) do
enter "s"
assertion 7
enter "quit"
end
end
end

# Tests step/next more than one.

class MoreThanOneStepTest < TestCase
def program
strip_line_numbers <<-RUBY
1: require 'debug/session'
2: DEBUGGER__.console
3: module DEBUGGER__
4: #
5: # Toy class to test advanced stepping.
6: #
7: class #{example_class}
8: def self.add_three(num)
9: 2.times do
10: num += 1
11: end
12:
13: num *= 2
14: num
15: end
16: end
17:
18: res = #{example_class}.add_three(7)
19:
20: res
21: end
RUBY
end

def test_step_steps_into_blocks
debug_code(program) do
enter "step"
assertion 7
enter "step"
assertion 8
enter "step"
assertion 18
enter "quit"
end
end
end
end
24 changes: 24 additions & 0 deletions test/support/assertions.rb
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
#frozen_string_literal: true

require "minitest/mock"

module Minitest
#
# Custom Minitest assertions
#
module Assertions
def assert test, msg = nil
self.assertions += 1
unless test
msg ||= "Expected #{mu_pp test} to be truthy."
msg = msg.call if Proc === msg
begin
raise Minitest::Assertion, msg
rescue Assertion
self.failures << $!
end
end
true
end
end
end
106 changes: 106 additions & 0 deletions test/support/test_case.rb
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
# frozen_string_literal: true

require 'test/unit'
require "tmpdir"

require_relative 'utils'
require_relative '../../lib/debug/test_console'
require_relative '../../lib/debug/console'

module DEBUGGER__
#
# Extends Minitest's base test case and provides defaults for all tests.
#
class TestCase < Test::Unit::TestCase
include TestUtils

def self.before_suite
DEBUGGER__::Session.ui_console = DEBUGGER__::TestUI_Console.new
end

#
# Reset to default state before each test
#
def setup
Thread.current[:DEBUGGER__ThreadClient] = nil
end

#
# Cleanup temp files, and dummy classes/modules.
#
def teardown
cleanup_namespace
clear_example_file
end

#
# Removes test example file and its memoization
#
def clear_example_file
example_file.close

delete_example_file

@example_file = nil
end

def cleanup_namespace
force_remove_const(DEBUGGER__, example_class)
force_remove_const(DEBUGGER__, example_module)
force_remove_const(DEBUGGER__, 'SESSION')
end

#
# Path to file where test code is saved
#
def example_path
File.join(example_folder, 'debugger_example.rb')
end

#
# Temporary file where code for each test is saved
#
def example_file
@example_file ||= File.new(example_path, 'w+')
end

#
# Temporary folder where the test file lives
#
def example_folder
@example_folder ||= File.realpath(Dir.tmpdir)
end

#
# Name of the temporary test class
#
def example_class
"#{camelized_path}Class"
end

#
# Name of the temporary test module
#
def example_module
"#{camelized_path}Module"
end

private

def camelized_path
#
# Converts +str+ from an_underscored-or-dasherized_string to
# ACamelizedString.
#
File.basename(example_path, '.rb').dup.split(/[_-]/).map(&:capitalize).join('')
end

def delete_example_file
File.unlink(example_file)
rescue StandardError
# On windows we need the file closed before deleting it, and sometimes it
# didn't have time to close yet. So retry until we can delete it.
retry
end
end
end
Loading