#include #include #include #include #include "internal.h" #include "testutils.h" #include "virbuffer.h" #include "viralloc.h" #include "virstring.h" #define VIR_FROM_THIS VIR_FROM_NONE struct testInfo { int doEscape; }; static int testBufInfiniteLoop(const void *data) { virBuffer bufinit = VIR_BUFFER_INITIALIZER; virBufferPtr buf = &bufinit; char *addstr = NULL, *bufret = NULL; int ret = -1; const struct testInfo *info = data; virBufferAddChar(buf, 'a'); /* * Infinite loop used to trigger if: * (strlen + 1 > 1000) && (strlen == buf-size - buf-use - 1) * which was the case after the above addchar at the time of the bug. * This test is a bit fragile, since it relies on virBuffer internals. */ if (virAsprintf(&addstr, "%*s", buf->a - buf->b - 1, "a") < 0) goto out; if (info->doEscape) virBufferEscapeString(buf, "%s", addstr); else virBufferAsprintf(buf, "%s", addstr); ret = 0; out: bufret = virBufferContentAndReset(buf); if (!bufret) { VIR_TEST_DEBUG("Buffer had error set"); ret = -1; } VIR_FREE(addstr); VIR_FREE(bufret); return ret; } static int testBufAutoIndent(const void *data ATTRIBUTE_UNUSED) { virBuffer bufinit = VIR_BUFFER_INITIALIZER; virBufferPtr buf = &bufinit; const char expected[] = " 1\n 2\n 3\n 4\n 5\n 6\n 7\n &\n 8\n 9\n 10\n ' 11'\n"; char *result = NULL; int ret = 0; if (virBufferGetIndent(buf, false) != 0 || virBufferGetIndent(buf, true) != 0) { VIR_TEST_DEBUG("Wrong indentation"); ret = -1; } virBufferAdjustIndent(buf, 3); if (STRNEQ(virBufferCurrentContent(buf), "")) { VIR_TEST_DEBUG("Wrong content"); ret = -1; } if (virBufferGetIndent(buf, false) != 3 || virBufferGetIndent(buf, true) != 3 || virBufferError(buf)) { VIR_TEST_DEBUG("Wrong indentation"); ret = -1; } virBufferAdjustIndent(buf, -2); if (virBufferGetIndent(buf, false) != 1 || virBufferGetIndent(buf, true) != 1 || virBufferError(buf)) { VIR_TEST_DEBUG("Wrong indentation"); ret = -1; } virBufferAdjustIndent(buf, -3); if (virBufferGetIndent(buf, false) != -1 || virBufferGetIndent(buf, true) != -1 || virBufferError(buf) != -1) { VIR_TEST_DEBUG("Usage error not flagged"); ret = -1; } virBufferFreeAndReset(buf); if (virBufferGetIndent(buf, false) != 0 || virBufferGetIndent(buf, true) != 0 || virBufferError(buf)) { VIR_TEST_DEBUG("Reset didn't clear indentation"); ret = -1; } virBufferAdjustIndent(buf, 2); virBufferAddLit(buf, "1"); if (virBufferError(buf)) { VIR_TEST_DEBUG("Buffer had error"); return -1; } if (STRNEQ(virBufferCurrentContent(buf), " 1")) { VIR_TEST_DEBUG("Wrong content"); ret = -1; } if (virBufferGetIndent(buf, false) != 2 || virBufferGetIndent(buf, true) != 0) { VIR_TEST_DEBUG("Wrong indentation"); ret = -1; } virBufferAddLit(buf, "\n"); virBufferAdd(buf, "" "2\n", -1); /* Extra "" appeases syntax-check */ virBufferAddChar(buf, '3'); virBufferAddChar(buf, '\n'); virBufferAsprintf(buf, "%d", 4); virBufferAsprintf(buf, "%c", '\n'); virBufferStrcat(buf, "5", "\n", "6\n", NULL); virBufferEscapeString(buf, "%s\n", "7"); virBufferEscapeString(buf, "%s\n", "&"); virBufferEscapeSexpr(buf, "%s", "8\n"); virBufferURIEncodeString(buf, "9"); virBufferAddChar(buf, '\n'); virBufferEscapeShell(buf, "10"); virBufferAddChar(buf, '\n'); virBufferEscapeShell(buf, " 11"); virBufferAddChar(buf, '\n'); if (virBufferError(buf)) { VIR_TEST_DEBUG("Buffer had error"); return -1; } result = virBufferContentAndReset(buf); if (!result || STRNEQ(result, expected)) { virTestDifference(stderr, expected, result); ret = -1; } VIR_FREE(result); return ret; } static int testBufTrim(const void *data ATTRIBUTE_UNUSED) { virBuffer bufinit = VIR_BUFFER_INITIALIZER; virBufferPtr buf = NULL; char *result = NULL; const char *expected = "a,b"; int ret = -1; virBufferTrim(buf, "", 0); buf = &bufinit; virBufferAddLit(buf, "a;"); virBufferTrim(buf, "", 0); virBufferTrim(buf, "", -1); virBufferTrim(buf, NULL, 1); virBufferTrim(buf, NULL, 5); virBufferTrim(buf, "a", 2); virBufferAddLit(buf, ",b,,"); virBufferTrim(buf, "b", -1); virBufferTrim(buf, "b,,", 1); virBufferTrim(buf, ",", -1); if (virBufferError(buf)) { VIR_TEST_DEBUG("Buffer had error"); return -1; } result = virBufferContentAndReset(buf); if (!result || STRNEQ(result, expected)) { virTestDifference(stderr, expected, result); goto cleanup; } virBufferTrim(buf, NULL, -1); if (virBufferError(buf) != -1) { VIR_TEST_DEBUG("Usage error not flagged"); goto cleanup; } ret = 0; cleanup: virBufferFreeAndReset(buf); VIR_FREE(result); return ret; } static int testBufAddBuffer(const void *data ATTRIBUTE_UNUSED) { virBuffer buf1 = VIR_BUFFER_INITIALIZER; virBuffer buf2 = VIR_BUFFER_INITIALIZER; virBuffer buf3 = VIR_BUFFER_INITIALIZER; int ret = -1; char *result = NULL; const char *expected = \ " A long time ago, in a galaxy far,\n" \ " far away...\n" \ " It is a period of civil war.\n" \ " Rebel spaceships, striking\n" \ " from a hidden base, have won\n" \ " their first victory against\n" \ " the evil Galactic Empire.\n" \ " During the battle, rebel\n" \ " spies managed to steal secret\n" \ " plans to the Empire's\n" \ " ultimate weapon, the DEATH\n" \ " STAR, an armored space\n" \ " station with enough power to\n" \ " destroy an entire planet.\n"; if (virBufferUse(&buf1)) { VIR_TEST_DEBUG("buf1 already in use"); goto cleanup; } if (virBufferUse(&buf2)) { VIR_TEST_DEBUG("buf2 already in use"); goto cleanup; } if (virBufferUse(&buf3)) { VIR_TEST_DEBUG("buf3 already in use"); goto cleanup; } virBufferAdjustIndent(&buf1, 2); virBufferAddLit(&buf1, "A long time ago, in a galaxy far,\n"); virBufferAddLit(&buf1, "far away...\n"); virBufferAdjustIndent(&buf2, 4); virBufferAddLit(&buf2, "It is a period of civil war.\n"); virBufferAddLit(&buf2, "Rebel spaceships, striking\n"); virBufferAddLit(&buf2, "from a hidden base, have won\n"); virBufferAddLit(&buf2, "their first victory against\n"); virBufferAddLit(&buf2, "the evil Galactic Empire.\n"); virBufferAdjustIndent(&buf3, 2); virBufferAddLit(&buf3, "During the battle, rebel\n"); virBufferAddLit(&buf3, "spies managed to steal secret\n"); virBufferAddLit(&buf3, "plans to the Empire's\n"); virBufferAddLit(&buf3, "ultimate weapon, the DEATH\n"); virBufferAddLit(&buf3, "STAR, an armored space\n"); virBufferAddLit(&buf3, "station with enough power to\n"); virBufferAddLit(&buf3, "destroy an entire planet.\n"); if (!virBufferUse(&buf1)) { VIR_TEST_DEBUG("Error adding to buf1"); goto cleanup; } if (!virBufferUse(&buf2)) { VIR_TEST_DEBUG("Error adding to buf2"); goto cleanup; } if (!virBufferUse(&buf3)) { VIR_TEST_DEBUG("Error adding to buf3"); goto cleanup; } virBufferAddBuffer(&buf2, &buf3); if (!virBufferUse(&buf2)) { VIR_TEST_DEBUG("buf2 cleared mistakenly"); goto cleanup; } if (virBufferUse(&buf3)) { VIR_TEST_DEBUG("buf3 is not clear even though it should be"); goto cleanup; } virBufferAddBuffer(&buf1, &buf2); if (!virBufferUse(&buf1)) { VIR_TEST_DEBUG("buf1 cleared mistakenly"); goto cleanup; } if (virBufferUse(&buf2)) { VIR_TEST_DEBUG("buf2 is not clear even though it should be"); goto cleanup; } result = virBufferContentAndReset(&buf1); if (STRNEQ_NULLABLE(result, expected)) { virTestDifference(stderr, expected, result); goto cleanup; } ret = 0; cleanup: virBufferFreeAndReset(&buf1); virBufferFreeAndReset(&buf2); VIR_FREE(result); return ret; } struct testBufAddStrData { const char *data; const char *expect; }; static int testBufAddStr(const void *opaque ATTRIBUTE_UNUSED) { const struct testBufAddStrData *data = opaque; virBuffer buf = VIR_BUFFER_INITIALIZER; char *actual; int ret = -1; virBufferAddLit(&buf, "\n"); virBufferAdjustIndent(&buf, 2); virBufferAddStr(&buf, data->data); virBufferAdjustIndent(&buf, -2); virBufferAddLit(&buf, ""); if (!(actual = virBufferContentAndReset(&buf))) { VIR_TEST_DEBUG("buf is empty"); goto cleanup; } if (STRNEQ_NULLABLE(actual, data->expect)) { VIR_TEST_DEBUG("testBufAddStr(): Strings don't match:\n"); virTestDifference(stderr, data->expect, actual); goto cleanup; } ret = 0; cleanup: VIR_FREE(actual); return ret; } static int testBufEscapeStr(const void *opaque ATTRIBUTE_UNUSED) { const struct testBufAddStrData *data = opaque; virBuffer buf = VIR_BUFFER_INITIALIZER; char *actual; int ret = -1; virBufferAddLit(&buf, "\n"); virBufferAdjustIndent(&buf, 2); virBufferEscapeString(&buf, "%s\n", data->data); virBufferAdjustIndent(&buf, -2); virBufferAddLit(&buf, ""); if (!(actual = virBufferContentAndReset(&buf))) { VIR_TEST_DEBUG("buf is empty"); goto cleanup; } if (STRNEQ_NULLABLE(actual, data->expect)) { VIR_TEST_DEBUG("testBufEscapeStr(): Strings don't match:\n"); virTestDifference(stderr, data->expect, actual); goto cleanup; } ret = 0; cleanup: VIR_FREE(actual); return ret; } static int mymain(void) { int ret = 0; #define DO_TEST(msg, cb, data) \ do { \ struct testInfo info = { data }; \ if (virTestRun("Buf: " msg, cb, &info) < 0) \ ret = -1; \ } while (0) DO_TEST("EscapeString infinite loop", testBufInfiniteLoop, 1); DO_TEST("VSprintf infinite loop", testBufInfiniteLoop, 0); DO_TEST("Auto-indentation", testBufAutoIndent, 0); DO_TEST("Trim", testBufTrim, 0); DO_TEST("AddBuffer", testBufAddBuffer, 0); #define DO_TEST_ADD_STR(DATA, EXPECT) \ do { \ struct testBufAddStrData info = { DATA, EXPECT }; \ if (virTestRun("Buf: AddStr", testBufAddStr, &info) < 0) \ ret = -1; \ } while (0) DO_TEST_ADD_STR("", "\n"); DO_TEST_ADD_STR("", "\n "); DO_TEST_ADD_STR("\n", "\n \n"); DO_TEST_ADD_STR("\n \n\n", "\n \n \n \n"); #define DO_TEST_ESCAPE(data, expect) \ do { \ struct testBufAddStrData info = { data, expect }; \ if (virTestRun("Buf: EscapeStr", testBufEscapeStr, &info) < 0) \ ret = -1; \ } while (0) DO_TEST_ESCAPE("", "\n <td></td><td></td>\n"); DO_TEST_ESCAPE("\007\"&&\"\x15", "\n "&&"\n"); DO_TEST_ESCAPE(",,'..',,", "\n ,,'..',,\n"); DO_TEST_ESCAPE("\x01\x01\x02\x03\x05\x08", "\n \n"); return ret == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } VIRT_TEST_MAIN(mymain)