testtextbuffer.c 27.2 KB
Newer Older
1 2
/* Simplistic test suite */

Owen Taylor's avatar
Owen Taylor committed
3

4
#include <stdio.h>
5
#include <string.h>
6 7

#include <gtk/gtk.h>
Owen Taylor's avatar
Owen Taylor committed
8
#include "../gtk/gtktexttypes.h" /* Private header, for UNKNOWN_CHAR */
9

10 11 12 13 14 15 16 17 18 19 20
static void
gtk_text_iter_spew (const GtkTextIter *iter, const gchar *desc)
{
  g_print (" %20s: line %d / char %d / line char %d / line byte %d\n",
           desc,
           gtk_text_iter_get_line (iter),
           gtk_text_iter_get_offset (iter),
           gtk_text_iter_get_line_offset (iter),
           gtk_text_iter_get_line_index (iter));
}

21
static void fill_buffer (GtkTextBuffer *buffer);
22

23
static void run_tests (GtkTextBuffer *buffer);
24

25 26 27 28 29 30
static void check_get_set_text (GtkTextBuffer *buffer,
                                const char    *str);


static void line_separator_tests (void);

31 32
static void logical_motion_tests (void);

33
int
34
main (int argc, char** argv)
35 36 37
{
  GtkTextBuffer *buffer;
  int n;
38
  gunichar ch;
39
  GtkTextIter start, end;
40
  
41
  gtk_init (&argc, &argv);
42 43

  /* Check UTF8 unknown char thing */
44
  g_assert (g_utf8_strlen (gtk_text_unknown_char_utf8, 3) == 1);
45
  ch = g_utf8_get_char (gtk_text_unknown_char_utf8);
46
  g_assert (ch == GTK_TEXT_UNKNOWN_CHAR);
47

48 49 50
  /* First, we turn on btree debugging. */
  gtk_debug_flags |= GTK_DEBUG_TEXT;

51 52
  /* Check some line separator stuff */
  line_separator_tests ();
53 54 55

  /* Check log attr motion */
  logical_motion_tests ();
56
  
57
  /* Create a buffer */
58
  buffer = gtk_text_buffer_new (NULL);
59 60

  /* Check that buffer starts with one empty line and zero chars */
61

62
  n = gtk_text_buffer_get_line_count (buffer);
63
  if (n != 1)
64
    g_error ("%d lines, expected 1", n);
65

66
  n = gtk_text_buffer_get_char_count (buffer);
67 68
  if (n != 0)
    g_error ("%d chars, expected 0", n);
69

70
  /* Run gruesome alien test suite on buffer */
71
  run_tests (buffer);
72

73
  /* Check set/get text */
74 75 76 77 78 79
  check_get_set_text (buffer, "Hello");
  check_get_set_text (buffer, "Hello\n");
  check_get_set_text (buffer, "Hello\r\n");
  check_get_set_text (buffer, "Hello\r");
  check_get_set_text (buffer, "Hello\nBar\nFoo");
  check_get_set_text (buffer, "Hello\nBar\nFoo\n");
80
  
81 82
  /* Put stuff in the buffer */

83
  fill_buffer (buffer);
84 85

  /* Subject stuff-bloated buffer to further torment */
86
  run_tests (buffer);
87 88

  /* Delete all stuff from the buffer */
89 90
  gtk_text_buffer_get_bounds (buffer, &start, &end);
  gtk_text_buffer_delete (buffer, &start, &end);
91 92 93

  /* Check buffer for emptiness (note that a single
     empty line always remains in the buffer) */
94
  n = gtk_text_buffer_get_line_count (buffer);
95
  if (n != 1)
96
    g_error ("%d lines, expected 1", n);
97

98
  n = gtk_text_buffer_get_char_count (buffer);
99 100
  if (n != 0)
    g_error ("%d chars, expected 0", n);
101

102
  run_tests (buffer);
103

104 105
  g_object_unref (G_OBJECT (buffer));
  
106
  g_print ("All tests passed.\n");
107

108 109 110
  return 0;
}

111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
static void
check_get_set_text (GtkTextBuffer *buffer,
                    const char    *str)
{
  GtkTextIter start, end;
  char *text;
  int n;
  
  gtk_text_buffer_set_text (buffer, str, -1);
  if (gtk_text_buffer_get_char_count (buffer) != g_utf8_strlen (str, -1))
    g_error ("Wrong number of chars (%d not %d)",
             gtk_text_buffer_get_char_count (buffer),
             (int) g_utf8_strlen (str, -1));
  gtk_text_buffer_get_bounds (buffer, &start, &end);
  text = gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
  if (strcmp (text, str) != 0)
    g_error ("Got '%s' as buffer contents", text);
  g_free (text);

  gtk_text_buffer_set_text (buffer, "", -1);

  n = gtk_text_buffer_get_line_count (buffer);
  if (n != 1)
    g_error ("%d lines, expected 1", n);

  n = gtk_text_buffer_get_char_count (buffer);
  if (n != 0)
    g_error ("%d chars, expected 0", n);
}

141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
static gint
count_toggles_at_iter (GtkTextIter *iter,
                       GtkTextTag  *of_tag)
{
  GSList *tags;
  GSList *tmp;
  gint count = 0;
  
  /* get toggle-ons and toggle-offs */
  tags = gtk_text_iter_get_toggled_tags (iter, TRUE);
  tags = g_slist_concat (tags,
                         gtk_text_iter_get_toggled_tags (iter, FALSE));
  
  tmp = tags;
  while (tmp != NULL)
    {
      if (of_tag == NULL)
        ++count;
      else if (of_tag == tmp->data)
        ++count;
      
      tmp = g_slist_next (tmp);
    }
  
  g_slist_free (tags);

  return count;
}
     
static gint
count_toggles_in_buffer (GtkTextBuffer *buffer,
                         GtkTextTag    *of_tag)
{
  GtkTextIter iter;
  gint count = 0;
  
  gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
  do
    {
      count += count_toggles_at_iter (&iter, of_tag);
    }
182
  while (gtk_text_iter_forward_char (&iter));
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253

  /* Do the end iterator, because forward_char won't return TRUE
   * on it.
   */
  count += count_toggles_at_iter (&iter, of_tag);
  
  return count;
}

static void
check_specific_tag (GtkTextBuffer *buffer,
                    const gchar   *tag_name)
{
  GtkTextIter iter;
  GtkTextTag *tag;
  gboolean state;
  gint count;
  gint buffer_count;
  gint last_offset;
  
  tag = gtk_text_tag_table_lookup (gtk_text_buffer_get_tag_table (buffer),
                                   tag_name);

  buffer_count = count_toggles_in_buffer (buffer, tag);
  
  state = FALSE;
  count = 0;

  last_offset = -1;
  gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
  if (gtk_text_iter_toggles_tag (&iter, tag) ||
      gtk_text_iter_forward_to_tag_toggle (&iter, tag))
    {
      do
        {
          gint this_offset;
          
          ++count;

          this_offset = gtk_text_iter_get_offset (&iter);

          if (this_offset <= last_offset)
            g_error ("forward_to_tag_toggle moved in wrong direction");

          last_offset = this_offset;
          
          if (gtk_text_iter_begins_tag (&iter, tag))
            {
              if (state)
                g_error ("Tag %p is already on, and was toggled on?", tag);
              state = TRUE;
            }          
          else if (gtk_text_iter_ends_tag (&iter, tag))
            {
              if (!state)
                g_error ("Tag %p toggled off, but wasn't toggled on?", tag);
              state = FALSE;
            }
          else
            g_error ("forward_to_tag_toggle went to a location without a toggle");
        }
      while (gtk_text_iter_forward_to_tag_toggle (&iter, tag));
    }

  if (count != buffer_count)
    g_error ("Counted %d tags iterating by char, %d iterating by tag toggle\n",
             buffer_count, count);
  
  state = FALSE;
  count = 0;
  
254
  gtk_text_buffer_get_end_iter (buffer, &iter);
255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295
  last_offset = gtk_text_iter_get_offset (&iter);
  if (gtk_text_iter_toggles_tag (&iter, tag) ||
      gtk_text_iter_backward_to_tag_toggle (&iter, tag))
    {
      do
        {
          gint this_offset;
          
          ++count;

          this_offset = gtk_text_iter_get_offset (&iter);
          
          if (this_offset >= last_offset)
            g_error ("backward_to_tag_toggle moved in wrong direction");
          
          last_offset = this_offset;

          if (gtk_text_iter_begins_tag (&iter, tag))
            {
              if (!state)
                g_error ("Tag %p wasn't on when we got to the on toggle going backward?", tag);
              state = FALSE;
            }
          else if (gtk_text_iter_ends_tag (&iter, tag))
            {
              if (state)
                g_error ("Tag %p off toggle, but we were already inside a tag?", tag);
              state = TRUE;
            }
          else
            g_error ("backward_to_tag_toggle went to a location without a toggle");
        }
      while (gtk_text_iter_backward_to_tag_toggle (&iter, tag));
    }

  if (count != buffer_count)
    g_error ("Counted %d tags iterating by char, %d iterating by tag toggle\n",
             buffer_count, count);

}

296
static void
297
run_tests (GtkTextBuffer *buffer)
298 299 300 301 302 303 304 305
{
  GtkTextIter iter;
  GtkTextIter start;
  GtkTextIter end;
  GtkTextIter mark;
  gint i, j;
  gint num_chars;
  GtkTextMark *bar_mark;
306 307 308 309
  GtkTextTag *tag;
  GHashTable *tag_states;
  gint count;
  gint buffer_count;
310
  
311
  gtk_text_buffer_get_bounds (buffer, &start, &end);
312

313
  /* Check that walking the tree via chars and via iterators produces
314 315
   * the same number of indexable locations.
   */
316
  num_chars = gtk_text_buffer_get_char_count (buffer);
317
  iter = start;
318
  bar_mark = gtk_text_buffer_create_mark (buffer, "bar", &iter, FALSE);
319 320 321 322 323
  i = 0;
  while (i < num_chars)
    {
      GtkTextIter current;
      GtkTextMark *foo_mark;
324

325
      gtk_text_buffer_get_iter_at_offset (buffer, &current, i);
326

327
      if (!gtk_text_iter_equal (&iter, &current))
328
        {
329
          g_error ("get_char_index didn't return current iter");
330 331
        }

332
      j = gtk_text_iter_get_offset (&iter);
333 334 335

      if (i != j)
        {
336
          g_error ("iter converted to %d not %d", j, i);
337 338 339
        }

      /* get/set mark */
340
      gtk_text_buffer_get_iter_at_mark (buffer, &mark, bar_mark);
341

342
      if (!gtk_text_iter_equal (&iter, &mark))
343
        {
344 345 346
          gtk_text_iter_spew (&iter, "iter");
          gtk_text_iter_spew (&mark, "mark");
          g_error ("Mark not moved to the right place.");
347
        }
348

349 350 351
      foo_mark = gtk_text_buffer_create_mark (buffer, "foo", &iter, FALSE);
      gtk_text_buffer_get_iter_at_mark (buffer, &mark, foo_mark);
      gtk_text_buffer_delete_mark (buffer, foo_mark);
352

353
      if (!gtk_text_iter_equal (&iter, &mark))
354
        {
355 356 357
          gtk_text_iter_spew (&iter, "iter");
          gtk_text_iter_spew (&mark, "mark");
          g_error ("Mark not created in the right place.");
358
        }
359

360
      if (gtk_text_iter_is_end (&iter))
361 362
        g_error ("iterators ran out before chars (offset %d of %d)",
                 i, num_chars);
363

364
      gtk_text_iter_forward_char (&iter);
365

366
      gtk_text_buffer_move_mark (buffer, bar_mark, &iter);
367

368 369 370
      ++i;
    }

371 372
  if (!gtk_text_iter_equal (&iter, &end))
    g_error ("Iterating over all chars didn't end with the end iter");
373

374
  /* Do the tree-walk backward
375
   */
376 377
  num_chars = gtk_text_buffer_get_char_count (buffer);
  gtk_text_buffer_get_iter_at_offset (buffer, &iter, -1);
378

379
  gtk_text_buffer_move_mark (buffer, bar_mark, &iter);
380

381 382
  i = num_chars;

383 384
  if (!gtk_text_iter_equal (&iter, &end))
    g_error ("iter at char -1 is not equal to the end iterator");
385

386 387 388 389
  while (i >= 0)
    {
      GtkTextIter current;
      GtkTextMark *foo_mark;
390

391
      gtk_text_buffer_get_iter_at_offset (buffer, &current, i);
392

393
      if (!gtk_text_iter_equal (&iter, &current))
394
        {
395
          g_error ("get_char_index didn't return current iter while going backward");
396
        }
397
      j = gtk_text_iter_get_offset (&iter);
398 399 400

      if (i != j)
        {
401
          g_error ("going backward, iter converted to %d not %d", j, i);
402 403 404
        }

      /* get/set mark */
405
      gtk_text_buffer_get_iter_at_mark (buffer, &mark, bar_mark);
406

407
      if (!gtk_text_iter_equal (&iter, &mark))
408
        {
409 410 411
          gtk_text_iter_spew (&iter, "iter");
          gtk_text_iter_spew (&mark, "mark");
          g_error ("Mark not moved to the right place.");
412
        }
413

414 415 416
      foo_mark = gtk_text_buffer_create_mark (buffer, "foo", &iter, FALSE);
      gtk_text_buffer_get_iter_at_mark (buffer, &mark, foo_mark);
      gtk_text_buffer_delete_mark (buffer, foo_mark);
417

418
      if (!gtk_text_iter_equal (&iter, &mark))
419
        {
420 421 422
          gtk_text_iter_spew (&iter, "iter");
          gtk_text_iter_spew (&mark, "mark");
          g_error ("Mark not created in the right place.");
423
        }
424

425 426
      if (i > 0)
        {
427
          if (!gtk_text_iter_backward_char (&iter))
428
            g_error ("iterators ran out before char indexes");
429

430
          gtk_text_buffer_move_mark (buffer, bar_mark, &iter);
431 432 433
        }
      else
        {
434
          if (gtk_text_iter_backward_char (&iter))
435
            g_error ("went backward from 0?");
436
        }
437

438 439
      --i;
    }
440

441 442
  if (!gtk_text_iter_equal (&iter, &start))
    g_error ("Iterating backward over all chars didn't end with the start iter");
443 444 445 446 447 448

  /*
   * Check that get_line_count returns the same number of lines
   * as walking the tree by line
   */
  i = 1; /* include current (first) line */
449 450
  gtk_text_buffer_get_iter_at_line (buffer, &iter, 0);
  while (gtk_text_iter_forward_line (&iter))
451
    ++i;
452

453 454
  if (i != gtk_text_buffer_get_line_count (buffer))
    g_error ("Counted %d lines, buffer has %d", i,
455
             gtk_text_buffer_get_line_count (buffer));
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541

  /*
   * Check that moving over tag toggles thinks about working.
   */

  buffer_count = count_toggles_in_buffer (buffer, NULL);
  
  tag_states = g_hash_table_new (NULL, NULL);
  count = 0;
  
  gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
  if (gtk_text_iter_toggles_tag (&iter, NULL) ||
      gtk_text_iter_forward_to_tag_toggle (&iter, NULL))
    {
      do
        {
          GSList *tags;
          GSList *tmp;
          gboolean found_some = FALSE;
          
          /* get toggled-on tags */
          tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);

          if (tags)
            found_some = TRUE;
          
          tmp = tags;
          while (tmp != NULL)
            {
              ++count;
              
              tag = tmp->data;
              
              if (g_hash_table_lookup (tag_states, tag))
                g_error ("Tag %p is already on, and was toggled on?", tag);

              g_hash_table_insert (tag_states, tag, GINT_TO_POINTER (TRUE));
          
              tmp = g_slist_next (tmp);
            }

          g_slist_free (tags);
      
          /* get toggled-off tags */
          tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);

          if (tags)
            found_some = TRUE;
          
          tmp = tags;
          while (tmp != NULL)
            {
              ++count;
              
              tag = tmp->data;

              if (!g_hash_table_lookup (tag_states, tag))
                g_error ("Tag %p is already off, and was toggled off?", tag);

              g_hash_table_remove (tag_states, tag);
          
              tmp = g_slist_next (tmp);
            }

          g_slist_free (tags);

          if (!found_some)
            g_error ("No tags found going forward to tag toggle.");

        }
      while (gtk_text_iter_forward_to_tag_toggle (&iter, NULL));
    }
  
  g_hash_table_destroy (tag_states);

  if (count != buffer_count)
    g_error ("Counted %d tags iterating by char, %d iterating by tag toggle\n",
             buffer_count, count);
  
  /* Go backward; here TRUE in the hash means we saw
   * an off toggle last.
   */
  
  tag_states = g_hash_table_new (NULL, NULL);
  count = 0;
  
542
  gtk_text_buffer_get_end_iter (buffer, &iter);
543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
  if (gtk_text_iter_toggles_tag (&iter, NULL) ||
      gtk_text_iter_backward_to_tag_toggle (&iter, NULL))
    {
      do
        {
          GSList *tags;
          GSList *tmp;
          gboolean found_some = FALSE;
          
          /* get toggled-off tags */
          tags = gtk_text_iter_get_toggled_tags (&iter, FALSE);

          if (tags)
            found_some = TRUE;
          
          tmp = tags;
          while (tmp != NULL)
            {
              ++count;
              
              tag = tmp->data;

              if (g_hash_table_lookup (tag_states, tag))
                g_error ("Tag %p has two off-toggles in a row?", tag);
          
              g_hash_table_insert (tag_states, tag, GINT_TO_POINTER (TRUE));
          
              tmp = g_slist_next (tmp);
            }

          g_slist_free (tags);
      
          /* get toggled-on tags */
          tags = gtk_text_iter_get_toggled_tags (&iter, TRUE);

          if (tags)
            found_some = TRUE;
          
          tmp = tags;
          while (tmp != NULL)
            {
              ++count;
              
              tag = tmp->data;

              if (!g_hash_table_lookup (tag_states, tag))
                g_error ("Tag %p was toggled on, but saw no off-toggle?", tag);

              g_hash_table_remove (tag_states, tag);
          
              tmp = g_slist_next (tmp);
            }

          g_slist_free (tags);

          if (!found_some)
            g_error ("No tags found going backward to tag toggle.");
        }
      while (gtk_text_iter_backward_to_tag_toggle (&iter, NULL));
    }
  
  g_hash_table_destroy (tag_states);

  if (count != buffer_count)
    g_error ("Counted %d tags iterating by char, %d iterating by tag toggle\n",
             buffer_count, count);

  check_specific_tag (buffer, "fg_red");
  check_specific_tag (buffer, "bg_green");
  check_specific_tag (buffer, "front_tag");
  check_specific_tag (buffer, "center_tag");
  check_specific_tag (buffer, "end_tag");
615 616 617
}


618
static const char  *book_closed_xpm[] = {
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
"16 16 6 1",
"       c None s None",
".      c black",
"X      c red",
"o      c yellow",
"O      c #808080",
"#      c white",
"                ",
"       ..       ",
"     ..XX.      ",
"   ..XXXXX.     ",
" ..XXXXXXXX.    ",
".ooXXXXXXXXX.   ",
"..ooXXXXXXXXX.  ",
".X.ooXXXXXXXXX. ",
".XX.ooXXXXXX..  ",
" .XX.ooXXX..#O  ",
"  .XX.oo..##OO. ",
"   .XX..##OO..  ",
"    .X.#OO..    ",
"     ..O..      ",
"      ..        ",
"                "};

static void
644
fill_buffer (GtkTextBuffer *buffer)
645 646 647 648 649
{
  GtkTextTag *tag;
  GdkColor color, color2;
  GtkTextIter iter;
  GtkTextIter iter2;
Havoc Pennington's avatar
Havoc Pennington committed
650
  GdkPixbuf *pixbuf;
651
  int i;
652

653 654 655 656 657
  color.red = color.green = 0;
  color.blue = 0xffff;
  color2.red = 0xfff;
  color2.blue = 0x0;
  color2.green = 0;
658 659 660 661 662 663
  
  gtk_text_buffer_create_tag (buffer, "fg_blue",
                              "foreground_gdk", &color,
                              "background_gdk", &color2,
                              "font", "-*-courier-bold-r-*-*-30-*-*-*-*-*-*-*",
                              NULL);
664 665 666

  color.blue = color.green = 0;
  color.red = 0xffff;
667 668 669 670 671
  
  gtk_text_buffer_create_tag (buffer, "fg_red",
                              "rise", -4,
                              "foreground_gdk", &color,
                              NULL);
672 673 674

  color.blue = color.red = 0;
  color.green = 0xffff;
675 676 677 678 679
  
  gtk_text_buffer_create_tag (buffer, "bg_green",
                              "background_gdk", &color,
                              "font", "-*-courier-bold-r-*-*-10-*-*-*-*-*-*-*",
                              NULL);
680

Havoc Pennington's avatar
Havoc Pennington committed
681
  pixbuf = gdk_pixbuf_new_from_xpm_data (book_closed_xpm);
682

Havoc Pennington's avatar
Havoc Pennington committed
683
  g_assert (pixbuf != NULL);
684

685 686 687 688 689
  i = 0;
  while (i < 10)
    {
      gchar *str;

690
      gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
691

Havoc Pennington's avatar
Havoc Pennington committed
692
      gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
693

694
      gtk_text_buffer_get_iter_at_offset (buffer, &iter, 1);
695

Havoc Pennington's avatar
Havoc Pennington committed
696
      gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
697

698
      str = g_strdup_printf ("%d Hello World!\nwoo woo woo woo woo woo woo woo\n",
699
                            i);
700

701
      gtk_text_buffer_insert (buffer, &iter, str, -1);
702

703
      g_free (str);
704

705
      gtk_text_buffer_insert (buffer, &iter,
706 707 708 709
                              "(Hello World!)\nfoo foo Hello this is some text we are using to text word wrap. It has punctuation! gee; blah - hmm, great.\nnew line\n\n"
                              /* This is UTF8 stuff, Emacs doesn't
                                 really know how to display it */
                              "Spanish (Español) ¡Hola! / French (Français) Bonjour, Salut / German (Deutsch Süd) Grüß Gott (testing Latin-1 chars encoded in UTF8)\nThai (we can't display this, just making sure we don't crash)  (ภาษาไทย)  สวัสดีครับ, สวัสดีค่ะ\n",
710 711
                              -1);

Havoc Pennington's avatar
Havoc Pennington committed
712 713
      gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
      gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
714

715
      gtk_text_buffer_get_iter_at_offset (buffer, &iter, 4);
716

Havoc Pennington's avatar
Havoc Pennington committed
717
      gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
718

719
      gtk_text_buffer_get_iter_at_offset (buffer, &iter, 7);
720

Havoc Pennington's avatar
Havoc Pennington committed
721
      gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
722

723
      gtk_text_buffer_get_iter_at_offset (buffer, &iter, 8);
724

Havoc Pennington's avatar
Havoc Pennington committed
725
      gtk_text_buffer_insert_pixbuf (buffer, &iter, pixbuf);
726

727
      gtk_text_buffer_get_iter_at_line_offset (buffer, &iter, 0, 8);
728
      iter2 = iter;
729
      gtk_text_iter_forward_chars (&iter2, 10);
730

731
      gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
732

733 734
      gtk_text_iter_forward_chars (&iter, 7);
      gtk_text_iter_forward_chars (&iter2, 10);
735

736
      gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
737

738 739
      gtk_text_iter_forward_chars (&iter, 12);
      gtk_text_iter_forward_chars (&iter2, 10);
740

741
      gtk_text_buffer_apply_tag_by_name (buffer, "bg_green", &iter, &iter2);
742

743 744
      gtk_text_iter_forward_chars (&iter, 10);
      gtk_text_iter_forward_chars (&iter2, 15);
745

746
      gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2);
747
      gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
748

749 750
      gtk_text_iter_forward_chars (&iter, 20);
      gtk_text_iter_forward_chars (&iter2, 20);
751

752
      gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2);
753
      gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
754

755 756
      gtk_text_iter_backward_chars (&iter, 25);
      gtk_text_iter_forward_chars (&iter2, 5);
757

758
      gtk_text_buffer_apply_tag_by_name (buffer, "fg_red", &iter, &iter2);
759
      gtk_text_buffer_apply_tag_by_name (buffer, "fg_blue", &iter, &iter2);
760

761 762
      gtk_text_iter_forward_chars (&iter, 15);
      gtk_text_iter_backward_chars (&iter2, 10);
763

764
      gtk_text_buffer_remove_tag_by_name (buffer, "fg_red", &iter, &iter2);
765 766
      gtk_text_buffer_remove_tag_by_name (buffer, "fg_blue", &iter, &iter2);

767 768 769
      ++i;
    }

770 771 772
  /* Put in tags that are just at the beginning, and just near the end,
   * and just near the middle.
   */
773
  tag = gtk_text_buffer_create_tag (buffer, "front_tag", NULL);
774 775 776 777 778
  gtk_text_buffer_get_iter_at_offset (buffer, &iter, 3);
  gtk_text_buffer_get_iter_at_offset (buffer, &iter2, 300);

  gtk_text_buffer_apply_tag (buffer, tag, &iter, &iter2);  
  
779
  tag = gtk_text_buffer_create_tag (buffer, "end_tag", NULL);
780
  gtk_text_buffer_get_end_iter (buffer, &iter2);
781 782 783 784 785 786
  gtk_text_iter_backward_chars (&iter2, 12);
  iter = iter2;
  gtk_text_iter_backward_chars (&iter, 157);

  gtk_text_buffer_apply_tag (buffer, tag, &iter, &iter2);
  
787
  tag = gtk_text_buffer_create_tag (buffer, "center_tag", NULL);
788 789 790 791 792 793 794 795
  gtk_text_buffer_get_iter_at_offset (buffer, &iter,
                                      gtk_text_buffer_get_char_count (buffer)/2);
  gtk_text_iter_backward_chars (&iter, 37);
  iter2 = iter;
  gtk_text_iter_forward_chars (&iter2, 57);

  gtk_text_buffer_apply_tag (buffer, tag, &iter, &iter2);  

Havoc Pennington's avatar
Havoc Pennington committed
796
  gdk_pixbuf_unref (pixbuf);
797
}
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891


/*
 * Line separator tests (initially to avoid regression on bugzilla #57428)
 */

static void
test_line_separation (const char* str,
                      gboolean    expect_next_line,
                      gboolean    expect_end_iter,
                      int         expected_line_count,
                      int         expected_line_break,
                      int         expected_next_line_start)
{
  GtkTextIter iter;
  GtkTextBuffer* buffer;
  gboolean on_next_line;
  gboolean on_end_iter;
  gint new_pos;

  buffer = gtk_text_buffer_new (NULL);

  gtk_text_buffer_set_text (buffer, str, -1);
  gtk_text_buffer_get_iter_at_offset (buffer, &iter, expected_line_break);

  g_assert (gtk_text_iter_ends_line (&iter) || gtk_text_iter_is_end (&iter));

  g_assert (gtk_text_buffer_get_line_count (buffer) == expected_line_count);
  
  on_next_line = gtk_text_iter_forward_line (&iter);

  g_assert (expect_next_line == on_next_line);

  on_end_iter = gtk_text_iter_is_end (&iter);

  g_assert (on_end_iter == expect_end_iter);
  
  new_pos = gtk_text_iter_get_offset (&iter);
    
  if (on_next_line)
    g_assert (expected_next_line_start == new_pos);

  ++expected_line_break;
  while (expected_line_break < expected_next_line_start)
    {
      gtk_text_buffer_get_iter_at_offset (buffer, &iter, expected_line_break);

      g_assert (!gtk_text_iter_ends_line (&iter));

      on_next_line = gtk_text_iter_forward_line (&iter);
        
      g_assert (expect_next_line == on_next_line);
        
      new_pos = gtk_text_iter_get_offset (&iter);
        
      if (on_next_line)
        g_assert (expected_next_line_start == new_pos);
        
      ++expected_line_break;
    }

  /* FIXME tests for backward line */
  
  g_object_unref (G_OBJECT (buffer));
}


static void
line_separator_tests (void)
{
  char *str;
  char buf[7] = { '\0', };

  /* Only one character has type G_UNICODE_PARAGRAPH_SEPARATOR in
   * Unicode 3.0; update this if that changes.
   */
#define PARAGRAPH_SEPARATOR 0x2029
  
  test_line_separation ("line", FALSE, TRUE, 1, 4, 4);
  test_line_separation ("line\r\n", FALSE, TRUE, 2, 4, 6);
  test_line_separation ("line\r", FALSE, TRUE, 2, 4, 5);
  test_line_separation ("line\n", FALSE, TRUE, 2, 4, 5);
  test_line_separation ("line\rqw", TRUE, FALSE, 2, 4, 5);
  test_line_separation ("line\nqw", TRUE, FALSE, 2, 4, 5);
  test_line_separation ("line\r\nqw", TRUE, FALSE, 2, 4, 6);
  
  g_unichar_to_utf8 (PARAGRAPH_SEPARATOR, buf);
  
  str = g_strdup_printf ("line%s", buf);
  test_line_separation (str, FALSE, TRUE, 2, 4, 5);
  g_free (str);
  str = g_strdup_printf ("line%sqw", buf);
  test_line_separation (str, TRUE, FALSE, 2, 4, 5);
  g_free (str);
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993

  g_print ("Line separator tests passed\n");
}

static void
logical_motion_tests (void)
{
  char *str;
  char buf1[7] = { '\0', };
  char buf2[7] = { '\0', };
  char buf3[7] = { '\0', };
  int expected[30];
  int expected_steps;
  int i;
  GtkTextBuffer *buffer;
  GtkTextIter iter;
  
  buffer = gtk_text_buffer_new (NULL);
  
#define LEADING_JAMO 0x1111
#define VOWEL_JAMO 0x1167
#define TRAILING_JAMO 0x11B9
  
  g_unichar_to_utf8 (LEADING_JAMO, buf1);
  g_unichar_to_utf8 (VOWEL_JAMO, buf2);
  g_unichar_to_utf8 (TRAILING_JAMO, buf3);

  /* Build the string "abc<leading><vowel><trailing>def\r\nxyz" */
  str = g_strconcat ("abc", buf1, buf2, buf3, "def\r\nxyz", NULL);
  gtk_text_buffer_set_text (buffer, str, -1);
  g_free (str);
  
  /* Check cursor positions */
  memset (expected, 0, sizeof (expected));
  expected[0] = 0;    /* before 'a' */
  expected[1] = 1;    /* before 'b' */
  expected[2] = 2;    /* before 'c' */
  expected[3] = 3;    /* before jamo */
  expected[4] = 6;    /* before 'd' */
  expected[5] = 7;    /* before 'e' */
  expected[6] = 8;    /* before 'f' */
  expected[7] = 9;    /* before '\r' */
  expected[8] = 11;   /* before 'x' */
  expected[9] = 12;   /* before 'y' */
  expected[10] = 13;  /* before 'z' */
  expected[11] = 14;  /* after 'z' */
  expected_steps = 11;
  
  gtk_text_buffer_get_start_iter (buffer, &iter);
  i = 0;
  do
    {
      int pos;

      pos = gtk_text_iter_get_offset (&iter);
      
      if (pos != expected[i])
        {
          g_error ("Cursor position %d, expected %d",
                   pos, expected[i]);
        }

      /* g_print ("%d = %d\n", pos, expected[i]); */

      ++i;      
    }
  while (gtk_text_iter_forward_cursor_position (&iter));

  if (i != expected_steps)
    g_error ("Expected %d steps, there were actually %d\n", expected_steps, i);

  if (!gtk_text_iter_is_end (&iter))
    g_error ("Expected to stop at the end iterator\n");

  i = expected_steps;
  do
    {
      int pos;

      pos = gtk_text_iter_get_offset (&iter);
      
      if (pos != expected[i])
        {
          g_error ("Moving backward, cursor position %d, expected %d",
                   pos, expected[i]);
        }

      /* g_print ("%d = %d\n", pos, expected[i]); */
      
      --i;
    }
  while (gtk_text_iter_backward_cursor_position (&iter));

  if (i != -1)
    g_error ("Expected %d steps, there were actually %d\n", expected_steps - i, i);

  if (!gtk_text_iter_is_start (&iter))
    g_error ("Expected to stop at the start iterator\n");
  
  g_print ("Logical motion tests passed\n");

  g_object_unref (G_OBJECT (buffer));
994
}