https://github.com/akkartik/mu/blob/main/baremetal/504test-screen.mu
  1 # Some primitives for checking the state of fake screen objects.
  2 
  3 # validate data on screen regardless of attributes (color, bold, etc.)
  4 # Mu doesn't have multi-line strings, so we provide functions for rows or portions of rows.
  5 # Tab characters (that translate into multiple screen cells) not supported.
  6 
  7 fn check-screen-row screen: (addr screen), y: int, expected: (addr array byte), msg: (addr array byte) {
  8   check-screen-row-from screen, y, 0, expected, msg
  9 }
 10 
 11 fn check-screen-row-from screen-on-stack: (addr screen), x: int, y: int, expected: (addr array byte), msg: (addr array byte) {
 12   var screen/esi: (addr screen) <- copy screen-on-stack
 13   var idx/ecx: int <- screen-cell-index screen, y, x
 14   # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme
 15   var e: (stream byte 0x100)
 16   var e-addr/edx: (addr stream byte) <- address e
 17   write e-addr, expected
 18   {
 19     var done?/eax: boolean <- stream-empty? e-addr
 20     compare done?, 0
 21     break-if-!=
 22     var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx
 23     var g/ebx: grapheme <- copy _g
 24     var expected-grapheme/eax: grapheme <- read-grapheme e-addr
 25     # compare graphemes
 26     $check-screen-row-from:compare-graphemes: {
 27       # if expected-grapheme is space, null grapheme is also ok
 28       {
 29         compare expected-grapheme, 0x20
 30         break-if-!=
 31         compare g, 0
 32         break-if-= $check-screen-row-from:compare-graphemes
 33       }
 34       # if (g == expected-grapheme) print "."
 35       compare g, expected-grapheme
 36       {
 37         break-if-!=
 38         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, ".", 3  # 3=cyan
 39         break $check-screen-row-from:compare-graphemes
 40       }
 41       # otherwise print an error
 42       count-test-failure
 43       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, msg, 3  # 3=cyan
 44       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, ": expected '", 3
 45       draw-grapheme-at-cursor 0, expected-grapheme, 3
 46       move-cursor-rightward-and-downward 0, 0, 0x80  # screen-width
 47       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, "' at (", 3
 48       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0, x, 3
 49       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, ", ", 3
 50       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0, y, 3
 51       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, ") but observed '", 3
 52       draw-grapheme-at-cursor 0, g, 3
 53       move-cursor-rightward-and-downward 0, 0, 0x80  # screen-width
 54       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, "'", 3
 55     }
 56     idx <- increment
 57     increment x
 58     loop
 59   }
 60 }
 61 
 62 # various variants by screen-cell attribute; spaces in the 'expected' data should not match the attribute
 63 
 64 fn check-screen-row-in-color screen: (addr screen), fg: int, y: int, expected: (addr array byte), msg: (addr array byte) {
 65   check-screen-row-in-color-from screen, fg, y, 0, expected, msg
 66 }
 67 
 68 fn check-screen-row-in-color-from screen-on-stack: (addr screen), fg: int, y: int, x: int, expected: (addr array byte), msg: (addr array byte) {
 69   var screen/esi: (addr screen) <- copy screen-on-stack
 70   var idx/ecx: int <- screen-cell-index screen, y, x
 71   # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme
 72   var e: (stream byte 0x100)
 73   var e-addr/edx: (addr stream byte) <- address e
 74   write e-addr, expected
 75   {
 76     var done?/eax: boolean <- stream-empty? e-addr
 77     compare done?, 0
 78     break-if-!=
 79     var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx
 80     var g/ebx: grapheme <- copy _g
 81     var _expected-grapheme/eax: grapheme <- read-grapheme e-addr
 82     var expected-grapheme/edi: grapheme <- copy _expected-grapheme
 83     $check-screen-row-in-color-from:compare-cells: {
 84       # if expected-grapheme is space, null grapheme is also ok
 85       {
 86         compare expected-grapheme, 0x20
 87         break-if-!=
 88         compare g, 0
 89         break-if-= $check-screen-row-in-color-from:compare-cells
 90       }
 91       # if expected-grapheme is space, a different color is ok
 92       {
 93         compare expected-grapheme, 0x20
 94         break-if-!=
 95         var color/eax: int <- screen-color-at-idx screen, idx
 96         compare color, fg
 97         break-if-!= $check-screen-row-in-color-from:compare-cells
 98       }
 99       # compare graphemes
100       $check-screen-row-in-color-from:compare-graphemes: {
101         # if (g == expected-grapheme) print "."
102         compare g, expected-grapheme
103         {
104           break-if-!=
105           draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, ".", 3  # 3=cyan
106           break $check-screen-row-in-color-from:compare-graphemes
107         }
108         # otherwise print an error
109         count-test-failure
110         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, msg, 3  # 3=cyan
111         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, ": expected '", 3
112         draw-grapheme-at-cursor 0, expected-grapheme, 3
113         move-cursor-rightward-and-downward 0, 0, 0x80  # screen-width
114         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, "' at (", 3
115         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0, x, 3
116         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, ", ", 3
117         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0, y, 3
118         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, ") but observed '", 3
119         draw-grapheme-at-cursor 0, g, 3
120         move-cursor-rightward-and-downward 0, 0, 0x80  # screen-width
121         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, "'", 3
122       }
123       $check-screen-row-in-color-from:compare-colors: {
124         var color/eax: int <- screen-color-at-idx screen, idx
125         compare fg, color
126         {
127           break-if-!=
128           draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, ".", 3  # 3=cyan
129           break $check-screen-row-in-color-from:compare-colors
130         }
131         # otherwise print an error
132         count-test-failure
133         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, msg, 3  # 3=cyan
134         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, ": expected '", 3
135         draw-grapheme-at-cursor 0, expected-grapheme, 3
136         move-cursor-rightward-and-downward 0, 0, 0x80  # screen-width
137         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, "' at (", 3
138         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0, x, 3
139         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, ", ", 3
140         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0, y, 3
141         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, ") in color ", 3
142         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0, fg, 3
143         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0, " but observed color ", 3
144         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0, color, 3
145       }
146     }
147     idx <- increment
148     increment x
149     loop
150   }
151 }
152 
153 fn test-draw-single-grapheme {
154   var screen-on-stack: screen
155   var screen/esi: (addr screen) <- address screen-on-stack
156   initialize-screen screen, 5, 4
157   var c/eax: grapheme <- copy 0x61  # 'a'
158   draw-grapheme screen, c, 0, 0, 1  # color=1
159   check-screen-row screen, 0, "a", "F - test-draw-single-grapheme"  # top-left corner of the screen
160 }
161 
162 fn test-draw-multiple-graphemes {
163   var screen-on-stack: screen
164   var screen/esi: (addr screen) <- address screen-on-stack
165   initialize-screen screen, 0x10, 4
166   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "Hello, 世界", 1  # color=1
167   check-screen-row screen, 0, "Hello, 世界", "F - test-draw-multiple-graphemes"
168 }