Repository: deno
Issue: [Feature request] Option to only print failing tests
Labels: suggestion,needs discussion,testing

This is a feature request to reduce the verbosity of `deno test` output:

1. Don't print tests that have passed.
2. Don't re-print cached test results.
3. Aggregate successful test.step() output.

Deno's `--quiet` flag could be repurposed or a new option added.

I write a lot of unit tests and many of them are parameterized. I only care about test failures and want to hide all passing test outputs because they interfere with my ability to debug and sometimes even identify real issues. In my tiny project, I don't have _that_ many tests but all the passing test reports totally blows away all other meaningful build and test process outputs. I can redirect Deno's stdout or maybe some kind of magic grep but I'd prefer Deno natively support different logging levels and that `--quiet` was actually quiet (only print warnings and errors, not successes).

Thank you for Deno! <3

## Example

This is some toy text layout engine test code and its output. It's only one file of many. Most of the files include tests that are parameterized with test.step() like this similar to [Jest's test.each()](https://jestjs.io/docs/api#testeachtablename-fn-timeout).

### Test

```ts
import {
  Font,
  FontParser,
  I16,
  I16Box,
  I16XY,
  TextLayout,
  Uint,
} from '../mod.ts';
import { memProp5x5 } from '@/mem';
import { assertEquals } from 'std/testing/asserts.ts';

const font: Font = FontParser.parse(memProp5x5, I16.cast);
Deno.test('layout()', async (test) => {
  for (
    const [caseNumber, [string, width, expected]] of ([
      [
        '',
        I16.max,
        { chars: [], cursor: I16XY.cast(0, 0 * font.lineHeight) },
      ],
      [
        ' ',
        I16.max,
        { chars: [undefined], cursor: I16XY.cast(3, 0 * font.lineHeight) },
      ],
      [
        '\n',
        I16.max,
        { chars: [undefined], cursor: I16XY.cast(0, 1 * font.lineHeight) },
      ],
      [
        'abc def ghi jkl mno',
        I16.max,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(8, 0 * font.lineHeight, 3, font.cellHeight),
            undefined,
            I16Box.cast(14, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(18, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(22, 0 * font.lineHeight, 3, font.cellHeight),
            undefined,
            I16Box.cast(28, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(32, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(36, 0 * font.lineHeight, 1, font.cellHeight),
            undefined,
            I16Box.cast(40, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(44, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(48, 0 * font.lineHeight, 1, font.cellHeight),
            undefined,
            I16Box.cast(52, 0 * font.lineHeight, 5, font.cellHeight),
            I16Box.cast(58, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(62, 0 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(65, 0 * font.lineHeight),
        },
      ],
      [
        'abc def ghi jkl mno',
        10,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            undefined,
            I16Box.cast(6, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 2 * font.lineHeight, 3, font.cellHeight),
            undefined,
            I16Box.cast(0, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(8, 3 * font.lineHeight, 1, font.cellHeight),
            undefined,
            I16Box.cast(0, 4 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 4 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(8, 4 * font.lineHeight, 1, font.cellHeight),
            undefined,
            I16Box.cast(0, 5 * font.lineHeight, 5, font.cellHeight),
            I16Box.cast(6, 5 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 6 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(3, 6 * font.lineHeight),
        },
      ],
      [
        'abc def ghi jkl mno',
        20,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(8, 0 * font.lineHeight, 3, font.cellHeight),
            undefined,
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(8, 1 * font.lineHeight, 3, font.cellHeight),
            undefined,
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(8, 2 * font.lineHeight, 1, font.cellHeight),
            undefined,
            I16Box.cast(0, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(8, 3 * font.lineHeight, 1, font.cellHeight),
            undefined,
            I16Box.cast(0, 4 * font.lineHeight, 5, font.cellHeight),
            I16Box.cast(6, 4 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(10, 4 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(13, 4 * font.lineHeight),
        },
      ],
      [
        'abc def ghi jkl mno',
        21,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(8, 0 * font.lineHeight, 3, font.cellHeight),
            undefined,
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(8, 1 * font.lineHeight, 3, font.cellHeight),
            undefined,
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(8, 2 * font.lineHeight, 1, font.cellHeight),
            undefined,
            I16Box.cast(12, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(16, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(20, 2 * font.lineHeight, 1, font.cellHeight),
            undefined,
            I16Box.cast(0, 3 * font.lineHeight, 5, font.cellHeight),
            I16Box.cast(6, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(10, 3 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(13, 3 * font.lineHeight),
        },
      ],
      [
        'a  b',
        4,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            undefined,
            undefined,
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(3, 2 * font.lineHeight),
        },
      ],
      [
        'a  b ',
        4,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            undefined,
            undefined,
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            undefined,
          ],
          cursor: I16XY.cast(0, 3 * font.lineHeight),
        },
      ],
    ] as const).entries()
  ) {
    await test.step(`Case ${caseNumber}: string="${string}" width=${width}.`, () =>
      assertEquals(
        TextLayout.layout(font, string, I16.cast(width), I16XY.cast(1, 1)),
        expected as unknown,
      ));
  }
});

Deno.test('layout_word()', async (test) => {
  for (
    const [caseNumber, [xy, width, string, index, expected]] of ([
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        ' ',
        0,
        { chars: [], cursor: I16XY.cast(0, 0 * font.lineHeight) },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        '',
        0,
        { chars: [], cursor: I16XY.cast(0, 0 * font.lineHeight) },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        '\n',
        0,
        { chars: [], cursor: I16XY.cast(0, 0 * font.lineHeight) },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        'a',
        0,
        {
          chars: [I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight)],
          cursor: I16XY.cast(3, 0 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        '.',
        0,
        {
          chars: [I16Box.cast(0, 0 * font.lineHeight, 1, font.cellHeight)],
          cursor: I16XY.cast(1, 0 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        'a ',
        0,
        {
          chars: [I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight)],
          cursor: I16XY.cast(3, 0 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        'a\n',
        0,
        {
          chars: [I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight)],
          cursor: I16XY.cast(3, 0 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        'a a',
        0,
        {
          chars: [I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight)],
          cursor: I16XY.cast(3, 0 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        'a.',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 1, font.cellHeight),
          ],
          cursor: I16XY.cast(5, 0 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        'aa',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(7, 0 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        'aa\n',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(7, 0 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        'aa aa',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(7, 0 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        'g',
        0,
        {
          chars: [I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight)],
          cursor: I16XY.cast(3, 0 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(8, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(12, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(16, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(20, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(24, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(28, 0 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(31, 0 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        'abcdefgh',
        1,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(8, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(12, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(16, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(20, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(24, 0 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(27, 0 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        I16.max,
        'abcdefgh',
        8,
        { chars: [], cursor: I16XY.cast(0, 0 * font.lineHeight) },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        0,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 4 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 5 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 6 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 7 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(3, 7 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        1,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 4 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 5 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 6 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 7 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(3, 7 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        3,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 4 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 5 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 6 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 7 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(3, 7 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        5,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 4 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 5 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 6 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 7 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(3, 7 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        6,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 4 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 5 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 6 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 7 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(3, 7 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        7,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 4 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 5 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 6 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 6 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(7, 6 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        8,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 3 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(7, 3 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        9,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 3 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(7, 3 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        10,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 3 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(7, 3 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        11,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 3 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(7, 3 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(0, 0 * font.lineHeight),
        12,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(0, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(8, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(8, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(4, 2 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(7, 2 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(1, 0 * font.lineHeight),
        5,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(1, 0 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 4 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 5 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 6 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 7 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(3, 7 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(2, 0 * font.lineHeight),
        5,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(0, 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 4 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 5 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 6 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 7 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 8 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(3, 8 * font.lineHeight),
        },
      ],
      [
        I16XY.cast(2, 1 + 0 * font.lineHeight),
        5,
        'abcdefgh',
        0,
        {
          chars: [
            I16Box.cast(0, 1 + 1 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 + 2 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 + 3 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 + 4 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 + 5 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 + 6 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 + 7 * font.lineHeight, 3, font.cellHeight),
            I16Box.cast(0, 1 + 8 * font.lineHeight, 3, font.cellHeight),
          ],
          cursor: I16XY.cast(3, 1 + 8 * font.lineHeight),
        },
      ],
    ] as const).entries()
  ) {
    await test.step(`Case ${caseNumber}: xy=${I16XY.toString(xy)}, width=${width}, string="${string}", index=${index}.`, () =>
      assertEquals(
        TextLayout.layoutWord(
          font,
          xy,
          I16.cast(width),
          string,
          Uint.cast(index),
          I16XY.cast(1, 1),
        ),
        expected as unknown,
      ));
  }
});
```

### Actual output

```
running 2 tests from ../liboid/src/text/TextLayout.test.ts
layout() ...
  Case 0: string="" width=32767. ... ok (4ms)
  Case 1: string=" " width=32767. ... ok (3ms)
  Case 2: string="
" width=32767. ... ok (3ms)
  Case 3: string="abc def ghi jkl mno" width=32767. ... ok (3ms)
  Case 4: string="abc def ghi jkl mno" width=10. ... ok (3ms)
  Case 5: string="abc def ghi jkl mno" width=20. ... ok (3ms)
  Case 6: string="abc def ghi jkl mno" width=21. ... ok (3ms)
  Case 7: string="a  b" width=4. ... ok (2ms)
  Case 8: string="a  b " width=4. ... ok (2ms)
layout() ... ok (32ms)
layout_word() ...
  Case 0: xy=(0, 0), width=32767, string=" ", index=0. ... ok (3ms)
  Case 1: xy=(0, 0), width=32767, string="", index=0. ... ok (3ms)
  Case 2: xy=(0, 0), width=32767, string="
", index=0. ... ok (3ms)
  Case 3: xy=(0, 0), width=32767, string="a", index=0. ... ok (3ms)
  Case 4: xy=(0, 0), width=32767, string=".", index=0. ... ok (3ms)
  Case 5: xy=(0, 0), width=32767, string="a ", index=0. ... ok (2ms)
  Case 6: xy=(0, 0), width=32767, string="a
", index=0. ... ok (2ms)
  Case 7: xy=(0, 0), width=32767, string="a a", index=0. ... ok (2ms)
  Case 8: xy=(0, 0), width=32767, string="a.", index=0. ... ok (3ms)
  Case 9: xy=(0, 0), width=32767, string="aa", index=0. ... ok (3ms)
  Case 10: xy=(0, 0), width=32767, string="aa
", index=0. ... ok (2ms)
  Case 11: xy=(0, 0), width=32767, string="aa aa", index=0. ... ok (2ms)
  Case 12: xy=(0, 0), width=32767, string="g", index=0. ... ok (2ms)
  Case 13: xy=(0, 0), width=32767, string="abcdefgh", index=0. ... ok (2ms)
  Case 14: xy=(0, 0), width=32767, string="abcdefgh", index=1. ... ok (3ms)
  Case 15: xy=(0, 0), width=32767, string="abcdefgh", index=8. ... ok (2ms)
  Case 16: xy=(0, 0), width=0, string="abcdefgh", index=0. ... ok (2ms)
  Case 17: xy=(0, 0), width=1, string="abcdefgh", index=0. ... ok (3ms)
  Case 18: xy=(0, 0), width=3, string="abcdefgh", index=0. ... ok (3ms)
  Case 19: xy=(0, 0), width=5, string="abcdefgh", index=0. ... ok (4ms)
  Case 20: xy=(0, 0), width=6, string="abcdefgh", index=0. ... ok (4ms)
  Case 21: xy=(0, 0), width=7, string="abcdefgh", index=0. ... ok (3ms)
  Case 22: xy=(0, 0), width=8, string="abcdefgh", index=0. ... ok (3ms)
  Case 23: xy=(0, 0), width=9, string="abcdefgh", index=0. ... ok (3ms)
  Case 24: xy=(0, 0), width=10, string="abcdefgh", index=0. ... ok (3ms)
  Case 25: xy=(0, 0), width=11, string="abcdefgh", index=0. ... ok (3ms)
  Case 26: xy=(0, 0), width=12, string="abcdefgh", index=0. ... ok (2ms)
  Case 27: xy=(1, 0), width=5, string="abcdefgh", index=0. ... ok (3ms)
  Case 28: xy=(2, 0), width=5, string="abcdefgh", index=0. ... ok (2ms)
  Case 29: xy=(2, 1), width=5, string="abcdefgh", index=0. ... ok (3ms)
layout_word() ... ok (94ms)

ok | 2 passed (39 steps) | 0 failed (159ms)


```

### Desired output

```
```

(Intentionally empty!)