#define _POSIX_C_SOURCE 200809L #include #include #include #include "test.h" void ipc_masks_modifiers(struct ct *t) { uchar buf[Ipcreqsz]; u32int key, mod; int want; ipcpackreq(buf, 1, Mctrl|Malt|(1<<1)|(1<<4)|(1<<7), 0x1f642); ipcunpackreq(buf, &want, &mod, &key); CT_EQ_INT(t, 1, want); CT_EQ_UINT(t, Mctrl|Malt, mod); CT_EQ_UINT(t, 0x1f642, key); CT_CHECK(t, !ipcreqreset(buf)); ipcpackreset(buf, 1); ipcunpackreq(buf, &want, &mod, &key); CT_EQ_INT(t, 1, want); CT_EQ_UINT(t, 0, mod); CT_EQ_UINT(t, 0, key); CT_CHECK(t, ipcreqreset(buf)); } void ipc_runtime_path(struct ct *t) { char buf[128], fallback[128], *old, *saved; old = getenv("XDG_RUNTIME_DIR"); saved = old == nil ? nil : strdup(old); setenv("XDG_RUNTIME_DIR", "/tmp/strans-runtime-test", 1); CT_EQ_INT(t, 0, ipcpath(buf, sizeof buf)); CT_EQ_STR(t, "/tmp/strans-runtime-test/strans.sock", buf); setenv("XDG_RUNTIME_DIR", "/tmp/strans-runtime-test/", 1); CT_EQ_INT(t, 0, ipcpath(buf, sizeof buf)); CT_EQ_STR(t, "/tmp/strans-runtime-test/strans.sock", buf); setenv("XDG_RUNTIME_DIR", "relative", 1); CT_EQ_INT(t, 0, ipcpath(buf, sizeof buf)); snprint(fallback, sizeof fallback, "/tmp/strans.%d", getuid()); CT_EQ_STR(t, fallback, buf); CT_EQ_INT(t, -1, ipcpath(buf, 4)); CT_EQ_INT(t, -1, ipcpath(nil, sizeof buf)); if(saved != nil){ setenv("XDG_RUNTIME_DIR", saved, 1); free(saved); }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]); }