github.com/jmigpin/editor@v1.6.0/util/drawutil/drawer4/drawer_test.go (about) 1 package drawer4 2 3 import ( 4 "fmt" 5 "image" 6 "image/color" 7 "image/draw" 8 "image/png" 9 "os" 10 "path/filepath" 11 "testing" 12 13 "github.com/golang/freetype/truetype" 14 "github.com/jmigpin/editor/util/fontutil" 15 "github.com/jmigpin/editor/util/iout/iorw" 16 "golang.org/x/image/colornames" 17 ) 18 19 //godebug:annotatepackage 20 21 func init() { 22 useSpaceForMargin = true 23 } 24 25 func TestEmpty(t *testing.T) { 26 d := New() 27 d.SetFontFace(fontutil.DefaultFontFace()) 28 d.SetBounds(image.Rect(0, 0, 100, 100)) 29 30 s := "" 31 r := iorw.NewStringReaderAt(s) 32 d.SetReader(r) 33 34 w := d.wlineStartIndex(true, 10, 0, nil) 35 if w != 0 { 36 t.Fatal() 37 } 38 } 39 40 func TestNLinesStartIndex1(t *testing.T) { 41 d := New() 42 d.SetFontFace(fontutil.DefaultFontFace()) 43 d.SetBounds(image.Rect(0, 0, 100, 100)) 44 45 s := "111\n222\n333" 46 r := iorw.NewStringReaderAt(s) 47 d.SetReader(r) 48 pos := r.Max() 49 d.SetRuneOffset(pos) 50 w := d.iters.lineStart.lineStartIndex(pos, 0) 51 if w != 8 { 52 t.Fatal() 53 } 54 w = d.iters.lineStart.lineStartIndex(pos, 1) 55 if w != 4 { 56 t.Fatal() 57 } 58 w = d.iters.lineStart.lineStartIndex(pos, 2) 59 if w != 0 { 60 t.Fatal() 61 } 62 w = d.iters.lineStart.lineStartIndex(pos, 100) 63 if w != 0 { 64 t.Fatal() 65 } 66 } 67 68 //---------- 69 70 func TestImg01(t *testing.T) { 71 d, img := newTestDrawer() 72 73 s := "11111\n22222\n33333\n44444" 74 r := iorw.NewStringReaderAt(s) 75 d.SetReader(r) 76 77 d.Draw(img) 78 cmpResult(t, img, "img01") 79 } 80 81 func TestImg01bDrawFullLineAtEndOfLineOffset(t *testing.T) { 82 d, img := newTestDrawer() 83 84 s := "11111\n22222\n33333\n44444" 85 r := iorw.NewStringReaderAt(s) 86 d.SetReader(r) 87 88 d.SetRuneOffset(5) 89 90 d.Draw(img) 91 cmpResult(t, img, "img01b") 92 } 93 94 func TestImg02WrapLine(t *testing.T) { 95 d, img := newTestDrawer() 96 97 s := "111111111\n22222\n33333\n44444" 98 r := iorw.NewStringReaderAt(s) 99 d.SetReader(r) 100 101 d.Draw(img) 102 cmpResult(t, img, "img02") 103 } 104 105 func TestImg03Ident(t *testing.T) { 106 d, img := newTestDrawer() 107 108 s := " 11111111111\n22222\n33333\n44444" 109 r := iorw.NewStringReaderAt(s) 110 d.SetReader(r) 111 112 d.Draw(img) 113 cmpResult(t, img, "img03") 114 } 115 116 func TestImg04Offset1(t *testing.T) { 117 d, img := newTestDrawer() 118 119 s := " 111111111111\n22222\n33333\n44444" 120 r := iorw.NewStringReaderAt(s) 121 d.SetReader(r) 122 d.SetRuneOffset(8) 123 124 d.Draw(img) 125 cmpResult(t, img, "img04") 126 } 127 128 func TestImg04bOffset2(t *testing.T) { 129 d, img := newTestDrawer() 130 131 s := " 1111111\n22222\n33333\n44444" 132 r := iorw.NewStringReaderAt(s) 133 d.SetReader(r) 134 d.SetRuneOffset(8) 135 136 d.Draw(img) 137 cmpResult(t, img, "img04b") 138 } 139 140 func TestImg05RunePerLine(t *testing.T) { 141 rect := image.Rect(0, 0, 14, 100) 142 d, img := newTestDrawerRect(rect) 143 144 s := "WWW" 145 r := iorw.NewStringReaderAt(s) 146 d.SetReader(r) 147 148 d.Draw(img) 149 cmpResult(t, img, "img05") 150 } 151 152 func TestImg06Scroll1(t *testing.T) { 153 d, img := newTestDrawer() 154 155 s := "111111\n22222\n33333\n44444" 156 r := iorw.NewStringReaderAt(s) 157 d.SetReader(r) 158 159 sy := d.scrollSizeYDown(2) 160 d.SetScrollOffset(image.Point{0, sy}) 161 162 d.Draw(img) 163 cmpResult(t, img, "img06") 164 } 165 166 func TestImg07Scroll2(t *testing.T) { 167 d, img := newTestDrawer() 168 169 s := " 11111111111\n22222\n33333\n44444" 170 r := iorw.NewStringReaderAt(s) 171 d.SetReader(r) 172 173 sy := d.scrollSizeYDown(1) 174 d.SetRuneOffset(sy) 175 176 sy = d.scrollSizeYDown(1) // 2nd line 177 d.SetRuneOffset(sy) 178 179 d.Draw(img) 180 cmpResult(t, img, "img07") 181 } 182 183 func TestImg08Scroll3(t *testing.T) { 184 d, img := newTestDrawer() 185 186 s := " 11111111111\n22222\n33333\n44444" 187 r := iorw.NewStringReaderAt(s) 188 d.SetReader(r) 189 190 d.SetRuneOffset(15) 191 192 sy := d.scrollSizeYUp(1) 193 d.SetRuneOffset(sy) 194 195 sy = d.scrollSizeYUp(1) // 2nd line 196 d.SetRuneOffset(sy) 197 198 d.Draw(img) 199 cmpResult(t, img, "img08") 200 } 201 202 func TestImg09Visible(t *testing.T) { 203 d, img := newTestDrawer() 204 205 s := "11111\n22222\n33333\n44444\n55555\n66666\n77777\n88888" 206 r := iorw.NewStringReaderAt(s) 207 d.SetReader(r) 208 209 o := d.RangeVisibleOffset(r.Max(), 0) 210 d.SetRuneOffset(o) 211 212 d.Draw(img) 213 cmpResult(t, img, "img09") 214 } 215 216 func TestImg10Visible(t *testing.T) { 217 d, img := newTestDrawer() 218 219 s := "11111\n22222\n33333\n44444\n55555\n66666\n77777\n88888" 220 r := iorw.NewStringReaderAt(s) 221 d.SetReader(r) 222 223 o := d.RangeVisibleOffset(19, 4) // line with 4's 224 d.SetRuneOffset(o) 225 226 d.Draw(img) 227 cmpResult(t, img, "img10") 228 } 229 230 func TestImg11Visible(t *testing.T) { 231 d, img := newTestDrawer() 232 233 s := "11111\n22222\n33333\n44444\n55555\n66666\n77777\n88888" 234 r := iorw.NewStringReaderAt(s) 235 d.SetReader(r) 236 237 o := d.RangeVisibleOffset(19, 7) // line with 4's 238 d.SetRuneOffset(o) 239 240 d.Draw(img) 241 cmpResult(t, img, "img11") 242 } 243 244 func TestImg12Cursor(t *testing.T) { 245 d, img := newTestDrawer() 246 247 s := "11111\n22222\n33333\n44444\n55555\n66666\n77777\n88888" 248 r := iorw.NewStringReaderAt(s) 249 d.SetReader(r) 250 251 d.Opt.Cursor.On = true 252 253 c := 17 254 d.SetRuneOffset(c) 255 d.SetCursorOffset(c) 256 257 p := d.LocalPointOf(c) 258 p.Y -= d.LineHeight() - 1 259 k := d.LocalIndexOf(p) 260 261 d.SetRuneOffset(k) 262 d.SetCursorOffset(k) 263 264 d.Draw(img) 265 cmpResult(t, img, "img12") 266 } 267 268 func TestImg13Cursor(t *testing.T) { 269 d, img := newTestDrawer() 270 271 s := "11111\n22222\n33333\n44444\n55555\n66666\n77777\n88888" 272 r := iorw.NewStringReaderAt(s) 273 d.SetReader(r) 274 275 d.Opt.Cursor.On = true 276 277 c := r.Max() 278 d.SetRuneOffset(c - 3) 279 d.SetCursorOffset(c) 280 281 // range visible when offset was eof was causing draw at bottom 282 u := d.RangeVisibleOffset(c, 1) 283 d.SetRuneOffset(u) 284 285 d.Draw(img) 286 cmpResult(t, img, "img13") 287 } 288 289 func TestImg14Cursor(t *testing.T) { 290 d, img := newTestDrawer() 291 292 s := "11111\n22222\n33333\n44444\n55555\n66666\n77777\n88888" 293 rw := iorw.NewBytesReadWriterAt([]byte(s)) 294 d.SetReader(rw) 295 296 d.Opt.Cursor.On = true 297 298 c := rw.Max() 299 d.SetRuneOffset(c) 300 301 l := 8 302 rw.OverwriteAt(rw.Max()-l, l, nil) 303 304 d.Draw(img) 305 cmpResult(t, img, "img14") 306 } 307 308 func TestImg15Visible(t *testing.T) { 309 d, img := newTestDrawer() 310 311 s := "11111\n22222\n33333" 312 rw := iorw.NewBytesReadWriterAt([]byte(s)) 313 d.SetReader(rw) 314 315 d.Opt.Cursor.On = true 316 317 c := rw.Max() 318 d.SetRuneOffset(c) 319 320 rw.OverwriteAt(rw.Min(), rw.Max()-rw.Min(), nil) 321 b, _ := rw.ReadFastAt(rw.Min(), rw.Max()-rw.Min()) 322 _ = string(b) 323 324 o := d.RangeVisibleOffset(0, 0) 325 d.SetRuneOffset(o) 326 327 rw.OverwriteAt(rw.Min(), 0, []byte("44444\n")) 328 329 d.Draw(img) 330 cmpResult(t, img, "img15") 331 } 332 333 func TestImg16Select(t *testing.T) { 334 rect := image.Rect(0, 0, 100, 100) 335 d, img := newTestDrawerRect(rect) 336 337 tmp := limitedReaderPadding 338 defer func() { limitedReaderPadding = tmp }() 339 limitedReaderPadding = 3 340 341 s := "" 342 for i := 0; i < 10; i++ { 343 s += fmt.Sprintf("%v", i%10) 344 } 345 346 r := iorw.NewStringReaderAt(s) 347 d.SetReader(r) 348 349 d.Opt.Cursor.On = true 350 351 d.SetRuneOffset(7) 352 d.SetCursorOffset(7) 353 354 d.Draw(img) 355 cmpResult(t, img, "img16") 356 } 357 358 func TestImg17Tab(t *testing.T) { 359 d, img := newTestDrawer() 360 361 s := "012\t456\t89" 362 363 r := iorw.NewStringReaderAt(s) 364 d.SetReader(r) 365 366 //d.SetRuneOffset(0) 367 d.SetRuneOffset(7) 368 369 // problem: prints 8th forward on the same line (y), but the image shows runes on another line 370 //for i := 5; i <= 9; i++ { 371 // p := d.LocalPointOf(i) 372 // fmt.Printf("%v: %v\n", i, p) 373 //} 374 375 d.Draw(img) 376 cmpResult(t, img, "img17") 377 } 378 379 func TestImg18LongWrap(t *testing.T) { 380 d, img := newTestDrawer() 381 382 s := "" 383 for i := 0; i < 10000; i++ { 384 s += fmt.Sprintf("%010d;", i) 385 } 386 387 r := iorw.NewStringReaderAt(s) 388 d.SetReader(r) 389 390 d.SetRuneOffset(len(s) / 2) 391 392 d.Draw(img) 393 cmpResult(t, img, "img18") 394 } 395 396 //---------- 397 398 func newTestDrawer() (*Drawer, draw.Image) { 399 rect := image.Rect(0, 0, 70, 70) 400 return newTestDrawerRect(rect) 401 } 402 403 func newTestDrawerRect(rect image.Rectangle) (*Drawer, draw.Image) { 404 face := newTestFace() 405 d := New() 406 d.SetFontFace(face) 407 d.SetBounds(rect) 408 d.SetFg(color.Black) 409 410 d.smoothScroll = false 411 d.Opt.LineWrap.Bg = colornames.Red 412 413 NoPaddedIndentedLines = true 414 415 img := image.NewRGBA(rect) 416 return d, img 417 } 418 419 func newTestFace() *fontutil.FontFace { 420 f := fontutil.DefaultFont() 421 opt := truetype.Options{DPI: 100} 422 return f.FontFace(opt) 423 424 } 425 426 var testImg0Dir = "testimgs" 427 428 func imgFilename(name string) string { 429 return filepath.Join(testImg0Dir, name+".png") 430 } 431 432 func cmpResult(t *testing.T, img image.Image, name string) { 433 t.Helper() 434 435 // auto save if file doesn't exit 436 fname := imgFilename(name) 437 if _, err := os.Stat(fname); os.IsNotExist(err) { 438 saveResult(img, name) 439 return 440 } 441 442 compareResult(t, img, name) 443 } 444 445 func saveResult(img image.Image, name string) { 446 fname := filepath.Join(testImg0Dir, name+".png") 447 f, err := os.Create(fname) 448 if err != nil { 449 panic(err) 450 } 451 defer f.Close() 452 if err := png.Encode(f, img); err != nil { 453 panic(err) 454 } 455 } 456 457 func openResult(name string) image.Image { 458 fname := filepath.Join(testImg0Dir, name+".png") 459 f, err := os.Open(fname) 460 if err != nil { 461 panic(err) 462 } 463 defer f.Close() 464 img, err := png.Decode(f) 465 if err != nil { 466 panic(err) 467 } 468 return img 469 } 470 471 func compareResult(t *testing.T, img image.Image, name string) { 472 t.Helper() 473 img2 := openResult(name) 474 if img.Bounds() != img2.Bounds() { 475 saveResult(img, name+"_err") 476 t.Fatal("different bounds") 477 } 478 b := img.Bounds() 479 for y := b.Min.Y; y < b.Max.Y; y++ { 480 for x := b.Min.X; x < b.Max.X; x++ { 481 c := color.RGBAModel.Convert(img.At(x, y)) 482 c2 := color.RGBAModel.Convert(img2.At(x, y)) 483 if c != c2 { 484 saveResult(img, name+"_err") 485 t.Fatalf("different color value: %vx%v: %v %v", x, y, c, c2) 486 } 487 } 488 } 489 }