qemu/tests/unit/test-iov.c
<<
>>
Prefs
   1#include "qemu/osdep.h"
   2#include "qemu-common.h"
   3#include "qemu/iov.h"
   4#include "qemu/sockets.h"
   5
   6/* create a randomly-sized iovec with random vectors */
   7static void iov_random(struct iovec **iovp, unsigned *iov_cntp)
   8{
   9     unsigned niov = g_test_rand_int_range(3,8);
  10     struct iovec *iov = g_malloc(niov * sizeof(*iov));
  11     unsigned i;
  12     for (i = 0; i < niov; ++i) {
  13         iov[i].iov_len = g_test_rand_int_range(5,20);
  14         iov[i].iov_base = g_malloc(iov[i].iov_len);
  15     }
  16     *iovp = iov;
  17     *iov_cntp = niov;
  18}
  19
  20static void iov_free(struct iovec *iov, unsigned niov)
  21{
  22    unsigned i;
  23    for (i = 0; i < niov; ++i) {
  24        g_free(iov[i].iov_base);
  25    }
  26    g_free(iov);
  27}
  28
  29static bool iov_equals(const struct iovec *a, const struct iovec *b,
  30                       unsigned niov)
  31{
  32    return memcmp(a, b, sizeof(a[0]) * niov) == 0;
  33}
  34
  35static void test_iov_bytes(struct iovec *iov, unsigned niov,
  36                           size_t offset, size_t bytes)
  37{
  38    unsigned i;
  39    size_t j, o;
  40    unsigned char *b;
  41    o = 0;
  42
  43    /* we walk over all elements, */
  44    for (i = 0; i < niov; ++i) {
  45        b = iov[i].iov_base;
  46        /* over each char of each element, */
  47        for (j = 0; j < iov[i].iov_len; ++j) {
  48            /* counting each of them and
  49             * verifying that the ones within [offset,offset+bytes)
  50             * range are equal to the position number (o) */
  51            if (o >= offset && o < offset + bytes) {
  52                g_assert(b[j] == (o & 255));
  53            } else {
  54                g_assert(b[j] == 0xff);
  55            }
  56            ++o;
  57        }
  58    }
  59}
  60
  61static void test_to_from_buf_1(void)
  62{
  63     unsigned niov;
  64     struct iovec *iov;
  65     size_t sz;
  66     unsigned char *ibuf, *obuf;
  67     unsigned i, j, n;
  68
  69     iov_random(&iov, &niov);
  70
  71     sz = iov_size(iov, niov);
  72
  73     ibuf = g_malloc(sz + 8) + 4;
  74     memcpy(ibuf-4, "aaaa", 4); memcpy(ibuf + sz, "bbbb", 4);
  75     obuf = g_malloc(sz + 8) + 4;
  76     memcpy(obuf-4, "xxxx", 4); memcpy(obuf + sz, "yyyy", 4);
  77
  78     /* fill in ibuf with 0123456... */
  79     for (i = 0; i < sz; ++i) {
  80         ibuf[i] = i & 255;
  81     }
  82
  83     for (i = 0; i <= sz; ++i) {
  84
  85         /* Test from/to buf for offset(i) in [0..sz] up to the end of buffer.
  86          * For last iteration with offset == sz, the procedure should
  87          * skip whole vector and process exactly 0 bytes */
  88
  89         /* first set bytes [i..sz) to some "random" value */
  90         n = iov_memset(iov, niov, 0, 0xff, sz);
  91         g_assert(n == sz);
  92
  93         /* next copy bytes [i..sz) from ibuf to iovec */
  94         n = iov_from_buf(iov, niov, i, ibuf + i, sz - i);
  95         g_assert(n == sz - i);
  96
  97         /* clear part of obuf */
  98         memset(obuf + i, 0, sz - i);
  99         /* and set this part of obuf to values from iovec */
 100         n = iov_to_buf(iov, niov, i, obuf + i, sz - i);
 101         g_assert(n == sz - i);
 102
 103         /* now compare resulting buffers */
 104         g_assert(memcmp(ibuf, obuf, sz) == 0);
 105
 106         /* test just one char */
 107         n = iov_to_buf(iov, niov, i, obuf + i, 1);
 108         g_assert(n == (i < sz));
 109         if (n) {
 110             g_assert(obuf[i] == (i & 255));
 111         }
 112
 113         for (j = i; j <= sz; ++j) {
 114             /* now test num of bytes cap up to byte no. j,
 115              * with j in [i..sz]. */
 116
 117             /* clear iovec */
 118             n = iov_memset(iov, niov, 0, 0xff, sz);
 119             g_assert(n == sz);
 120
 121             /* copy bytes [i..j) from ibuf to iovec */
 122             n = iov_from_buf(iov, niov, i, ibuf + i, j - i);
 123             g_assert(n == j - i);
 124
 125             /* clear part of obuf */
 126             memset(obuf + i, 0, j - i);
 127
 128             /* copy bytes [i..j) from iovec to obuf */
 129             n = iov_to_buf(iov, niov, i, obuf + i, j - i);
 130             g_assert(n == j - i);
 131
 132             /* verify result */
 133             g_assert(memcmp(ibuf, obuf, sz) == 0);
 134
 135             /* now actually check if the iovec contains the right data */
 136             test_iov_bytes(iov, niov, i, j - i);
 137         }
 138    }
 139    g_assert(!memcmp(ibuf-4, "aaaa", 4) && !memcmp(ibuf+sz, "bbbb", 4));
 140    g_free(ibuf-4);
 141    g_assert(!memcmp(obuf-4, "xxxx", 4) && !memcmp(obuf+sz, "yyyy", 4));
 142    g_free(obuf-4);
 143    iov_free(iov, niov);
 144}
 145
 146static void test_to_from_buf(void)
 147{
 148    int x;
 149    for (x = 0; x < 4; ++x) {
 150        test_to_from_buf_1();
 151    }
 152}
 153
 154static void test_io(void)
 155{
 156#ifndef _WIN32
 157/* socketpair(PF_UNIX) which does not exist on windows */
 158
 159    int sv[2];
 160    int r;
 161    unsigned i, j, k, s, t;
 162    fd_set fds;
 163    unsigned niov;
 164    struct iovec *iov, *siov;
 165    unsigned char *buf;
 166    size_t sz;
 167
 168    iov_random(&iov, &niov);
 169    sz = iov_size(iov, niov);
 170    buf = g_malloc(sz);
 171    for (i = 0; i < sz; ++i) {
 172        buf[i] = i & 255;
 173    }
 174    iov_from_buf(iov, niov, 0, buf, sz);
 175
 176    siov = g_memdup(iov, sizeof(*iov) * niov);
 177
 178    if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) < 0) {
 179       perror("socketpair");
 180       exit(1);
 181    }
 182
 183    FD_ZERO(&fds);
 184
 185    t = 0;
 186    if (fork() == 0) {
 187       /* writer */
 188
 189       close(sv[0]);
 190       FD_SET(sv[1], &fds);
 191       fcntl(sv[1], F_SETFL, O_RDWR|O_NONBLOCK);
 192       r = g_test_rand_int_range(sz / 2, sz);
 193       setsockopt(sv[1], SOL_SOCKET, SO_SNDBUF, &r, sizeof(r));
 194
 195       for (i = 0; i <= sz; ++i) {
 196           for (j = i; j <= sz; ++j) {
 197               k = i;
 198               do {
 199                   s = g_test_rand_int_range(0, j - k + 1);
 200                   r = iov_send(sv[1], iov, niov, k, s);
 201                   g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
 202                   if (r >= 0) {
 203                       k += r;
 204                       t += r;
 205                       usleep(g_test_rand_int_range(0, 30));
 206                   } else if (errno == EAGAIN) {
 207                       select(sv[1]+1, NULL, &fds, NULL, NULL);
 208                       continue;
 209                   } else {
 210                       perror("send");
 211                       exit(1);
 212                   }
 213               } while(k < j);
 214           }
 215       }
 216       iov_free(iov, niov);
 217       g_free(buf);
 218       g_free(siov);
 219       exit(0);
 220
 221    } else {
 222       /* reader & verifier */
 223
 224       close(sv[1]);
 225       FD_SET(sv[0], &fds);
 226       fcntl(sv[0], F_SETFL, O_RDWR|O_NONBLOCK);
 227       r = g_test_rand_int_range(sz / 2, sz);
 228       setsockopt(sv[0], SOL_SOCKET, SO_RCVBUF, &r, sizeof(r));
 229       usleep(500000);
 230
 231       for (i = 0; i <= sz; ++i) {
 232           for (j = i; j <= sz; ++j) {
 233               k = i;
 234               iov_memset(iov, niov, 0, 0xff, sz);
 235               do {
 236                   s = g_test_rand_int_range(0, j - k + 1);
 237                   r = iov_recv(sv[0], iov, niov, k, s);
 238                   g_assert(memcmp(iov, siov, sizeof(*iov)*niov) == 0);
 239                   if (r > 0) {
 240                       k += r;
 241                       t += r;
 242                   } else if (!r) {
 243                       if (s) {
 244                           break;
 245                       }
 246                   } else if (errno == EAGAIN) {
 247                       select(sv[0]+1, &fds, NULL, NULL, NULL);
 248                       continue;
 249                   } else {
 250                       perror("recv");
 251                       exit(1);
 252                   }
 253               } while(k < j);
 254               test_iov_bytes(iov, niov, i, j - i);
 255           }
 256        }
 257
 258       iov_free(iov, niov);
 259       g_free(buf);
 260       g_free(siov);
 261     }
 262#endif
 263}
 264
 265static void test_discard_front(void)
 266{
 267    struct iovec *iov;
 268    struct iovec *iov_tmp;
 269    unsigned int iov_cnt;
 270    unsigned int iov_cnt_tmp;
 271    void *old_base;
 272    size_t size;
 273    size_t ret;
 274
 275    /* Discard zero bytes */
 276    iov_random(&iov, &iov_cnt);
 277    iov_tmp = iov;
 278    iov_cnt_tmp = iov_cnt;
 279    ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, 0);
 280    g_assert(ret == 0);
 281    g_assert(iov_tmp == iov);
 282    g_assert(iov_cnt_tmp == iov_cnt);
 283    iov_free(iov, iov_cnt);
 284
 285    /* Discard more bytes than vector size */
 286    iov_random(&iov, &iov_cnt);
 287    iov_tmp = iov;
 288    iov_cnt_tmp = iov_cnt;
 289    size = iov_size(iov, iov_cnt);
 290    ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size + 1);
 291    g_assert(ret == size);
 292    g_assert(iov_cnt_tmp == 0);
 293    iov_free(iov, iov_cnt);
 294
 295    /* Discard entire vector */
 296    iov_random(&iov, &iov_cnt);
 297    iov_tmp = iov;
 298    iov_cnt_tmp = iov_cnt;
 299    size = iov_size(iov, iov_cnt);
 300    ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
 301    g_assert(ret == size);
 302    g_assert(iov_cnt_tmp == 0);
 303    iov_free(iov, iov_cnt);
 304
 305    /* Discard within first element */
 306    iov_random(&iov, &iov_cnt);
 307    iov_tmp = iov;
 308    iov_cnt_tmp = iov_cnt;
 309    old_base = iov->iov_base;
 310    size = g_test_rand_int_range(1, iov->iov_len);
 311    ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
 312    g_assert(ret == size);
 313    g_assert(iov_tmp == iov);
 314    g_assert(iov_cnt_tmp == iov_cnt);
 315    g_assert(iov_tmp->iov_base == old_base + size);
 316    iov_tmp->iov_base = old_base; /* undo before g_free() */
 317    iov_free(iov, iov_cnt);
 318
 319    /* Discard entire first element */
 320    iov_random(&iov, &iov_cnt);
 321    iov_tmp = iov;
 322    iov_cnt_tmp = iov_cnt;
 323    ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, iov->iov_len);
 324    g_assert(ret == iov->iov_len);
 325    g_assert(iov_tmp == iov + 1);
 326    g_assert(iov_cnt_tmp == iov_cnt - 1);
 327    iov_free(iov, iov_cnt);
 328
 329    /* Discard within second element */
 330    iov_random(&iov, &iov_cnt);
 331    iov_tmp = iov;
 332    iov_cnt_tmp = iov_cnt;
 333    old_base = iov[1].iov_base;
 334    size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len);
 335    ret = iov_discard_front(&iov_tmp, &iov_cnt_tmp, size);
 336    g_assert(ret == size);
 337    g_assert(iov_tmp == iov + 1);
 338    g_assert(iov_cnt_tmp == iov_cnt - 1);
 339    g_assert(iov_tmp->iov_base == old_base + (size - iov->iov_len));
 340    iov_tmp->iov_base = old_base; /* undo before g_free() */
 341    iov_free(iov, iov_cnt);
 342}
 343
 344static void test_discard_front_undo(void)
 345{
 346    IOVDiscardUndo undo;
 347    struct iovec *iov;
 348    struct iovec *iov_tmp;
 349    struct iovec *iov_orig;
 350    unsigned int iov_cnt;
 351    unsigned int iov_cnt_tmp;
 352    size_t size;
 353
 354    /* Discard zero bytes */
 355    iov_random(&iov, &iov_cnt);
 356    iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
 357    iov_tmp = iov;
 358    iov_cnt_tmp = iov_cnt;
 359    iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, 0, &undo);
 360    iov_discard_undo(&undo);
 361    assert(iov_equals(iov, iov_orig, iov_cnt));
 362    g_free(iov_orig);
 363    iov_free(iov, iov_cnt);
 364
 365    /* Discard more bytes than vector size */
 366    iov_random(&iov, &iov_cnt);
 367    iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
 368    iov_tmp = iov;
 369    iov_cnt_tmp = iov_cnt;
 370    size = iov_size(iov, iov_cnt);
 371    iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size + 1, &undo);
 372    iov_discard_undo(&undo);
 373    assert(iov_equals(iov, iov_orig, iov_cnt));
 374    g_free(iov_orig);
 375    iov_free(iov, iov_cnt);
 376
 377    /* Discard entire vector */
 378    iov_random(&iov, &iov_cnt);
 379    iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
 380    iov_tmp = iov;
 381    iov_cnt_tmp = iov_cnt;
 382    size = iov_size(iov, iov_cnt);
 383    iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo);
 384    iov_discard_undo(&undo);
 385    assert(iov_equals(iov, iov_orig, iov_cnt));
 386    g_free(iov_orig);
 387    iov_free(iov, iov_cnt);
 388
 389    /* Discard within first element */
 390    iov_random(&iov, &iov_cnt);
 391    iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
 392    iov_tmp = iov;
 393    iov_cnt_tmp = iov_cnt;
 394    size = g_test_rand_int_range(1, iov->iov_len);
 395    iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo);
 396    iov_discard_undo(&undo);
 397    assert(iov_equals(iov, iov_orig, iov_cnt));
 398    g_free(iov_orig);
 399    iov_free(iov, iov_cnt);
 400
 401    /* Discard entire first element */
 402    iov_random(&iov, &iov_cnt);
 403    iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
 404    iov_tmp = iov;
 405    iov_cnt_tmp = iov_cnt;
 406    iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, iov->iov_len, &undo);
 407    iov_discard_undo(&undo);
 408    assert(iov_equals(iov, iov_orig, iov_cnt));
 409    g_free(iov_orig);
 410    iov_free(iov, iov_cnt);
 411
 412    /* Discard within second element */
 413    iov_random(&iov, &iov_cnt);
 414    iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
 415    iov_tmp = iov;
 416    iov_cnt_tmp = iov_cnt;
 417    size = iov->iov_len + g_test_rand_int_range(1, iov[1].iov_len);
 418    iov_discard_front_undoable(&iov_tmp, &iov_cnt_tmp, size, &undo);
 419    iov_discard_undo(&undo);
 420    assert(iov_equals(iov, iov_orig, iov_cnt));
 421    g_free(iov_orig);
 422    iov_free(iov, iov_cnt);
 423}
 424
 425static void test_discard_back(void)
 426{
 427    struct iovec *iov;
 428    unsigned int iov_cnt;
 429    unsigned int iov_cnt_tmp;
 430    void *old_base;
 431    size_t size;
 432    size_t ret;
 433
 434    /* Discard zero bytes */
 435    iov_random(&iov, &iov_cnt);
 436    iov_cnt_tmp = iov_cnt;
 437    ret = iov_discard_back(iov, &iov_cnt_tmp, 0);
 438    g_assert(ret == 0);
 439    g_assert(iov_cnt_tmp == iov_cnt);
 440    iov_free(iov, iov_cnt);
 441
 442    /* Discard more bytes than vector size */
 443    iov_random(&iov, &iov_cnt);
 444    iov_cnt_tmp = iov_cnt;
 445    size = iov_size(iov, iov_cnt);
 446    ret = iov_discard_back(iov, &iov_cnt_tmp, size + 1);
 447    g_assert(ret == size);
 448    g_assert(iov_cnt_tmp == 0);
 449    iov_free(iov, iov_cnt);
 450
 451    /* Discard entire vector */
 452    iov_random(&iov, &iov_cnt);
 453    iov_cnt_tmp = iov_cnt;
 454    size = iov_size(iov, iov_cnt);
 455    ret = iov_discard_back(iov, &iov_cnt_tmp, size);
 456    g_assert(ret == size);
 457    g_assert(iov_cnt_tmp == 0);
 458    iov_free(iov, iov_cnt);
 459
 460    /* Discard within last element */
 461    iov_random(&iov, &iov_cnt);
 462    iov_cnt_tmp = iov_cnt;
 463    old_base = iov[iov_cnt - 1].iov_base;
 464    size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len);
 465    ret = iov_discard_back(iov, &iov_cnt_tmp, size);
 466    g_assert(ret == size);
 467    g_assert(iov_cnt_tmp == iov_cnt);
 468    g_assert(iov[iov_cnt - 1].iov_base == old_base);
 469    iov_free(iov, iov_cnt);
 470
 471    /* Discard entire last element */
 472    iov_random(&iov, &iov_cnt);
 473    iov_cnt_tmp = iov_cnt;
 474    old_base = iov[iov_cnt - 1].iov_base;
 475    size = iov[iov_cnt - 1].iov_len;
 476    ret = iov_discard_back(iov, &iov_cnt_tmp, size);
 477    g_assert(ret == size);
 478    g_assert(iov_cnt_tmp == iov_cnt - 1);
 479    iov_free(iov, iov_cnt);
 480
 481    /* Discard within second-to-last element */
 482    iov_random(&iov, &iov_cnt);
 483    iov_cnt_tmp = iov_cnt;
 484    old_base = iov[iov_cnt - 2].iov_base;
 485    size = iov[iov_cnt - 1].iov_len +
 486           g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len);
 487    ret = iov_discard_back(iov, &iov_cnt_tmp, size);
 488    g_assert(ret == size);
 489    g_assert(iov_cnt_tmp == iov_cnt - 1);
 490    g_assert(iov[iov_cnt - 2].iov_base == old_base);
 491    iov_free(iov, iov_cnt);
 492}
 493
 494static void test_discard_back_undo(void)
 495{
 496    IOVDiscardUndo undo;
 497    struct iovec *iov;
 498    struct iovec *iov_orig;
 499    unsigned int iov_cnt;
 500    unsigned int iov_cnt_tmp;
 501    size_t size;
 502
 503    /* Discard zero bytes */
 504    iov_random(&iov, &iov_cnt);
 505    iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
 506    iov_cnt_tmp = iov_cnt;
 507    iov_discard_back_undoable(iov, &iov_cnt_tmp, 0, &undo);
 508    iov_discard_undo(&undo);
 509    assert(iov_equals(iov, iov_orig, iov_cnt));
 510    g_free(iov_orig);
 511    iov_free(iov, iov_cnt);
 512
 513    /* Discard more bytes than vector size */
 514    iov_random(&iov, &iov_cnt);
 515    iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
 516    iov_cnt_tmp = iov_cnt;
 517    size = iov_size(iov, iov_cnt);
 518    iov_discard_back_undoable(iov, &iov_cnt_tmp, size + 1, &undo);
 519    iov_discard_undo(&undo);
 520    assert(iov_equals(iov, iov_orig, iov_cnt));
 521    g_free(iov_orig);
 522    iov_free(iov, iov_cnt);
 523
 524    /* Discard entire vector */
 525    iov_random(&iov, &iov_cnt);
 526    iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
 527    iov_cnt_tmp = iov_cnt;
 528    size = iov_size(iov, iov_cnt);
 529    iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
 530    iov_discard_undo(&undo);
 531    assert(iov_equals(iov, iov_orig, iov_cnt));
 532    g_free(iov_orig);
 533    iov_free(iov, iov_cnt);
 534
 535    /* Discard within last element */
 536    iov_random(&iov, &iov_cnt);
 537    iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
 538    iov_cnt_tmp = iov_cnt;
 539    size = g_test_rand_int_range(1, iov[iov_cnt - 1].iov_len);
 540    iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
 541    iov_discard_undo(&undo);
 542    assert(iov_equals(iov, iov_orig, iov_cnt));
 543    g_free(iov_orig);
 544    iov_free(iov, iov_cnt);
 545
 546    /* Discard entire last element */
 547    iov_random(&iov, &iov_cnt);
 548    iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
 549    iov_cnt_tmp = iov_cnt;
 550    size = iov[iov_cnt - 1].iov_len;
 551    iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
 552    iov_discard_undo(&undo);
 553    assert(iov_equals(iov, iov_orig, iov_cnt));
 554    g_free(iov_orig);
 555    iov_free(iov, iov_cnt);
 556
 557    /* Discard within second-to-last element */
 558    iov_random(&iov, &iov_cnt);
 559    iov_orig = g_memdup(iov, sizeof(iov[0]) * iov_cnt);
 560    iov_cnt_tmp = iov_cnt;
 561    size = iov[iov_cnt - 1].iov_len +
 562           g_test_rand_int_range(1, iov[iov_cnt - 2].iov_len);
 563    iov_discard_back_undoable(iov, &iov_cnt_tmp, size, &undo);
 564    iov_discard_undo(&undo);
 565    assert(iov_equals(iov, iov_orig, iov_cnt));
 566    g_free(iov_orig);
 567    iov_free(iov, iov_cnt);
 568}
 569
 570int main(int argc, char **argv)
 571{
 572    g_test_init(&argc, &argv, NULL);
 573    g_test_rand_int();
 574    g_test_add_func("/basic/iov/from-to-buf", test_to_from_buf);
 575    g_test_add_func("/basic/iov/io", test_io);
 576    g_test_add_func("/basic/iov/discard-front", test_discard_front);
 577    g_test_add_func("/basic/iov/discard-back", test_discard_back);
 578    g_test_add_func("/basic/iov/discard-front-undo", test_discard_front_undo);
 579    g_test_add_func("/basic/iov/discard-back-undo", test_discard_back_undo);
 580    return g_test_run();
 581}
 582