static int test_update(void) { logbuffer_t logbuf = logbuffer_FREE; thread_t * thread = 0; pipe_t pipe = pipe_FREE; uint8_t buffer[1024]; uint8_t readbuffer[1024+1]; // prepare TEST(0 == init_pipe(&pipe)); logbuf = (logbuffer_t) logbuffer_INIT(sizeof(buffer), buffer, pipe.write); // TEST truncate_logbuffer for (unsigned i = 0; i < 32; ++i) { logbuf.logsize = 32; logbuf.addr[i] = 'a'; truncate_logbuffer(&logbuf, i); TEST(logbuf.addr == buffer); TEST(logbuf.size == sizeof(buffer)); TEST(logbuf.io == pipe.write); TEST(logbuf.addr[i] == 0); TEST(logbuf.logsize == i); } // TEST truncate_logbuffer: parameter with bigger or equal size are ignored for (unsigned i = 0; i < 32; ++i) { logbuf.logsize = i; logbuf.addr[i] = 'a'; logbuf.addr[i+1] = 'a'; truncate_logbuffer(&logbuf, i+1); truncate_logbuffer(&logbuf, i); TEST(logbuf.addr == buffer); TEST(logbuf.size == sizeof(buffer)); TEST(logbuf.io == pipe.write); TEST(logbuf.addr[i] == 'a'); TEST(logbuf.addr[i+1] == 'a'); TEST(logbuf.logsize == i); } // TEST write_logbuffer memset(readbuffer, 0, sizeof(readbuffer)); for (unsigned i = 0; i < sizeof(buffer); ++i) { buffer[i] = (uint8_t)i; } logbuf.logsize = logbuf.size; // test TEST( 0 == write_logbuffer(&logbuf)); // check logbuf TEST( logbuf.addr == buffer); TEST( logbuf.size == sizeof(buffer)); TEST( logbuf.logsize == sizeof(buffer)); TEST( logbuf.io == pipe.write); // check content of pipe static_assert(sizeof(readbuffer) > sizeof(buffer), "check that only sizeof(buffer) are written"); TEST(sizeof(buffer) == read(pipe.read, readbuffer, sizeof(readbuffer))); for (unsigned i = 0; i < sizeof(buffer); ++i) { TEST(buffer[i] == readbuffer[i]); } // TEST printheader_logbuffer logbuf.logsize = 0; log_header_t header = log_header_INIT("test_update", "file", 123456); printheader_logbuffer(&logbuf, &header); TEST(0 == compare_header(logbuf.logsize, logbuf.addr, "test_update", "file", 123456)); for (size_t len = logbuf.logsize, i = 1; i < 10; ++i) { printheader_logbuffer(&logbuf, &header); TEST((i+1)*len == logbuf.logsize); TEST(0 == compare_header(len, logbuf.addr + i*len, "test_update", "file", 123456)); } // TEST printheader_logbuffer: other thread TEST(0 == newgeneric_thread(&thread, &thread_printheader, &logbuf)); TEST(0 == join_thread(thread)); TEST(0 == returncode_thread(thread)); TEST(0 == delete_thread(&thread)); // TEST printheader_logbuffer: adds " ..." at end in case of truncated message logbuf.logsize = logbuf.size - 10; logbuf.addr[logbuf.logsize] = 0; printheader_logbuffer(&logbuf, &header); TEST(logbuf.logsize == logbuf.size - 1) TEST(0 == memcmp(logbuf.addr + logbuf.size - 10, "[", 1)); TEST(0 == memcmp(logbuf.addr + logbuf.size - 5, " ...", 5)); // TEST vprintf_logbuffer: append on already stored content for (unsigned i = 0; i < sizeof(buffer)-100; ++i) { memset(buffer, 0, sizeof(buffer)); memset(readbuffer, 0, sizeof(readbuffer)); logbuf.logsize = i; printf_logbuffer(&logbuf, "%d : %s : %c;;", i, "OK!", '0'); snprintf((char*)readbuffer + i, 100, "%d : %s : %c;;", i, "OK!", '0'); TEST(0 == memcmp(buffer, readbuffer, sizeof(buffer))); } // TEST vprintf_logbuffer: different formats logbuf.logsize = 0; printf_logbuffer(&logbuf, "%%%s%%", "str" ); printf_logbuffer(&logbuf, "%"PRIi8";", (int8_t)-1); printf_logbuffer(&logbuf, "%"PRIu8";", (uint8_t)1); printf_logbuffer(&logbuf, "%"PRIi16";", (int16_t)-256); printf_logbuffer(&logbuf, "%"PRIu16";", (uint16_t)256); printf_logbuffer(&logbuf, "%"PRIi32";", (int32_t)-65536); printf_logbuffer(&logbuf, "%"PRIu32";", (uint32_t)65536); printf_logbuffer(&logbuf, "%zd;", (ssize_t)-65536); printf_logbuffer(&logbuf, "%zu;", (size_t)65536); printf_logbuffer(&logbuf, "%g;", 2e100); printf_logbuffer(&logbuf, "%.0f;", (double)1234567); const char * result = "%str%-1;1;-256;256;-65536;65536;-65536;65536;2e+100;1234567;"; TEST(strlen(result) == logbuf.logsize); TEST(0 == memcmp(logbuf.addr, result, logbuf.logsize)); // TEST vprintf_logwriter: adds " ..." at end in case of truncated message char strtoobig[100]; memset(strtoobig, '1', sizeof(strtoobig)); logbuf.logsize = logbuf.size - sizeof(strtoobig); logbuf.addr[logbuf.logsize] = 0; printf_logbuffer(&logbuf, "%.100s", strtoobig); TEST(logbuf.logsize == logbuf.size - 1) TEST(0 == memcmp(logbuf.addr + logbuf.size - sizeof(strtoobig), strtoobig, sizeof(strtoobig)-5)); TEST(0 == memcmp(logbuf.addr + logbuf.size - 5, " ...", 5)); // TEST vprintf_logbuffer: format == 0 logbuf.logsize = 0; printf_logbuffer(&logbuf, 0); // nothing printed TEST(0 == logbuf.logsize); // TEST vprintf_logbuffer: sizefree_logbuffer() == 0 logbuf.logsize = logbuf.size; memset(logbuf.addr, 255, logbuf.size); printf_logbuffer(&logbuf, "%d", 12345); // check logbuf not changed TEST(buffer == logbuf.addr); TEST(sizeof(buffer) == logbuf.size); TEST(sizeof(buffer) == logbuf.logsize); TEST(pipe.write == logbuf.io); // check content of logbuf not changed except for " ..." for (size_t i = 0; i < logbuf.logsize - 5; ++i) { TEST(255 == logbuf.addr[i]); } TEST(0 == memcmp(logbuf.addr + logbuf.logsize - 5, " ...", 4)); TEST(255 == logbuf.addr[logbuf.logsize-1]); // TEST vprintf_logbuffer: logbuffer_t.size <= 5 for (size_t s = 5; s <= 5; --s) { TEST(sizeof(buffer) == logbuf.size); logbuf.size = s; logbuf.logsize = 0; memset(logbuf.addr, 255, s); printf_logbuffer(&logbuf, "%d", 12345); // check logbuf TEST(buffer == logbuf.addr); TEST(s == logbuf.size); TEST((s?s-1:0) == logbuf.logsize); TEST(pipe.write == logbuf.io); // check content of logbuf if (s == 5) { // " ..." TEST(0 == memcmp(logbuf.addr, " ...", 5)); } else { // truncated 12345 for (size_t i = 0; i < logbuf.logsize; ++i) { TEST(i+'1' == logbuf.addr[i]); } TEST(0 == (logbuf.size ? logbuf.addr[logbuf.size-1] : 0)); } // reset logbuf.size = sizeof(buffer); } // unprepare TEST(-1 == read(pipe.read, readbuffer, sizeof(readbuffer))); TEST(0 == free_pipe(&pipe)); return 0; ONERR: delete_thread(&thread); free_pipe(&pipe); return EINVAL; }
static int test_logininfo(void) { syslogin_info_t* info = 0; thread_t* thr = 0; uid_t uid; gid_t gid; int fd[2] = { -1, -1 }; uint8_t buffer[16]; // prepare TEST(0 == pipe2(fd, O_CLOEXEC|O_NONBLOCK)); // == lifetime == for (unsigned entrypos = 0; true; ++entrypos) { setpwent(); for (unsigned i = 0; i < entrypos; ++i) { TEST(0 != getpwent()); } struct passwd* pwd = getpwent(); if (pwd == 0) { TEST(entrypos > 2); // tested at least 2 entries break; } uid = pwd->pw_uid; gid = pwd->pw_gid; // TEST new_syslogininfo: read entries TEST(0 == new_syslogininfo(&info, uid)); TEST(0 != info); TEST(0 < info->size); TEST(uid == info->uid); TEST(1 <= info->nrgroups); TEST(info->nrgroups > info->gmain); TEST(gid == info->gid[info->gmain]); // check memory addr TEST(info->gname == (const char**)(&info[1])); TEST(info->gid == (sys_groupid_t*)((uint8_t*)info->gname + info->nrgroups * sizeof(char*))); TEST(info->uname == (const char*)((uint8_t*)info->gid + info->nrgroups * sizeof(sys_groupid_t))); TEST(info->gname[0] == info->uname + strlen(info->uname) + 1); TEST((uint8_t*)info + info->size == (const uint8_t*)info->gname[info->nrgroups-1] + strlen(info->gname[info->nrgroups-1]) + 1); for (size_t i = 1; i < info->nrgroups; ++i) { TEST(info->gname[i-1] + strlen(info->gname[i-1]) + 1 == info->gname[i]); } // DEBUG printf("user %s(%d) groups ", info->uname, info->uid); // DEBUG for (size_t i = 0; i < info->nrgroups; ++i) { // DEBUG if (i == info->gmain) printf("*"); // DEBUG printf("%s(%d),", info->gname[i], info->gid[i]); // DEBUG } // DEBUG printf("\n"); // TEST delete_syslogininfo TEST(0 != info); TEST(0 == delete_syslogininfo(&info)); TEST(0 == info); TEST(0 == delete_syslogininfo(&info)); TEST(0 == info); } // TEST new_syslogininfo: lock TEST(0 == new_thread(&thr, &thread_initinfo, (void*)(intptr_t)fd[1])); TEST(0 == lock_mutex(&s_syslogininfo_lock)); struct pollfd pfd = { .fd = fd[0], .events = POLLIN }; TEST(1 == poll(&pfd, 1, 10000)); TEST(1 == read(fd[0], buffer, sizeof(buffer))); TEST(EBUSY == tryjoin_thread(thr)); TEST(-1 == read(fd[0], buffer, sizeof(buffer))); TEST(EAGAIN == errno); TEST(0 == unlock_mutex(&s_syslogininfo_lock)); TEST(0 == join_thread(thr)); TEST(0 == returncode_thread(thr)); TEST(0 == delete_thread(&thr)); // TEST new_syslogininfo: ENOENT info = (void*)1; TEST(ENOENT == new_syslogininfo(&info, (uid_t)-2)); TEST((void*)1 == info); info = 0; // == query == // TEST username_syslogininfo syslogin_info_t info2; info2.uname = 0; TEST(0 == username_syslogininfo(&info2)); for (uintptr_t i = 1; i; i <<= 1) { info2.uname = (const char*)i; TEST((const char*)i == username_syslogininfo(&info2)); } // unprepare TEST(0 == close(fd[0])); TEST(0 == close(fd[1])); return 0; ONERR: if (info != (void*)1) { delete_syslogininfo(&info); } close(fd[0]); close(fd[1]); return EINVAL; }