diff --git a/tests/ipc_test.c b/tests/ipc_test.c index ac51bf2..e6e0e17 100644 --- a/tests/ipc_test.c +++ b/tests/ipc_test.c @@ -1,6 +1,7 @@ #define _POSIX_C_SOURCE 200809L #include +#include #include #include "test.h" @@ -51,3 +52,166 @@ ipc_runtime_path(struct ct *t) }else unsetenv("XDG_RUNTIME_DIR"); } + +void +ipc_response_pack_boundaries(struct ct *t) +{ + static const uchar withpre[] = { 1, 1, 0, 'A', 2, 0, 'x', 'y' }; + static const uchar withoutpre[] = { 1, 1, 0, 'A' }; + uchar out[Ipcmaxresp+1], field[Ipcfieldmax]; + int n; + + n = ipcpackresp(out, sizeof out, 7, "A", 1, "xy", 2, 1); + CT_EQ_INT(t, sizeof withpre, n); + CT_EQ_MEM(t, withpre, out, sizeof withpre); + n = ipcpackresp(out, sizeof out, 1, "A", 1, "xy", 2, 0); + CT_EQ_INT(t, sizeof withoutpre, n); + CT_EQ_MEM(t, withoutpre, out, sizeof withoutpre); + n = ipcpackresp(out, sizeof out, 0, nil, 0, nil, 0, 1); + CT_EQ_INT(t, Ipcresphdrsz + Ipclensz, n); + + memset(field, 'x', sizeof field); + memset(out, 0xa5, sizeof out); + n = ipcpackresp(out, Ipcmaxresp, 1, + (char*)field, sizeof field, (char*)field, sizeof field, 1); + CT_EQ_INT(t, Ipcmaxresp, n); + CT_EQ_INT(t, 0, out[1]); + CT_EQ_INT(t, 1, out[2]); + CT_EQ_INT(t, 0, out[3+Ipcfieldmax]); + CT_EQ_INT(t, 1, out[4+Ipcfieldmax]); + CT_EQ_INT(t, 0xa5, out[Ipcmaxresp]); + CT_EQ_INT(t, -1, ipcpackresp(out, Ipcmaxresp-1, 1, + (char*)field, sizeof field, (char*)field, sizeof field, 1)); + CT_EQ_INT(t, -1, ipcpackresp(out, sizeof out, 0, + nil, 1, nil, 0, 0)); + CT_EQ_INT(t, -1, ipcpackresp(out, sizeof out, 0, + nil, 0, nil, 1, 1)); + CT_EQ_INT(t, -1, ipcpackresp(out, sizeof out, 0, + (char*)field, Ipcfieldmax+1, nil, 0, 0)); +} + +void +ipc_response_empty_and_preedit(struct ct *t) +{ + uchar first[Ipcmaxresp], second[Ipcmaxresp]; + char commit[16], preedit[16]; + Ipcresp resp; + int fd[2], nfirst, nsecond; + + nfirst = ipcpackresp(first, sizeof first, 0, nil, 0, nil, 0, 0); + nsecond = ipcpackresp(second, sizeof second, 1, + "go", 2, "kana", 4, 1); + if(!CT_CHECK(t, nfirst > 0 && nsecond > 0)) + return; + if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0){ + CT_ERRORF(t, "socketpair failed"); + return; + } + if(CT_EQ_INT(t, 0, ipcsend(fd[0], first, nfirst)) && + CT_EQ_INT(t, 0, ipcsend(fd[0], second, nsecond)) && + CT_EQ_INT(t, 0, ipcreadresp(fd[1], 0, commit, sizeof commit, + nil, 0, &resp))){ + CT_EQ_INT(t, 0, resp.eaten); + CT_EQ_SIZE(t, 0, resp.ncommit); + CT_EQ_SIZE(t, 0, resp.npreedit); + CT_EQ_STR(t, "", commit); + } + if(CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1, commit, sizeof commit, + preedit, sizeof preedit, &resp))){ + CT_EQ_INT(t, 1, resp.eaten); + CT_EQ_SIZE(t, 2, resp.ncommit); + CT_EQ_SIZE(t, 4, resp.npreedit); + CT_EQ_STR(t, "go", commit); + CT_EQ_STR(t, "kana", preedit); + } + close(fd[0]); + close(fd[1]); +} + +void +ipc_response_max_and_drain(struct ct *t) +{ + uchar first[Ipcmaxresp], second[Ipcmaxresp], field[Ipcfieldmax]; + char commit[8], preedit[8]; + Ipcresp resp; + int fd[2], nfirst, nsecond; + + memset(field, 'x', sizeof field); + nfirst = ipcpackresp(first, sizeof first, 1, + (char*)field, sizeof field, (char*)field, sizeof field, 1); + nsecond = ipcpackresp(second, sizeof second, 0, "ok", 2, nil, 0, 0); + if(!CT_CHECK(t, nfirst == Ipcmaxresp && nsecond > 0)) + return; + if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0){ + CT_ERRORF(t, "socketpair failed"); + return; + } + if(CT_EQ_INT(t, 0, ipcsend(fd[0], first, nfirst)) && + CT_EQ_INT(t, 0, ipcsend(fd[0], second, nsecond)) && + CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1, commit, sizeof commit, + preedit, sizeof preedit, &resp))){ + CT_EQ_SIZE(t, Ipcfieldmax, resp.ncommit); + CT_EQ_SIZE(t, Ipcfieldmax, resp.npreedit); + CT_EQ_STR(t, "xxxxxxx", commit); + CT_EQ_STR(t, "xxxxxxx", preedit); + } + if(CT_EQ_INT(t, 0, ipcreadresp(fd[1], 0, commit, sizeof commit, + nil, 0, &resp))) + CT_EQ_STR(t, "ok", commit); + close(fd[0]); + close(fd[1]); +} + +void +ipc_response_fragmented_and_truncated(struct ct *t) +{ + uchar frame[Ipcmaxresp]; + char commit[8], preedit[8]; + Ipcresp resp; + int fd[2], i, n; + + n = ipcpackresp(frame, sizeof frame, 1, "abc", 3, "xy", 2, 1); + if(!CT_CHECK(t, n > 0)) + return; + if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0){ + CT_ERRORF(t, "socketpair failed"); + return; + } + for(i = 0; i < n; i++) + if(ipcsend(fd[0], frame+i, 1) < 0){ + CT_ERRORF(t, "fragment send failed"); + break; + } + if(i == n && CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1, + commit, sizeof commit, preedit, sizeof preedit, &resp))){ + CT_EQ_STR(t, "abc", commit); + CT_EQ_STR(t, "xy", preedit); + } + close(fd[0]); + close(fd[1]); + + if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0){ + CT_ERRORF(t, "socketpair failed"); + return; + } + CT_EQ_INT(t, 0, ipcsend(fd[0], frame, n-1)); + shutdown(fd[0], SHUT_WR); + CT_EQ_INT(t, -1, ipcreadresp(fd[1], 1, commit, sizeof commit, + preedit, sizeof preedit, &resp)); + close(fd[0]); + close(fd[1]); +} + +void +ipc_broken_peer_send(struct ct *t) +{ + int fd[2]; + + if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0){ + CT_ERRORF(t, "socketpair failed"); + return; + } + close(fd[1]); + CT_EQ_INT(t, -1, ipcsend(fd[0], "x", 1)); + close(fd[0]); +} diff --git a/tests/test.h b/tests/test.h index b360b82..0776244 100644 --- a/tests/test.h +++ b/tests/test.h @@ -65,5 +65,10 @@ void dictionary_misses_clear_result(struct ct*); void dictionary_emoji_identity(struct ct*); void ipc_masks_modifiers(struct ct*); void ipc_runtime_path(struct ct*); +void ipc_response_pack_boundaries(struct ct*); +void ipc_response_empty_and_preedit(struct ct*); +void ipc_response_max_and_drain(struct ct*); +void ipc_response_fragmented_and_truncated(struct ct*); +void ipc_broken_peer_send(struct ct*); #endif diff --git a/tests/unit_test.c b/tests/unit_test.c index ce28a33..815d5e1 100644 --- a/tests/unit_test.c +++ b/tests/unit_test.c @@ -114,6 +114,11 @@ static const struct ct_test tests[] = { { "dict/emoji-identity", dictionary_emoji_identity }, { "ipc/masks-modifiers", ipc_masks_modifiers }, { "ipc/runtime-path", ipc_runtime_path }, + { "ipc/response-pack-boundaries", ipc_response_pack_boundaries }, + { "ipc/response-empty-preedit", ipc_response_empty_and_preedit }, + { "ipc/response-max-drain", ipc_response_max_and_drain }, + { "ipc/response-fragmented-truncated", ipc_response_fragmented_and_truncated }, + { "ipc/broken-peer-send", ipc_broken_peer_send }, }; void