debugger 1.4.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. data/CHANGELOG.md +4 -0
  2. data/README.md +9 -3
  3. data/debugger.gemspec +1 -1
  4. data/ext/ruby_debug/192/ruby_debug.c +21 -9
  5. data/ext/ruby_debug/193/ruby_debug.c +15 -5
  6. data/lib/debugger/test.rb +6 -0
  7. data/{test/support → lib/debugger/test}/breakpoint.rb +0 -0
  8. data/{test/support → lib/debugger/test}/context.rb +0 -0
  9. data/{test/support → lib/debugger/test}/matchers.rb +0 -0
  10. data/{test/support → lib/debugger/test}/mocha_extensions.rb +1 -1
  11. data/lib/debugger/test/printer_helpers.rb +8 -0
  12. data/{test/support → lib/debugger/test}/processor.rb +0 -0
  13. data/{test/support → lib/debugger/test}/test_dsl.rb +22 -2
  14. data/{test/support → lib/debugger/test}/test_interface.rb +4 -0
  15. data/lib/debugger/version.rb +1 -1
  16. data/lib/ruby-debug.rb +4 -1
  17. data/lib/ruby-debug/command.rb +18 -6
  18. data/lib/ruby-debug/commands/breakpoints.rb +27 -29
  19. data/lib/ruby-debug/commands/condition.rb +7 -2
  20. data/lib/ruby-debug/commands/continue.rb +1 -2
  21. data/lib/ruby-debug/commands/control.rb +8 -9
  22. data/lib/ruby-debug/commands/display.rb +7 -15
  23. data/lib/ruby-debug/commands/edit.rb +6 -6
  24. data/lib/ruby-debug/commands/enable.rb +6 -7
  25. data/lib/ruby-debug/commands/eval.rb +1 -3
  26. data/lib/ruby-debug/commands/frame.rb +72 -101
  27. data/lib/ruby-debug/commands/info.rb +8 -14
  28. data/lib/ruby-debug/commands/irb.rb +1 -1
  29. data/lib/ruby-debug/commands/jump.rb +6 -6
  30. data/lib/ruby-debug/commands/kill.rb +0 -1
  31. data/lib/ruby-debug/commands/list.rb +4 -4
  32. data/lib/ruby-debug/commands/method.rb +8 -11
  33. data/lib/ruby-debug/commands/quit.rb +1 -1
  34. data/lib/ruby-debug/commands/reload.rb +1 -1
  35. data/lib/ruby-debug/commands/save.rb +1 -1
  36. data/lib/ruby-debug/commands/set.rb +10 -15
  37. data/lib/ruby-debug/commands/show.rb +28 -42
  38. data/lib/ruby-debug/commands/skip.rb +1 -1
  39. data/lib/ruby-debug/commands/source.rb +1 -1
  40. data/lib/ruby-debug/commands/start.rb +26 -0
  41. data/lib/ruby-debug/commands/threads.rb +29 -18
  42. data/lib/ruby-debug/commands/tmate.rb +1 -1
  43. data/lib/ruby-debug/commands/trace.rb +6 -7
  44. data/lib/ruby-debug/commands/variables.rb +36 -19
  45. data/lib/ruby-debug/helper.rb +5 -5
  46. data/lib/ruby-debug/interface.rb +15 -3
  47. data/lib/ruby-debug/printers/base.rb +58 -0
  48. data/lib/ruby-debug/printers/plain.rb +41 -0
  49. data/lib/ruby-debug/printers/texts/base.yml +146 -0
  50. data/lib/ruby-debug/printers/texts/plain.yml +60 -0
  51. data/lib/ruby-debug/processor.rb +56 -47
  52. data/test/breakpoints_test.rb +43 -54
  53. data/test/conditions_test.rb +18 -6
  54. data/test/continue_test.rb +1 -1
  55. data/test/display_test.rb +11 -11
  56. data/test/edit_test.rb +1 -2
  57. data/test/eval_test.rb +5 -6
  58. data/test/finish_test.rb +1 -1
  59. data/test/frame_test.rb +29 -27
  60. data/test/help_test.rb +0 -1
  61. data/test/info_test.rb +10 -14
  62. data/test/irb_test.rb +0 -1
  63. data/test/jump_test.rb +21 -2
  64. data/test/method_test.rb +3 -3
  65. data/test/new/printers/plain_test.rb +84 -0
  66. data/test/reload_test.rb +2 -2
  67. data/test/restart_test.rb +1 -2
  68. data/test/set_test.rb +8 -7
  69. data/test/show_test.rb +22 -22
  70. data/test/source_test.rb +1 -1
  71. data/test/test_helper.rb +2 -1
  72. data/test/thread_test.rb +11 -13
  73. data/test/trace_test.rb +7 -7
  74. data/test/variables_test.rb +33 -15
  75. metadata +20 -12
@@ -0,0 +1,60 @@
1
+ breakpoints:
2
+ set_breakpoint_to_line: "Breakpoint {id} file {file}, line {line}"
3
+ set_breakpoint_to_method: "Breakpoint {id} at {class}::{method}"
4
+ stop_at_breakpoint: "Breakpoint {id} at {file}:{line}"
5
+ delete: "Breakpoint {id} has been deleted"
6
+
7
+ conditions:
8
+ set_condition: "Condition '{expr}' is set for the breakpoint {id}"
9
+ unset_condition: "Condition is cleared for the breakpoint {id}"
10
+
11
+ display:
12
+ result: "{n}: {exp} = {result}"
13
+
14
+ eval:
15
+ exception: "{text_message}"
16
+ result: "{result}"
17
+
18
+ frame:
19
+ line: "{mark}#{pos} {call_str}at line {file}:{line}"
20
+
21
+ method:
22
+ methods: "{name}|c"
23
+
24
+ stop:
25
+ suspend: "{file}:{line_number}\n{line}"
26
+
27
+ toggle:
28
+ breakpoint_enabled: "Breakpoint {id} is enabled"
29
+ breakpoint_disabled: "Breakpoint {id} is disabled"
30
+
31
+ restart:
32
+ success: "Re exec'ing:\n\t{cmd}"
33
+
34
+ set:
35
+ errors:
36
+ no_subcommand: "\"set\" must be followed by the name of an set command:\nList of set subcommands:\n\n{subcommands}"
37
+
38
+ show:
39
+ errors:
40
+ no_subcommand: "\"show\" must be followed by the name of an show command:\nList of show subcommands:\n\n{subcommands}"
41
+
42
+ thread:
43
+ context: "{status_flag}{debug_flag}{id} {thread}\t{file_line}"
44
+
45
+ tmate:
46
+ errors:
47
+ wrong_frame: "Wrong frame number"
48
+
49
+ trace:
50
+ messages:
51
+ all_threads: "Tracing {status} all threads"
52
+ current_thread: "Tracing {status} on current thread"
53
+ errors:
54
+ wrong_var_subcommand: "expecting 'stop' or 'nostop'; got {subcmd}"
55
+ var_is_not_global: "{name} is not a global variable"
56
+ wrong_subcommand: "expecting 'on', 'off', 'var' or 'variable'; got: {subcmd}"
57
+ trace: "traced variable {name} has value {value}"
58
+
59
+ variable:
60
+ variable: "{key} = {value}"
@@ -6,6 +6,27 @@ module Debugger
6
6
  # Should this be a mixin?
7
7
  class Processor # :nodoc
8
8
  attr_accessor :interface
9
+ extend Forwardable
10
+ def_delegator :"Debugger.printer", :print, :pr
11
+
12
+ def self.protect(mname)
13
+ alias_method "__#{mname}", mname
14
+ module_eval %{
15
+ def #{mname}(*args)
16
+ @mutex.synchronize do
17
+ return unless @interface
18
+ __#{mname}(*args)
19
+ end
20
+ rescue IOError, Errno::EPIPE
21
+ self.interface = nil
22
+ rescue SignalException
23
+ raise
24
+ rescue Exception
25
+ print "INTERNAL ERROR!!! #\{$!\}\n" rescue nil
26
+ print $!.backtrace.map{|l| "\t#\{l\}"}.join("\n") rescue nil
27
+ end
28
+ }
29
+ end
9
30
 
10
31
  # Format msg with gdb-style annotation header
11
32
  def afmt(msg, newline="\n")
@@ -31,6 +52,11 @@ module Debugger
31
52
  @interface.print(*args)
32
53
  end
33
54
 
55
+ # Split commands like this:
56
+ # split_commands("abc;def\\;ghi;jkl") => ["abc", "def;ghi", "jkl"]
57
+ def split_commands(input)
58
+ input.split(/(?<!\\);/).map { |e| e.gsub("\\;", ";") }
59
+ end
34
60
  end
35
61
 
36
62
  class CommandProcessor < Processor # :nodoc:
@@ -94,35 +120,23 @@ module Debugger
94
120
  end
95
121
  end
96
122
 
97
- def self.print_location_and_text(file, line)
98
- file_line = "%s:%s\n%s" % [canonic_file(file), line,
99
- Debugger.line_at(file, line)]
123
+ def self.print_location_and_text(file, line, context)
124
+ result = Debugger.printer.print("stop.suspend",
125
+ file: canonic_file(file), line_number: line, line: Debugger.line_at(file, line),
126
+ thnum: context && context.thnum, frames: context && context.stack_size
127
+ )
128
+ Debugger.handler.interface.print(annotate_location_and_text(result))
129
+ end
130
+
131
+ def self.annotate_location_and_text(output)
100
132
  # FIXME: use annotations routines
101
133
  if Debugger.annotate.to_i > 2
102
- file_line = "\032\032source #{file_line}"
134
+ "\032\032source #{output}"
103
135
  elsif ENV['EMACS']
104
- file_line = "\032\032#{file_line}"
136
+ "\032\032#{output}"
137
+ else
138
+ output
105
139
  end
106
- print file_line
107
- end
108
-
109
- def self.protect(mname)
110
- alias_method "__#{mname}", mname
111
- module_eval %{
112
- def #{mname}(*args)
113
- @mutex.synchronize do
114
- return unless @interface
115
- __#{mname}(*args)
116
- end
117
- rescue IOError, Errno::EPIPE
118
- self.interface = nil
119
- rescue SignalException
120
- raise
121
- rescue Exception
122
- print "INTERNAL ERROR!!! #\{$!\}\n" rescue nil
123
- print $!.backtrace.map{|l| "\t#\{l\}"}.join("\n") rescue nil
124
- end
125
- }
126
140
  end
127
141
 
128
142
  def at_breakpoint(context, breakpoint)
@@ -133,7 +147,10 @@ module Debugger
133
147
  if Debugger.annotate.to_i > 2
134
148
  print afmt("source #{file}:#{line}")
135
149
  end
136
- print "Breakpoint %d at %s:%s\n", n, file, line
150
+ print pr(
151
+ "breakpoints.stop_at_breakpoint", id: n, file: file, line: line, thread_id: Debugger.current_context.thnum
152
+ )
153
+ @last_breakpoint = breakpoint
137
154
  end
138
155
  protect :at_breakpoint
139
156
 
@@ -170,12 +187,16 @@ module Debugger
170
187
  protect :at_tracing
171
188
 
172
189
  def at_line(context, file, line)
190
+ CommandProcessor.print_location_and_text(file, line, context) unless @last_breakpoint
173
191
  process_commands(context, file, line)
192
+ ensure
193
+ @last_breakpoint = nil
174
194
  end
175
195
  protect :at_line
176
196
 
177
197
  def at_return(context, file, line)
178
198
  context.stop_frame = -1
199
+ CommandProcessor.print_location_and_text(file, line, context)
179
200
  process_commands(context, file, line)
180
201
  end
181
202
 
@@ -225,30 +246,14 @@ module Debugger
225
246
  def process_commands(context, file, line)
226
247
  state, commands = always_run(context, file, line, 1)
227
248
  $rdebug_state = state if Command.settings[:debuggertesting]
228
- splitter = lambda do |str|
229
- str.split(/;/).inject([]) do |m, v|
230
- if m.empty?
231
- m << v
232
- else
233
- if m.last[-1] == ?\\
234
- m.last[-1,1] = ''
235
- m.last << ';' << v
236
- else
237
- m << v
238
- end
239
- end
240
- m
241
- end
242
- end
243
249
 
244
250
  preloop(commands, context)
245
- CommandProcessor.print_location_and_text(file, line)
246
251
  while !state.proceed?
247
252
  input = if @interface.command_queue.empty?
248
- @interface.read_command(prompt(context))
249
- else
250
- @interface.command_queue.shift
251
- end
253
+ @interface.read_command(prompt(context))
254
+ else
255
+ @interface.command_queue.shift
256
+ end
252
257
  break unless input
253
258
  catch(:debug_error) do
254
259
  if input == ""
@@ -257,7 +262,7 @@ module Debugger
257
262
  else
258
263
  @last_cmd = input
259
264
  end
260
- splitter[input].each do |cmd|
265
+ split_commands(input).each do |cmd|
261
266
  one_cmd(commands, context, cmd)
262
267
  postcmd(commands, context, cmd)
263
268
  end
@@ -375,6 +380,10 @@ module Debugger
375
380
  @interface.print(*args)
376
381
  end
377
382
 
383
+ def print_debug(*args)
384
+ @interface.print_debug(*args)
385
+ end
386
+
378
387
  def confirm(*args)
379
388
  @interface.confirm(*args)
380
389
  end
@@ -40,23 +40,9 @@ describe "Breakpoints" do
40
40
  debug_file("breakpoint1") { Debugger.breakpoints.must_be_empty }
41
41
  end
42
42
 
43
- it "must show an error" do
44
- debug_file("breakpoint1")
45
- check_output_includes "There are only #{LineCache.size(fullpath('breakpoint1'))} lines in file \"breakpoint1.rb\".", interface.error_queue
46
- end
47
- end
48
-
49
-
50
- describe "setting breakpoint to incorrect line" do
51
- before { enter 'break 8' }
52
-
53
- it "must not create a breakpoint" do
54
- debug_file("breakpoint1") { Debugger.breakpoints.must_be_empty }
55
- end
56
-
57
- it "must show an error" do
43
+ it "shows an error" do
58
44
  debug_file("breakpoint1")
59
- check_output_includes 'Line 8 is not a stopping point in file "breakpoint1.rb".', interface.error_queue
45
+ check_output_includes "There are only #{LineCache.size(fullpath('breakpoint1'))} lines in file 'breakpoint1.rb'", interface.error_queue
60
46
  end
61
47
  end
62
48
 
@@ -72,7 +58,7 @@ describe "Breakpoints" do
72
58
  debug_file("breakpoint1") { state.file.must_equal fullpath("breakpoint1") }
73
59
  end
74
60
 
75
- describe "show a message" do
61
+ describe "shows a message" do
76
62
  temporary_change_hash_value(Debugger::Command.settings, :basename, false)
77
63
 
78
64
  it "must show a message with full filename" do
@@ -90,32 +76,6 @@ describe "Breakpoints" do
90
76
  end
91
77
 
92
78
 
93
- describe "reloading source on change" do
94
- temporary_change_hash_value(Debugger::Command.settings, :reload_source_on_change, false)
95
-
96
- it "must not reload source if autoreload is not set" do
97
- enter(
98
- 'set noautoreload',
99
- ->{change_line_in_file(fullpath('breakpoint1'), 14, ''); 'break 14'},
100
- ->{change_line_in_file(fullpath('breakpoint1'), 14, 'c = a + b'); 'cont'}
101
- )
102
- debug_file "breakpoint1"
103
- check_output_includes "Breakpoint 1 at #{fullpath('breakpoint1')}:14"
104
- end
105
-
106
- it "must reload source if autoreload is set" do
107
- enter(
108
- 'set autoreload',
109
- ->{change_line_in_file(fullpath('breakpoint1'), 14, ''); 'break 14'},
110
- # Setting second breakpoint just to reload the source code after rolling the file changes back
111
- ->{change_line_in_file(fullpath('breakpoint1'), 14, 'c = a + b'); 'break 15'}, 'cont'
112
- )
113
- debug_file "breakpoint1"
114
- check_output_includes "Line 14 is not a stopping point in file \"breakpoint1.rb\".", interface.error_queue
115
- end
116
- end
117
-
118
-
119
79
  describe "set breakpoint in a file" do
120
80
  describe "successfully" do
121
81
  before do
@@ -132,10 +92,12 @@ describe "Breakpoints" do
132
92
  end
133
93
 
134
94
  describe "when setting breakpoint to unexisted file" do
95
+
135
96
  before do
136
97
  enter "break asf:324"
137
98
  debug_file("breakpoint1")
138
99
  end
100
+
139
101
  it "must show an error" do
140
102
  check_output_includes "No source file named asf", interface.error_queue
141
103
  end
@@ -160,6 +122,12 @@ describe "Breakpoints" do
160
122
  it "must stop at the correct file" do
161
123
  debug_file("breakpoint1") { state.file.must_equal fullpath("breakpoint1") }
162
124
  end
125
+
126
+ it "must show output in plain text" do
127
+ id = nil
128
+ debug_file("breakpoint1") { id = breakpoint.id }
129
+ check_output_includes "Breakpoint #{id} at A::b"
130
+ end
163
131
  end
164
132
 
165
133
  describe "set breakpoint to a class method" do
@@ -180,7 +148,7 @@ describe "Breakpoints" do
180
148
  it "must show an error" do
181
149
  enter "break B.a"
182
150
  debug_file("breakpoint1")
183
- check_output_includes "Unknown class B.", interface.error_queue
151
+ check_output_includes "Unknown class B", interface.error_queue
184
152
  end
185
153
  end
186
154
  end
@@ -195,7 +163,7 @@ describe "Breakpoints" do
195
163
 
196
164
  it "must show an error" do
197
165
  debug_file("breakpoint1")
198
- check_output_includes 'Invalid breakpoint location: foo.', interface.error_queue
166
+ check_output_includes 'Invalid breakpoint location: foo', interface.error_queue
199
167
  end
200
168
  end
201
169
 
@@ -214,6 +182,12 @@ describe "Breakpoints" do
214
182
  enter "cont"
215
183
  debug_file("breakpoint1") { state.line.must_equal 15 }
216
184
  end
185
+
186
+ it "must show success message" do
187
+ id = nil
188
+ debug_file("breakpoint1") { id = breakpoint.id }
189
+ check_output_includes "Breakpoint #{id} is disabled"
190
+ end
217
191
  end
218
192
 
219
193
  describe "full syntax" do
@@ -229,7 +203,7 @@ describe "Breakpoints" do
229
203
  enter "disable"
230
204
  debug_file("breakpoint1")
231
205
  check_output_includes(
232
- '"disable" must be followed "display", "breakpoints" or breakpoint numbers.',
206
+ "'disable' must be followed 'display', 'breakpoints' or breakpoint numbers",
233
207
  interface.error_queue
234
208
  )
235
209
  end
@@ -237,14 +211,15 @@ describe "Breakpoints" do
237
211
  it "must show an error if no breakpoints is set" do
238
212
  enter "disable 1"
239
213
  debug_file("breakpoint1")
240
- check_output_includes 'No breakpoints have been set.', interface.error_queue
214
+ check_output_includes 'No breakpoints have been set', interface.error_queue
241
215
  end
242
216
 
243
217
  it "must show an error if not a number is provided as an argument to 'disable' command" do
244
218
  enter "break 14", "disable foo"
245
219
  debug_file("breakpoint1")
246
- check_output_includes "Disable breakpoints argument 'foo' needs to be a number."
220
+ check_output_includes "Disable breakpoints argument 'foo' needs to be a number"
247
221
  end
222
+
248
223
  end
249
224
  end
250
225
 
@@ -263,6 +238,12 @@ describe "Breakpoints" do
263
238
  enter "cont"
264
239
  debug_file("breakpoint1") { state.line.must_equal 14 }
265
240
  end
241
+
242
+ it "must show success message" do
243
+ id = nil
244
+ debug_file("breakpoint1") { id = breakpoint.id }
245
+ check_output_includes "Breakpoint #{id} is enabled"
246
+ end
266
247
  end
267
248
 
268
249
  describe "full syntax" do
@@ -279,7 +260,7 @@ describe "Breakpoints" do
279
260
  enter "enable"
280
261
  debug_file("breakpoint1")
281
262
  check_output_includes(
282
- '"enable" must be followed "display", "breakpoints" or breakpoint numbers.',
263
+ "'enable' must be followed 'display', 'breakpoints' or breakpoint numbers",
283
264
  interface.error_queue
284
265
  )
285
266
  end
@@ -288,7 +269,10 @@ describe "Breakpoints" do
288
269
 
289
270
 
290
271
  describe "deleting a breakpoint" do
291
- before { enter "break 14", ->{"delete #{breakpoint.id}"}, "break 15" }
272
+ before do
273
+ @breakpoint_id = nil
274
+ enter "break 14", ->{@breakpoint_id = breakpoint.id; "delete #{@breakpoint_id}"}, "break 15"
275
+ end
292
276
 
293
277
  it "must have only one breakpoint" do
294
278
  debug_file("breakpoint1") { Debugger.breakpoints.size.must_equal 1 }
@@ -298,6 +282,11 @@ describe "Breakpoints" do
298
282
  enter "cont"
299
283
  debug_file("breakpoint1") { state.line.must_equal 15 }
300
284
  end
285
+
286
+ it "must show a success message" do
287
+ debug_file("breakpoint1")
288
+ check_output_includes "Breakpoint #{@breakpoint_id} has been deleted"
289
+ end
301
290
  end
302
291
 
303
292
 
@@ -315,7 +304,7 @@ describe "Breakpoints" do
315
304
  it "must show an error when conditional syntax is wrong" do
316
305
  enter "break 14 ifa b == 3", "break 15", "cont"
317
306
  debug_file("breakpoint1") { state.line.must_equal 15 }
318
- check_output_includes "Expecting 'if' in breakpoint condition; got: ifa b == 3.", interface.error_queue
307
+ check_output_includes "Expecting 'if' in breakpoint condition; got: ifa b == 3", interface.error_queue
319
308
  end
320
309
 
321
310
  describe "enabling with wrong conditional syntax" do
@@ -335,7 +324,7 @@ describe "Breakpoints" do
335
324
  it "must show an error" do
336
325
  debug_file("breakpoint1")
337
326
  check_output_includes(
338
- 'Expression "b -=( 3" syntactically incorrect; breakpoint remains disabled.',
327
+ "Expression 'b -=( 3' syntactically incorrect; breakpoint remains disabled",
339
328
  interface.error_queue
340
329
  )
341
330
  end
@@ -344,13 +333,13 @@ describe "Breakpoints" do
344
333
  it "must show an error if no file or line is specified" do
345
334
  enter "break ifa b == 3", "break 15", "cont"
346
335
  debug_file("breakpoint1") { state.line.must_equal 15 }
347
- check_output_includes "Invalid breakpoint location: ifa b == 3.", interface.error_queue
336
+ check_output_includes "Invalid breakpoint location: ifa b == 3", interface.error_queue
348
337
  end
349
338
 
350
339
  it "must show an error if expression syntax is invalid" do
351
340
  enter "break if b -=) 3", "break 15", "cont"
352
341
  debug_file("breakpoint1") { state.line.must_equal 15 }
353
- check_output_includes 'Expression "b -=) 3" syntactically incorrect; breakpoint disabled.', interface.error_queue
342
+ check_output_includes "Expression 'b -=) 3' syntactically incorrect; breakpoint disabled", interface.error_queue
354
343
  end
355
344
  end
356
345