https://github.com/akkartik/mu/blob/main/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, 0/x, y, 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 failure-count/edi: int <- copy 0
     14   var idx/ecx: int <- screen-cell-index screen, x, y
     15   # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme
     16   var e: (stream byte 0x100)
     17   var e-addr/edx: (addr stream byte) <- address e
     18   write e-addr, expected
     19   {
     20     var done?/eax: boolean <- stream-empty? e-addr
     21     compare done?, 0
     22     break-if-!=
     23     var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx
     24     var g/ebx: grapheme <- copy _g
     25     var expected-grapheme/eax: grapheme <- read-grapheme e-addr
     26     # compare graphemes
     27     $check-screen-row-from:compare-graphemes: {
     28       # if expected-grapheme is space, null grapheme is also ok
     29       {
     30         compare expected-grapheme, 0x20
     31         break-if-!=
     32         compare g, 0
     33         break-if-= $check-screen-row-from:compare-graphemes
     34       }
     35       # if (g == expected-grapheme) print "."
     36       compare g, expected-grapheme
     37       break-if-=
     38       # otherwise print an error
     39       failure-count <- increment
     40       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
     41       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg
     42       draw-grapheme-at-cursor 0/screen, expected-grapheme, 3/cyan, 0/bg
     43       move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width
     44       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg
     45       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg
     46       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg
     47       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg
     48       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") but observed '", 3/fg/cyan, 0/bg
     49       draw-grapheme-at-cursor 0/screen, g, 3/cyan, 0/bg
     50       move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width
     51       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg
     52       move-cursor-to-left-margin-of-next-line 0/screen
     53     }
     54     idx <- increment
     55     increment x
     56     loop
     57   }
     58   # if any assertions failed, count the test as failed
     59   compare failure-count, 0
     60   {
     61     break-if-=
     62     count-test-failure
     63     return
     64   }
     65   # otherwise print a "."
     66   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg
     67 }
     68
     69 # various variants by screen-cell attribute; spaces in the 'expected' data should not match the attribute
     70
     71 fn check-screen-row-in-color screen: (addr screen), fg: int, y: int, expected: (addr array byte), msg: (addr array byte) {
     72   check-screen-row-in-color-from screen, fg, y, 0/x, expected, msg
     73 }
     74
     75 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) {
     76   var screen/esi: (addr screen) <- copy screen-on-stack
     77   var idx/ecx: int <- screen-cell-index screen, x, y
     78   # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme
     79   var e: (stream byte 0x100)
     80   var e-addr/edx: (addr stream byte) <- address e
     81   write e-addr, expected
     82   {
     83     var done?/eax: boolean <- stream-empty? e-addr
     84     compare done?, 0
     85     break-if-!=
     86     var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx
     87     var g/ebx: grapheme <- copy _g
     88     var _expected-grapheme/eax: grapheme <- read-grapheme e-addr
     89     var expected-grapheme/edi: grapheme <- copy _expected-grapheme
     90     $check-screen-row-in-color-from:compare-cells: {
     91       # if expected-grapheme is space, null grapheme is also ok
     92       {
     93         compare expected-grapheme, 0x20
     94         break-if-!=
     95         compare g, 0
     96         break-if-= $check-screen-row-in-color-from:compare-cells
     97       }
     98       # if expected-grapheme is space, a different color is ok
     99       {
    100         compare expected-grapheme, 0x20
    101         break-if-!=
    102         var color/eax: int <- screen-color-at-idx screen, idx
    103         compare color, fg
    104         break-if-!= $check-screen-row-in-color-from:compare-cells
    105       }
    106       # compare graphemes
    107       $check-screen-row-in-color-from:compare-graphemes: {
    108         # if (g == expected-grapheme) print "."
    109         compare g, expected-grapheme
    110         {
    111           break-if-!=
    112           draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg
    113           break $check-screen-row-in-color-from:compare-graphemes
    114         }
    115         # otherwise print an error
    116         count-test-failure
    117         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
    118         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg
    119         draw-grapheme-at-cursor 0/screen, expected-grapheme, 3/cyan, 0/bg
    120         move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width
    121         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg
    122         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg
    123         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg
    124         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg
    125         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") but observed '", 3/fg/cyan, 0/bg
    126         draw-grapheme-at-cursor 0/screen, g, 3/cyan, 0/bg
    127         move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width
    128         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg
    129         move-cursor-to-left-margin-of-next-line 0/screen
    130       }
    131       $check-screen-row-in-color-from:compare-colors: {
    132         var color/eax: int <- screen-color-at-idx screen, idx
    133         compare fg, color
    134         {
    135           break-if-!=
    136           draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg
    137           break $check-screen-row-in-color-from:compare-colors
    138         }
    139         # otherwise print an error
    140         count-test-failure
    141         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
    142         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg
    143         draw-grapheme-at-cursor 0/screen, expected-grapheme, 3/cyan, 0/bg
    144         move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width
    145         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg
    146         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg
    147         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg
    148         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg
    149         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") in color ", 3/fg/cyan, 0/bg
    150         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, fg, 3/fg/cyan, 0/bg
    151         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " but observed color ", 3/fg/cyan, 0/bg
    152         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, color, 3/fg/cyan, 0/bg
    153         move-cursor-to-left-margin-of-next-line 0/screen
    154       }
    155     }
    156     idx <- increment
    157     increment x
    158     loop
    159   }
    160 }
    161
    162 fn check-screen-row-in-background-color screen: (addr screen), bg: int, y: int, expected: (addr array byte), msg: (addr array byte) {
    163   check-screen-row-in-background-color-from screen, bg, y, 0/x, expected, msg
    164 }
    165
    166 fn check-screen-row-in-background-color-from screen-on-stack: (addr screen), bg: int, y: int, x: int, expected: (addr array byte), msg: (addr array byte) {
    167   var screen/esi: (addr screen) <- copy screen-on-stack
    168   var idx/ecx: int <- screen-cell-index screen, x, y
    169   # compare 'expected' with the screen contents starting at 'idx', grapheme by grapheme
    170   var e: (stream byte 0x100)
    171   var e-addr/edx: (addr stream byte) <- address e
    172   write e-addr, expected
    173   {
    174     var done?/eax: boolean <- stream-empty? e-addr
    175     compare done?, 0
    176     break-if-!=
    177     var _g/eax: grapheme <- screen-grapheme-at-idx screen, idx
    178     var g/ebx: grapheme <- copy _g
    179     var _expected-grapheme/eax: grapheme <- read-grapheme e-addr
    180     var expected-grapheme/edi: grapheme <- copy _expected-grapheme
    181     $check-screen-row-in-background-color-from:compare-cells: {
    182       # if expected-grapheme is space, null grapheme is also ok
    183       {
    184         compare expected-grapheme, 0x20
    185         break-if-!=
    186         compare g, 0
    187         break-if-= $check-screen-row-in-background-color-from:compare-cells
    188       }
    189       # if expected-grapheme is space, a different background-color is ok
    190       {
    191         compare expected-grapheme, 0x20
    192         break-if-!=
    193         var background-color/eax: int <- screen-background-color-at-idx screen, idx
    194         compare background-color, bg
    195         break-if-!= $check-screen-row-in-background-color-from:compare-cells
    196       }
    197       # compare graphemes
    198       $check-screen-row-in-background-color-from:compare-graphemes: {
    199         # if (g == expected-grapheme) print "."
    200         compare g, expected-grapheme
    201         {
    202           break-if-!=
    203           draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg
    204           break $check-screen-row-in-background-color-from:compare-graphemes
    205         }
    206         # otherwise print an error
    207         count-test-failure
    208         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
    209         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg
    210         draw-grapheme-at-cursor 0/screen, expected-grapheme, 3/cyan, 0/bg
    211         move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width
    212         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg
    213         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg
    214         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg
    215         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg
    216         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") but observed '", 3/fg/cyan, 0/bg
    217         draw-grapheme-at-cursor 0/screen, g, 3/cyan, 0/bg
    218         move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width
    219         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "'", 3/fg/cyan, 0/bg
    220         move-cursor-to-left-margin-of-next-line 0/screen
    221         break $check-screen-row-in-background-color-from:compare-graphemes
    222       }
    223       $check-screen-row-in-background-color-from:compare-background-colors: {
    224         var background-color/eax: int <- screen-background-color-at-idx screen, idx
    225         compare bg, background-color
    226         {
    227           break-if-!=
    228           draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg
    229           break $check-screen-row-in-background-color-from:compare-background-colors
    230         }
    231         # otherwise print an error
    232         count-test-failure
    233         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
    234         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected '", 3/fg/cyan, 0/bg
    235         draw-grapheme-at-cursor 0/screen, expected-grapheme, 3/cyan, 0/bg
    236         move-cursor-rightward-and-downward 0/screen, 0/xmin, 0x80/xmax=screen-width
    237         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "' at (", 3/fg/cyan, 0/bg
    238         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg
    239         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg
    240         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg
    241         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") in background-color ", 3/fg/cyan, 0/bg
    242         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, bg, 3/fg/cyan, 0/bg
    243         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " but observed background-color ", 3/fg/cyan, 0/bg
    244         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, background-color, 3/fg/cyan, 0/bg
    245         move-cursor-to-left-margin-of-next-line 0/screen
    246       }
    247     }
    248     idx <- increment
    249     increment x
    250     loop
    251   }
    252 }
    253
    254 # helpers for checking just background color, not screen contents
    255 # these can validate bg for spaces
    256
    257 fn check-background-color-in-screen-row screen: (addr screen), bg: int, y: int, expected-bitmap: (addr array byte), msg: (addr array byte) {
    258   check-background-color-in-screen-row-from screen, bg, y, 0/x, expected-bitmap, msg
    259 }
    260
    261 fn check-background-color-in-screen-row-from screen-on-stack: (addr screen), bg: int, y: int, x: int, expected-bitmap: (addr array byte), msg: (addr array byte) {
    262   var screen/esi: (addr screen) <- copy screen-on-stack
    263   var failure-count: int
    264   var idx/ecx: int <- screen-cell-index screen, x, y
    265   # compare background color where 'expected-bitmap' is a non-space
    266   var e: (stream byte 0x100)
    267   var e-addr/edx: (addr stream byte) <- address e
    268   write e-addr, expected-bitmap
    269   {
    270     var done?/eax: boolean <- stream-empty? e-addr
    271     compare done?, 0
    272     break-if-!=
    273     var _expected-bit/eax: grapheme <- read-grapheme e-addr
    274     var expected-bit/edi: grapheme <- copy _expected-bit
    275     $check-background-color-in-screen-row-from:compare-cells: {
    276       var background-color/eax: int <- screen-background-color-at-idx screen, idx
    277       # if expected-bit is space, assert that background is NOT bg
    278       compare expected-bit, 0x20
    279       {
    280         break-if-!=
    281         compare background-color, bg
    282         break-if-!= $check-background-color-in-screen-row-from:compare-cells
    283         increment failure-count
    284         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
    285         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected (", 3/fg/cyan, 0/bg
    286         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg
    287         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg
    288         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg
    289         draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") to not be in background-color ", 3/fg/cyan, 0/bg
    290         draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, bg, 3/fg/cyan, 0/bg
    291         move-cursor-to-left-margin-of-next-line 0/screen
    292         break $check-background-color-in-screen-row-from:compare-cells
    293       }
    294       # otherwise assert that background IS bg
    295       compare background-color, bg
    296       break-if-= $check-background-color-in-screen-row-from:compare-cells
    297       increment failure-count
    298       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, msg, 3/fg/cyan, 0/bg
    299       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ": expected (", 3/fg/cyan, 0/bg
    300       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, x, 3/fg/cyan, 0/bg
    301       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ", ", 3/fg/cyan, 0/bg
    302       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, y, 3/fg/cyan, 0/bg
    303       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ") in background-color ", 3/fg/cyan, 0/bg
    304       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, bg, 3/fg/cyan, 0/bg
    305       draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, " but observed background-color ", 3/fg/cyan, 0/bg
    306       draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, background-color, 3/fg/cyan, 0/bg
    307       move-cursor-to-left-margin-of-next-line 0/screen
    308     }
    309     idx <- increment
    310     increment x
    311     loop
    312   }
    313   # if any assertions failed, count the test as failed
    314   compare failure-count, 0
    315   {
    316     break-if-=
    317     count-test-failure
    318     return
    319   }
    320   # otherwise print a "."
    321   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg/cyan, 0/bg
    322 }
    323
    324 fn test-draw-single-grapheme {
    325   var screen-on-stack: screen
    326   var screen/esi: (addr screen) <- address screen-on-stack
    327   initialize-screen screen, 5, 4, 0/no-pixel-graphics
    328   draw-code-point screen, 0x61/a, 0/x, 0/y, 1/fg, 2/bg
    329   check-screen-row screen, 0/y, "a", "F - test-draw-single-grapheme"  # top-left corner of the screen
    330   check-screen-row-in-color screen, 1/fg, 0/y, "a", "F - test-draw-single-grapheme-fg"
    331   check-screen-row-in-background-color screen, 2/bg, 0/y, "a", "F - test-draw-single-grapheme-bg"
    332   check-background-color-in-screen-row screen, 2/bg, 0/y, "x ", "F - test-draw-single-grapheme-bg2"
    333 }
    334
    335 fn test-draw-multiple-graphemes {
    336   var screen-on-stack: screen
    337   var screen/esi: (addr screen) <- address screen-on-stack
    338   initialize-screen screen, 0x10/rows, 4/cols, 0/no-pixel-graphics
    339   draw-text-wrapping-right-then-down-from-cursor-over-full-screen screen, "Hello, 世界", 1/fg, 2/bg
    340   check-screen-row screen, 0/y, "Hello, 世界", "F - test-draw-multiple-graphemes"
    341   check-screen-row-in-color screen, 1/fg, 0/y, "Hello, 世界", "F - test-draw-multiple-graphemes-fg"
    342   check-background-color-in-screen-row screen, 2/bg, 0/y, "xxxxxxxxx ", "F - test-draw-multiple-graphemes-bg2"
    343 }