tui-td 0.2.9 → 0.2.11
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +16 -1
- data/lib/tui_td/ansi_parser.rb +139 -131
- data/lib/tui_td/ansi_utils.rb +22 -20
- data/lib/tui_td/cairo_renderer.rb +5 -2
- data/lib/tui_td/cli.rb +12 -10
- data/lib/tui_td/driver.rb +43 -12
- data/lib/tui_td/html_renderer.rb +19 -17
- data/lib/tui_td/matchers.rb +21 -12
- data/lib/tui_td/mcp/server.rb +146 -76
- data/lib/tui_td/screenshot.rb +70 -52
- data/lib/tui_td/state.rb +11 -4
- data/lib/tui_td/test_runner.rb +25 -25
- data/lib/tui_td/unifont_glyphs.rb +2142 -2141
- data/lib/tui_td/version.rb +1 -1
- data/lib/tui_td.rb +7 -3
- metadata +40 -11
data/lib/tui_td/screenshot.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/BlockNesting, Metrics/ParameterLists, Metrics/ClassLength, Metrics/CollectionLiteralLength
|
|
4
|
+
|
|
3
5
|
require "chunky_png"
|
|
4
6
|
require_relative "ansi_utils"
|
|
5
7
|
require_relative "cairo_renderer"
|
|
@@ -200,7 +202,7 @@ module TUITD
|
|
|
200
202
|
"╧" => [true, false, true, true, :double],
|
|
201
203
|
"╨" => [true, false, true, true, :double],
|
|
202
204
|
"╪" => [true, true, true, true, :double],
|
|
203
|
-
"╫" => [true, true, true, true, :double]
|
|
205
|
+
"╫" => [true, true, true, true, :double],
|
|
204
206
|
}.freeze
|
|
205
207
|
|
|
206
208
|
private_constant :FONT
|
|
@@ -219,8 +221,10 @@ module TUITD
|
|
|
219
221
|
|
|
220
222
|
@grid.each_with_index do |row, ri|
|
|
221
223
|
next unless row
|
|
224
|
+
|
|
222
225
|
row.each_with_index do |cell, ci|
|
|
223
226
|
next unless cell
|
|
227
|
+
|
|
224
228
|
render_cell(image, ri, ci, cell)
|
|
225
229
|
end
|
|
226
230
|
end
|
|
@@ -256,15 +260,15 @@ module TUITD
|
|
|
256
260
|
end
|
|
257
261
|
|
|
258
262
|
char_ord = char.ord
|
|
259
|
-
if char_ord ==
|
|
263
|
+
if char_ord == 10_095 # '❯'
|
|
260
264
|
draw_chevron(image, px, py, fg_rgb)
|
|
261
265
|
draw_underline(image, px, py, CELL_W, fg_rgb) if underline
|
|
262
266
|
return
|
|
263
|
-
elsif
|
|
267
|
+
elsif [9210, 9679].include?(char_ord) # '⏺' or '●'
|
|
264
268
|
draw_circle(image, px, py, fg_rgb)
|
|
265
269
|
draw_underline(image, px, py, CELL_W, fg_rgb) if underline
|
|
266
270
|
return
|
|
267
|
-
elsif char_ord
|
|
271
|
+
elsif char_ord.between?(0x2800, 0x28ff) # Braille spinner
|
|
268
272
|
draw_braille(image, px, py, char, fg_rgb)
|
|
269
273
|
draw_underline(image, px, py, CELL_W, fg_rgb) if underline
|
|
270
274
|
return
|
|
@@ -399,7 +403,7 @@ module TUITD
|
|
|
399
403
|
|
|
400
404
|
def glyph_rows(char)
|
|
401
405
|
idx = (char.ord - 32) * 16
|
|
402
|
-
return nil if idx
|
|
406
|
+
return nil if idx.negative? || idx + 15 >= FONT.length
|
|
403
407
|
|
|
404
408
|
FONT[idx, 16]
|
|
405
409
|
end
|
|
@@ -408,7 +412,7 @@ module TUITD
|
|
|
408
412
|
color = ChunkyPNG::Color.rgb(*fg_rgb)
|
|
409
413
|
|
|
410
414
|
rows.each_with_index do |byte, dy|
|
|
411
|
-
next if byte
|
|
415
|
+
next if byte.zero?
|
|
412
416
|
|
|
413
417
|
slant = italic ? dy / 8 : 0
|
|
414
418
|
|
|
@@ -429,7 +433,7 @@ module TUITD
|
|
|
429
433
|
|
|
430
434
|
def box_drawing?(char)
|
|
431
435
|
char_ord = char.ord
|
|
432
|
-
char_ord
|
|
436
|
+
char_ord.between?(0x2500, 0x257F)
|
|
433
437
|
end
|
|
434
438
|
|
|
435
439
|
def draw_box_character(image, px, py, char, fg_rgb)
|
|
@@ -438,10 +442,18 @@ module TUITD
|
|
|
438
442
|
unless config
|
|
439
443
|
char_ord = char.ord
|
|
440
444
|
if [0x2500, 0x2501, 0x2504, 0x2505, 0x2508, 0x2509, 0x254c, 0x254d, 0x2550].include?(char_ord)
|
|
441
|
-
style = [0x2501, 0x2505, 0x2509, 0x254d].include?(char_ord)
|
|
445
|
+
style = if [0x2501, 0x2505, 0x2509, 0x254d].include?(char_ord)
|
|
446
|
+
:heavy
|
|
447
|
+
else
|
|
448
|
+
(char_ord == 0x2550 ? :double : :light)
|
|
449
|
+
end
|
|
442
450
|
config = [false, false, true, true, style]
|
|
443
451
|
elsif [0x2502, 0x2503, 0x2506, 0x2507, 0x250a, 0x250b, 0x254e, 0x254f, 0x2551].include?(char_ord)
|
|
444
|
-
style = [0x2503, 0x2507, 0x250b, 0x254f].include?(char_ord)
|
|
452
|
+
style = if [0x2503, 0x2507, 0x250b, 0x254f].include?(char_ord)
|
|
453
|
+
:heavy
|
|
454
|
+
else
|
|
455
|
+
(char_ord == 0x2551 ? :double : :light)
|
|
456
|
+
end
|
|
445
457
|
config = [true, true, false, false, style]
|
|
446
458
|
else
|
|
447
459
|
config = [true, true, true, true, :light]
|
|
@@ -454,24 +466,31 @@ module TUITD
|
|
|
454
466
|
|
|
455
467
|
color = ChunkyPNG::Color.rgb(*fg_rgb)
|
|
456
468
|
|
|
457
|
-
|
|
469
|
+
case style
|
|
470
|
+
when :double
|
|
458
471
|
if left
|
|
459
|
-
(px..(cx + 2)).each
|
|
460
|
-
|
|
472
|
+
(px..(cx + 2)).each do |x|
|
|
473
|
+
image[x, py + 6] = color
|
|
474
|
+
image[x, py + 10] = color
|
|
475
|
+
end
|
|
461
476
|
end
|
|
462
477
|
if right
|
|
463
478
|
((cx - 2)..(px + 7)).each { |x| image[x, py + 6] = color }
|
|
464
479
|
((cx - 2)..(px + 10)).each { |x| image[x, py + 10] = color }
|
|
465
480
|
end
|
|
466
481
|
if up
|
|
467
|
-
(py..(cy + 2)).each
|
|
468
|
-
|
|
482
|
+
(py..(cy + 2)).each do |y|
|
|
483
|
+
image[px + 2, y] = color
|
|
484
|
+
image[px + 6, y] = color
|
|
485
|
+
end
|
|
469
486
|
end
|
|
470
487
|
if down
|
|
471
|
-
((cy - 2)..(py + 15)).each
|
|
472
|
-
|
|
488
|
+
((cy - 2)..(py + 15)).each do |y|
|
|
489
|
+
image[px + 2, y] = color
|
|
490
|
+
image[px + 6, y] = color
|
|
491
|
+
end
|
|
473
492
|
end
|
|
474
|
-
|
|
493
|
+
when :heavy
|
|
475
494
|
if left
|
|
476
495
|
(px..cx).each do |x|
|
|
477
496
|
image[x, cy - 1] = color
|
|
@@ -500,42 +519,34 @@ module TUITD
|
|
|
500
519
|
image[cx + 1, y] = color
|
|
501
520
|
end
|
|
502
521
|
end
|
|
503
|
-
|
|
522
|
+
when :light_rounded
|
|
504
523
|
case char
|
|
505
524
|
when "╭"
|
|
506
|
-
(px + 5..px + 7).each { |x| image[x, py + 8] = color }
|
|
507
|
-
(py + 10..py + 15).each { |y| image[px + 4, y] = color }
|
|
525
|
+
((px + 5)..(px + 7)).each { |x| image[x, py + 8] = color }
|
|
526
|
+
((py + 10)..(py + 15)).each { |y| image[px + 4, y] = color }
|
|
508
527
|
image[px + 4, py + 9] = color
|
|
509
528
|
image[px + 5, py + 9] = color
|
|
510
529
|
when "╮"
|
|
511
|
-
(px..px + 3).each { |x| image[x, py + 8] = color }
|
|
512
|
-
(py + 10..py + 15).each { |y| image[px + 4, y] = color }
|
|
530
|
+
(px..(px + 3)).each { |x| image[x, py + 8] = color }
|
|
531
|
+
((py + 10)..(py + 15)).each { |y| image[px + 4, y] = color }
|
|
513
532
|
image[px + 4, py + 9] = color
|
|
514
533
|
image[px + 3, py + 9] = color
|
|
515
534
|
when "╯"
|
|
516
|
-
(px..px + 3).each { |x| image[x, py + 8] = color }
|
|
517
|
-
(py..py + 6).each { |y| image[px + 4, y] = color }
|
|
535
|
+
(px..(px + 3)).each { |x| image[x, py + 8] = color }
|
|
536
|
+
(py..(py + 6)).each { |y| image[px + 4, y] = color }
|
|
518
537
|
image[px + 4, py + 7] = color
|
|
519
538
|
image[px + 3, py + 7] = color
|
|
520
539
|
when "╰"
|
|
521
|
-
(px + 5..px + 7).each { |x| image[x, py + 8] = color }
|
|
522
|
-
(py..py + 6).each { |y| image[px + 4, y] = color }
|
|
540
|
+
((px + 5)..(px + 7)).each { |x| image[x, py + 8] = color }
|
|
541
|
+
(py..(py + 6)).each { |y| image[px + 4, y] = color }
|
|
523
542
|
image[px + 4, py + 7] = color
|
|
524
543
|
image[px + 5, py + 7] = color
|
|
525
544
|
end
|
|
526
545
|
else # :light
|
|
527
|
-
if left
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
if
|
|
531
|
-
(cx..(px + 7)).each { |x| image[x, cy] = color }
|
|
532
|
-
end
|
|
533
|
-
if up
|
|
534
|
-
(py..cy).each { |y| image[cx, y] = color }
|
|
535
|
-
end
|
|
536
|
-
if down
|
|
537
|
-
(cy..(py + 15)).each { |y| image[cx, y] = color }
|
|
538
|
-
end
|
|
546
|
+
(px..cx).each { |x| image[x, cy] = color } if left
|
|
547
|
+
(cx..(px + 7)).each { |x| image[x, cy] = color } if right
|
|
548
|
+
(py..cy).each { |y| image[cx, y] = color } if up
|
|
549
|
+
(cy..(py + 15)).each { |y| image[cx, y] = color } if down
|
|
539
550
|
end
|
|
540
551
|
end
|
|
541
552
|
|
|
@@ -551,7 +562,7 @@ module TUITD
|
|
|
551
562
|
ri = cursor_info[:row] || cursor_info["row"] || 0
|
|
552
563
|
ci = cursor_info[:col] || cursor_info["col"] || 0
|
|
553
564
|
|
|
554
|
-
return if ri
|
|
565
|
+
return if ri.negative? || ri >= @rows || ci.negative? || ci >= @cols
|
|
555
566
|
|
|
556
567
|
style_val = @state[:cursor_style] || cursor_info[:style] || cursor_info["style"] || 1
|
|
557
568
|
|
|
@@ -568,6 +579,7 @@ module TUITD
|
|
|
568
579
|
x = px + dx
|
|
569
580
|
y = py + dy
|
|
570
581
|
next if x >= image.width || y >= image.height
|
|
582
|
+
|
|
571
583
|
original_color = image[x, y]
|
|
572
584
|
r = 255 - ChunkyPNG::Color.r(original_color)
|
|
573
585
|
g = 255 - ChunkyPNG::Color.g(original_color)
|
|
@@ -579,9 +591,11 @@ module TUITD
|
|
|
579
591
|
2.times do |h_offset|
|
|
580
592
|
y = py + CELL_H - 1 - h_offset
|
|
581
593
|
next if y >= image.height
|
|
594
|
+
|
|
582
595
|
CELL_W.times do |dx|
|
|
583
596
|
x = px + dx
|
|
584
597
|
next if x >= image.width
|
|
598
|
+
|
|
585
599
|
image[x, y] = color
|
|
586
600
|
end
|
|
587
601
|
end
|
|
@@ -589,9 +603,11 @@ module TUITD
|
|
|
589
603
|
2.times do |w_offset|
|
|
590
604
|
x = px + w_offset
|
|
591
605
|
next if x >= image.width
|
|
606
|
+
|
|
592
607
|
CELL_H.times do |dy|
|
|
593
608
|
y = py + dy
|
|
594
609
|
next if y >= image.height
|
|
610
|
+
|
|
595
611
|
image[x, y] = color
|
|
596
612
|
end
|
|
597
613
|
end
|
|
@@ -603,7 +619,7 @@ module TUITD
|
|
|
603
619
|
(0..3).each do |i|
|
|
604
620
|
image[px + 2 + i, py + 4 + i] = color
|
|
605
621
|
image[px + 3 + i, py + 4 + i] = color # bold/thick chevron
|
|
606
|
-
|
|
622
|
+
|
|
607
623
|
image[px + 5 - i, py + 8 + i] = color
|
|
608
624
|
image[px + 6 - i, py + 8 + i] = color # bold/thick chevron
|
|
609
625
|
end
|
|
@@ -623,6 +639,7 @@ module TUITD
|
|
|
623
639
|
x = cx + dx
|
|
624
640
|
y = cy + dy
|
|
625
641
|
next if x < px || x >= px + CELL_W || y < py || y >= py + CELL_H
|
|
642
|
+
|
|
626
643
|
image[x, y] = color
|
|
627
644
|
end
|
|
628
645
|
end
|
|
@@ -639,17 +656,18 @@ module TUITD
|
|
|
639
656
|
[5, 6], # Dot 5
|
|
640
657
|
[5, 9], # Dot 6
|
|
641
658
|
[2, 12], # Dot 7
|
|
642
|
-
[5, 12]
|
|
659
|
+
[5, 12], # Dot 8
|
|
643
660
|
]
|
|
644
661
|
dot_coords.each_with_index do |(dx, dy), idx|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
662
|
+
next unless mask.anybits?(1 << idx)
|
|
663
|
+
|
|
664
|
+
2.times do |ddy|
|
|
665
|
+
2.times do |ddx|
|
|
666
|
+
x = px + dx + ddx
|
|
667
|
+
y = py + dy + ddy
|
|
668
|
+
next if x >= image.width || y >= image.height
|
|
669
|
+
|
|
670
|
+
image[x, y] = color
|
|
653
671
|
end
|
|
654
672
|
end
|
|
655
673
|
end
|
|
@@ -659,7 +677,7 @@ module TUITD
|
|
|
659
677
|
color = ChunkyPNG::Color.rgb(*fg_rgb)
|
|
660
678
|
(5..8).each do |dy|
|
|
661
679
|
width = dy - 5
|
|
662
|
-
(4 - width..4 + width).each do |dx|
|
|
680
|
+
((4 - width)..(4 + width)).each do |dx|
|
|
663
681
|
image[px + dx, py + dy] = color
|
|
664
682
|
end
|
|
665
683
|
end
|
|
@@ -669,7 +687,7 @@ module TUITD
|
|
|
669
687
|
color = ChunkyPNG::Color.rgb(*fg_rgb)
|
|
670
688
|
(5..8).each do |dy|
|
|
671
689
|
width = 8 - dy
|
|
672
|
-
(4 - width..4 + width).each do |dx|
|
|
690
|
+
((4 - width)..(4 + width)).each do |dx|
|
|
673
691
|
image[px + dx, py + dy] = color
|
|
674
692
|
end
|
|
675
693
|
end
|
|
@@ -874,6 +892,6 @@ module TUITD
|
|
|
874
892
|
image[px + 3, py + 8] = color
|
|
875
893
|
image[px + 4, py + 8] = color
|
|
876
894
|
end
|
|
877
|
-
|
|
878
895
|
end
|
|
879
896
|
end
|
|
897
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/BlockNesting, Metrics/ParameterLists, Metrics/ClassLength, Metrics/CollectionLiteralLength
|
data/lib/tui_td/state.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
|
4
|
+
|
|
3
5
|
module TUITD
|
|
4
6
|
# Represents the parsed state of a terminal screen.
|
|
5
7
|
# Provides high-level query methods for AI consumption.
|
|
@@ -31,6 +33,7 @@ module TUITD
|
|
|
31
33
|
# Get text at a specific position
|
|
32
34
|
def text_at(row, col, length = @cols - col)
|
|
33
35
|
return "" if row >= @rows || col >= @cols
|
|
36
|
+
|
|
34
37
|
@grid[row][col, length].map { |c| c[:char] }.join
|
|
35
38
|
end
|
|
36
39
|
|
|
@@ -51,16 +54,19 @@ module TUITD
|
|
|
51
54
|
# Get the color at a specific cell
|
|
52
55
|
def foreground_at(row, col)
|
|
53
56
|
return nil if row >= @rows || col >= @cols
|
|
57
|
+
|
|
54
58
|
@grid[row][col][:fg]
|
|
55
59
|
end
|
|
56
60
|
|
|
57
61
|
def background_at(row, col)
|
|
58
62
|
return nil if row >= @rows || col >= @cols
|
|
63
|
+
|
|
59
64
|
@grid[row][col][:bg]
|
|
60
65
|
end
|
|
61
66
|
|
|
62
67
|
def style_at(row, col)
|
|
63
68
|
return nil if row >= @rows || col >= @cols
|
|
69
|
+
|
|
64
70
|
cell = @grid[row][col]
|
|
65
71
|
{ bold: cell[:bold], italic: cell[:italic], underline: cell[:underline] }
|
|
66
72
|
end
|
|
@@ -72,12 +78,12 @@ module TUITD
|
|
|
72
78
|
c = cursor_info[:col] || cursor_info["col"] || 0
|
|
73
79
|
styled_count = h.count { |hl| hl[:bold] || hl[:italic] || hl[:underline] || hl[:fg] || hl[:bg] }
|
|
74
80
|
|
|
75
|
-
summary =
|
|
76
|
-
summary << "#{styled_count} styled row#{styled_count == 1
|
|
81
|
+
summary = "Cursor at [#{r},#{c}]. "
|
|
82
|
+
summary << "#{styled_count} styled row#{"s" unless styled_count == 1}"
|
|
77
83
|
fgs = h.flat_map { |hl| hl[:fg] }.compact.uniq
|
|
78
84
|
bgs = h.flat_map { |hl| hl[:bg] }.compact.uniq
|
|
79
|
-
summary << ", colors: fg=#{fgs.sort.join(
|
|
80
|
-
summary << ", bg=#{bgs.sort.join(
|
|
85
|
+
summary << ", colors: fg=#{fgs.sort.join(",")}" unless fgs.empty?
|
|
86
|
+
summary << ", bg=#{bgs.sort.join(",")}" unless bgs.empty?
|
|
81
87
|
summary << "."
|
|
82
88
|
|
|
83
89
|
{
|
|
@@ -119,3 +125,4 @@ module TUITD
|
|
|
119
125
|
end
|
|
120
126
|
end
|
|
121
127
|
end
|
|
128
|
+
# rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
data/lib/tui_td/test_runner.rb
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/BlockLength
|
|
4
|
+
|
|
3
5
|
require "json"
|
|
4
6
|
|
|
5
7
|
module TUITD
|
|
@@ -39,10 +41,6 @@ module TUITD
|
|
|
39
41
|
@on_step = on_step
|
|
40
42
|
rescue JSON::ParserError => e
|
|
41
43
|
raise Error, "Invalid JSON: #{e.message}"
|
|
42
|
-
@plan[:steps] = @plan[:steps].map { |s| s.transform_keys(&:to_sym) }
|
|
43
|
-
@plan[:before_all] = @plan[:before_all]&.map { |s| s.transform_keys(&:to_sym) }
|
|
44
|
-
@plan[:after_all] = @plan[:after_all]&.map { |s| s.transform_keys(&:to_sym) }
|
|
45
|
-
@on_step = on_step
|
|
46
44
|
end
|
|
47
45
|
|
|
48
46
|
def run
|
|
@@ -55,7 +53,7 @@ module TUITD
|
|
|
55
53
|
hooks = [
|
|
56
54
|
{ label: :before_all, steps: @plan[:before_all] || [] },
|
|
57
55
|
{ label: :main, steps: @plan[:steps] },
|
|
58
|
-
{ label: :after_all, steps: @plan[:after_all] || [] }
|
|
56
|
+
{ label: :after_all, steps: @plan[:after_all] || [] },
|
|
59
57
|
]
|
|
60
58
|
|
|
61
59
|
all_results = []
|
|
@@ -120,7 +118,8 @@ module TUITD
|
|
|
120
118
|
if match
|
|
121
119
|
Result.new(step: action, passed: true, message: "Style at [#{row},#{col}] matches #{expected}")
|
|
122
120
|
else
|
|
123
|
-
Result.new(step: action, passed: false,
|
|
121
|
+
Result.new(step: action, passed: false,
|
|
122
|
+
message: "Style at [#{row},#{col}] is #{actual}, expected #{expected}",)
|
|
124
123
|
end
|
|
125
124
|
|
|
126
125
|
when "screenshot"
|
|
@@ -159,7 +158,6 @@ module TUITD
|
|
|
159
158
|
else
|
|
160
159
|
Result.new(step: action, passed: false, message: "Unknown action: #{action}")
|
|
161
160
|
end
|
|
162
|
-
|
|
163
161
|
rescue StandardError => e
|
|
164
162
|
r = Result.new(step: action, passed: false, message: "#{e.class}: #{e.message}")
|
|
165
163
|
end
|
|
@@ -167,23 +165,23 @@ module TUITD
|
|
|
167
165
|
all_results << r
|
|
168
166
|
all_passed &&= r.passed
|
|
169
167
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
@on_step.call(
|
|
178
|
-
index: all_results.size - 1,
|
|
179
|
-
total: total_steps,
|
|
180
|
-
action: action,
|
|
181
|
-
value: value,
|
|
182
|
-
result: r,
|
|
183
|
-
driver: driver,
|
|
184
|
-
state_data: state_data
|
|
185
|
-
)
|
|
168
|
+
next unless @on_step
|
|
169
|
+
|
|
170
|
+
state_data = nil
|
|
171
|
+
begin
|
|
172
|
+
state_data = driver.state_data if driver
|
|
173
|
+
rescue StandardError
|
|
174
|
+
# ignore — state retrieval is best-effort
|
|
186
175
|
end
|
|
176
|
+
@on_step.call(
|
|
177
|
+
index: all_results.size - 1,
|
|
178
|
+
total: total_steps,
|
|
179
|
+
action: action,
|
|
180
|
+
value: value,
|
|
181
|
+
result: r,
|
|
182
|
+
driver: driver,
|
|
183
|
+
state_data: state_data,
|
|
184
|
+
)
|
|
187
185
|
end
|
|
188
186
|
end
|
|
189
187
|
|
|
@@ -192,7 +190,7 @@ module TUITD
|
|
|
192
190
|
{
|
|
193
191
|
name: @plan[:name] || "(unnamed)",
|
|
194
192
|
passed: all_passed,
|
|
195
|
-
results: all_results.map(&:to_h)
|
|
193
|
+
results: all_results.map(&:to_h),
|
|
196
194
|
}
|
|
197
195
|
end
|
|
198
196
|
|
|
@@ -261,8 +259,10 @@ module TUITD
|
|
|
261
259
|
if actual == expected
|
|
262
260
|
Result.new(step: step.keys.first.to_s, passed: true, message: "#{label} at [#{row},#{col}] is #{expected}")
|
|
263
261
|
else
|
|
264
|
-
Result.new(step: step.keys.first.to_s, passed: false,
|
|
262
|
+
Result.new(step: step.keys.first.to_s, passed: false,
|
|
263
|
+
message: "#{label} at [#{row},#{col}] is #{actual}, expected #{expected}",)
|
|
265
264
|
end
|
|
266
265
|
end
|
|
267
266
|
end
|
|
268
267
|
end
|
|
268
|
+
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity, Metrics/BlockLength
|