From 82276bf37f6f782cdc0072242d139d7c1065c64f Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Tue, 11 Aug 2026 21:12:23 +0900 Subject: [PATCH] strengthen core unit tests Add table-driven dictionary miss and language-switch state coverage, regress stale candidates after backspace, and clear them before dictionary refresh. Keep IPC and runtime-created file checks outside the unit runner. --- README.md | 4 +- strans.c | 7 +- tests/Makefile | 4 +- tests/data/hira.map | 2 + tests/dict_test.c | 35 ++++ tests/engine_test.c | 99 +++++++++++ tests/ipc_test.c | 411 -------------------------------------------- tests/test.h | 9 +- tests/trie_test.c | 33 ---- tests/unit_test.c | 9 +- 10 files changed, 149 insertions(+), 464 deletions(-) delete mode 100644 tests/ipc_test.c diff --git a/README.md b/README.md index 4e17cc5..8d592d5 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,8 @@ mirrors must provide the same sibling; initialize it after cloning with The suite covers the fixed-size UTF-8 string, hash table, trie fixtures, Japanese/Hangul/Telex state transitions, dictionary candidates, engine -selection state, and the byte-stream IPC path. Tests use explicit case tables, -boundary values, and small regressions for repaired core contracts. GUI +selection state, and production map loading. Tests use explicit case tables, +boundary values, and small regressions for repaired core contracts. IPC and GUI protocol stacks are outside this suite and require separate integration checks. ## Run diff --git a/strans.c b/strans.c index 9566007..50ddbc9 100644 --- a/strans.c +++ b/strans.c @@ -86,11 +86,10 @@ dictqmap(Im *im) { Str dict; - if(!mapget(im->l->map, &im->pre, &dict)){ - clearkouho(); - show(); + clearkouho(); + show(); + if(!mapget(im->l->map, &im->pre, &dict)) return; - } dictsend(im, &dict); } diff --git a/tests/Makefile b/tests/Makefile index 89ce884..3cebdc9 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -5,9 +5,9 @@ LIBS = -lthread -lbio PROG = unit_test TESTSRC = unit_test.c test_util.c str_test.c hash_test.c trie_test.c \ - ko_test.c vi_test.c engine_test.c dict_test.c ipc_test.c + ko_test.c vi_test.c engine_test.c dict_test.c TESTOBJ = $(TESTSRC:.c=.o) -PARENTSRC = str.c hash.c trie.c dict.c ko.c vi.c ipc.c srv.c +PARENTSRC = str.c hash.c trie.c dict.c ko.c vi.c PARENTOBJ = $(PARENTSRC:%.c=unit_%.o) OBJS = $(TESTOBJ) $(PARENTOBJ) diff --git a/tests/data/hira.map b/tests/data/hira.map index 5c324a9..77916ec 100644 --- a/tests/data/hira.map +++ b/tests/data/hira.map @@ -1,2 +1,4 @@ ka か sa さ +n ん +na な diff --git a/tests/dict_test.c b/tests/dict_test.c index 93ae638..0f9a735 100644 --- a/tests/dict_test.c +++ b/tests/dict_test.c @@ -51,3 +51,38 @@ cleanup: hmapfree(lang->dict); lang->dict = saved; } + +void +dictionary_misses_clear_result(struct ct *t) +{ + static const struct { + char *name; + char *key; + char *pre; + } cases[] = { + { "empty key", "", "empty-preedit" }, + { "missing key", "missing", "missing-preedit" }, + }; + Dictreq req; + Dictres res; + Hmap *saved; + Lang *lang; + int i; + + lang = getlang(LangJP); + saved = lang->dict; + lang->dict = hmapalloc(1); + for(i = 0; i < nelem(cases); i++){ + memset(&res, 0xa5, sizeof res); + req.key = mkstr(cases[i].key); + req.pre = mkstr(cases[i].pre); + req.lang = LangJP; + dictlookup(&req, &res); + if(res.nkouho != 0) + CT_ERRORF(t, "%s: want 0 candidates, got %d", + cases[i].name, res.nkouho); + checkstr(t, cases[i].name, cases[i].pre, &res.key); + } + hmapfree(lang->dict); + lang->dict = saved; +} diff --git a/tests/engine_test.c b/tests/engine_test.c index eb89373..710ac9a 100644 --- a/tests/engine_test.c +++ b/tests/engine_test.c @@ -54,6 +54,32 @@ engine_clears_candidates(struct ct *t) CT_EQ_INT(t, -1, im.sel); } +void +engine_backspace_clears_candidates(struct ct *t) +{ + Lang *lang; + Str com, shown; + + lang = getlang(LangJP); + init(); + im.l = lang; + sclear(&com); + CT_CHECK(t, keystroke('n', 0, &com)); + CT_CHECK(t, keystroke('a', 0, &com)); + shown = shownpre(&im); + checkstr(t, "before backspace", "な", &shown); + im.kouho[0] = mkstr("stale-candidate"); + im.nkouho = 1; + im.sel = 0; + CT_CHECK(t, keystroke(Kback, 0, &com)); + checkstr(t, "backspace commit", "", &com); + checkstr(t, "raw preedit after backspace", "n", &im.pre); + shown = shownpre(&im); + checkstr(t, "shown preedit after backspace", "ん", &shown); + CT_EQ_INT(t, 0, im.nkouho); + CT_EQ_INT(t, -1, im.sel); +} + void engine_selects_visible_candidate(struct ct *t) { @@ -156,3 +182,76 @@ engine_telex_history_bound(struct ct *t) CT_EQ_INT(t, 0, im.pre.n); CT_EQ_INT(t, 0, im.raw.n); } + +void +engine_language_switch_state(struct ct *t) +{ + static const struct { + char *name; + Rune key; + int mod; + int lang; + char *pre; + char *raw; + char *commit; + int stale; + } steps[] = { + { "select Vietnamese", 'v', Mctrl, LangVI, "", "", "", 0 }, + { "Vietnamese a", 'a', 0, LangVI, "a", "a", "", 0 }, + { "Vietnamese tone", 's', 0, LangVI, "as", "as", "", 0 }, + { "switch to Korean", 's', Mctrl, LangKO, "", "", "", 1 }, + { "Korean initial", 'r', 0, LangKO, "ㄱ", "", "", 0 }, + { "Korean syllable", 'k', 0, LangKO, "가", "", "", 0 }, + { "switch to Vietnamese", 'v', Mctrl, LangVI, "", "", "", 0 }, + { "Vietnamese a again", 'a', 0, LangVI, "a", "a", "", 0 }, + { "Vietnamese tone again", 's', 0, LangVI, "as", "as", "", 0 }, + { "commit Vietnamese", Kret, 0, LangVI, "", "", "á", 0 }, + }; + char where[80]; + Lang *vi; + Trie *saved; + Str com; + int eaten, i; + + vi = getlang(LangVI); + if(!CT_CHECK(t, vi != nil)) + return; + saved = vi->map; + vi->map = testvi.map; + init(); + for(i = 0; i < nelem(steps); i++){ + if(steps[i].stale){ + im.kouho[0] = mkstr("stale"); + im.nkouho = 1; + im.sel = 0; + } + sclear(&com); + eaten = keystroke(steps[i].key, steps[i].mod, &com); + if(eaten != 1){ + CT_ERRORF(t, "%s: want eaten 1, got %d", + steps[i].name, eaten); + break; + } + if(im.l == nil || im.l->lang != steps[i].lang){ + CT_ERRORF(t, "%s: want language %d, got %d", + steps[i].name, steps[i].lang, + im.l == nil ? -1 : im.l->lang); + break; + } + snprint(where, sizeof where, "%s preedit", steps[i].name); + if(!checkstr(t, where, steps[i].pre, &im.pre)) + break; + snprint(where, sizeof where, "%s raw", steps[i].name); + if(!checkstr(t, where, steps[i].raw, &im.raw)) + break; + snprint(where, sizeof where, "%s commit", steps[i].name); + if(!checkstr(t, where, steps[i].commit, &com)) + break; + if(im.nkouho != 0 || im.sel != -1){ + CT_ERRORF(t, "%s: want candidates 0 and selection -1, got %d and %d", + steps[i].name, im.nkouho, im.sel); + break; + } + } + vi->map = saved; +} diff --git a/tests/ipc_test.c b/tests/ipc_test.c deleted file mode 100644 index 7854076..0000000 --- a/tests/ipc_test.c +++ /dev/null @@ -1,411 +0,0 @@ -#define _POSIX_C_SOURCE 200809L - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "test.h" - -#undef waitpid - -enum -{ - Childtimeout = 2000, -}; - -typedef struct Childres Childres; -struct Childres -{ - int rc; - unsigned int want; - unsigned int mod; - unsigned int key; -}; - -static long long -nowms(void) -{ - struct timespec ts; - - if(clock_gettime(CLOCK_MONOTONIC, &ts) < 0) - return -1; - return (long long)ts.tv_sec * 1000 + ts.tv_nsec / 1000000; -} - -static int -waitreadable(int fd, int timeout) -{ - struct pollfd pfd; - long long end, now; - int n, left; - - end = nowms() + timeout; - pfd.fd = fd; - pfd.events = POLLIN; - for(;;){ - now = nowms(); - if(now < 0 || now >= end) - return -1; - left = end - now; - n = poll(&pfd, 1, left); - if(n > 0) - return (pfd.revents & (POLLIN|POLLHUP)) != 0 ? 0 : -1; - if(n == 0) - return -1; - if(errno != EINTR) - return -1; - } -} - -static int -readdeadline(int fd, void *buf, size_t n, int timeout) -{ - unsigned char *p; - long long end, now; - ssize_t got; - - p = buf; - end = nowms() + timeout; - while(n > 0){ - now = nowms(); - if(now < 0 || now >= end || waitreadable(fd, end - now) < 0) - return -1; - got = read(fd, p, n); - if(got < 0 && errno == EINTR) - continue; - if(got <= 0) - return -1; - p += got; - n -= got; - } - return 0; -} - -static int -waitqueueempty(int fd, int timeout) -{ - long long end; - int n; - - end = nowms() + timeout; - for(;;){ - if(ioctl(fd, FIONREAD, &n) < 0) - return -1; - if(n == 0) - return 0; - if(nowms() >= end) - return -1; - sched_yield(); - } -} - -static int -reapchild(pid_t pid, int *status, int timeout) -{ - long long end; - pid_t got; - - end = nowms() + timeout; - for(;;){ - got = waitpid(pid, status, WNOHANG); - if(got == pid) - return 0; - if(got < 0 && errno != EINTR) - return -1; - if(nowms() >= end) - break; - poll(nil, 0, 1); - } - if(kill(pid, SIGKILL) < 0 && errno != ESRCH) - return -1; - end = nowms() + timeout; - for(;;){ - got = waitpid(pid, status, WNOHANG); - if(got == pid) - return 0; - if(got < 0 && errno != EINTR) - return -1; - if(nowms() >= end) - return -1; - poll(nil, 0, 1); - } -} - -void -ipc_request_codec(struct ct *t) -{ - static const struct { - int want; - unsigned int mod, key; - unsigned char bytes[Ipcreqsz]; - } cases[] = { - { 0, 0, 0, { 0, 0, 0, 0, 0, 0 } }, - { 1, Mctrl|Mshift, 0x1234, - { 1, Mctrl|Mshift, 0x34, 0x12, 0, 0 } }, - { 1, Malt, 0x1f600, - { 1, Malt, 0x00, 0xf6, 0x01, 0x00 } }, - { 1, 0, 0xf008, - { 1, 0, 0x08, 0xf0, 0x00, 0x00 } }, - { 1, 0, Kback, - { 1, 0, 0x08, 0x00, 0x11, 0x00 } }, - { 1, Msuper, 0x89abcdefU, - { 1, Msuper, 0xef, 0xcd, 0xab, 0x89 } }, - }; - unsigned char got[Ipcreqsz]; - unsigned int mod, key; - int i, want; - - for(i = 0; i < nelem(cases); i++){ - ipcpackreq(got, cases[i].want, cases[i].mod, cases[i].key); - if(!CT_EQ_MEM(t, cases[i].bytes, got, sizeof got)) - continue; - ipcunpackreq(got, &want, &mod, &key); - CT_EQ_INT(t, cases[i].want != 0, want); - CT_EQ_UINT(t, cases[i].mod, mod); - CT_EQ_UINT(t, cases[i].key, key); - } -} - -void -ipc_response_pack_boundaries(struct ct *t) -{ - static const unsigned char want[] = { 1, 1, 0, 'A', 2, 0, 'x', 'y' }; - static const unsigned char want0[] = { 1, 1, 0, 'A' }; - unsigned char out[Ipcmaxresp+1], field[Ipcfieldmax]; - int n; - - n = ipcpackresp(out, sizeof out, 7, "A", 1, "xy", 2, 1); - CT_EQ_INT(t, sizeof want, n); - CT_EQ_MEM(t, want, out, sizeof want); - n = ipcpackresp(out, sizeof out, 1, "A", 1, "xy", 2, 0); - CT_EQ_INT(t, sizeof want0, n); - CT_EQ_MEM(t, want0, out, sizeof want0); - - 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, 'x', out[Ipcmaxresp-1]); - - memset(out, 0xa5, sizeof out); - CT_EQ_INT(t, -1, ipcpackresp(out, Ipcmaxresp-1, 1, - (char*)field, sizeof field, (char*)field, sizeof field, 1)); - CT_EQ_INT(t, 0xa5, out[0]); - 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_codec_and_drain(struct ct *t) -{ - unsigned char first[Ipcmaxresp]; - static const unsigned char second[] = { 0, 2, 0, 'o', 'k' }; - unsigned char field[Ipcfieldmax]; - char commit[8], preedit[8]; - Ipcresp resp; - int fd[2], n; - - memset(field, 'x', sizeof field); - n = ipcpackresp(first, sizeof first, 1, - (char*)field, sizeof field, (char*)field, sizeof field, 1); - if(!CT_EQ_INT(t, Ipcmaxresp, n)) - 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, n))) - goto cleanup; - if(!CT_EQ_INT(t, 0, ipcsend(fd[0], second, sizeof second))) - goto cleanup; - if(!CT_EQ_INT(t, 0, shutdown(fd[0], SHUT_WR))) - goto cleanup; - if(!CT_EQ_INT(t, 0, - ipcreadresp(fd[1], 1, commit, sizeof commit, - preedit, sizeof preedit, &resp))) - goto cleanup; - CT_EQ_INT(t, 1, resp.eaten); - 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, - preedit, sizeof preedit, &resp))) - goto cleanup; - CT_EQ_INT(t, 0, resp.eaten); - CT_EQ_STR(t, "ok", commit); - CT_EQ_STR(t, "", preedit); -cleanup: - close(fd[0]); - close(fd[1]); -} - -void -ipc_truncated_frame(struct ct *t) -{ - unsigned char b = 1, req[Ipcreqsz]; - int fd[2]; - - if(pipe(fd) < 0){ - CT_ERRORF(t, "pipe failed"); - return; - } - if(!CT_EQ_INT(t, 1, write(fd[1], &b, 1))){ - close(fd[0]); - close(fd[1]); - return; - } - close(fd[1]); - CT_EQ_INT(t, -1, ipcreadn(fd[0], req, sizeof req)); - close(fd[0]); -} - -void -ipc_fragmented_request(struct ct *t) -{ - unsigned char req[Ipcreqsz]; - Childres res; - Keyreq got; - pid_t pid; - int data[2], result[2], status; - - pid = -1; - data[0] = data[1] = result[0] = result[1] = -1; - ipcpackreq(req, 1, Mctrl|Mshift, 0x1f600); - if(socketpair(AF_UNIX, SOCK_STREAM, 0, data) < 0){ - CT_ERRORF(t, "data socketpair failed"); - return; - } - if(socketpair(AF_UNIX, SOCK_STREAM, 0, result) < 0){ - CT_ERRORF(t, "result socketpair failed"); - goto cleanup; - } - pid = fork(); - if(pid < 0){ - CT_ERRORF(t, "fork failed"); - goto cleanup; - } - if(pid == 0){ - close(data[0]); - close(result[0]); - memset(&res, 0, sizeof res); - res.rc = srvreadkey(data[1], &got); - if(res.rc == 0){ - res.want = got.want; - res.mod = got.mod; - res.key = got.ks; - } - _exit(ipcsend(result[1], &res, sizeof res) < 0 ? 1 : 0); - } - close(result[1]); - result[1] = -1; - if(ipcsend(data[0], req, Ipcreqsz/2) < 0){ - CT_ERRORF(t, "first request fragment failed"); - goto cleanup; - } - if(waitqueueempty(data[1], Childtimeout) < 0){ - CT_ERRORF(t, "child did not consume first request fragment"); - goto cleanup; - } - if(ipcsend(data[0], req+Ipcreqsz/2, Ipcreqsz-Ipcreqsz/2) < 0){ - CT_ERRORF(t, "second request fragment failed"); - goto cleanup; - } - if(readdeadline(result[0], &res, sizeof res, Childtimeout) < 0){ - CT_ERRORF(t, "timed out waiting for decoded request"); - goto cleanup; - } - CT_EQ_INT(t, 0, res.rc); - CT_EQ_INT(t, 1, res.want); - CT_EQ_UINT(t, Mctrl|Mshift, res.mod); - CT_EQ_UINT(t, 0x1f600, res.key); -cleanup: - if(data[0] >= 0) - close(data[0]); - if(data[1] >= 0) - close(data[1]); - if(result[0] >= 0) - close(result[0]); - if(result[1] >= 0) - close(result[1]); - if(pid > 0){ - if(reapchild(pid, &status, Childtimeout) < 0) - CT_ERRORF(t, "could not reap request reader"); - else if(!WIFEXITED(status) || WEXITSTATUS(status) != 0) - CT_ERRORF(t, "request reader failed"); - } -} - -void -ipc_closed_peer(struct ct *t) -{ - unsigned char b; - pid_t pid; - int data[2], syncfd[2], status; - - pid = -1; - data[0] = data[1] = syncfd[0] = syncfd[1] = -1; - if(socketpair(AF_UNIX, SOCK_STREAM, 0, data) < 0){ - CT_ERRORF(t, "data socketpair failed"); - return; - } - if(socketpair(AF_UNIX, SOCK_STREAM, 0, syncfd) < 0){ - CT_ERRORF(t, "synchronization socketpair failed"); - goto cleanup; - } - pid = fork(); - if(pid < 0){ - CT_ERRORF(t, "fork failed"); - goto cleanup; - } - if(pid == 0){ - signal(SIGPIPE, SIG_DFL); - close(data[1]); - close(syncfd[0]); - if(ipcsend(syncfd[1], "r", 1) < 0 || - readdeadline(syncfd[1], &b, 1, Childtimeout) < 0) - _exit(2); - _exit(ipcsend(data[0], "x", 1) < 0 ? 0 : 1); - } - close(data[0]); - data[0] = -1; - close(data[1]); - data[1] = -1; - close(syncfd[1]); - syncfd[1] = -1; - if(readdeadline(syncfd[0], &b, 1, Childtimeout) < 0 || - ipcsend(syncfd[0], "g", 1) < 0) - CT_ERRORF(t, "child synchronization failed"); -cleanup: - if(data[0] >= 0) - close(data[0]); - if(data[1] >= 0) - close(data[1]); - if(syncfd[0] >= 0) - close(syncfd[0]); - if(syncfd[1] >= 0) - close(syncfd[1]); - if(pid > 0){ - if(reapchild(pid, &status, Childtimeout) < 0) - CT_ERRORF(t, "could not reap closed-peer writer"); - else if(!WIFEXITED(status) || WEXITSTATUS(status) != 0) - CT_ERRORF(t, "write to closed peer did not return -1"); - } -} diff --git a/tests/test.h b/tests/test.h index e1084ec..cc80a2d 100644 --- a/tests/test.h +++ b/tests/test.h @@ -28,15 +28,12 @@ void vietnamese_transitions(struct ct*); void vietnamese_backspace(struct ct*); void vietnamese_state_lifetime(struct ct*); void engine_clears_candidates(struct ct*); +void engine_backspace_clears_candidates(struct ct*); void engine_selects_visible_candidate(struct ct*); void engine_commit_contract(struct ct*); +void engine_language_switch_state(struct ct*); void engine_telex_history_bound(struct ct*); void dictionary_candidates(struct ct*); -void ipc_request_codec(struct ct*); -void ipc_response_pack_boundaries(struct ct*); -void ipc_response_codec_and_drain(struct ct*); -void ipc_truncated_frame(struct ct*); -void ipc_fragmented_request(struct ct*); -void ipc_closed_peer(struct ct*); +void dictionary_misses_clear_result(struct ct*); #endif diff --git a/tests/trie_test.c b/tests/trie_test.c index b3f85b1..2daeb4c 100644 --- a/tests/trie_test.c +++ b/tests/trie_test.c @@ -1,37 +1,5 @@ #include "test.h" -static void -checkcrlf(struct ct *t) -{ - static char data[] = "crlf\tvalue\r\n"; - char path[80], *v; - Trie *trie; - int fd, n; - - snprint(path, sizeof path, "/tmp/strans-crlf-%d.map", getpid()); - remove(path); - fd = create(path, OWRITE, 0600); - if(fd < 0){ - CT_ERRORF(t, "cannot create CRLF fixture"); - return; - } - if(write(fd, data, sizeof data - 1) != (long)(sizeof data - 1)){ - CT_ERRORF(t, "cannot write CRLF fixture"); - close(fd); - remove(path); - return; - } - close(fd); - trie = trieopen(path); - remove(path); - v = trieget(trie, "crlf", 4, &n); - if(CT_CHECK(t, v != nil)){ - CT_EQ_INT(t, 5, n); - CT_EQ_MEM(t, "value", v, n); - } - trieclose(trie); -} - void trie_exact_prefix_and_duplicate(struct ct *t) { @@ -64,7 +32,6 @@ trie_exact_prefix_and_duplicate(struct ct *t) CT_EQ_PTR(t, nil, trieget(trie, "missing", 7, &n)); cleanup: trieclose(trie); - checkcrlf(t); } void diff --git a/tests/unit_test.c b/tests/unit_test.c index e905635..19433bd 100644 --- a/tests/unit_test.c +++ b/tests/unit_test.c @@ -75,16 +75,13 @@ static const struct ct_test tests[] = { { "telex/backspace", vietnamese_backspace }, { "telex/state-lifetime", vietnamese_state_lifetime }, { "engine/clears-candidates", engine_clears_candidates }, + { "engine/backspace-clears-candidates", engine_backspace_clears_candidates }, { "engine/selects-visible-candidate", engine_selects_visible_candidate }, { "engine/commit-contract", engine_commit_contract }, + { "engine/language-switch-state", engine_language_switch_state }, { "engine/telex-history-bound", engine_telex_history_bound }, { "dict/candidates", dictionary_candidates }, - { "ipc/request-codec", ipc_request_codec }, - { "ipc/response-pack-boundaries", ipc_response_pack_boundaries }, - { "ipc/response-codec-drain", ipc_response_codec_and_drain }, - { "ipc/truncated-frame", ipc_truncated_frame }, - { "ipc/fragmented-request", ipc_fragmented_request }, - { "ipc/closed-peer", ipc_closed_peer }, + { "dict/misses-clear-result", dictionary_misses_clear_result }, }; void