mtest: align correctly tests with wide Unicode characters

This correctly formats tests with CJK names or, well, emoji.  It is not perfect
(for example it does not correctly format emoji that are variations of 1-wide
characters), but it is as good as most terminal emulators.

Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
pull/8029/head
Paolo Bonzini 4 years ago
parent fa4fb3e350
commit f97521a1ff
  1. 16
      mesonbuild/mtest.py

@ -34,6 +34,7 @@ import sys
import textwrap import textwrap
import time import time
import typing as T import typing as T
import unicodedata
import xml.etree.ElementTree as et import xml.etree.ElementTree as et
from . import build from . import build
@ -61,6 +62,14 @@ def is_windows() -> bool:
def is_cygwin() -> bool: def is_cygwin() -> bool:
return sys.platform == 'cygwin' return sys.platform == 'cygwin'
UNIWIDTH_MAPPING = {'F': 2, 'H': 1, 'W': 2, 'Na': 1, 'N': 1, 'A': 1}
def uniwidth(s: str) -> int:
result = 0
for c in s:
w = unicodedata.east_asian_width(c)
result += UNIWIDTH_MAPPING[w]
return result
def determine_worker_count() -> int: def determine_worker_count() -> int:
varname = 'MESON_TESTTHREADS' varname = 'MESON_TESTTHREADS'
if varname in os.environ: if varname in os.environ:
@ -1272,12 +1281,13 @@ class TestHarness:
l.log(self, result) l.log(self, result)
def format(self, result: TestRun, colorize: bool) -> str: def format(self, result: TestRun, colorize: bool) -> str:
result_str = '{num:{numlen}}/{testcount} {name:{name_max_len}} {res} {dur:.2f}s'.format( extra_name_width = self.name_max_len + 1 - uniwidth(result.name)
result_str = '{num:{numlen}}/{testcount} {name}{extra_name_padding}{res} {dur:.2f}s'.format(
numlen=len(str(self.test_count)), numlen=len(str(self.test_count)),
num=result.num, num=result.num,
testcount=self.test_count, testcount=self.test_count,
name_max_len=self.name_max_len,
name=result.name, name=result.name,
extra_name_padding=' ' * max(1, extra_name_width),
res=result.res.get_text(colorize), res=result.res.get_text(colorize),
dur=result.duration) dur=result.duration)
if result.res is TestResult.FAIL: if result.res is TestResult.FAIL:
@ -1315,7 +1325,7 @@ class TestHarness:
sys.exit(125) sys.exit(125)
self.test_count = len(tests) self.test_count = len(tests)
self.name_max_len = max([len(self.get_pretty_suite(test)) for test in tests]) self.name_max_len = max([uniwidth(self.get_pretty_suite(test)) for test in tests])
self.run_tests(tests) self.run_tests(tests)
return self.total_failure_count() return self.total_failure_count()

Loading…
Cancel
Save