test-lib.c revision 49a7e4dba84bbf35d82669d1ae79ad43949eed19
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "test-lib.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "array.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "str.h"
9c6a09aa16095ff72837799a37e0e3b3e93bb3d8Timo Sirainen#include "base64.h"
31a9637b38d37451b649c86301b2c12e53a7810eTimo Sirainen#include "bsearch-insert-pos.h"
9c6a09aa16095ff72837799a37e0e3b3e93bb3d8Timo Sirainen#include "aqueue.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "network.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "primes.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "priorityq.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "seq-range-array.h"
6d2b3ce2c6ef62334985ece4f0ab8b154e0e9560Timo Sirainen#include "str-find.h"
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen#include "str-sanitize.h"
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen#include "utc-mktime.h"
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen
01230de017cd273de41143d88e9c18df1243ae8aTimo Sirainen#include <stdlib.h>
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen#include <time.h>
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen
047c00cd3f7f403672f81569413669238df8c15aTimo Sirainenstatic void test_array(void)
1f9d1bedae25d86f26c239055c5487499dfeeb58Timo Sirainen{
047c00cd3f7f403672f81569413669238df8c15aTimo Sirainen ARRAY_DEFINE(intarr, int);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen int input[] = { -1234567890, -272585721, 2724859223U, 824725652 };
f37ecd72aad9b806aae83f71bacafdce32146945Timo Sirainen const int *output;
f37ecd72aad9b806aae83f71bacafdce32146945Timo Sirainen unsigned int i, j;
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen bool success = TRUE;
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen t_array_init(&intarr, 5);
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen for (i = 0; i < N_ELEMENTS(input); i++) {
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen array_clear(&intarr);
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen array_append(&intarr, input, i);
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen array_reverse(&intarr);
8b5c520883aa37bb55646286d375fdbae294d710Timo Sirainen
8b5c520883aa37bb55646286d375fdbae294d710Timo Sirainen output = i == 0 ? NULL : array_idx(&intarr, 0);
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen for (j = 0; j < i; j++) {
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen if (input[i-j-1] != output[j]) {
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen success = FALSE;
0679f8a70a8dda43b204ae35fc6a903818cc6584Timo Sirainen break;
b63e20ea9bc84f1aa90a551f217d01385e070b73Timo Sirainen }
b63e20ea9bc84f1aa90a551f217d01385e070b73Timo Sirainen }
b63e20ea9bc84f1aa90a551f217d01385e070b73Timo Sirainen }
b63e20ea9bc84f1aa90a551f217d01385e070b73Timo Sirainen test_out("array_reverse()", success);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomistatic void test_base64_encode(void)
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi{
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi static const char *input[] = {
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi "hello world",
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi "foo barits",
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi "just niin"
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi };
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi static const char *output[] = {
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi "aGVsbG8gd29ybGQ=",
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi "Zm9vIGJhcml0cw==",
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi "anVzdCBuaWlu"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen };
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen string_t *str, *dest;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i, j, max;
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen char buf[10];
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen bool success;
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen str = t_str_new(256);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dest = t_str_new(256);
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen for (i = 0; i < N_ELEMENTS(input); i++) {
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen str_truncate(str, 0);
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch base64_encode(input[i], strlen(input[i]), str);
009217abb57a24a4076092e8e4e165545747839eStephan Bosch success = strcmp(output[i], str_c(str)) == 0;
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch test_out(t_strdup_printf("base64_encode(%d)", i), success);
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen }
72f21884c0bb9bb26edad63623427ac2120901eaStephan Bosch
009217abb57a24a4076092e8e4e165545747839eStephan Bosch for (i = 0; i < 1000; i++) {
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen max = rand() % sizeof(buf);
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi for (j = 0; j < max; j++)
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi buf[j] = rand();
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi str_truncate(str, 0);
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi str_truncate(dest, 0);
b68b98e1545bad8af9cb58ef89e8d7f6e16577beAki Tuomi base64_encode(buf, max, str);
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen base64_decode(str_data(str), str_len(str), NULL, dest);
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen if (str_len(dest) != max &&
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen memcmp(buf, str_data(dest), max) != 0)
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen break;
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen }
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen test_out("base64 random", success);
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen}
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainen
541f258d86b2db26efd5670883966183b4fb6323Timo Sirainenstruct test_base64_decode_output {
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen const char *text;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int src_pos;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen};
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void test_base64_decode(void)
4d4d6d4745682790c20d759ba93dbea46b812c5dTimo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen static const char *input[] = {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "\taGVsbG8gd29ybGQ=",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "\nZm9v\n \tIGJh \t\ncml0cw==",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen " anVzdCBuaWlu \n",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "aGVsb",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "aGVsb!!!!!",
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen "aGVs!!!!!"
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen };
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen static const struct test_base64_decode_output output[] = {
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen { "hello world", 0, -1 },
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen { "foo barits", 0, -1 },
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen { "just niin", 1, -1 },
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen { "hel", 1, 4 },
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen { "hel", -1, 4 },
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen { "hel", -1, 4 }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen };
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen string_t *str;
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen unsigned int i;
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen size_t src_pos;
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen int ret;
d6b3cfd855c0eebed68be50d3111de1b5a6afeb0Timo Sirainen bool success;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen str = t_str_new(256);
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen for (i = 0; i < N_ELEMENTS(input); i++) {
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen str_truncate(str, 0);
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen src_pos = 0;
8a0a8c982a6ffc75a4b1c8717b6180a811655794Timo Sirainen ret = base64_decode(input[i], strlen(input[i]), &src_pos, str);
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen success = output[i].ret == ret &&
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen strcmp(output[i].text, str_c(str)) == 0 &&
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (src_pos == output[i].src_pos ||
719abeb2088987f213a33a7dd1fe78958beaef03Timo Sirainen (output[i].src_pos == (unsigned int)-1 &&
719abeb2088987f213a33a7dd1fe78958beaef03Timo Sirainen src_pos == strlen(input[i])));
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen test_out(t_strdup_printf("base64_decode(%d)", i), success);
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainenstatic int cmp_uint(const void *p1, const void *p2)
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen{
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen const unsigned int *i1 = p1, *i2 = p2;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen return *i1 - *i2;
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen}
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainenstatic void test_bsearch_insert_pos(void)
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen{
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen static const unsigned int input[] = {
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen 1, 5, 9, 15, 16, -1,
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen 1, 5, 9, 15, 16, 17, -1,
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen -1
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen };
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen static const unsigned int max_key = 18;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen const unsigned int *cur;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen unsigned int key, len, i, idx;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen bool success;
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen cur = input;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; cur[0] != -1U; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (len = 0; cur[len] != -1U; len++) ;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (key = 0; key < max_key; key++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (bsearch_insert_pos(&key, cur, len, sizeof(*cur),
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen cmp_uint, &idx))
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen success = cur[idx] == key;
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainen else if (idx == 0)
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen success = cur[0] > key;
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen else if (idx == len)
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen success = cur[len-1] < key;
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen else {
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen success = cur[idx-1] < key &&
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen cur[idx+1] > key;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (!success)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen cur += len + 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen test_out(t_strdup_printf("bsearch_insert_pos(%d,%d)", i, key),
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen success);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainenstatic void test_buffer(void)
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define BUF_TEST_SIZE (1024*2)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define BUF_TEST_COUNT 1000
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen buffer_t *buf;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned char *p, testdata[BUF_TEST_SIZE], shadowbuf[BUF_TEST_SIZE];
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int i, shadowbuf_size;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen size_t pos, pos2, size;
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen int test = -1;
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainen bool zero;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen buf = buffer_create_dynamic(default_pool, 1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < BUF_TEST_SIZE; i++)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen testdata[i] = random();
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen memset(shadowbuf, 0, sizeof(shadowbuf));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen srand(1);
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen shadowbuf_size = 0;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen for (i = 0; i < BUF_TEST_COUNT; i++) {
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen if (buf->used == BUF_TEST_SIZE) {
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen size = shadowbuf_size = rand() % (buf->used - 1);
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainen buffer_set_used_size(buf, size);
57397188558fcd1a9e24dbbbd2952eac9c45c20dTimo Sirainen memset(shadowbuf + shadowbuf_size, 0,
03baa1c4c51f7b08fb285e82b528fcb00ac09ebfTimo Sirainen BUF_TEST_SIZE - shadowbuf_size);
03baa1c4c51f7b08fb285e82b528fcb00ac09ebfTimo Sirainen i_assert(buf->used < BUF_TEST_SIZE);
57397188558fcd1a9e24dbbbd2952eac9c45c20dTimo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen test = rand() % 6;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen zero = rand() % 10 == 0;
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen switch (test) {
db693bf6fcae96d834567f1782257517b7207655Timo Sirainen case 0:
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen pos = rand() % (BUF_TEST_SIZE-1);
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen size = rand() % (BUF_TEST_SIZE - pos);
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen if (!zero) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen buffer_write(buf, pos, testdata, size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen memcpy(shadowbuf + pos, testdata, size);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen buffer_write_zero(buf, pos, size);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen memset(shadowbuf + pos, 0, size);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen if (pos + size > shadowbuf_size)
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen shadowbuf_size = pos + size;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen break;
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen case 1:
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen size = rand() % (BUF_TEST_SIZE - buf->used);
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen if (!zero) {
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen buffer_append(buf, testdata, size);
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen memcpy(shadowbuf + shadowbuf_size,
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen testdata, size);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen } else {
754896551f0422cda5d78500b26700eec5343c5bAki Tuomi buffer_append_zero(buf, size);
754896551f0422cda5d78500b26700eec5343c5bAki Tuomi memset(shadowbuf + shadowbuf_size, 0, size);
754896551f0422cda5d78500b26700eec5343c5bAki Tuomi }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen shadowbuf_size += size;
break;
case 2:
pos = rand() % (BUF_TEST_SIZE-1);
size = rand() % (BUF_TEST_SIZE - I_MAX(buf->used, pos));
if (!zero) {
buffer_insert(buf, pos, testdata, size);
memmove(shadowbuf + pos + size,
shadowbuf + pos,
BUF_TEST_SIZE - (pos + size));
memcpy(shadowbuf + pos, testdata, size);
} else {
buffer_insert_zero(buf, pos, size);
memmove(shadowbuf + pos + size,
shadowbuf + pos,
BUF_TEST_SIZE - (pos + size));
memset(shadowbuf + pos, 0, size);
}
if (pos < shadowbuf_size)
shadowbuf_size += size;
else
shadowbuf_size = pos + size;
break;
case 3:
pos = rand() % (BUF_TEST_SIZE-1);
size = rand() % (BUF_TEST_SIZE - pos);
buffer_delete(buf, pos, size);
if (pos < shadowbuf_size) {
if (pos + size > shadowbuf_size)
size = shadowbuf_size - pos;
memmove(shadowbuf + pos,
shadowbuf + pos + size,
BUF_TEST_SIZE - (pos + size));
shadowbuf_size -= size;
memset(shadowbuf + shadowbuf_size, 0,
BUF_TEST_SIZE - shadowbuf_size);
}
break;
case 4:
if (shadowbuf_size == 0)
break;
pos = rand() % (shadowbuf_size-1); /* dest */
pos2 = rand() % (shadowbuf_size-1); /* source */
size = rand() % (shadowbuf_size - I_MAX(pos, pos2));
buffer_copy(buf, pos, buf, pos2, size);
memmove(shadowbuf + pos,
shadowbuf + pos2, size);
if (pos > pos2 && pos + size > shadowbuf_size)
shadowbuf_size = pos + size;
break;
case 5:
pos = rand() % (BUF_TEST_SIZE-1);
size = rand() % (BUF_TEST_SIZE - pos);
p = buffer_get_space_unsafe(buf, pos, size);
memcpy(p, testdata, size);
memcpy(shadowbuf + pos, testdata, size);
if (pos + size > shadowbuf_size)
shadowbuf_size = pos + size;
break;
}
i_assert(shadowbuf_size <= BUF_TEST_SIZE);
if (buf->used != shadowbuf_size ||
memcmp(buf->data, shadowbuf, buf->used) != 0)
break;
}
if (i == BUF_TEST_COUNT)
test_out("buffer", TRUE);
else {
test_out_reason("buffer", FALSE,
t_strdup_printf("round %u test %d failed", i, test));
}
buffer_free(&buf);
}
static bool aqueue_is_ok(struct aqueue *aqueue, unsigned int deleted_n)
{
const unsigned int *p;
unsigned int n, i, count;
count = aqueue_count(aqueue);
for (i = 0, n = 1; i < count; i++, n++) {
p = array_idx_i(aqueue->arr, aqueue_idx(aqueue, i));
if (i == deleted_n)
n++;
if (*p != n)
return FALSE;
}
return TRUE;
}
static const unsigned int aqueue_input[] = { 1, 2, 3, 4, 5, 6 };
static const char *test_aqueue2(unsigned int initial_size)
{
ARRAY_DEFINE(aqueue_array, unsigned int);
unsigned int i, j, k;
struct aqueue *aqueue;
for (i = 0; i < N_ELEMENTS(aqueue_input); i++) {
for (k = 0; k < N_ELEMENTS(aqueue_input); k++) {
t_array_init(&aqueue_array, initial_size);
aqueue = aqueue_init(&aqueue_array.arr);
aqueue->head = aqueue->tail = initial_size - 1;
for (j = 0; j < k; j++) {
aqueue_append(aqueue, &aqueue_input[j]);
if (aqueue_count(aqueue) != j + 1) {
return t_strdup_printf("Wrong count after append %u vs %u)",
aqueue_count(aqueue), j + 1);
}
if (!aqueue_is_ok(aqueue, -1U))
return "Invalid data after append";
}
if (k != 0 && i < k) {
aqueue_delete(aqueue, i);
if (aqueue_count(aqueue) != k - 1)
return "Wrong count after delete";
if (!aqueue_is_ok(aqueue, i))
return "Invalid data after delete";
}
}
}
aqueue_clear(aqueue);
if (aqueue_count(aqueue) != 0)
return "aqueue_clear() broken";
return NULL;
}
static void test_aqueue(void)
{
unsigned int i;
const char *reason = NULL;
for (i = 1; i <= N_ELEMENTS(aqueue_input) + 1 && reason == NULL; i++) {
T_BEGIN {
reason = test_aqueue2(i);
} T_END;
}
test_out_reason("aqueue", reason == NULL, reason);
}
static bool mem_has_bytes(const void *mem, size_t size, uint8_t b)
{
const uint8_t *bytes = mem;
unsigned int i;
for (i = 0; i < size; i++) {
if (bytes[i] != b)
return FALSE;
}
return TRUE;
}
static void test_mempool_alloconly(void)
{
#define PMALLOC_MAX_COUNT 128
pool_t pool;
unsigned int i, j, k;
void *mem[PMALLOC_MAX_COUNT + 1];
bool success = TRUE;
for (i = 0; i < 64; i++) {
for (j = 1; j <= 128; j++) {
pool = pool_alloconly_create(MEMPOOL_GROWING"test", i);
mem[0] = p_malloc(pool, j);
memset(mem[0], j, j);
for (k = 1; k <= PMALLOC_MAX_COUNT; k++) {
mem[k] = p_malloc(pool, k);
memset(mem[k], k, k);
}
if (!mem_has_bytes(mem[0], j, j))
success = FALSE;
for (k = 1; k <= PMALLOC_MAX_COUNT; k++) {
if (!mem_has_bytes(mem[k], k, k))
success = FALSE;
}
pool_unref(&pool);
}
}
test_out("mempool_alloconly", success);
}
struct test_net_is_in_network_input {
const char *ip;
const char *net;
unsigned int bits;
bool ret;
};
static void test_net_is_in_network(void)
{
static struct test_net_is_in_network_input input[] = {
{ "1.2.3.4", "1.2.3.4", 32, TRUE },
{ "1.2.3.4", "1.2.3.3", 32, FALSE },
{ "1.2.3.4", "1.2.3.5", 32, FALSE },
{ "1.2.3.4", "1.2.2.4", 32, FALSE },
{ "1.2.3.4", "1.1.3.4", 32, FALSE },
{ "1.2.3.4", "0.2.3.4", 32, FALSE },
{ "1.2.3.253", "1.2.3.254", 31, FALSE },
{ "1.2.3.254", "1.2.3.254", 31, TRUE },
{ "1.2.3.255", "1.2.3.254", 31, TRUE },
{ "1.2.3.255", "1.2.3.0", 24, TRUE },
{ "1.2.255.255", "1.2.254.0", 23, TRUE },
{ "255.255.255.255", "128.0.0.0", 1, TRUE },
{ "255.255.255.255", "127.0.0.0", 1, FALSE }
#ifdef HAVE_IPV6
,
{ "1234:5678::abcf", "1234:5678::abce", 127, TRUE },
{ "1234:5678::abcd", "1234:5678::abce", 127, FALSE },
{ "123e::ffff", "123e::0", 15, TRUE },
{ "123d::ffff", "123e::0", 15, FALSE }
#endif
};
struct ip_addr ip, net_ip;
unsigned int i;
bool success;
for (i = 0; i < N_ELEMENTS(input); i++) {
net_addr2ip(input[i].ip, &ip);
net_addr2ip(input[i].net, &net_ip);
success = net_is_in_network(&ip, &net_ip, input[i].bits) ==
input[i].ret;
test_out(t_strdup_printf("net_is_in_network(%u)", i), success);
}
}
struct pq_test_item {
struct priorityq_item item;
int num;
};
static int cmp_int(const void *p1, const void *p2)
{
const struct pq_test_item *i1 = p1, *i2 = p2;
return i1->num - i2->num;
}
static void test_primes(void)
{
unsigned int i, j, num;
bool success;
success = primes_closest(0) > 0;
for (num = 1; num < 1024; num++) {
if (primes_closest(num) < num)
success = FALSE;
}
for (i = 10; i < 32; i++) {
num = (1 << i) - 100;
for (j = 0; j < 200; j++, num++) {
if (primes_closest(num) < num)
success = FALSE;
}
}
test_out("primes_closest()", success);
}
static void test_priorityq(void)
{
#define PQ_MAX_ITEMS 100
static const int input[] = {
1, 2, 3, 4, 5, 6, 7, 8, -1,
8, 7, 6, 5, 4, 3, 2, 1, -1,
8, 7, 5, 6, 1, 3, 4, 2, -1,
-1
};
static const int output[] = {
1, 2, 3, 4, 5, 6, 7, 8
};
struct pq_test_item *item, items[PQ_MAX_ITEMS];
unsigned int i, j;
struct priorityq *pq;
pool_t pool;
int prev;
bool success = TRUE;
pool = pool_alloconly_create("priorityq items", 1024);
/* simple tests with popping only */
for (i = 0; input[i] != -1; i++) {
p_clear(pool);
pq = priorityq_init(cmp_int, 1);
for (j = 0; input[i] != -1; i++, j++) {
if (priorityq_count(pq) != j)
success = FALSE;
item = p_new(pool, struct pq_test_item, 1);
item->num = input[i];
priorityq_add(pq, &item->item);
}
for (j = 0; j < N_ELEMENTS(output); j++) {
if (priorityq_count(pq) != N_ELEMENTS(output) - j)
success = FALSE;
item = (struct pq_test_item *)priorityq_peek(pq);
if (output[j] != item->num)
success = FALSE;
item = (struct pq_test_item *)priorityq_pop(pq);
if (output[j] != item->num)
success = FALSE;
}
if (priorityq_count(pq) != 0)
success = FALSE;
if (priorityq_peek(pq) != NULL || priorityq_pop(pq) != NULL)
success = FALSE;
priorityq_deinit(&pq);
}
test_out("priorityq(1)", success);
/* randomized tests, remove elements */
success = TRUE;
for (i = 0; i < 100; i++) {
pq = priorityq_init(cmp_int, 1);
for (j = 0; j < PQ_MAX_ITEMS; j++) {
items[j].num = rand();
priorityq_add(pq, &items[j].item);
}
for (j = 0; j < PQ_MAX_ITEMS; j++) {
if (rand() % 3 == 0) {
priorityq_remove(pq, &items[j].item);
items[j].num = -1;
}
}
prev = 0;
while (priorityq_count(pq) > 0) {
item = (struct pq_test_item *)priorityq_pop(pq);
if (item->num < 0 || prev > item->num)
success = FALSE;
prev = item->num;
item->num = -1;
}
for (j = 0; j < PQ_MAX_ITEMS; j++) {
if (items[j].num != -1)
success = FALSE;
}
priorityq_deinit(&pq);
}
test_out("priorityq(2)", success);
pool_unref(&pool);
}
static void test_seq_range_array_random(void)
{
#define SEQ_RANGE_TEST_BUFSIZE 20
#define SEQ_RANGE_TEST_COUNT 10000
unsigned char shadowbuf[SEQ_RANGE_TEST_BUFSIZE];
ARRAY_TYPE(seq_range) range;
const struct seq_range *seqs;
uint32_t seq1, seq2;
unsigned int i, j, ret, ret2, count;
int test = -1;
ret = ret2 = 0;
i_array_init(&range, 1);
memset(shadowbuf, 0, sizeof(shadowbuf));
for (i = 0; i < SEQ_RANGE_TEST_COUNT; i++) {
seq1 = rand() % SEQ_RANGE_TEST_BUFSIZE;
seq2 = seq1 + rand() % (SEQ_RANGE_TEST_BUFSIZE - seq1);
test = rand() % 4;
switch (test) {
case 0:
seq_range_array_add(&range, 0, seq1);
shadowbuf[seq1] = 1;
break;
case 1:
seq_range_array_add_range(&range, seq1, seq2);
memset(shadowbuf + seq1, 1, seq2 - seq1 + 1);
break;
case 2:
ret = seq_range_array_remove(&range, seq1) ? 1 : 0;
ret2 = shadowbuf[seq1] != 0 ? 1 : 0;
shadowbuf[seq1] = 0;
break;
case 3:
ret = seq_range_array_remove_range(&range, seq1, seq2);
for (ret2 = 0; seq1 <= seq2; seq1++) {
if (shadowbuf[seq1] != 0) {
ret2++;
shadowbuf[seq1] = 0;
}
}
break;
}
if (ret != ret2)
break;
seqs = array_get(&range, &count);
for (j = 0, seq1 = 0; j < count; j++) {
if (j > 0 && seqs[j-1].seq2 >= seqs[j].seq1)
goto fail;
for (; seq1 < seqs[j].seq1; seq1++) {
if (shadowbuf[seq1] != 0)
goto fail;
}
for (; seq1 <= seqs[j].seq2; seq1++) {
if (shadowbuf[seq1] == 0)
goto fail;
}
}
i_assert(seq1 <= SEQ_RANGE_TEST_BUFSIZE);
for (; seq1 < SEQ_RANGE_TEST_BUFSIZE; seq1++) {
if (shadowbuf[seq1] != 0)
goto fail;
}
}
fail:
if (i == SEQ_RANGE_TEST_COUNT)
test_out("seq_range_array random", TRUE);
else {
test_out_reason("seq_range_array random", FALSE,
t_strdup_printf("round %u test %d failed", i, test));
}
}
static void test_seq_range_array_invert(void)
{
static const unsigned int input_min = 1, input_max = 5;
static const unsigned int input[] = {
1, 2, 3, 4, 5, -1U,
2, 3, 4, -1U,
1, 2, 4, 5, -1U,
1, 3, 5, -1U,
1, -1U,
5, -1U,
-1U
};
ARRAY_TYPE(seq_range) range = ARRAY_INIT;
unsigned int i, j, seq, start, num;
bool old_exists, success;
for (i = num = 0; input[i] != -1U; num++, i++) {
success = TRUE;
start = i;
for (; input[i] != -1U; i++) {
seq_range_array_add(&range, 32, input[i]);
for (j = start; j < i; j++) {
if (!seq_range_exists(&range, input[j]))
success = FALSE;
}
}
seq_range_array_invert(&range, input_min, input_max);
for (seq = input_min; seq <= input_max; seq++) {
for (j = start; input[j] != -1U; j++) {
if (input[j] == seq)
break;
}
old_exists = input[j] != -1U;
if (seq_range_exists(&range, seq) == old_exists)
success = FALSE;
}
test_out(t_strdup_printf("seq_range_array_invert(%u)", num),
success);
array_free(&range);
}
}
static void test_seq_range_create(ARRAY_TYPE(seq_range) *array, uint8_t byte)
{
unsigned int i;
array_clear(array);
for (i = 0; i < 8; i++) {
if ((byte & (1 << i)) != 0)
seq_range_array_add(array, 0, i + 1);
}
}
static void test_seq_range_array_have_common(void)
{
ARRAY_TYPE(seq_range) arr1, arr2;
unsigned int i, j;
bool ret1, ret2, success = TRUE;
t_array_init(&arr1, 8);
t_array_init(&arr2, 8);
for (i = 0; i < 256; i++) {
test_seq_range_create(&arr1, i);
for (j = 0; j < 256; j++) {
test_seq_range_create(&arr2, j);
ret1 = seq_range_array_have_common(&arr1, &arr2);
ret2 = (i & j) != 0;
if (ret1 != ret2)
success = FALSE;
}
}
test_out("seq_range_array_have_common()", success);
}
static void test_seq_range_array(void)
{
test_seq_range_array_invert();
test_seq_range_array_have_common();
test_seq_range_array_random();
}
static const char *str_find_text = "xababcd";
static bool test_str_find_substring(const char *key, int expected_pos)
{
const unsigned char *text = (const unsigned char *)str_find_text;
const unsigned int text_len = strlen(str_find_text);
struct str_find_context *ctx;
unsigned int i, j, pos, max, offset;
bool ret;
ctx = str_find_init(pool_datastack_create(), key);
/* divide text into every possible block combination and test that
it matches */
max = 1 << (text_len-1);
for (i = 0; i < max; i++) {
str_find_reset(ctx);
pos = 0; offset = 0; ret = FALSE;
for (j = 0; j < text_len; j++) {
if ((i & (1 << j)) != 0) {
if (str_find_more(ctx, text+pos, j-pos+1)) {
ret = TRUE;
break;
}
offset += j-pos + 1;
pos = j + 1;
}
}
if (pos != text_len && !ret) {
if (str_find_more(ctx, text+pos, j-pos))
ret = TRUE;
}
if (expected_pos < 0) {
if (ret)
return FALSE;
} else {
if (!ret)
return FALSE;
pos = str_find_get_match_end_pos(ctx) +
offset - strlen(key);
if ((int)pos != expected_pos)
return FALSE;
}
}
return TRUE;
}
struct str_find_input {
const char *str;
int pos;
};
static void test_str_find(void)
{
static const char *fail_input[] = {
"xabc",
"xabd",
"abd"
};
unsigned int idx, len;
const char *key, *p;
unsigned int i;
bool success = TRUE;
for (idx = 0; idx < strlen(str_find_text); idx++) {
for (len = strlen(str_find_text)-idx; len > 0; len--) {
/* we'll get a search key for all substrings of text */
T_BEGIN {
key = t_strndup(str_find_text + idx, len);
p = strstr(str_find_text, key);
success = test_str_find_substring(key, p - str_find_text);
} T_END;
if (!success)
break;
}
}
for (i = 0; i < N_ELEMENTS(fail_input) && success; i++)
success = test_str_find_substring(fail_input[i], -1);
test_out("str_find()", success);
}
struct str_sanitize_input {
const char *str;
unsigned int max_len;
};
static void test_str_sanitize(void)
{
static struct str_sanitize_input input[] = {
{ NULL, 2 },
{ "", 2 },
{ "a", 2 },
{ "ab", 2 },
{ "abc", 2 },
{ "abcd", 3 },
{ "abcde", 4 }
};
static const char *output[] = {
NULL,
"",
"a",
"ab",
"...",
"...",
"a..."
};
const char *str;
unsigned int i;
bool success;
for (i = 0; i < N_ELEMENTS(input); i++) {
str = str_sanitize(input[i].str, input[i].max_len);
success = null_strcmp(output[i], str) == 0;
test_out(t_strdup_printf("str_sanitize(%d)", i), success);
}
}
struct test_message_date_output {
time_t time;
int tz_offset;
bool ret;
};
struct test_utc_mktime_input {
int year, month, day, hour, min, sec;
};
static void test_utc_mktime(void)
{
static struct test_utc_mktime_input input[] = {
#ifdef TIME_T_SIGNED
{ 1969, 12, 31, 23, 59, 59 },
{ 1901, 12, 13, 20, 45, 53 },
#endif
#if (TIME_T_MAX_BITS > 32 || !defined(TIME_T_SIGNED))
{ 2106, 2, 7, 6, 28, 15 },
#endif
{ 2007, 11, 7, 1, 7, 20 },
{ 1970, 1, 1, 0, 0, 0 },
{ 2038, 1, 19, 3, 14, 7 }
};
static time_t output[] = {
#ifdef TIME_T_SIGNED
-1,
-2147483647,
#endif
#if (TIME_T_MAX_BITS > 32 || !defined(TIME_T_SIGNED))
4294967295,
#endif
1194397640,
0,
2147483647
};
struct tm tm;
unsigned int i;
time_t t;
bool success;
for (i = 0; i < N_ELEMENTS(input); i++) {
memset(&tm, 0, sizeof(tm));
tm.tm_year = input[i].year - 1900;
tm.tm_mon = input[i].month - 1;
tm.tm_mday = input[i].day;
tm.tm_hour = input[i].hour;
tm.tm_min = input[i].min;
tm.tm_sec = input[i].sec;
t = utc_mktime(&tm);
success = t == output[i];
test_out_reason(t_strdup_printf("utc_mktime(%d)", i), success,
success ? NULL : t_strdup_printf("%ld != %ld",
(long)t, (long)output[i]));
}
}
int main(void)
{
static void (*test_functions[])(void) = {
test_array,
test_aqueue,
test_base64_encode,
test_base64_decode,
test_bsearch_insert_pos,
test_buffer,
test_mempool_alloconly,
test_net_is_in_network,
test_primes,
test_priorityq,
test_seq_range_array,
test_str_find,
test_str_sanitize,
test_utc_mktime,
test_istreams
};
unsigned int i;
test_init();
for (i = 0; i < N_ELEMENTS(test_functions); i++) {
T_BEGIN {
test_functions[i]();
} T_END;
}
return test_deinit();
}