@@ -65,6 +65,18 @@ def render(implicit_locals: [], **locals)
65
65
@template . render ( @context , locals , implicit_locals : implicit_locals )
66
66
end
67
67
68
+ def spot_highlight ( compiled , highlight , first_column : nil , **options )
69
+ # rindex by default since our tests usually put the highlight last
70
+ first_column ||= compiled . rindex ( highlight ) || 999
71
+ last_column = first_column + highlight . size
72
+ spot = {
73
+ first_column :, last_column :, snippet : compiled ,
74
+ first_lineno : 1 , last_lineno : 1 , script_lines : compiled . lines ,
75
+ }
76
+ spot . merge! ( options )
77
+ spot
78
+ end
79
+
68
80
def setup
69
81
@context = Context . with_empty_template_cache . empty
70
82
super
@@ -314,4 +326,111 @@ def test_template_inspect
314
326
@template = new_template ( "hello" )
315
327
assert_equal "#<ActionView::Template hello template locals=[]>" , @template . inspect
316
328
end
329
+
330
+ def test_template_translate_location
331
+ highlight = "nomethoderror"
332
+ source = "<%= nomethoderror %>"
333
+ compiled = "'.freeze; @output_buffer.append= nomethoderror ; @output_buffer.safe_append='\n "
334
+
335
+ backtrace_location = Data . define ( :lineno ) . new ( lineno : 1 )
336
+ spot = spot_highlight ( compiled , highlight )
337
+ expected = spot_highlight ( source , highlight , snippet : compiled )
338
+
339
+ assert_equal expected , new_template ( source ) . translate_location ( backtrace_location , spot )
340
+ end
341
+
342
+ def test_template_translate_location_lineno_offset
343
+ highlight = "nomethoderror"
344
+ source = "<%= nomethoderror %>"
345
+ compiled = "\n '.freeze; @output_buffer.append= nomethoderror ; @output_buffer.safe_append='\n "
346
+
347
+ backtrace_location = Data . define ( :lineno ) . new ( lineno : 1 )
348
+ spot = spot_highlight ( compiled , highlight , first_lineno : 2 , last_lineno : 2 )
349
+ expected = spot_highlight ( source , highlight , snippet : compiled )
350
+
351
+ assert_equal expected , new_template ( source ) . translate_location ( backtrace_location , spot )
352
+ end
353
+
354
+ def test_template_translate_location_with_multibye_string_before_highlight
355
+ highlight = "nomethoderror"
356
+ source = String . new ( "\u{a5} <%= nomethoderror %>" , encoding : Encoding ::UTF_8 ) # yen symbol
357
+ compiled = String . new ( "\u{a5} '.freeze; @output_buffer.append= nomethoderror ; @output_buffer.safe_append='\n " , encoding : Encoding ::UTF_8 )
358
+
359
+ backtrace_location = Data . define ( :lineno ) . new ( lineno : 1 )
360
+ spot = spot_highlight ( compiled , highlight )
361
+ expected = spot_highlight ( source , highlight , snippet : compiled )
362
+
363
+ assert_equal expected , new_template ( source ) . translate_location ( backtrace_location , spot )
364
+ end
365
+
366
+ def test_template_translate_location_no_match_in_compiled
367
+ highlight = "nomatch"
368
+ source = "<%= nomatch %>"
369
+ compiled = "this source does not contain the highlight, so the original spot is returned"
370
+
371
+ backtrace_location = Data . define ( :lineno ) . new ( lineno : 1 )
372
+ spot = spot_highlight ( compiled , highlight , first_column : 50 )
373
+
374
+ assert_equal spot , new_template ( source ) . translate_location ( backtrace_location , spot )
375
+ end
376
+
377
+ def test_template_translate_location_text_includes_highlight
378
+ highlight = "nomethoderror"
379
+ source = " nomethoderror <%= nomethoderror %>"
380
+ compiled = " nomethoderror '.freeze; @output_buffer.append= nomethoderror ; @output_buffer.safe_append='\n "
381
+
382
+ backtrace_location = Data . define ( :lineno ) . new ( lineno : 1 )
383
+ spot = spot_highlight ( compiled , highlight )
384
+ expected = spot_highlight ( source , highlight , snippet : compiled )
385
+
386
+ assert_equal expected , new_template ( source ) . translate_location ( backtrace_location , spot )
387
+ end
388
+
389
+ def test_template_translate_location_space_separated_erb_tags
390
+ highlight = "nomethoderror"
391
+ source = "<%= goodcode %> <%= nomethoderror %>"
392
+ compiled = "'.freeze; @output_buffer.append= goodcode ; @output_buffer.safe_append=' '.freeze; @output_buffer.append= nomethoderror ; @output_buffer.safe_append='\n "
393
+
394
+ backtrace_location = Data . define ( :lineno ) . new ( lineno : 1 )
395
+ spot = spot_highlight ( compiled , highlight )
396
+ expected = spot_highlight ( source , highlight , snippet : compiled )
397
+
398
+ assert_equal expected , new_template ( source ) . translate_location ( backtrace_location , spot )
399
+ end
400
+
401
+ def test_template_translate_location_consecutive_erb_tags
402
+ highlight = "nomethoderror"
403
+ source = "<%= goodcode %><%= nomethoderror %>"
404
+ compiled = "'.freeze; @output_buffer.append= goodcode ; @output_buffer.append= nomethoderror ; @output_buffer.safe_append='\n "
405
+
406
+ backtrace_location = Data . define ( :lineno ) . new ( lineno : 1 )
407
+ spot = spot_highlight ( compiled , highlight )
408
+ expected = spot_highlight ( source , highlight , snippet : compiled )
409
+
410
+ assert_equal expected , new_template ( source ) . translate_location ( backtrace_location , spot )
411
+ end
412
+
413
+ def test_template_translate_location_repeated_highlight_in_compiled_template
414
+ highlight = "nomethoderror"
415
+ source = "<%= nomethoderror %>"
416
+ compiled = "ValidatedOutputBuffer.wrap(@output_buffer, ({}), ' nomethoderror '.freeze, true).safe_none_append= nomethoderror ; @output_buffer.safe_append='\n "
417
+
418
+ backtrace_location = Data . define ( :lineno ) . new ( lineno : 1 )
419
+ spot = spot_highlight ( compiled , highlight )
420
+ expected = spot_highlight ( source , highlight , snippet : compiled )
421
+
422
+ assert_equal expected , new_template ( source ) . translate_location ( backtrace_location , spot )
423
+ end
424
+
425
+ def test_template_translate_location_flaky_pathological_template
426
+ highlight = "flakymethod"
427
+ source = "<%= flakymethod %> flakymethod <%= flakymethod " # fails on second call, no tailing %>
428
+ compiled = "ValidatedOutputBuffer.wrap(@output_buffer, ({}), ' flakymethod '.freeze, true).safe_none_append=( flakymethod );@output_buffer.safe_append=' flakymethod '.freeze;ValidatedOutputBuffer.wrap(@output_buffer, ({}), ' flakymethod '.freeze, true).safe_none_append=( flakymethod "
429
+
430
+ backtrace_location = Data . define ( :lineno ) . new ( lineno : 1 )
431
+ spot = spot_highlight ( compiled , highlight )
432
+ expected = spot_highlight ( source , highlight , snippet : compiled )
433
+
434
+ assert_equal expected , new_template ( source ) . translate_location ( backtrace_location , spot )
435
+ end
317
436
end
0 commit comments