sistema_progs

Programas para customizar o meu entorno de traballo nos meus equipos persoais
Log | Files | Refs

test-canvas.sh (23851B)


      1 #!/bin/bash
      2 
      3 ble-import lib/core-test
      4 
      5 _ble_test_canvas_contra=
      6 if [[ -x ext/contra ]]; then
      7   _ble_test_canvas_contra=ext/contra
      8 elif [[ $(printf 'hello world' | contra test 5 2 2>/dev/null) == $' worl\nd    ' ]]; then
      9   _ble_test_canvas_contra=contra
     10 fi
     11 
     12 function ble/test:canvas/trace.contra {
     13   [[ $_ble_test_canvas_contra ]] || return 0 # skip
     14 
     15   local w=${1%%:*} h=${1#*:} esc=$2 opts=$3 test_opts=$4
     16   local expect=$(sed 's/\$$//')
     17 
     18   local ret x=0 y=0 g=0 rex termw=$w termh=$h
     19   rex=':x=([^:]+):'; [[ :$test_opts: =~ $rex ]] && ((x=BASH_REMATCH[1]))
     20   rex=':y=([^:]+):'; [[ :$test_opts: =~ $rex ]] && ((y=BASH_REMATCH[1]))
     21   rex=':termw=([^:]+):'; [[ :$test_opts: =~ $rex ]] && ((termw=BASH_REMATCH[1]))
     22   rex=':termh=([^:]+):'; [[ :$test_opts: =~ $rex ]] && ((termh=BASH_REMATCH[1]))
     23 
     24   local x0=$x y0=$y
     25   LINES=$h COLUMNS=$w ble/canvas/trace "$esc" "$opts"
     26   local out=$ret
     27 
     28   ble/string#quote-word "$esc"; local q_esc=$ret
     29   ble/string#quote-word "$opts"; local q_opts=$ret
     30   ble/test --depth=1 --display-code="trace $q_esc $q_opts" \
     31            '{ printf "\e['$((y0+1))';'$((x0+1))'H"; ble/util/put "$out";} | "$_ble_test_canvas_contra" test "$termw" "$termh"' \
     32            stdout="$expect"
     33 }
     34 
     35 #------------------------------------------------------------------------------
     36 # from lib/test-canvas.sh
     37 
     38 ble/test/start-section 'ble/canvas/trace (relative:confine:measure-bbox)' 17
     39 
     40 # test1
     41 
     42 ble/test:canvas/trace.contra 10:10 'hello world this is a flow world' relative x=3:y=3:termw=20 << EOF
     43                     $
     44                     $
     45                     $
     46    hello w          $
     47 orld this           $
     48 is a flow           $
     49 world               $
     50                     $
     51                     $
     52                     $
     53 EOF
     54 
     55 ble/test:canvas/trace.contra 20:1 '12345678901234567890hello' confine << EOF
     56 12345678901234567890$
     57 EOF
     58 
     59 ble/test:canvas/trace.contra 10:1 $'hello\nworld' confine << EOF
     60 helloworld$
     61 EOF
     62 ble/test:canvas/trace.contra 10:2 $'hello\nworld check' confine << EOF
     63 hello     $
     64 world chec$
     65 EOF
     66 
     67 # ble/test:ble/canvas/trace
     68 
     69 ble/test:canvas/trace.contra 10:6 $'hello\e[B\e[4D123' measure-bbox x=3:y=2 << EOF
     70           $
     71           $
     72    hello  $
     73     123   $
     74           $
     75           $
     76 EOF
     77 [[ $_ble_test_canvas_contra ]] &&
     78   ble/test 'echo "$x1-$x2:$y1-$y2"' stdout='3-8:2-4'
     79 
     80 ble/test:canvas/trace.contra 10:2 日本語 measure-bbox << EOF
     81 日本語    $
     82           $
     83 EOF
     84 [[ $_ble_test_canvas_contra ]] &&
     85   ble/test 'echo "$x1-$x2:$y1-$y2"' stdout='0-6:0-1'
     86 
     87 ble/test:canvas/trace.contra 10:2 $'hello\eDworld' measure-bbox << EOF
     88 hello     $
     89      world$
     90 EOF
     91 [[ $_ble_test_canvas_contra ]] &&
     92   ble/test 'echo "$x1-$x2:$y1-$y2"' stdout='0-10:0-2'
     93 
     94 ble/test:canvas/trace.contra 10:2 $'hello\eMworld' measure-bbox << EOF
     95      world$
     96 hello     $
     97 EOF
     98 [[ $_ble_test_canvas_contra ]] &&
     99   ble/test 'echo "$x1-$x2:$y1-$y2"' stdout='0-10:-1-1'
    100 
    101 (
    102   LINES=10 COLUMNS=10 _ble_term_xenl=1
    103   ble/test 'x=0 y=0; ble/canvas/trace "HelloWorld"; ret=$x,$y' ret=10,0
    104   ble/test 'x=0 y=0; ble/canvas/trace "HelloWorldH"; ret=$x,$y' ret=1,1
    105   ble/test 'x=0 y=0; ble/canvas/trace "HelloWorldHello"; ret=$x,$y' ret=5,1
    106   ble/test 'x=0 y=0; ble/canvas/trace "HelloWorldHelloWorldHello"; ret=$x,$y' ret=5,2
    107   ble/test 'x=0 y=0; ble/canvas/trace "HelloWorldHelloWorldHelloWorldHello"; ret=$x,$y' ret=5,3
    108 )
    109 
    110 #------------------------------------------------------------------------------
    111 # from test/check-trace.sh
    112 
    113 ble/test/start-section 'ble/canvas/trace (cfuncs)' 18
    114 
    115 function ble/test:canvas/check-trace-1 {
    116   local input=$1 ex=$2 ey=$3
    117   ble/canvas/trace.draw "$input"
    118   ble/test --depth=1 '((x==ex&&y==ey))'
    119 }
    120 
    121 function ble/test:canvas/check-trace {
    122   local -a DRAW_BUFF=()
    123   ble/canvas/put.draw "$_ble_term_clear"
    124   local x=0 y=0
    125 
    126   # 0-9
    127   ble/test:canvas/check-trace-1 "abc" 3 0
    128   ble/test:canvas/check-trace-1 $'\n\n\nn' 1 3
    129   ble/test:canvas/check-trace-1 $'\e[3BB' 2 6
    130   ble/test:canvas/check-trace-1 $'\e[2AA' 3 4
    131   ble/test:canvas/check-trace-1 $'\e[20CC' 24 4
    132   ble/test:canvas/check-trace-1 $'\e[8DD' 17 4
    133   ble/test:canvas/check-trace-1 $'\e[9EE' 1 13
    134   ble/test:canvas/check-trace-1 $'\e[6FF' 1 7
    135   ble/test:canvas/check-trace-1 $'\e[28GG' 28 7
    136   ble/test:canvas/check-trace-1 $'\e[II' 33 7
    137 
    138   ble/test:canvas/check-trace-1 $'\e[3ZZ' 17 7
    139   ble/test:canvas/check-trace-1 $'\eDD' 18 8
    140   ble/test:canvas/check-trace-1 $'\eMM' 19 7
    141   ble/test:canvas/check-trace-1 $'\e77\e[3;3Hexcur\e8\e[C8' 21 7
    142   ble/test:canvas/check-trace-1 $'\eEE' 1 8
    143   ble/test:canvas/check-trace-1 $'\e[10;24HH' 24 9
    144   ble/test:canvas/check-trace-1 $'\e[1;94mb\e[m' 25 9
    145 
    146   local expect=$(sed 's/\$$//' << EOF
    147 abc                                     $
    148                                         $
    149   excur                                 $
    150 n                                       $
    151   A             D      C                $
    152                                         $
    153  B                                      $
    154 F               Z M78      G    I       $
    155 E                D                      $
    156                        Hb               $
    157                                         $
    158                                         $
    159                                         $
    160 E                                       $
    161                                         $
    162 EOF
    163 )
    164   [[ $_ble_test_canvas_contra ]] &&
    165     ble/test --depth=1 \
    166              'ble/canvas/flush.draw | $_ble_test_canvas_contra test 40 15' \
    167              stdout="$expect"
    168 }
    169 ble/test:canvas/check-trace
    170 
    171 #------------------------------------------------------------------------------
    172 # test-trace.sh
    173 
    174 ble/test/start-section 'ble/canvas/trace (justify)' 30
    175 
    176 ble/test:canvas/trace.contra 30:1 'a b c' justify << EOF
    177 a             b              c$
    178 EOF
    179 ble/test:canvas/trace.contra 30:1 ' center ' justify << EOF
    180             center            $
    181 EOF
    182 ble/test:canvas/trace.contra 30:1 ' right-aligned' justify << EOF
    183                  right-aligned$
    184 EOF
    185 ble/test:canvas/trace.contra 30:1 'left-aligned' justify << EOF
    186 left-aligned                  $
    187 EOF
    188 ble/test:canvas/trace.contra 30:1 ' 日本語' justify << EOF
    189                         日本語$
    190 EOF
    191 ble/test:canvas/trace.contra 30:1 'a b c d e f' justify << EOF
    192 a    b     c     d     e     f$
    193 EOF
    194 ble/test:canvas/trace.contra 30:2 $'hello center world\na b c d e f' justify << EOF
    195 hello       center       world$
    196 a    b     c     d     e     f$
    197 EOF
    198 ble/test:canvas/trace.contra 30:3 'A brown fox jumped over the lazy dog. A brown fox jumped over the lazy dog.' justify << EOF
    199 A brown fox jumped over the la$
    200 zy dog. A brown fox jumped ove$
    201 r      the      lazy      dog.$
    202 EOF
    203 
    204 # ' ' による分割点は最低幅1を保持しつつ空白の分配が均等に行われるかのテスト。
    205 ble/test:canvas/trace.contra 30:2 $'hello blesh world\rHELLO WORLD\nhello world HELLO BLESH WORLD' justify=$' \r' << EOF
    206 hello blesh  worldHELLO  WORLD$
    207 hello world HELLO BLESH  WORLD$
    208 EOF
    209 
    210 # justify & measure-bbox
    211 COLUMNS=10 LINES=10 x=3 y=2 ble/canvas/trace $'a b c\n' justify:measure-bbox
    212 # ble/string#quote-word "$ret"
    213 # ble/util/print "ret=$ret"
    214 ble/test 'echo "$x1,$y1:$x2,$y2"' stdout:'0,2:10,4'
    215 COLUMNS=10 LINES=10 x=3 y=2 ble/canvas/trace $' hello ' justify:measure-bbox
    216 ble/test 'echo "$x1,$y1:$x2,$y2"' stdout:'2,2:7,3'
    217 
    218 # フィールドの x1:x2 がそのまま出力すると画面外に出るという時に正しくシフトでき
    219 # ているか。
    220 ble/test:canvas/trace.contra 30:1 $'\e[3Dhello\rblesh\rworld\e[1D' justify=$'\r' x=5 << EOF
    221 hello      blesh         world$
    222 EOF
    223 
    224 # justify x clip のテスト
    225 ble/test:canvas/trace.contra \
    226   30:5 $'hello world\nfoo bar buzz\nA quick brown fox\nLorem ipsum\n1 1 2 3 5 8 13 21 34 55 89 144' \
    227   justify:clip=2,1+24,5 << EOF
    228 o          bar                $
    229     quick     brown           $
    230 rem                    i      $
    231 1 2 3 5 8 13 21 34 55 89      $
    232                               $
    233 EOF
    234 
    235 ble/test:canvas/trace.contra 30:1 $'hello1 world long long word quick brown' justify:confine << EOF
    236 hello1 world long long word qu$
    237 EOF
    238 
    239 ble/test:canvas/trace.contra 30:1 $'hello2 world long long word quick brown' justify:truncate << EOF
    240 hello2 world long long word qu$
    241 EOF
    242 
    243 ble/test:canvas/trace.contra 60:2 $'-- INSERT --\r/home/murase\r2021-01-01 00:00:00' justify << EOF
    244 --           INSERT           2021-01-01            00:00:00$
    245                                                             $
    246 EOF
    247 
    248 ble/test:canvas/trace.contra 30:3 $'hello\r\vquick check\v\rtest \e[2Afoo\r\vbar' justify:truncate << EOF
    249 hello                      foo$
    250 quick         check        bar$
    251               test            $
    252 EOF
    253 
    254 ble/test:canvas/trace.contra 30:3 $'hello\n2021-01-01\nA' right:measure-bbox:measure-gbox << EOF
    255                          hello$
    256                     2021-01-01$
    257                              A$
    258 EOF
    259 if [[ $_ble_test_canvas_contra ]]; then
    260   ble/test 'echo "bbox:$x1,$y1-$x2,$y2"' stdout='bbox:0,0-30,3'
    261   ble/test 'echo "gbox:$gx1,$gy1-$gx2,$gy2"' stdout='gbox:20,0-30,3'
    262 fi
    263 
    264 ble/test:canvas/trace.contra 30:3 $'hello\n2021-01-01\nA' center:measure-bbox:measure-gbox << EOF
    265             hello             $
    266           2021-01-01          $
    267               A               $
    268 EOF
    269 if [[ $_ble_test_canvas_contra ]]; then
    270   ble/test 'echo "bbox:$x1,$y1-$x2,$y2"' stdout='bbox:0,0-20,3'
    271   ble/test 'echo "gbox:$gx1,$gy1-$gx2,$gy2"' stdout='gbox:10,0-20,3'
    272 fi
    273 
    274 ble/test:canvas/trace.contra 10:1 $'xyz\e[4Daxyz' relative:measure-bbox x=3 << EOF
    275   axyz    $
    276 EOF
    277 if [[ $_ble_test_canvas_contra ]]; then
    278   ble/test 'echo "bbox:$x1,$y1-$x2,$y2"' stdout='bbox:2,0-6,1'
    279 fi
    280 
    281 
    282 # regression tests for https://github.com/akinomyoga/ble.sh/issues/239
    283 ble/test:canvas/trace.contra 30:3 $'\n2022-11-28' right:measure-bbox:measure-gbox << EOF
    284                               $
    285                     2022-11-28$
    286                               $
    287 EOF
    288 if [[ $_ble_test_canvas_contra ]]; then
    289   ble/test 'echo "bbox:$x1,$y1-$x2,$y2"' stdout='bbox:0,0-30,2'
    290   ble/test 'echo "gbox:$gx1,$gy1-$gx2,$gy2"' stdout='gbox:20,1-30,2'
    291 fi
    292 ble/test:canvas/trace.contra 30:3 $'\n\n2022-11-28' right:measure-bbox:measure-gbox << EOF
    293                               $
    294                               $
    295                     2022-11-28$
    296 EOF
    297 if [[ $_ble_test_canvas_contra ]]; then
    298   ble/test 'echo "bbox:$x1,$y1-$x2,$y2"' stdout='bbox:0,0-30,3'
    299   ble/test 'echo "gbox:$gx1,$gy1-$gx2,$gy2"' stdout='gbox:20,2-30,3'
    300 fi
    301 
    302 #------------------------------------------------------------------------------
    303 # trace-text
    304 
    305 ble/test/start-section 'ble/canvas/trace-text' 11
    306 
    307 (
    308   sgr0= sgr1=
    309 
    310   # truncate
    311   lines=1 cols=10 _ble_term_xenl=1 x=0 y=0
    312   ble/test 'ble/canvas/trace-text "Hello World";ret="$x,$y,$ret"' ret='10,0,Hello Worl'
    313   lines=1 cols=10 _ble_term_xenl= x=0 y=0
    314   ble/test 'ble/canvas/trace-text "Hello World";ret="$x,$y,$ret"' ret='9,0,Hello Wor'
    315   lines=1 cols=10 _ble_term_xenl=1 x=3 y=0
    316   ble/test 'ble/canvas/trace-text "Hello World";ret="$x,$y,$ret"' ret='10,0,Hello W'
    317 
    318   # 折返し
    319   lines=3 cols=10 _ble_term_xenl=1 x=3 y=0
    320   ble/test 'ble/canvas/trace-text "Hello Bash World";ret="$x,$y,$ret"' ret='9,1,Hello Bash World'
    321 
    322   # 全角文字の折返し (nonewline on/off)
    323   lines=3 cols=10 _ble_term_xenl=1 x=3 y=0
    324   ble/test 'ble/canvas/trace-text "これは日本語の文章";ret="$x,$y,$ret"' ret=$'2,2,これは\n日本語の文章'
    325   lines=3 cols=10 _ble_term_xenl=1 x=3 y=0
    326   ble/test 'ble/canvas/trace-text "これは日本語の文章" nonewline;ret="$x,$y,$ret"' ret='2,2,これは 日本語の文章'
    327 
    328   # 行末での改行 (nonewline)
    329   lines=3 cols=10 _ble_term_xenl=1 x=0 y=0
    330   ble/test 'ble/canvas/trace-text "これは日本";ret="$x,$y,$ret"' ret=$'0,1,これは日本\n'
    331   lines=3 cols=10 _ble_term_xenl=0 x=0 y=0
    332   ble/test 'ble/canvas/trace-text "これは日本";ret="$x,$y,$ret"' ret=$'0,1,これは日本'
    333   lines=3 cols=10 _ble_term_xenl=1 x=0 y=0
    334   ble/test 'ble/canvas/trace-text "これは日本" nonewline;ret="$x,$y,$ret"' ret=$'10,0,これは日本'
    335   lines=3 cols=10 _ble_term_xenl=0 x=0 y=0
    336   ble/test 'ble/canvas/trace-text "これは日本" nonewline;ret="$x,$y,$ret"' ret=$'0,1,これは日本'
    337 
    338   # 改行は ^J と表示
    339   lines=1 cols=12 _ble_term_xenl=1 x=0 y=0
    340   ble/test $'ble/canvas/trace-text "あ\nい\nう" external-sgr;ret="$x,$y,$ret"' ret=$'10,0,あ^Jい^Jう'
    341 )
    342 
    343 ble/test/end-section
    344 
    345 #------------------------------------------------------------------------------
    346 
    347 ble/test/start-section 'ble/textmap#update' 5
    348 
    349 function ble/test:canvas/textmap {
    350   local text=$1
    351   x=0 y=0
    352   _ble_textmap_length=
    353   _ble_textmap_pos=()
    354   _ble_textmap_glyph=()
    355   _ble_textmap_ichg=()
    356   _ble_textmap_dbeg=0
    357   _ble_textmap_dend=${#text}
    358   _ble_textmap_dend0=0
    359   ble/textmap#update "$text"
    360   [[ :$opts: == *:stderr:* ]] &&
    361     declare -p _ble_textmap_pos >&2
    362 }
    363 (
    364   ble/test:canvas/textmap $'hello\nworld\ncheck'
    365   ble/test 'ble/textmap#getxy.out 5; ret=$x,$y' ret='5,0'
    366   ble/test 'ble/textmap#getxy.out 6; ret=$x,$y' ret='0,1'
    367   ble/test 'ble/textmap#getxy.out 11; ret=$x,$y' ret='5,1'
    368   ble/test 'ble/textmap#getxy.out 12; ret=$x,$y' ret='0,2'
    369   ble/test 'ble/textmap#getxy.out 17; ret=$x,$y' ret='5,2'
    370 )
    371 
    372 
    373 #------------------------------------------------------------------------------
    374 # Grapheme_Cluster_Break
    375 
    376 ble/test/start-section 'ble/unicode/GraphemeCluster/c2break' 77
    377 
    378 if (LC_ALL=C.UTF-8 builtin eval "s=\$'\\U1F6D1'"; ((${#s}==2))) 2>/dev/null; then
    379   function ble/test:canvas/GraphemeCluster/.locate-code-point {
    380     local s=$1 k=$2 len=${#1} i=0 shift
    381     while ((k-->=1&&i<len)); do
    382       ble/unicode/GraphemeCluster/s2break-right "$s" "$i" shift
    383       ((i+=shift))
    384     done
    385     ret=$i
    386   }
    387 else
    388   function ble/test:canvas/GraphemeCluster/.locate-code-point {
    389     ret=$2
    390   }
    391 fi
    392 
    393 (
    394   # Disable terminal-specific tailored grapheme cluster for testing purpose.
    395   _ble_unicode_GraphemeClusterBreak_custom=()
    396 
    397   bleopt emoji_opts=ri:tpvs:epvs:zwj
    398   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x20))"' ret="$_ble_unicode_GraphemeClusterBreak_Other"
    399   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x41))"' ret="$_ble_unicode_GraphemeClusterBreak_Other"
    400   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x7E))"' ret="$_ble_unicode_GraphemeClusterBreak_Other"
    401   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x00))"' ret="$_ble_unicode_GraphemeClusterBreak_Control"
    402   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x0d))"' ret="$_ble_unicode_GraphemeClusterBreak_Control"
    403   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x0a))"' ret="$_ble_unicode_GraphemeClusterBreak_Control"
    404   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x1F))"' ret="$_ble_unicode_GraphemeClusterBreak_Control"
    405   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x80))"' ret="$_ble_unicode_GraphemeClusterBreak_Control"
    406   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x9F))"' ret="$_ble_unicode_GraphemeClusterBreak_Control"
    407   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x0308))"' ret="$_ble_unicode_GraphemeClusterBreak_InCB_Extend"
    408   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x200C))"' ret="$_ble_unicode_GraphemeClusterBreak_Extend" # ZWNJ
    409   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x200D))"' ret="$_ble_unicode_GraphemeClusterBreak_ZWJ"    # ZWJ
    410   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x0600))"' ret="$_ble_unicode_GraphemeClusterBreak_Prepend"
    411   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x0605))"' ret="$_ble_unicode_GraphemeClusterBreak_Prepend"
    412   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x06DD))"' ret="$_ble_unicode_GraphemeClusterBreak_Prepend"
    413   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x110BD))"' ret="$_ble_unicode_GraphemeClusterBreak_Prepend"
    414   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0xE33))"' ret="$_ble_unicode_GraphemeClusterBreak_SpacingMark" # THAI CHARACTER SARA AM
    415   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0xEB3))"' ret="$_ble_unicode_GraphemeClusterBreak_SpacingMark" # LAO VOWEL SIGN AM
    416   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x1100))"' ret="$_ble_unicode_GraphemeClusterBreak_L"
    417   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x115F))"' ret="$_ble_unicode_GraphemeClusterBreak_L"
    418   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0xA960))"' ret="$_ble_unicode_GraphemeClusterBreak_L"
    419   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0xA97C))"' ret="$_ble_unicode_GraphemeClusterBreak_L"
    420   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x1160))"' ret="$_ble_unicode_GraphemeClusterBreak_V"
    421   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x11A2))"' ret="$_ble_unicode_GraphemeClusterBreak_V"
    422   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0xD7B0))"' ret="$_ble_unicode_GraphemeClusterBreak_V"
    423   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0xD7C6))"' ret="$_ble_unicode_GraphemeClusterBreak_V"
    424   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x11A8))"' ret="$_ble_unicode_GraphemeClusterBreak_T"
    425   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x11F9))"' ret="$_ble_unicode_GraphemeClusterBreak_T"
    426   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0xD7CB))"' ret="$_ble_unicode_GraphemeClusterBreak_T"
    427   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0xD7FB))"' ret="$_ble_unicode_GraphemeClusterBreak_T"
    428   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0xAC00))"' ret="$_ble_unicode_GraphemeClusterBreak_LV"
    429   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0xAC1C))"' ret="$_ble_unicode_GraphemeClusterBreak_LV"
    430   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0xAC38))"' ret="$_ble_unicode_GraphemeClusterBreak_LV"
    431   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0xAC01))"' ret="$_ble_unicode_GraphemeClusterBreak_LVT"
    432   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0xAC04))"' ret="$_ble_unicode_GraphemeClusterBreak_LVT"
    433   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x1F1E6))"' ret="$_ble_unicode_GraphemeClusterBreak_Regional_Indicator" # RI A
    434   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x1F1FF))"' ret="$_ble_unicode_GraphemeClusterBreak_Regional_Indicator" # RI Z
    435   ble/test 'ble/unicode/GraphemeCluster/c2break "$((0x1F32B))"' ret="$_ble_unicode_GraphemeClusterBreak_Pictographic"
    436 
    437   if ((_ble_bash>=40200)); then
    438     function ble/test:canvas/GraphemeClusterBreak/find-previous-boundary {
    439       local str=$1 index=$2 ans=$3 ret=
    440       ble/test:canvas/GraphemeCluster/.locate-code-point "$str." "$index"; index=$ret
    441       ble/test:canvas/GraphemeCluster/.locate-code-point "$str" "$ans"; ans=$ret
    442       ble/test "ble/unicode/GraphemeCluster/find-previous-boundary '$str' $index" ret="$ans"
    443     }
    444 
    445     # Regional_Indicator
    446     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'\U1F1E6\U1F1FF\U1F1E6\U1F1FF' 1 0
    447     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'\U1F1E6\U1F1FF\U1F1E6\U1F1FF' 2 0
    448     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'\U1F1E6\U1F1FF\U1F1E6\U1F1FF' 3 2
    449     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'\U1F1E6\U1F1FF\U1F1E6\U1F1FF' 4 2
    450     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'\U1F1E6\U1F1FF\U1F1E6\U1F1FF' 5 4
    451     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'A\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6' 2 1
    452     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'B\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6' 3 1
    453     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'C\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6' 4 3
    454     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'D\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6' 5 3
    455     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'E\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6' 6 5
    456     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'F\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6' 7 6
    457     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'G\U1F1E6\U1F1FF\U1F1E6\U1F1FF\U1F1E6Z' 7 6
    458     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'H\u600\u600\u600\u600\U1F1E6\U1F1FF' 7 1
    459     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'I\u600\u600\u600\u600\U1F1E6\U1F1FF' 6 1
    460     bleopt_grapheme_cluster=legacy ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'J\u600\u600\u600\u600\U1F1E6\U1F1FF' 7 5
    461     bleopt_grapheme_cluster=legacy ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'K\u600\u600\u600\u600\U1F1E6\U1F1FF' 6 5
    462 
    463     # ZWJ sequence
    464     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'\U1F636\U200D\U1F32B\UFE0F' 1 0
    465     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'\U1F636\U200D\U1F32B\UFE0F' 2 0
    466     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'\U1F636\U200D\U1F32B\UFE0F' 3 0
    467     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'\U1F636\U200D\U1F32B\UFE0F' 4 0
    468     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'\U1F636\U200D\U1F32B\UFE0F' 5 4
    469     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'a\U1F636\U200D\U1F32B\UFE0F' 2 1
    470     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'b\U1F636\U200D\U1F32B\UFE0F' 3 1
    471     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'c\U1F636\U200D\U1F32B\UFE0F' 4 1
    472     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'d\U1F636\U200D\U1F32B\UFE0F' 5 1
    473     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'e\U1F636\U200D\U1F32B\UFE0F' 6 5
    474     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'f\U200D\U1F32B\UFE0F' 2 0
    475     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'g\U200D\U1F32B\UFE0F' 3 2
    476     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'h\U200D\U1F32B\UFE0F' 4 2
    477     ble/test:canvas/GraphemeClusterBreak/find-previous-boundary $'i\U200D\U1F32B\UFE0F' 5 4
    478 
    479     ble/test "ble/test:canvas/textmap \$'@@'                   stderr; ble/textmap#get-index-at -v ret 1 0" ret=1
    480     ble/test "ble/test:canvas/textmap \$'@\u0308@'             stderr; ble/textmap#get-index-at -v ret 1 0" ret=2
    481     ble/test "ble/test:canvas/textmap \$'@\u0308\u0308@'       stderr; ble/textmap#get-index-at -v ret 1 0" ret=3
    482     ble/test "ble/test:canvas/textmap \$'@\u0308\u0308\u0308@' stderr; ble/textmap#get-index-at -v ret 1 0" ret=4
    483 
    484     # s2break-{right,left}
    485     ble/test 'ble/util/is-unicode-output'
    486     c1=$'\uFE0F'
    487     ble/test code:'code=; ble/unicode/GraphemeCluster/s2break-right "$c1" 0 code; ret=$code' ret="$((0xFE0F))"
    488     ble/test code:'code=; ble/unicode/GraphemeCluster/s2break-left "$c1" "${#c1}" code; ret=$code' ret="$((0xFE0F))"
    489     c2=$'\U1F6D1'
    490     ble/test code:'code=; ble/unicode/GraphemeCluster/s2break-right "$c2" 0 code; ret=$code' ret="$((0x1F6D1))"
    491     ble/test code:'code=; ble/unicode/GraphemeCluster/s2break-left "$c2" "${#c2}" code; ret=$code' ret="$((0x1F6D1))"
    492   fi
    493 )
    494 
    495 ble/test/start-section 'ble/unicode/GraphemeCluster/c2break (GraphemeBreakTest.txt)' 6244
    496 (
    497   # Disable terminal-specific tailored grapheme cluster for testing purpose.
    498   _ble_unicode_c2w_version=17 # Test cases contain 15.1.0 features
    499   _ble_unicode_GraphemeClusterBreak_custom=()
    500 
    501   bleopt emoji_opts=ri:tpvs:epvs:zwj
    502   tests_cases=(
    503 #%< test-canvas.GraphemeClusterTest.sh
    504   )
    505 
    506   function ble/test:canvas/GraphemeClusterBreak/find-previous-boundary {
    507     local ans=${1%%:*} str=${1#*:}
    508     builtin eval "local s=\$'$str'"
    509     ble/string#split ans , "$ans"
    510     local k=0 b=0
    511     for k in "${!ans[@]}"; do
    512       ble/test:canvas/GraphemeCluster/.locate-code-point "$s." "$((k+1))"; local i=$ret
    513       ble/test:canvas/GraphemeCluster/.locate-code-point "$s" "${ans[k]}"; local a=$ret
    514       ble/test "ble/unicode/GraphemeCluster/find-previous-boundary \$'$str' $i" ret="$a"
    515       if ((a>b)); then
    516         local ret= c= w= cs= extend=
    517         ble/test "ble/unicode/GraphemeCluster/match \$'$str' $b && ((ret=b+1+extend))" ret="$a"
    518         ((b=a))
    519       fi
    520     done
    521   }
    522 
    523   if ((_ble_bash>=40200)); then
    524     for spec in "${tests_cases[@]}"; do
    525       ble/test:canvas/GraphemeClusterBreak/find-previous-boundary "$spec"
    526     done
    527   fi
    528 )
    529 
    530 ble/test/end-section