debugger 1.2.4 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. data/.gitignore +14 -0
  2. data/.travis.yml +0 -1
  3. data/CHANGELOG.md +9 -0
  4. data/Gemfile +3 -0
  5. data/README.md +2 -0
  6. data/Rakefile +3 -55
  7. data/debugger.gemspec +2 -0
  8. data/lib/debugger/version.rb +1 -1
  9. data/lib/ruby-debug-base.rb +3 -1
  10. data/lib/ruby-debug/commands/irb.rb +1 -1
  11. data/lib/ruby-debug/commands/jump.rb +1 -1
  12. data/lib/ruby-debug/commands/method.rb +1 -1
  13. data/lib/ruby-debug/commands/show.rb +1 -1
  14. data/lib/ruby-debug/commands/trace.rb +2 -2
  15. data/lib/ruby-debug/commands/variables.rb +3 -3
  16. data/test/breakpoints_test.rb +365 -0
  17. data/test/conditions_test.rb +76 -0
  18. data/test/continue_test.rb +28 -0
  19. data/test/display_test.rb +141 -0
  20. data/test/edit_test.rb +55 -0
  21. data/test/eval_test.rb +92 -0
  22. data/test/examples/breakpoint1.rb +15 -0
  23. data/test/examples/breakpoint2.rb +7 -0
  24. data/test/examples/conditions.rb +4 -0
  25. data/test/examples/continue.rb +4 -0
  26. data/test/examples/display.rb +5 -0
  27. data/test/examples/edit.rb +3 -0
  28. data/test/examples/edit2.rb +3 -0
  29. data/test/examples/eval.rb +4 -0
  30. data/test/examples/finish.rb +20 -0
  31. data/test/examples/frame.rb +31 -0
  32. data/test/examples/help.rb +2 -0
  33. data/test/examples/info.rb +48 -0
  34. data/test/examples/info2.rb +3 -0
  35. data/test/examples/irb.rb +6 -0
  36. data/test/examples/jump.rb +14 -0
  37. data/test/examples/kill.rb +2 -0
  38. data/test/examples/list.rb +12 -0
  39. data/test/examples/method.rb +15 -0
  40. data/test/examples/post_mortem.rb +19 -0
  41. data/test/examples/quit.rb +2 -0
  42. data/test/examples/reload.rb +6 -0
  43. data/test/examples/restart.rb +6 -0
  44. data/test/examples/save.rb +3 -0
  45. data/test/examples/set.rb +3 -0
  46. data/test/examples/set_annotate.rb +12 -0
  47. data/test/examples/settings.rb +1 -0
  48. data/test/examples/show.rb +2 -0
  49. data/test/examples/source.rb +3 -0
  50. data/test/examples/stepping.rb +21 -0
  51. data/test/examples/thread.rb +32 -0
  52. data/test/examples/tmate.rb +10 -0
  53. data/test/examples/trace.rb +7 -0
  54. data/test/examples/trace_threads.rb +20 -0
  55. data/test/examples/variables.rb +26 -0
  56. data/test/finish_test.rb +48 -0
  57. data/test/frame_test.rb +140 -0
  58. data/test/help_test.rb +50 -0
  59. data/test/info_test.rb +325 -0
  60. data/test/irb_test.rb +81 -0
  61. data/test/jump_test.rb +70 -0
  62. data/test/kill_test.rb +47 -0
  63. data/test/list_test.rb +145 -0
  64. data/test/method_test.rb +70 -0
  65. data/test/post_mortem_test.rb +25 -0
  66. data/test/quit_test.rb +55 -0
  67. data/test/reload_test.rb +43 -0
  68. data/test/restart_test.rb +143 -0
  69. data/test/save_test.rb +92 -0
  70. data/test/set_test.rb +163 -0
  71. data/test/show_test.rb +292 -0
  72. data/test/source_test.rb +44 -0
  73. data/test/stepping_test.rb +118 -0
  74. data/test/support/breakpoint.rb +12 -0
  75. data/test/support/context.rb +14 -0
  76. data/test/support/matchers.rb +67 -0
  77. data/test/support/mocha_extensions.rb +71 -0
  78. data/test/support/processor.rb +7 -0
  79. data/test/support/test_dsl.rb +205 -0
  80. data/test/support/test_interface.rb +66 -0
  81. data/test/test_helper.rb +8 -0
  82. data/test/thread_test.rb +122 -0
  83. data/test/tmate_test.rb +43 -0
  84. data/test/trace_test.rb +154 -0
  85. data/test/variables_test.rb +114 -0
  86. metadata +107 -158
  87. data/test/base/base.rb +0 -71
  88. data/test/base/binding.rb +0 -24
  89. data/test/base/catchpoint.rb +0 -22
  90. data/test/base/load.rb +0 -36
  91. data/test/bp_loop_issue.rb +0 -3
  92. data/test/classes.rb +0 -11
  93. data/test/config.yaml +0 -8
  94. data/test/data/annotate.cmd +0 -29
  95. data/test/data/annotate.right +0 -139
  96. data/test/data/break_bad.cmd +0 -18
  97. data/test/data/break_bad.right +0 -28
  98. data/test/data/break_loop_bug.cmd +0 -5
  99. data/test/data/break_loop_bug.right +0 -15
  100. data/test/data/breakpoints.cmd +0 -38
  101. data/test/data/breakpoints.right +0 -98
  102. data/test/data/catch.cmd +0 -20
  103. data/test/data/catch.right +0 -49
  104. data/test/data/catch2.cmd +0 -19
  105. data/test/data/catch2.right +0 -65
  106. data/test/data/catch3.cmd +0 -11
  107. data/test/data/catch3.right +0 -37
  108. data/test/data/condition.cmd +0 -28
  109. data/test/data/condition.right +0 -65
  110. data/test/data/ctrl.cmd +0 -23
  111. data/test/data/ctrl.right +0 -70
  112. data/test/data/display.cmd +0 -24
  113. data/test/data/display.right +0 -44
  114. data/test/data/dollar-0.right +0 -2
  115. data/test/data/dollar-0a.right +0 -2
  116. data/test/data/dollar-0b.right +0 -2
  117. data/test/data/edit.cmd +0 -12
  118. data/test/data/edit.right +0 -19
  119. data/test/data/emacs_basic.cmd +0 -43
  120. data/test/data/emacs_basic.right +0 -106
  121. data/test/data/enable.cmd +0 -20
  122. data/test/data/enable.right +0 -36
  123. data/test/data/finish.cmd +0 -16
  124. data/test/data/finish.right +0 -31
  125. data/test/data/frame.cmd +0 -26
  126. data/test/data/frame.right +0 -55
  127. data/test/data/help.cmd +0 -20
  128. data/test/data/help.right +0 -21
  129. data/test/data/history.right +0 -7
  130. data/test/data/info-thread.cmd +0 -13
  131. data/test/data/info-thread.right +0 -37
  132. data/test/data/info-var-bug2.cmd +0 -5
  133. data/test/data/info-var-bug2.right +0 -10
  134. data/test/data/info-var.cmd +0 -23
  135. data/test/data/info-var.right +0 -52
  136. data/test/data/info.cmd +0 -21
  137. data/test/data/info.right +0 -65
  138. data/test/data/jump.cmd +0 -16
  139. data/test/data/jump.right +0 -56
  140. data/test/data/jump2.cmd +0 -16
  141. data/test/data/jump2.right +0 -44
  142. data/test/data/linetrace.cmd +0 -6
  143. data/test/data/linetrace.right +0 -23
  144. data/test/data/list.cmd +0 -19
  145. data/test/data/list.right +0 -127
  146. data/test/data/method.cmd +0 -10
  147. data/test/data/method.right +0 -21
  148. data/test/data/methodsig.cmd +0 -10
  149. data/test/data/methodsig.right +0 -20
  150. data/test/data/next.cmd +0 -22
  151. data/test/data/next.right +0 -61
  152. data/test/data/noquit.right +0 -1
  153. data/test/data/output.cmd +0 -6
  154. data/test/data/output.right +0 -31
  155. data/test/data/pm-bug.cmd +0 -7
  156. data/test/data/pm-bug.right +0 -12
  157. data/test/data/post-mortem-next.cmd +0 -8
  158. data/test/data/post-mortem-next.right +0 -14
  159. data/test/data/post-mortem-osx.right +0 -31
  160. data/test/data/post-mortem.cmd +0 -13
  161. data/test/data/post-mortem.right +0 -32
  162. data/test/data/quit.cmd +0 -6
  163. data/test/data/quit.right +0 -0
  164. data/test/data/raise.cmd +0 -11
  165. data/test/data/raise.right +0 -23
  166. data/test/data/save.cmd +0 -34
  167. data/test/data/save.right +0 -59
  168. data/test/data/scope-var.cmd +0 -42
  169. data/test/data/scope-var.right +0 -587
  170. data/test/data/setshow.cmd +0 -56
  171. data/test/data/setshow.right +0 -98
  172. data/test/data/source.cmd +0 -5
  173. data/test/data/source.right +0 -15
  174. data/test/data/stepping.cmd +0 -21
  175. data/test/data/stepping.right +0 -50
  176. data/test/data/test-init-cygwin.right +0 -7
  177. data/test/data/test-init-osx.right +0 -4
  178. data/test/data/test-init.right +0 -5
  179. data/test/data/trace.right +0 -14
  180. data/test/dollar-0.rb +0 -5
  181. data/test/gcd-dbg-nox.rb +0 -30
  182. data/test/gcd-dbg.rb +0 -29
  183. data/test/gcd.rb +0 -18
  184. data/test/helper.rb +0 -142
  185. data/test/info-var-bug.rb +0 -47
  186. data/test/info-var-bug2.rb +0 -2
  187. data/test/jump.rb +0 -14
  188. data/test/jump2.rb +0 -27
  189. data/test/lib/commands/catchpoint_test.rb +0 -28
  190. data/test/lib/commands/unit/regexp.rb +0 -38
  191. data/test/next.rb +0 -18
  192. data/test/null.rb +0 -1
  193. data/test/output.rb +0 -2
  194. data/test/pm-base.rb +0 -17
  195. data/test/pm-bug.rb +0 -3
  196. data/test/pm-catch.rb +0 -12
  197. data/test/pm-catch2.rb +0 -27
  198. data/test/pm-catch3.rb +0 -47
  199. data/test/pm.rb +0 -11
  200. data/test/raise.rb +0 -3
  201. data/test/rdebug-save.1 +0 -7
  202. data/test/runall +0 -12
  203. data/test/scope-var.rb +0 -29
  204. data/test/tdebug.rb +0 -246
  205. data/test/test-annotate.rb +0 -24
  206. data/test/test-break-bad.rb +0 -36
  207. data/test/test-breakpoints.rb +0 -24
  208. data/test/test-catch.rb +0 -24
  209. data/test/test-catch2.rb +0 -24
  210. data/test/test-catch3.rb +0 -24
  211. data/test/test-condition.rb +0 -24
  212. data/test/test-ctrl.rb +0 -51
  213. data/test/test-display.rb +0 -25
  214. data/test/test-dollar-0.rb +0 -39
  215. data/test/test-edit.rb +0 -25
  216. data/test/test-emacs-basic.rb +0 -25
  217. data/test/test-enable.rb +0 -24
  218. data/test/test-finish.rb +0 -33
  219. data/test/test-frame.rb +0 -33
  220. data/test/test-help.rb +0 -54
  221. data/test/test-hist.rb +0 -65
  222. data/test/test-info-thread.rb +0 -31
  223. data/test/test-info-var.rb +0 -46
  224. data/test/test-info.rb +0 -25
  225. data/test/test-init.rb +0 -43
  226. data/test/test-jump.rb +0 -34
  227. data/test/test-list.rb +0 -24
  228. data/test/test-method.rb +0 -33
  229. data/test/test-next.rb +0 -24
  230. data/test/test-output.rb +0 -25
  231. data/test/test-quit.rb +0 -29
  232. data/test/test-raise.rb +0 -24
  233. data/test/test-remote.rb +0 -14
  234. data/test/test-save.rb +0 -30
  235. data/test/test-scope-var.rb +0 -24
  236. data/test/test-setshow.rb +0 -24
  237. data/test/test-source.rb +0 -24
  238. data/test/test-stepping.rb +0 -25
  239. data/test/test-trace.rb +0 -46
  240. data/test/thread1.rb +0 -25
  241. data/test/trunc-call.rb +0 -30
@@ -0,0 +1,44 @@
1
+ require_relative 'test_helper'
2
+
3
+ describe "Source Command" do
4
+ include TestDsl
5
+
6
+ let(:filename) { 'source_example.txt' }
7
+ before do
8
+ File.open(filename, 'w') do |f|
9
+ f.puts 'break 2'
10
+ f.puts 'break 3 if true'
11
+ end
12
+ end
13
+ after do
14
+ FileUtils.rm(filename)
15
+ end
16
+
17
+ it "must run commands from file" do
18
+ enter "source #{filename}"
19
+ debug_file 'source' do
20
+ Debugger.breakpoints[0].pos.must_equal 2
21
+ Debugger.breakpoints[1].pos.must_equal 3
22
+ Debugger.breakpoints[1].expr.must_equal "true"
23
+ end
24
+ end
25
+
26
+ it "must be able to use shortcut" do
27
+ enter "so #{filename}"
28
+ debug_file('source') { Debugger.breakpoints[0].pos.must_equal 2 }
29
+ end
30
+
31
+ it "must show an error if file is not found" do
32
+ enter "source blabla"
33
+ debug_file 'source'
34
+ check_output_includes /Command file '.*blabla' is not found/, interface.error_queue
35
+ end
36
+
37
+ describe "Post Mortem" do
38
+ it "must work in post-mortem mode" do
39
+ enter 'cont', "so #{filename}"
40
+ debug_file('post_mortem') { Debugger.breakpoints[0].pos.must_equal 3 }
41
+ end
42
+ end
43
+
44
+ end
@@ -0,0 +1,118 @@
1
+ require_relative 'test_helper'
2
+
3
+ describe "Stepping Commands" do
4
+ include TestDsl
5
+
6
+ describe "Next Command" do
7
+ describe "Usual mode" do
8
+ before { enter 'break 10', 'cont' }
9
+
10
+ it "must go to the next line if forced by a setting" do
11
+ temporary_change_hash_value(Debugger::Command.settings, :force_stepping, true) do
12
+ enter 'next'
13
+ debug_file('stepping') { state.line.must_equal 11 }
14
+ end
15
+ end
16
+
17
+ it "must go to the next line by shortcut" do
18
+ temporary_change_hash_value(Debugger::Command.settings, :force_stepping, true) do
19
+ enter 'n'
20
+ debug_file('stepping') { state.line.must_equal 11 }
21
+ end
22
+ end
23
+
24
+ it "must leave on the same line if forced by a setting" do
25
+ temporary_change_hash_value(Debugger::Command.settings, :force_stepping, false) do
26
+ enter 'next'
27
+ debug_file('stepping') { state.line.must_equal 10 }
28
+ end
29
+ end
30
+
31
+ it "must go to the specified number of lines forward by default" do
32
+ temporary_change_hash_value(Debugger::Command.settings, :force_stepping, true) do
33
+ enter 'next 2'
34
+ debug_file('stepping') { state.line.must_equal 21 }
35
+ end
36
+ end
37
+
38
+ it "must go to the next line if forced to do that by 'plus' sign" do
39
+ enter 'next+'
40
+ debug_file('stepping') { state.line.must_equal 11 }
41
+ end
42
+
43
+ it "must leave on the same line if forced to do that by 'minus' sign" do
44
+ enter 'next-'
45
+ debug_file('stepping') { state.line.must_equal 10 }
46
+ end
47
+
48
+ it "must ignore the setting if 'minus' is specified" do
49
+ enter 'next-'
50
+ debug_file('stepping') { state.line.must_equal 10 }
51
+ end
52
+ end
53
+
54
+ describe "Post Mortem" do
55
+ temporary_change_hash_value(Debugger::Command.settings, :autoeval, false)
56
+ it "must not work in post-mortem mode" do
57
+ enter 'cont', "next"
58
+ debug_file('post_mortem')
59
+ check_output_includes 'Unknown command: "next". Try "help".', interface.error_queue
60
+ end
61
+ end
62
+ end
63
+
64
+
65
+ describe "Step Command" do
66
+ describe "Usual mode" do
67
+ before { enter 'break 10', 'cont' }
68
+
69
+ it "must go to the step line if forced by a setting" do
70
+ temporary_change_hash_value(Debugger::Command.settings, :force_stepping, true) do
71
+ enter 'step'
72
+ debug_file('stepping') { state.line.must_equal 11 }
73
+ end
74
+ end
75
+
76
+ it "must go to the next line by shortcut" do
77
+ temporary_change_hash_value(Debugger::Command.settings, :force_stepping, true) do
78
+ enter 's'
79
+ debug_file('stepping') { state.line.must_equal 11 }
80
+ end
81
+ end
82
+
83
+ it "must leave on the same line if forced by a setting" do
84
+ temporary_change_hash_value(Debugger::Command.settings, :force_stepping, false) do
85
+ enter 'step'
86
+ debug_file('stepping') { state.line.must_equal 10 }
87
+ end
88
+ end
89
+
90
+ it "must go to the specified number of lines forward by default" do
91
+ temporary_change_hash_value(Debugger::Command.settings, :force_stepping, true) do
92
+ enter 'step 2'
93
+ debug_file('stepping') { state.line.must_equal 15 }
94
+ end
95
+ end
96
+
97
+ it "must go to the step line if forced to do that by 'plus' sign" do
98
+ enter 'step+'
99
+ debug_file('stepping') { state.line.must_equal 11 }
100
+ end
101
+
102
+ it "must leave on the same line if forced to do that by 'minus' sign" do
103
+ enter 'step-'
104
+ debug_file('stepping') { state.line.must_equal 10 }
105
+ end
106
+ end
107
+
108
+ describe "Post Mortem" do
109
+ temporary_change_hash_value(Debugger::Command.settings, :autoeval, false)
110
+ it "must not work in post-mortem mode" do
111
+ enter 'cont', "step"
112
+ debug_file('post_mortem')
113
+ check_output_includes 'Unknown command: "step". Try "help".', interface.error_queue
114
+ end
115
+ end
116
+ end
117
+
118
+ end
@@ -0,0 +1,12 @@
1
+ module Debugger
2
+ class Breakpoint
3
+
4
+ def inspect
5
+ values = %w{id pos source expr hit_condition hit_count hit_value enabled?}.map do |field|
6
+ "#{field}: #{send(field)}"
7
+ end.join(", ")
8
+ "#<Debugger::Breakpoint #{values}>"
9
+ end
10
+
11
+ end
12
+ end
@@ -0,0 +1,14 @@
1
+ module Debugger
2
+ class Context
3
+
4
+ def inspect
5
+ values = %w{
6
+ thread thnum stop_reason suspended? tracing ignored? stack_size dead? frame_line frame_file frame_self
7
+ }.map do |field|
8
+ "#{field}: #{send(field)}"
9
+ end.join(", ")
10
+ "#<Debugger::Context #{values}>"
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,67 @@
1
+ module MiniTest::Assertions
2
+
3
+ # This matcher checks that given collection is included into the original collection,
4
+ # and in correct order. It accepts both strings and regexps.
5
+ #
6
+ # Examples:
7
+ #
8
+ # assert_includes_in_order(%w{1 2 3 4 5}, %w{1 3 5}) # => pass
9
+ # assert_includes_in_order(%w{1 2 3 4 5}, %w{1 5 3}) # => fail
10
+ # assert_includes_in_order(w{1 2 3 4 5}, ["1", /\d+/, "5"]) # => pass
11
+ # assert_includes_in_order(w{1 2 3 4 5}, ["1", /\[a-z]+/, "5"]) # => fail
12
+ #
13
+ def assert_includes_in_order(given_collection, original_collection, msg = nil)
14
+ msg = message(msg) do
15
+ "Expected #{mu_pp(original_collection)} to include #{mu_pp(given_collection)} in order"
16
+ end
17
+ assert includes_in_order_result(original_collection, given_collection), msg
18
+ end
19
+
20
+ def refute_includes_in_order(given_collection, original_collection, msg = nil)
21
+ msg = message(msg) do
22
+ "Expected #{mu_pp(original_collection)} to not include #{mu_pp(given_collection)} in order"
23
+ end
24
+ refute includes_in_order_result(original_collection, given_collection), msg
25
+ end
26
+
27
+
28
+ private
29
+
30
+ def includes_in_order_result(original_collection, given_collection)
31
+ result = true
32
+ given_collection.each do |given_item|
33
+ result &&= case given_item
34
+ when String
35
+ index = original_collection.index(given_item)
36
+ if index
37
+ original_collection = original_collection[(index + 1)..-1]
38
+ true
39
+ else
40
+ false
41
+ end
42
+ when Regexp
43
+ index = nil
44
+ original_collection.each_with_index do |original_item, i|
45
+ if original_item =~ given_item
46
+ index = i
47
+ break
48
+ end
49
+ end
50
+ if index
51
+ original_collection = original_collection[(index + 1)..-1]
52
+ true
53
+ else
54
+ false
55
+ end
56
+ else
57
+ false
58
+ end
59
+ end
60
+ result
61
+ end
62
+ end
63
+
64
+ module MiniTest::Expectations
65
+ infect_an_assertion :assert_includes_in_order, :must_include_in_order
66
+ infect_an_assertion :refute_includes_in_order, :wont_include_in_order
67
+ end
@@ -0,0 +1,71 @@
1
+ module Mocha
2
+ class Expectation
3
+
4
+ # Allows to specify a block to execute when expectation will be matched.
5
+ # This way, we can specify dynamic values to return or just make some side effects
6
+ #
7
+ # Example:
8
+ #
9
+ # foo.expects(:bar).with('bla').calls { 2 + 3 }
10
+ # foo.bar('bla') # => 5
11
+ #
12
+ def calls(&block)
13
+ @calls ||= Call.new
14
+ @calls += Call.new(block)
15
+ self
16
+ end
17
+
18
+ def invoke_with_calls(arguments, &block)
19
+ invoke_without_calls(&block) || (@calls.next(arguments, &block) if @calls)
20
+ end
21
+ alias_method :invoke_without_calls, :invoke
22
+ alias_method :invoke, :invoke_with_calls
23
+
24
+ end
25
+
26
+ class Mock
27
+
28
+ # We monkey-patch that method to be able to pass arguments to Expectation#invoke method
29
+ def method_missing(symbol, *arguments, &block)
30
+ if @responder and not @responder.respond_to?(symbol)
31
+ raise NoMethodError, "undefined method `#{symbol}' for #{self.mocha_inspect} which responds like #{@responder.mocha_inspect}"
32
+ end
33
+ if matching_expectation_allowing_invocation = @expectations.match_allowing_invocation(symbol, *arguments)
34
+ # We change this line - added arguments
35
+ matching_expectation_allowing_invocation.invoke(arguments, &block)
36
+ else
37
+ if (matching_expectation = @expectations.match(symbol, *arguments)) || (!matching_expectation && !@everything_stubbed)
38
+ # We change this line - added arguments
39
+ matching_expectation.invoke(arguments, &block) if matching_expectation
40
+ message = UnexpectedInvocation.new(self, symbol, *arguments).to_s
41
+ require 'mocha/mockery'
42
+ message << Mockery.instance.mocha_inspect
43
+ raise ExpectationError.new(message, caller)
44
+ end
45
+ end
46
+ end
47
+
48
+ end
49
+
50
+ class Call
51
+
52
+ attr_reader :blocks
53
+
54
+ def initialize(*blocks)
55
+ @blocks = [ *blocks ]
56
+ end
57
+
58
+ def next(arguments, &block)
59
+ case @blocks.length
60
+ when 0 then nil
61
+ when 1 then @blocks.first.call(*arguments, &block)
62
+ else @blocks.shift.call(*arguments, &block)
63
+ end
64
+ end
65
+
66
+ def +(other)
67
+ self.class.new(*(@blocks + other.blocks))
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,7 @@
1
+ class Debugger::Processor
2
+ class << self
3
+ def print(message)
4
+ Debugger.handler.interface.print_queue << message
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,205 @@
1
+ module TestDsl
2
+ module Shared
3
+ def fullpath(filename)
4
+ (Pathname.new(__FILE__) + "../../examples/#{filename}.rb").cleanpath.to_s
5
+ end
6
+ end
7
+ include Shared
8
+
9
+ def self.included(base)
10
+ base.class_eval do
11
+ extend ClassMethods
12
+ before do
13
+ Debugger.interface = TestInterface.new
14
+ Debugger.handler.display.clear
15
+ end
16
+ after do
17
+ Debugger.handler.display.clear
18
+ end
19
+ end
20
+ end
21
+
22
+ # Adds commands to the input queue, so they will be retrieved by Processor later.
23
+ # I.e. it emulates user's input.
24
+ #
25
+ # If a command is a Proc object, it will be executed before retrieving by Processor.
26
+ # May be handy when you need build a command depending on the current context/state.
27
+ #
28
+ # Usage:
29
+ #
30
+ # enter 'b 12'
31
+ # enter 'b 12', 'cont'
32
+ # enter ['b 12', 'cont']
33
+ # enter 'b 12', ->{"disable #{breakpoint.id}"}, 'cont'
34
+ #
35
+ def enter(*messages)
36
+ messages = messages.first.is_a?(Array) ? messages.first : messages
37
+ interface.input_queue.concat(messages)
38
+ end
39
+
40
+ # Runs a debugger with the provided basename for a file. The file should be placed
41
+ # to the test/new/examples dir.
42
+ #
43
+ # You also can specify block, which will be executed when Processor extracts all the
44
+ # commands from the input queue. You can use it e.g. for making asserts for the current
45
+ # test. If you specified the block, and it never was executed, the test will fail.
46
+ #
47
+ # Usage:
48
+ #
49
+ # debug "ex1" # ex1 should be placed in test/new/examples/ex1.rb
50
+ #
51
+ # enter 'b 4', 'cont'
52
+ # debug("ex1") { state.line.must_equal 4 } # It will be executed after running 'cont' and stopping at the breakpoint
53
+ #
54
+ def debug_file(filename, &block)
55
+ is_test_block_called = false
56
+ debug_completed = false
57
+ exception = nil
58
+ Debugger.stubs(:run_init_script)
59
+ if block
60
+ interface.test_block = lambda do
61
+ is_test_block_called = true
62
+ # We need to store exception and reraise it after completing debugging, because
63
+ # Debugger will swallow any exceptions, so e.g. our failed assertions will be ignored
64
+ begin
65
+ block.call
66
+ rescue Exception => e
67
+ exception = e
68
+ raise e
69
+ end
70
+ end
71
+ end
72
+ Debugger.start do
73
+ load fullpath(filename)
74
+ debug_completed = true
75
+ end
76
+ flunk "Debug block was not completed" unless debug_completed
77
+ flunk "test block is provided, but not called" if block && !is_test_block_called
78
+ raise exception if exception
79
+ end
80
+
81
+ # Checks the output of the debugger. By default it checks output queue of the current interface,
82
+ # but you can check again any queue by providing it as a second argument.
83
+ #
84
+ # Usage:
85
+ #
86
+ # enter 'break 4', 'cont'
87
+ # debug("ex1")
88
+ # check_output "Breakpoint 1 at #{fullpath('ex1')}:4"
89
+ #
90
+ def check_output(check_method, *args)
91
+ queue = args.last.is_a?(String) || args.last.is_a?(Regexp) ? interface.output_queue : args.pop
92
+ queue_messages = queue.map(&:strip)
93
+ messages = Array(args).map { |msg| msg.is_a?(String) ? msg.strip : msg }
94
+ queue_messages.send(check_method, messages)
95
+ end
96
+
97
+ def check_output_includes(*args)
98
+ check_output :must_include_in_order, *args
99
+ end
100
+
101
+ def check_output_doesnt_include(*args)
102
+ check_output :wont_include_in_order, *args
103
+ end
104
+
105
+ def interface
106
+ Debugger.handler.interface
107
+ end
108
+
109
+ def state
110
+ $rdebug_state
111
+ end
112
+
113
+ def context
114
+ state.context
115
+ end
116
+
117
+ def breakpoint
118
+ Debugger.breakpoints.first
119
+ end
120
+
121
+ def force_set_const(klass, const, value)
122
+ klass.send(:remove_const, const) if klass.const_defined?(const)
123
+ klass.const_set(const, value)
124
+ end
125
+
126
+ def change_line_in_file(file, line, new_line_content)
127
+ old_content = File.read(file)
128
+ new_content = old_content.split("\n").tap { |c| c[line - 1] = new_line_content }.join("\n")
129
+ File.open(file, 'w') { |f| f.write(new_content) }
130
+ end
131
+
132
+ def temporary_change_method_value(item, method, value)
133
+ old = item.send(method)
134
+ item.send("#{method}=", value)
135
+ yield
136
+ ensure
137
+ item.send("#{method}=", old)
138
+ end
139
+
140
+ def temporary_change_hash_value(item, key, value)
141
+ old_value = item[key]
142
+ begin
143
+ item[key] = value
144
+ yield
145
+ ensure
146
+ item[key] = old_value
147
+ end
148
+ end
149
+
150
+ def temporary_set_const(klass, const, value)
151
+ old_value = klass.const_defined?(const) ? klass.const_get(const) : :__undefined__
152
+ begin
153
+ force_set_const(klass, const, value)
154
+ yield
155
+ ensure
156
+ if old_value == :__undefined__
157
+ klass.send(:remove_const, const)
158
+ else
159
+ force_set_const(klass, const, old_value)
160
+ end
161
+ end
162
+ end
163
+
164
+ module ClassMethods
165
+ include Shared
166
+
167
+ def temporary_change_method_value(item, method, value)
168
+ old_value = nil
169
+ before do
170
+ old_value = item.send(method)
171
+ item.send("#{method}=", value)
172
+ end
173
+ after do
174
+ item.send("#{method}=", old_value)
175
+ end
176
+ end
177
+
178
+ def temporary_change_hash_value(item, key, value)
179
+ old_value = nil
180
+ before do
181
+ old_value = item[key]
182
+ item[key] = value
183
+ end
184
+ after do
185
+ item[key] = old_value
186
+ end
187
+ end
188
+
189
+ def temporary_set_const(klass, const, value)
190
+ old_value = nil
191
+ before do
192
+ old_value = klass.const_defined?(const) ? klass.const_get(const) : :__undefined__
193
+ force_set_const(klass, const, value)
194
+ end
195
+ after do
196
+ if old_value == :__undefined__
197
+ klass.send(:remove_const, const)
198
+ else
199
+ force_set_const(klass, const, old_value)
200
+ end
201
+ end
202
+ end
203
+ end
204
+
205
+ end