@@ -31,7 +31,7 @@ def emoji_zwj_sequence():
3131 "\u200d " # Joiner, Category Cf, East Asian Width property 'N' -- ZERO WIDTH JOINER
3232 "\U0001f4bb " ) # Fused, Category So, East Asian Width property 'W' -- PERSONAL COMPUTER
3333 # This test adapted from https://www.unicode.org/L2/L2023/23107-terminal-suppt.pdf
34- expect_length_each = (2 , 0 , 0 , 2 )
34+ expect_length_each = (2 , 2 , 0 , 2 )
3535 expect_length_phrase = 2
3636
3737 # exercise,
@@ -49,7 +49,7 @@ def test_unfinished_zwj_sequence():
4949 phrase = ("\U0001f469 " # Base, Category So, East Asian Width property 'W' -- WOMAN
5050 "\U0001f3fb " # Modifier, Category Sk, East Asian Width property 'W' -- EMOJI MODIFIER FITZPATRICK TYPE-1-2
5151 "\u200d " ) # Joiner, Category Cf, East Asian Width property 'N' -- ZERO WIDTH JOINER
52- expect_length_each = (2 , 0 , 0 )
52+ expect_length_each = (2 , 2 , 0 )
5353 expect_length_phrase = 2
5454
5555 # exercise,
@@ -67,7 +67,7 @@ def test_non_recommended_zwj_sequence():
6767 phrase = ("\U0001f469 " # Base, Category So, East Asian Width property 'W' -- WOMAN
6868 "\U0001f3fb " # Modifier, Category Sk, East Asian Width property 'W' -- EMOJI MODIFIER FITZPATRICK TYPE-1-2
6969 "\u200d " ) # Joiner, Category Cf, East Asian Width property 'N' -- ZERO WIDTH JOINER
70- expect_length_each = (2 , 0 , 0 )
70+ expect_length_each = (2 , 2 , 0 )
7171 expect_length_phrase = 2
7272
7373 # exercise,
@@ -87,7 +87,7 @@ def test_another_emoji_zwj_sequence():
8787 "\u200D " # ZERO WIDTH JOINER
8888 "\u2640 " # FEMALE SIGN
8989 "\uFE0F " ) # VARIATION SELECTOR-16
90- expect_length_each = (1 , 0 , 0 , 1 , 0 )
90+ expect_length_each = (1 , 2 , 0 , 1 , 0 )
9191 expect_length_phrase = 2
9292
9393 # exercise,
@@ -120,7 +120,7 @@ def test_longer_emoji_zwj_sequence():
120120 "\U0001F3FD " # 'Sk', 'W' -- EMOJI MODIFIER FITZPATRICK TYPE-4
121121 ) * 2
122122 # This test adapted from https://www.unicode.org/L2/L2023/23107-terminal-suppt.pdf
123- expect_length_each = (2 , 0 , 0 , 1 , 0 , 0 , 2 , 0 , 2 , 0 ) * 2
123+ expect_length_each = (2 , 2 , 0 , 1 , 0 , 0 , 2 , 0 , 2 , 2 ) * 2
124124 expect_length_phrase = 4
125125
126126 # exercise,
@@ -191,6 +191,56 @@ def measure_all():
191191 assert len (sequences ) >= 742
192192
193193
194+ @pytest .mark .skipif (NARROW_ONLY , reason = "Test cannot verify on python 'narrow' builds" )
195+ def test_regional_indicator_single ():
196+ """Single Regional Indicator symbol is width 2."""
197+ assert wcwidth .wcwidth ('\U0001F1FA ' ) == 2
198+ assert wcwidth .wcswidth ('\U0001F1FA ' ) == 2
199+
200+
201+ @pytest .mark .skipif (NARROW_ONLY , reason = "Test cannot verify on python 'narrow' builds" )
202+ def test_regional_indicator_pair ():
203+ """Flag pair (two Regional Indicators) is width 2, not 4."""
204+ assert wcwidth .wcswidth ('\U0001F1FA \U0001F1F8 ' ) == 2
205+
206+
207+ @pytest .mark .skipif (NARROW_ONLY , reason = "Test cannot verify on python 'narrow' builds" )
208+ def test_regional_indicator_three ():
209+ """Three Regional Indicators: one pair (2) + one single (2) = 4."""
210+ assert wcwidth .wcswidth ('\U0001F1FA \U0001F1F8 \U0001F1E6 ' ) == 4
211+
212+
213+ @pytest .mark .skipif (NARROW_ONLY , reason = "Test cannot verify on python 'narrow' builds" )
214+ def test_regional_indicator_four ():
215+ """Four Regional Indicators: two pairs = 2 + 2 = 4."""
216+ assert wcwidth .wcswidth (
217+ '\U0001F1FA \U0001F1F8 \U0001F1E6 \U0001F1FA ' ) == 4
218+
219+
220+ @pytest .mark .skipif (NARROW_ONLY , reason = "Test cannot verify on python 'narrow' builds" )
221+ def test_zwj_after_non_emoji ():
222+ """ZWJ after non-emoji unconditionally consumes next character."""
223+ # This does *not* match most terminal behavior -- it is a negative test,
224+ # they fail because our library doesn't handle 'glitch' emoji as an
225+ # optimization. Non-emoji + ZWJ is undefined per Unicode UAX #29 GB11.
226+ assert wcwidth .wcswidth ('xx\u200d \U0001F384 ' ) == 2
227+ assert wcwidth .wcswidth ('a\u200d \U0001F600 ' ) == 1
228+ assert wcwidth .wcswidth ('\u4e16 \u200d \U0001F600 ' ) == 2
229+
230+
231+ @pytest .mark .skipif (NARROW_ONLY , reason = "Test cannot verify on python 'narrow' builds" )
232+ def test_fitzpatrick_standalone ():
233+ """Standalone Fitzpatrick modifier is width 2."""
234+ assert wcwidth .wcwidth ('\U0001F3FB ' ) == 2
235+ assert wcwidth .wcswidth ('\U0001F3FB ' ) == 2
236+
237+
238+ @pytest .mark .skipif (NARROW_ONLY , reason = "Test cannot verify on python 'narrow' builds" )
239+ def test_fitzpatrick_after_emoji ():
240+ """Fitzpatrick modifier after emoji base combines, total width 2."""
241+ assert wcwidth .wcswidth ('\U0001F469 \U0001F3FB ' ) == 2
242+
243+
194244def test_vs16_effect ():
195245 """Verify effect of VS-16 (always active with latest Unicode version)."""
196246 phrase = ("\u2640 " # FEMALE SIGN
0 commit comments