use super::*;
use crate::options::AmbiguousWidthTreatment;
#[test]
fn empty_string() {
assert_eq!(string_width(""), 0);
}
#[test]
fn single_ascii_character() {
assert_eq!(string_width("a"), 1);
}
#[test]
fn ascii_string() {
assert_eq!(string_width("hello world"), 11);
}
#[test]
fn full_width_characters() {
assert_eq!(string_width("你好"), 4);
}
#[test]
fn half_width_characters() {
assert_eq!(string_width("hello"), 5);
}
#[test]
fn mixed_width() {
assert_eq!(string_width("hello世界"), 9);
}
#[test]
fn ambiguous_narrow_default() {
assert_eq!(string_width("±"), 1);
}
#[test]
fn ambiguous_wide() {
let options = StringWidthOptions {
count_ansi: false,
ambiguous_width: AmbiguousWidthTreatment::Wide,
};
assert_eq!(string_width_with_options("±", options), 2);
}
#[test]
fn null_character() {
assert_eq!(string_width("\u{0000}"), 0);
}
#[test]
fn tab_character() {
assert_eq!(string_width("\t"), 0);
}
#[test]
fn tab_sandwich_ascii() {
assert_eq!(string_width("a\tb"), 2);
}
#[test]
fn newline_character() {
assert_eq!(string_width("\n"), 0);
}
#[test]
fn escape_character() {
assert_eq!(string_width("\u{001B}"), 0);
}
#[test]
fn control_in_text() {
assert_eq!(string_width("a\u{0001}b"), 2);
}
#[test]
fn ansi_color_codes() {
assert_eq!(string_width("\u{001B}[31mred\u{001B}[0m"), 3);
}
#[test]
fn ansi_codes_counted() {
let options = StringWidthOptions {
count_ansi: true,
ambiguous_width: AmbiguousWidthTreatment::Narrow,
};
assert_eq!(string_width_with_options("\u{001B}[31m", options), 5);
}
#[test]
fn zero_width_space() {
assert_eq!(string_width("a\u{200B}b"), 2);
}
#[test]
fn zero_width_non_joiner() {
assert_eq!(string_width("a\u{200C}b"), 2);
}
#[test]
fn zero_width_joiner() {
assert_eq!(string_width("a\u{200D}b"), 2);
}
#[test]
fn zwnj_alone() {
assert_eq!(string_width("\u{200C}"), 0);
}
#[test]
fn zwj_alone() {
assert_eq!(string_width("\u{200D}"), 0);
}
#[test]
fn combining_diacritical_mark() {
assert_eq!(string_width("e\u{0301}"), 1);
}
#[test]
fn multiple_combining_marks() {
assert_eq!(string_width("e\u{0301}\u{0302}"), 1);
}
#[test]
fn combining_marks_only() {
assert_eq!(string_width("\u{0301}\u{0302}"), 0);
}
#[test]
fn emoji_hand() {
assert_eq!(string_width("👋"), 2);
}
#[test]
fn emoji_surrogate_pair() {
assert_eq!(string_width("😀"), 2);
}
#[test]
fn text_with_emoji() {
assert_eq!(string_width("a😀b"), 4);
}
#[test]
fn basic_emoji() {
assert_eq!(string_width("😀"), 2);
}
#[test]
fn variation_selector_ignored() {
assert_eq!(string_width("a\u{FE0F}"), 1);
}
#[test]
fn vs16_alone() {
assert_eq!(string_width("\u{FE0F}"), 0);
}
#[test]
fn vs15_alone() {
assert_eq!(string_width("\u{FE0E}"), 0);
}
#[test]
fn mixed_script_with_emoji() {
assert_eq!(string_width("Hello 👋 世界"), 13);
}
#[test]
fn only_combining_marks() {
assert_eq!(string_width("\u{0300}\u{0301}\u{0302}"), 0);
}
#[test]
fn only_control_characters() {
assert_eq!(string_width("\u{0000}\u{0001}\u{001B}"), 0);
}
#[test]
fn only_zero_width_characters() {
assert_eq!(string_width("\u{200B}\u{200C}\u{200D}"), 0);
}
#[test]
fn mixed_control_and_text() {
assert_eq!(string_width("a\u{0000}b\u{0001}c"), 3);
}
#[test]
fn colored_hello_stripped() {
assert_eq!(string_width("\x1b[31mhello\x1b[0m"), 5);
}
#[test]
fn colored_hello_count_ansi() {
let options = StringWidthOptions {
count_ansi: true,
ambiguous_width: AmbiguousWidthTreatment::Narrow,
};
assert_eq!(
string_width_with_options("\x1b[31mhello\x1b[0m", options),
14
);
}
#[test]
fn halfwidth_kana_voiced_sound_mark() {
assert_eq!(string_width("バ"), 2); }
#[test]
fn halfwidth_kana_semi_voiced_sound_mark() {
assert_eq!(string_width("パ"), 2); }
#[test]
fn halfwidth_vu() {
assert_eq!(string_width("ヴ"), 2);
}
#[test]
fn halfwidth_vu_with_prolonged_sound() {
assert_eq!(string_width("ヴー"), 3);
}
#[test]
fn voiced_sound_mark_alone() {
assert_eq!(string_width("゙"), 1);
}
#[test]
fn semi_voiced_sound_mark_alone() {
assert_eq!(string_width("゚"), 1);
}
#[test]
fn halfwidth_prolonged_sound_with_kana() {
assert_eq!(string_width("カー"), 2);
}
#[test]
fn halfwidth_kana_with_dakuten_and_prolonged_mark() {
assert_eq!(string_width("ガー"), 3);
}
#[test]
fn emoji_with_variation_selector() {
assert_eq!(string_width("⚡\u{FE0F}"), 2);
}
#[test]
fn warning_sign_emoji_style() {
assert_eq!(string_width("⚠\u{FE0F}"), 2);
}
#[test]
fn warning_sign_text_style() {
assert_eq!(string_width("⚠\u{FE0E}"), 1);
}
#[test]
fn check_mark_text_style() {
assert_eq!(string_width("✔\u{FE0E}"), 1);
}
#[test]
fn arrow_with_text_variation() {
assert_eq!(string_width("\u{21A9}\u{FE0E}"), 1);
}
#[test]
fn arrow_with_emoji_variation() {
assert_eq!(string_width("\u{21A9}\u{FE0F}"), 2);
}
#[test]
fn registered_sign_text_variation() {
assert_eq!(string_width("\u{00AE}\u{FE0E}"), 1);
}
#[test]
fn registered_sign_emoji_variation() {
assert_eq!(string_width("\u{00AE}\u{FE0F}"), 2);
}
#[test]
fn copyright_sign_text_variation() {
assert_eq!(string_width("\u{00A9}\u{FE0E}"), 1);
}
#[test]
fn copyright_sign_emoji_variation() {
assert_eq!(string_width("\u{00A9}\u{FE0F}"), 2);
}
#[test]
fn emoji_with_skin_tone() {
assert_eq!(string_width("👋🏽"), 2);
}
#[test]
fn zwj_sequence() {
assert_eq!(string_width("👨👩👧👦"), 2);
}
#[test]
fn keycap_sequence() {
assert_eq!(string_width("1️⃣"), 2);
}
#[test]
fn flag_sequence() {
assert_eq!(string_width("🇺🇸"), 2);
}
#[test]
fn single_regional_indicator() {
assert_eq!(string_width("🇦"), 1);
}
#[test]
fn flag_from_two_regional_indicators() {
assert_eq!(string_width("🇺🇸"), 2);
}
#[test]
fn three_regional_indicators() {
assert_eq!(string_width("🇺🇸🇦"), 3);
}
#[test]
fn word_joiner() {
assert_eq!(string_width("a\u{2060}b"), 2);
}
#[test]
fn function_application() {
assert_eq!(string_width("a\u{2061}b"), 2);
}
#[test]
fn ansi_with_emoji() {
assert_eq!(string_width("\u{001B}[32m✅ Pass\u{001B}[0m"), 7);
}
#[test]
fn combining_with_full_width() {
assert_eq!(string_width("東京\u{0301}"), 4);
}
#[test]
fn double_width_with_combining() {
assert_eq!(string_width("你\u{0301}好"), 4);
}
#[test]
fn ascii_with_trailing_zwj() {
assert_eq!(string_width("A\u{200D}\u{200D}"), 1);
}
#[test]
fn leading_zwj_plus_ascii() {
assert_eq!(string_width("\u{200D}A"), 1);
}
#[test]
fn leading_zwj_plus_cjk() {
assert_eq!(string_width("\u{200D}你"), 2);
}
#[test]
fn black_medium_square() {
assert_eq!(string_width("◼"), 1);
}
#[test]
fn warning_sign() {
assert_eq!(string_width("⚠"), 1);
}
#[test]
fn check_mark() {
assert_eq!(string_width("✔"), 1);
}
#[test]
fn heart_suit() {
assert_eq!(string_width("♥"), 1);
}
#[test]
fn female_sign() {
assert_eq!(string_width("♀"), 1);
}
#[test]
fn male_sign() {
assert_eq!(string_width("♂"), 1);
}
#[test]
fn keycap_sequence_0() {
assert_eq!(string_width("0️⃣"), 2);
}
#[test]
fn keycap_sequence_9() {
assert_eq!(string_width("9️⃣"), 2);
}
#[test]
fn keycap_sequence_asterisk() {
assert_eq!(string_width("*️⃣"), 2);
}
#[test]
fn keycap_sequence_hash() {
assert_eq!(string_width("#️⃣"), 2);
}
#[test]
fn skin_tone_modifier_light() {
assert_eq!(string_width("👋🏻"), 2);
}
#[test]
fn skin_tone_modifier_dark() {
assert_eq!(string_width("👋🏿"), 2);
}
#[test]
fn couple_with_heart() {
assert_eq!(string_width("👨❤️👨"), 2);
}
#[test]
fn woman_technologist() {
assert_eq!(string_width("👩💻"), 2);
}
#[test]
fn man_health_worker() {
assert_eq!(string_width("👨⚕️"), 2);
}
#[test]
fn multiple_tabs_between_ascii() {
assert_eq!(string_width("a\t\tb"), 2);
}
#[test]
fn leading_tab_before_ascii() {
assert_eq!(string_width("\ta"), 1);
}
#[test]
fn trailing_tab_after_ascii() {
assert_eq!(string_width("a\t"), 1);
}
#[test]
fn only_tabs() {
assert_eq!(string_width("\t\t"), 0);
}
#[test]
fn complex_ansi_sequence() {
assert_eq!(
string_width("\u{001B}]8;;https://example.com\u{0007}link\u{001B}]8;;\u{0007}"),
4
);
}
#[test]
fn zero_width_no_break_space() {
assert_eq!(string_width("a\u{FEFF}b"), 2);
}
#[test]
fn arabic_with_zwnj() {
assert_eq!(string_width("ب\u{200C}ه"), 2);
}
#[test]
fn multiple_zwnj_between_ascii() {
assert_eq!(string_width("a\u{200C}\u{200C}b"), 2);
}
#[test]
fn indic_conjunct_via_zwj() {
assert_eq!(string_width("क्\u{200D}ष"), 1);
}
#[test]
fn tag_sequence() {
assert_eq!(string_width("🏴"), 2);
}
#[test]
fn prepend_plus_ascii() {
assert_eq!(string_width("\u{0600}A"), 1);
}
#[test]
fn prepend_plus_cjk() {
assert_eq!(string_width("\u{0600}你"), 2);
}
#[test]
fn prepend_plus_emoji() {
assert_eq!(string_width("\u{0600}😀"), 2);
}
#[test]
fn only_default_ignorables_tags() {
assert_eq!(string_width("\u{E0020}\u{E007F}"), 0);
}
#[test]
fn digit_with_vs16_keycap_base() {
assert_eq!(string_width("0\u{FE0F}"), 1);
}
#[test]
fn asterisk_with_vs16() {
assert_eq!(string_width("*\u{FE0F}"), 1);
}
#[test]
fn pound_with_vs16() {
assert_eq!(string_width("#\u{FE0F}"), 1);
}
#[test]
fn trademark_with_vs16() {
assert_eq!(string_width("™\u{FE0F}"), 2);
}
#[test]
fn watch_with_vs16() {
assert_eq!(string_width("⌚\u{FE0F}"), 2);
}
#[test]
fn phone_with_vs16() {
assert_eq!(string_width("☎\u{FE0F}"), 2);
}
#[test]
fn keyboard_with_vs16() {
assert_eq!(string_width("⌨\u{FE0F}"), 2);
}
#[test]
fn envelope_with_vs16() {
assert_eq!(string_width("✉\u{FE0F}"), 2);
}
#[test]
fn heart_emoji_has_emoji_presentation() {
assert_eq!(string_width("❤️"), 2);
}
#[test]
fn fire_emoji_has_emoji_presentation() {
assert_eq!(string_width("🔥"), 2);
}
#[test]
fn rocket_emoji_has_emoji_presentation() {
assert_eq!(string_width("🚀"), 2);
}
#[test]
fn star_emoji_has_emoji_presentation() {
assert_eq!(string_width("⭐"), 2);
}
#[test]
fn heart_with_vs15_text_style() {
assert_eq!(string_width("❤\u{FE0E}"), 1);
}
#[test]
fn star_with_vs15_text_style() {
assert_eq!(string_width("⭐\u{FE0E}"), 2); }
#[test]
fn flag_emoji_gb() {
assert_eq!(string_width("🇬🇧"), 2);
}
#[test]
fn flag_emoji_jp() {
assert_eq!(string_width("🇯🇵"), 2);
}
#[test]
fn watch_without_vs() {
assert_eq!(string_width("⌚"), 2); }
#[test]
fn phone_without_vs_not_emoji_presentation() {
assert_eq!(string_width("☎"), 1);
}
#[test]
fn keyboard_without_vs_not_emoji_presentation() {
assert_eq!(string_width("⌨"), 1);
}
#[test]
fn envelope_without_vs_not_emoji_presentation() {
assert_eq!(string_width("✉"), 1);
}
#[test]
fn single_code_point_with_vs15() {
assert_eq!(string_width("A\u{FE0E}"), 1);
}
#[test]
fn emoji_with_vs15_only() {
assert_eq!(string_width("⌚\u{FE0E}"), 2); }
#[test]
fn three_code_points_with_vs15_at_end() {
assert_eq!(string_width("A👋\u{FE0E}"), 3);
}
#[test]
fn rgi_emoji_face() {
assert_eq!(string_width("😊"), 2);
}
#[test]
fn rgi_emoji_hand() {
assert_eq!(string_width("✋"), 2);
}
#[test]
fn rgi_emoji_animal() {
assert_eq!(string_width("🐶"), 2);
}
#[test]
fn rgi_emoji_food() {
assert_eq!(string_width("🍕"), 2);
}
#[test]
fn rgi_emoji_flag() {
assert_eq!(string_width("🏁"), 2);
}
#[test]
fn emoji_with_combining_mark() {
assert_eq!(string_width("😀\u{0301}"), 2);
}
#[test]
fn emoji_with_zwj_and_another_emoji() {
assert_eq!(string_width("😀\u{200D}😀"), 2);
}
#[test]
fn text_character_made_emoji_with_vs16() {
assert_eq!(string_width("↔\u{FE0F}"), 2);
}
#[test]
fn text_character_kept_text_with_vs15() {
assert_eq!(string_width("↔\u{FE0E}"), 1);
}
#[test]
fn non_rgi_with_vs16() {
assert_eq!(string_width("〰\u{FE0F}"), 2);
}
#[test]
fn non_rgi_multi_scalar() {
assert_eq!(string_width("☎\u{FE0F}\u{20E3}"), 1); }
#[test]
fn hourglass_with_vs15() {
assert_eq!(string_width("⌛\u{FE0E}"), 2);
}
#[test]
fn fast_forward_with_vs15() {
assert_eq!(string_width("⏩\u{FE0E}"), 2);
}
#[test]
fn rewind_with_vs15() {
assert_eq!(string_width("⏪\u{FE0E}"), 2);
}
#[test]
fn arrow_double_up_with_vs15() {
assert_eq!(string_width("⏫\u{FE0E}"), 2);
}
#[test]
fn arrow_double_down_with_vs15() {
assert_eq!(string_width("⏬\u{FE0E}"), 2);
}
#[test]
fn alarm_clock_with_vs15() {
assert_eq!(string_width("⏰\u{FE0E}"), 2);
}
#[test]
fn hourglass_flowing_sand_with_vs15() {
assert_eq!(string_width("⏳\u{FE0E}"), 2);
}
#[test]
fn umbrella_with_rain_with_vs15() {
assert_eq!(string_width("☔\u{FE0E}"), 2);
}
#[test]
fn hot_beverage_with_vs15() {
assert_eq!(string_width("☕\u{FE0E}"), 2);
}
#[test]
fn sun_with_vs15() {
assert_eq!(string_width("☀\u{FE0E}"), 1);
}
#[test]
fn cloud_with_vs15() {
assert_eq!(string_width("☁\u{FE0E}"), 1);
}
#[test]
fn umbrella_with_vs15() {
assert_eq!(string_width("☂\u{FE0E}"), 1);
}
#[test]
fn snowman_with_vs15() {
assert_eq!(string_width("☃\u{FE0E}"), 1);
}
#[test]
fn comet_with_vs15() {
assert_eq!(string_width("☄\u{FE0E}"), 1);
}
#[test]
fn black_nib_with_vs15() {
assert_eq!(string_width("✒\u{FE0E}"), 1);
}
#[test]
fn heavy_check_mark_with_vs15() {
assert_eq!(string_width("✔\u{FE0E}"), 1);
}
#[test]
fn digit_zero_as_plain_text() {
assert_eq!(string_width("0"), 1);
}
#[test]
fn digit_one_as_plain_text() {
assert_eq!(string_width("1"), 1);
}
#[test]
fn asterisk_as_plain_text() {
assert_eq!(string_width("*"), 1);
}
#[test]
fn hash_as_plain_text() {
assert_eq!(string_width("#"), 1);
}
#[test]
fn long_ascii_string() {
let long_string = "a".repeat(1000);
assert_eq!(string_width(&long_string), 1000);
}
#[test]
fn long_full_width_string() {
let long_string = "你".repeat(500);
assert_eq!(string_width(&long_string), 1000);
}
#[test]
fn mixed_long_string() {
let long_string = "a你".repeat(500);
assert_eq!(string_width(&long_string), 1500);
}
#[test]
fn malformed_surrogate() {
assert_eq!(string_width("�"), 1); }
#[test]
fn information_source_text_variation() {
assert_eq!(string_width("\u{2139}\u{FE0E}"), 1);
}
#[test]
fn information_source_emoji_variation() {
assert_eq!(string_width("\u{2139}\u{FE0F}"), 2);
}
#[test]
fn keycap_sequence_1() {
assert_eq!(string_width("1️⃣"), 2);
}