From c7d4f16d3e54f156c853cd61b080977a0815f01b Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Wed, 12 Aug 2026 16:16:25 +0900 Subject: [PATCH] test: stress engine transitions --- tests/engine_test.c | 114 ++++++++++++++++++++++++++++++++++++++++++++ tests/test.h | 1 + tests/unit_test.c | 1 + 3 files changed, 116 insertions(+) diff --git a/tests/engine_test.c b/tests/engine_test.c index f69a05b..246ae2f 100644 --- a/tests/engine_test.c +++ b/tests/engine_test.c @@ -1166,3 +1166,117 @@ engine_emoji_dictionary_identity(struct ct *t) checkstr(t, "matching response accepted", "right", &im.kouho[0]); emojiend(&f); } + +static u32int +stressrand(u32int *state) +{ + *state = *state * 1664525U + 1013904223U; + return *state; +} + +static int +stressstr(Str *s) +{ + return s->n >= 0 && s->n <= Maxrunes; +} + +void +engine_randomized_stress(struct ct *t) +{ + static Rune text[] = { + 'a', 'e', 'g', 'i', 'j', 'k', 'm', 'n', 'o', 'r', 's', 't', + 'u', 'w', 'y', '1', '2', '9', '\'', ' ', L'日', + }; + static Rune modes[] = { 't', 'n', 'k', 's', 'v' }; + Emojifix f; + Lang *vi; + Trie *vimap; + Keyres res; + Caret pos; + u32int rnd, mod; + uvlong owners[3], owner; + int i, j, op; + + vi = getlang(LangVI); + if(!CT_CHECK(t, vi != nil)) + return; + vimap = vi->map; + vi->map = testvi.map; + emojibegin(&f, 0); + owners[0] = ownernew(); + owners[1] = ownernew(); + owners[2] = ownernew(); + rnd = 0x5eed1234U; + for(i = 0; i < 16000; i++){ + rnd = stressrand(&rnd); + owner = owners[(rnd >> 8) % nelem(owners)]; + op = rnd % 28; + mod = (rnd >> 16) & Mmask; + memset(&pos, 0, sizeof pos); + pos.valid = (rnd >> 25) & 1; + pos.x = (rnd >> 3) & 0x3ff; + pos.y = (rnd >> 13) & 0x3ff; + pos.w = 1 + ((rnd >> 23) & 0x1f); + pos.h = 1 + ((rnd >> 18) & 0x1f); + if(op < 13) + res = ownerrequestat(owner, Keypress, + text[(rnd >> 5) % nelem(text)], mod, &pos); + else if(op == 13) + res = ownerrequestat(owner, Keypress, Kback, 0, &pos); + else if(op == 14) + res = ownerrequestat(owner, Keypress, Kret, 0, &pos); + else if(op == 15) + res = ownerrequestat(owner, Keypress, Kesc, 0, &pos); + else if(op == 16) + res = ownerrequestat(owner, Keypress, Kdown, 0, &pos); + else if(op == 17) + res = ownerrequestat(owner, Keypress, Kup, 0, &pos); + else if(op == 18) + res = ownerrequestat(owner, Keypress, Ktab, + (rnd & 0x1000) ? Mshift : 0, &pos); + else if(op == 19) + res = ownerrequestat(owner, Keypress, + modes[(rnd >> 12) % nelem(modes)], Mctrl, &pos); + else if(op == 20) + res = ownerrequestat(owner, Keypress, 'e', Mctrl, &pos); + else if(op == 21) + res = ownerrequest(owner, Keyreset, 0, 0); + else if(op == 22) + res = ownerrequest(owner, Keyrelease, 0, 0); + else if(op == 23) + res = ownerrequestat(owner, Keycaret, 0, 0, &pos); + else if(op == 24) + res = ownerrequest(owner, Keypress, + Kmodfirst + ((rnd >> 20) & 7), 0); + else if(op == 25) + res = ownerrequestat(owner, Keypress, 'p', Mctrl, &pos); + else if(op == 26) + res = ownerrequestat(owner, Keypress, 0xf008, 0, &pos); + else + res = ownerrequestat(owner, Keypress, + '1' + ((rnd >> 11) % 9), 0, &pos); + + if(!stressstr(&res.commit) || !stressstr(&res.preedit) || + !stressstr(&im.pre) || !stressstr(&im.raw) || + !stressstr(&search.raw) || !stressstr(&search.text) || + im.l == nil || im.nkouho < 0 || im.nkouho > Maxkouho || + im.sel < -1 || im.sel >= Maxkouho || + (im.nkouho > 0 && im.sel >= im.nkouho)){ + CT_ERRORF(t, "invalid engine state after stress operation %d", i); + break; + } + for(j = 0; j < im.nkouho; j++) + if(!stressstr(&im.kouho[j])){ + CT_ERRORF(t, "invalid candidate after stress operation %d", i); + i = 16000; + break; + } + if(activeowner != 0 && activeowner != owners[0] && + activeowner != owners[1] && activeowner != owners[2]){ + CT_ERRORF(t, "unknown active owner after stress operation %d", i); + break; + } + } + emojiend(&f); + vi->map = vimap; +} diff --git a/tests/test.h b/tests/test.h index 0776244..bff84af 100644 --- a/tests/test.h +++ b/tests/test.h @@ -60,6 +60,7 @@ void engine_emoji_navigation(struct ct*); void engine_emoji_preedit_languages(struct ct*); void engine_emoji_start_and_unknown(struct ct*); void engine_emoji_dictionary_identity(struct ct*); +void engine_randomized_stress(struct ct*); void dictionary_candidates(struct ct*); void dictionary_misses_clear_result(struct ct*); void dictionary_emoji_identity(struct ct*); diff --git a/tests/unit_test.c b/tests/unit_test.c index 815d5e1..508df79 100644 --- a/tests/unit_test.c +++ b/tests/unit_test.c @@ -109,6 +109,7 @@ static const struct ct_test tests[] = { { "engine/emoji-preedit-languages", engine_emoji_preedit_languages }, { "engine/emoji-start-and-unknown", engine_emoji_start_and_unknown }, { "engine/emoji-dictionary-identity", engine_emoji_dictionary_identity }, + { "engine/randomized-stress", engine_randomized_stress }, { "dict/candidates", dictionary_candidates }, { "dict/misses-clear-result", dictionary_misses_clear_result }, { "dict/emoji-identity", dictionary_emoji_identity },