1// +build !windows,!js 2 3package runewidth 4 5import ( 6 "os" 7 "sort" 8 "testing" 9) 10 11var _ sort.Interface = (*table)(nil) 12 13func init() { 14 os.Setenv("RUNEWIDTH_EASTASIAN", "") 15} 16 17func (t table) Len() int { 18 return len(t) 19} 20 21func (t table) Less(i, j int) bool { 22 return t[i].first < t[j].first 23} 24 25func (t *table) Swap(i, j int) { 26 (*t)[i], (*t)[j] = (*t)[j], (*t)[i] 27} 28 29var tables = []table{ 30 private, 31 nonprint, 32 combining, 33 doublewidth, 34 ambiguous, 35 emoji, 36 notassigned, 37 neutral, 38} 39 40func TestSorted(t *testing.T) { 41 for _, tbl := range tables { 42 if !sort.IsSorted(&tbl) { 43 t.Errorf("not sorted") 44 } 45 } 46} 47 48var runewidthtests = []struct { 49 in rune 50 out int 51 eaout int 52}{ 53 {'世', 2, 2}, 54 {'界', 2, 2}, 55 {'セ', 1, 1}, 56 {'カ', 1, 1}, 57 {'イ', 1, 1}, 58 {'☆', 1, 2}, // double width in ambiguous 59 {'\x00', 0, 0}, 60 {'\x01', 0, 0}, 61 {'\u0300', 0, 0}, 62 {'\u2028', 0, 0}, 63 {'\u2029', 0, 0}, 64} 65 66func TestRuneWidth(t *testing.T) { 67 c := NewCondition() 68 c.EastAsianWidth = false 69 for _, tt := range runewidthtests { 70 if out := c.RuneWidth(tt.in); out != tt.out { 71 t.Errorf("RuneWidth(%q) = %d, want %d", tt.in, out, tt.out) 72 } 73 } 74 c.EastAsianWidth = true 75 for _, tt := range runewidthtests { 76 if out := c.RuneWidth(tt.in); out != tt.eaout { 77 t.Errorf("RuneWidth(%q) = %d, want %d", tt.in, out, tt.eaout) 78 } 79 } 80} 81 82var isambiguouswidthtests = []struct { 83 in rune 84 out bool 85}{ 86 {'世', false}, 87 {'■', true}, 88 {'界', false}, 89 {'○', true}, 90 {'㈱', false}, 91 {'①', true}, 92 {'②', true}, 93 {'③', true}, 94 {'④', true}, 95 {'⑤', true}, 96 {'⑥', true}, 97 {'⑦', true}, 98 {'⑧', true}, 99 {'⑨', true}, 100 {'⑩', true}, 101 {'⑪', true}, 102 {'⑫', true}, 103 {'⑬', true}, 104 {'⑭', true}, 105 {'⑮', true}, 106 {'⑯', true}, 107 {'⑰', true}, 108 {'⑱', true}, 109 {'⑲', true}, 110 {'⑳', true}, 111 {'☆', true}, 112} 113 114func TestIsAmbiguousWidth(t *testing.T) { 115 for _, tt := range isambiguouswidthtests { 116 if out := IsAmbiguousWidth(tt.in); out != tt.out { 117 t.Errorf("IsAmbiguousWidth(%q) = %v, want %v", tt.in, out, tt.out) 118 } 119 } 120} 121 122var stringwidthtests = []struct { 123 in string 124 out int 125 eaout int 126}{ 127 {"■㈱の世界①", 10, 12}, 128 {"スター☆", 7, 8}, 129 {"つのだ☆HIRO", 11, 12}, 130} 131 132func TestStringWidth(t *testing.T) { 133 c := NewCondition() 134 c.EastAsianWidth = false 135 for _, tt := range stringwidthtests { 136 if out := c.StringWidth(tt.in); out != tt.out { 137 t.Errorf("StringWidth(%q) = %d, want %d", tt.in, out, tt.out) 138 } 139 } 140 c.EastAsianWidth = true 141 for _, tt := range stringwidthtests { 142 if out := c.StringWidth(tt.in); out != tt.eaout { 143 t.Errorf("StringWidth(%q) = %d, want %d", tt.in, out, tt.eaout) 144 } 145 } 146} 147 148func TestStringWidthInvalid(t *testing.T) { 149 s := "こんにちわ\x00世界" 150 if out := StringWidth(s); out != 14 { 151 t.Errorf("StringWidth(%q) = %d, want %d", s, out, 14) 152 } 153} 154 155func TestTruncateSmaller(t *testing.T) { 156 s := "あいうえお" 157 expected := "あいうえお" 158 159 if out := Truncate(s, 10, "..."); out != expected { 160 t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) 161 } 162} 163 164func TestTruncate(t *testing.T) { 165 s := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおおお" 166 expected := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおお..." 167 out := Truncate(s, 80, "...") 168 if out != expected { 169 t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) 170 } 171 width := StringWidth(out) 172 if width != 79 { 173 t.Errorf("width of Truncate(%q) should be %d, but %d", s, 79, width) 174 } 175} 176 177func TestTruncateFit(t *testing.T) { 178 s := "aあいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおおお" 179 expected := "aあいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおお..." 180 181 out := Truncate(s, 80, "...") 182 if out != expected { 183 t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) 184 } 185 width := StringWidth(out) 186 if width != 80 { 187 t.Errorf("width of Truncate(%q) should be %d, but %d", s, 80, width) 188 } 189} 190 191func TestTruncateJustFit(t *testing.T) { 192 s := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおお" 193 expected := "あいうえおあいうえおえおおおおおおおおおおおおおおおおおおおおおおおおおおおおお" 194 195 out := Truncate(s, 80, "...") 196 if out != expected { 197 t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) 198 } 199 width := StringWidth(out) 200 if width != 80 { 201 t.Errorf("width of Truncate(%q) should be %d, but %d", s, 80, width) 202 } 203} 204 205func TestWrap(t *testing.T) { 206 s := `東京特許許可局局長はよく柿喰う客だ/東京特許許可局局長はよく柿喰う客だ 207123456789012345678901234567890 208 209END` 210 expected := `東京特許許可局局長はよく柿喰う 211客だ/東京特許許可局局長はよく 212柿喰う客だ 213123456789012345678901234567890 214 215END` 216 217 if out := Wrap(s, 30); out != expected { 218 t.Errorf("Wrap(%q) = %q, want %q", s, out, expected) 219 } 220} 221 222func TestTruncateNoNeeded(t *testing.T) { 223 s := "あいうえおあい" 224 expected := "あいうえおあい" 225 226 if out := Truncate(s, 80, "..."); out != expected { 227 t.Errorf("Truncate(%q) = %q, want %q", s, out, expected) 228 } 229} 230 231var isneutralwidthtests = []struct { 232 in rune 233 out bool 234}{ 235 {'→', false}, 236 {'┊', false}, 237 {'┈', false}, 238 {'~', false}, 239 {'└', false}, 240 {'⣀', true}, 241 {'⣀', true}, 242} 243 244func TestIsNeutralWidth(t *testing.T) { 245 for _, tt := range isneutralwidthtests { 246 if out := IsNeutralWidth(tt.in); out != tt.out { 247 t.Errorf("IsNeutralWidth(%q) = %v, want %v", tt.in, out, tt.out) 248 } 249 } 250} 251 252func TestFillLeft(t *testing.T) { 253 s := "あxいうえお" 254 expected := " あxいうえお" 255 256 if out := FillLeft(s, 15); out != expected { 257 t.Errorf("FillLeft(%q) = %q, want %q", s, out, expected) 258 } 259} 260 261func TestFillLeftFit(t *testing.T) { 262 s := "あいうえお" 263 expected := "あいうえお" 264 265 if out := FillLeft(s, 10); out != expected { 266 t.Errorf("FillLeft(%q) = %q, want %q", s, out, expected) 267 } 268} 269 270func TestFillRight(t *testing.T) { 271 s := "あxいうえお" 272 expected := "あxいうえお " 273 274 if out := FillRight(s, 15); out != expected { 275 t.Errorf("FillRight(%q) = %q, want %q", s, out, expected) 276 } 277} 278 279func TestFillRightFit(t *testing.T) { 280 s := "あいうえお" 281 expected := "あいうえお" 282 283 if out := FillRight(s, 10); out != expected { 284 t.Errorf("FillRight(%q) = %q, want %q", s, out, expected) 285 } 286} 287