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