11cb0ef41Sopenharmony_ci// Flags: --expose-internals 21cb0ef41Sopenharmony_ci'use strict'; 31cb0ef41Sopenharmony_ciconst common = require('../common'); 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ciconst assert = require('assert'); 61cb0ef41Sopenharmony_ciconst { getStringWidth } = require('internal/util/inspect'); 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci// Test column width 91cb0ef41Sopenharmony_ci 101cb0ef41Sopenharmony_ci// Ll (Lowercase Letter): LATIN SMALL LETTER A 111cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('a'), 1); 121cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(String.fromCharCode(0x0061)), 1); 131cb0ef41Sopenharmony_ci// Lo (Other Letter) 141cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('丁'), 2); 151cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(String.fromCharCode(0x4E01)), 2); 161cb0ef41Sopenharmony_ci// Surrogate pairs 171cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\ud83d\udc78\ud83c\udfff'), 4); 181cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(''), 2); 191cb0ef41Sopenharmony_ci// Cs (Surrogate): High Surrogate 201cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\ud83d'), 1); 211cb0ef41Sopenharmony_ci// Cs (Surrogate): Low Surrogate 221cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\udc78'), 1); 231cb0ef41Sopenharmony_ci// Cc (Control): NULL 241cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\u0000'), 0); 251cb0ef41Sopenharmony_ci// Cc (Control): BELL 261cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(String.fromCharCode(0x0007)), 0); 271cb0ef41Sopenharmony_ci// Cc (Control): LINE FEED 281cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\n'), 0); 291cb0ef41Sopenharmony_ci// Cf (Format): SOFT HYPHEN 301cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(String.fromCharCode(0x00AD)), 1); 311cb0ef41Sopenharmony_ci// Cf (Format): LEFT-TO-RIGHT MARK 321cb0ef41Sopenharmony_ci// Cf (Format): RIGHT-TO-LEFT MARK 331cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\u200Ef\u200F'), 1); 341cb0ef41Sopenharmony_ci// Cn (Unassigned): Not a character 351cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(String.fromCharCode(0x10FFEF)), 1); 361cb0ef41Sopenharmony_ci// Cn (Unassigned): Not a character (but in a CJK range) 371cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(String.fromCharCode(0x3FFEF)), 1); 381cb0ef41Sopenharmony_ci// Mn (Nonspacing Mark): COMBINING ACUTE ACCENT 391cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(String.fromCharCode(0x0301)), 0); 401cb0ef41Sopenharmony_ci// Mc (Spacing Mark): BALINESE ADEG ADEG 411cb0ef41Sopenharmony_ci// Chosen as its Canonical_Combining_Class is not 0, but is not a 0-width 421cb0ef41Sopenharmony_ci// character. 431cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(String.fromCharCode(0x1B44)), 1); 441cb0ef41Sopenharmony_ci// Me (Enclosing Mark): COMBINING ENCLOSING CIRCLE 451cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(String.fromCharCode(0x20DD)), 0); 461cb0ef41Sopenharmony_ci 471cb0ef41Sopenharmony_ci// The following is an emoji sequence with ZWJ (zero-width-joiner). In some 481cb0ef41Sopenharmony_ci// implementations, it is represented as a single glyph, in other 491cb0ef41Sopenharmony_ci// implementations as a sequence of individual glyphs. By default, each 501cb0ef41Sopenharmony_ci// component will be counted individually, since not a lot of systems support 511cb0ef41Sopenharmony_ci// these fully. 521cb0ef41Sopenharmony_ci// See https://www.unicode.org/reports/tr51/tr51-16.html#Emoji_ZWJ_Sequences 531cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth(''), 8); 541cb0ef41Sopenharmony_ci// TODO(BridgeAR): This should have a width of two and six. The heart contains 551cb0ef41Sopenharmony_ci// the \uFE0F variation selector that indicates that it should be displayed as 561cb0ef41Sopenharmony_ci// emoji instead of as text. Emojis are all full width characters when not being 571cb0ef41Sopenharmony_ci// rendered as text. 581cb0ef41Sopenharmony_ci// https://en.wikipedia.org/wiki/Variation_Selectors_(Unicode_block) 591cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('❤️'), 1); 601cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('❤️'), 5); 611cb0ef41Sopenharmony_ci// The length of one is correct. It is an emoji treated as text. 621cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('❤'), 1); 631cb0ef41Sopenharmony_ci 641cb0ef41Sopenharmony_ci// By default, unicode characters whose width is considered ambiguous will 651cb0ef41Sopenharmony_ci// be considered half-width. For these characters, getStringWidth will return 661cb0ef41Sopenharmony_ci// 1. In some contexts, however, it is more appropriate to consider them full 671cb0ef41Sopenharmony_ci// width. By default, the algorithm will assume half width. 681cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\u01d4'), 1); 691cb0ef41Sopenharmony_ci 701cb0ef41Sopenharmony_ci// Control chars and combining chars are zero 711cb0ef41Sopenharmony_ciassert.strictEqual(getStringWidth('\u200E\n\u220A\u20D2'), 1); 721cb0ef41Sopenharmony_ci 731cb0ef41Sopenharmony_ci// Test that the fast path for ASCII characters yields results consistent 741cb0ef41Sopenharmony_ci// with the 'slow' path. 751cb0ef41Sopenharmony_cifor (let i = 0; i < 256; i++) { 761cb0ef41Sopenharmony_ci const char = String.fromCharCode(i); 771cb0ef41Sopenharmony_ci assert.strictEqual( 781cb0ef41Sopenharmony_ci getStringWidth(char + ''), 791cb0ef41Sopenharmony_ci getStringWidth(char) + 2); 801cb0ef41Sopenharmony_ci 811cb0ef41Sopenharmony_ci if (i < 32 || (i >= 127 && i < 160)) { // Control character 821cb0ef41Sopenharmony_ci assert.strictEqual(getStringWidth(char), 0); 831cb0ef41Sopenharmony_ci } else { // Regular ASCII character 841cb0ef41Sopenharmony_ci assert.strictEqual(getStringWidth(char), 1); 851cb0ef41Sopenharmony_ci } 861cb0ef41Sopenharmony_ci} 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ciif (common.hasIntl) { 891cb0ef41Sopenharmony_ci const a = '한글'.normalize('NFD'); // 한글 901cb0ef41Sopenharmony_ci const b = '한글'.normalize('NFC'); // 한글 911cb0ef41Sopenharmony_ci assert.strictEqual(a.length, 6); 921cb0ef41Sopenharmony_ci assert.strictEqual(b.length, 2); 931cb0ef41Sopenharmony_ci assert.strictEqual(getStringWidth(a), 4); 941cb0ef41Sopenharmony_ci assert.strictEqual(getStringWidth(b), 4); 951cb0ef41Sopenharmony_ci} 96