summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacob Moody <moody@posixcafe.org>2023-01-31 04:24:12 +0000
committerJacob Moody <moody@posixcafe.org>2023-01-31 04:24:12 +0000
commit05889d4454c61fb6f1caf6aba300ce23388ec47b (patch)
tree5dfbd13def918cf3f7d0393ade50aa1907a565b5
parent006b925a2aedeff506430c4b028a04687e8560ff (diff)
ktrans: tests and various bug fixes
* exit if we get eof on kbdtap * do not nuke the line if we restore a kanji selection without okurigana * guard against unfortunate scheduling, the dictthread needs to get through all it can before the keythread processes more. In typical use, the processing was fast enough to never notice this condition but writing out a large set of input can trigger it.
-rw-r--r--sys/src/cmd/ktrans/main.c10
-rw-r--r--sys/src/cmd/ktrans/mkfile6
-rw-r--r--sys/src/cmd/ktrans/test.c111
3 files changed, 126 insertions, 1 deletions
diff --git a/sys/src/cmd/ktrans/main.c b/sys/src/cmd/ktrans/main.c
index 196956201..bd87992cc 100644
--- a/sys/src/cmd/ktrans/main.c
+++ b/sys/src/cmd/ktrans/main.c
@@ -408,6 +408,8 @@ emitutf(Channel *out, char *u, int nrune)
return e - b;
}
+static int compacting = 0;
+
static void
dictthread(void*)
{
@@ -437,6 +439,7 @@ dictthread(void*)
threadsetname("dict");
while(recv(dictch, m) != -1){
+ compacting = 1;
for(p = m+1; *p; p += n){
n = chartorune(&r, p);
switch(r){
@@ -478,7 +481,8 @@ dictthread(void*)
}
if(kouho[selected] == nil){
/* cycled through all matches; bail */
- emitutf(output, backspace, utflen(okuri.b));
+ if(utflen(okuri.b) != 0)
+ emitutf(output, backspace, utflen(okuri.b));
emitutf(output, backspace, utflen(last.b));
emitutf(output, line.b, 0);
emitutf(output, okuri.b, 0);
@@ -547,6 +551,7 @@ dictthread(void*)
hmapget(dict, line.b, kouho);
send(displaych, kouho);
}
+ compacting = 0;
}
}
@@ -623,6 +628,8 @@ keythread(void*)
}
for(p = m+1; *p; p += n){
+ while(compacting)
+ yield();
n = chartorune(&r, p);
if(checklang(&lang, r)){
emitutf(dictch, " ", 1);
@@ -718,6 +725,7 @@ kbdtap(void*)
return;
}
}
+ threadexitsall(nil);
}
static void
diff --git a/sys/src/cmd/ktrans/mkfile b/sys/src/cmd/ktrans/mkfile
index 3b3fee778..1c0973630 100644
--- a/sys/src/cmd/ktrans/mkfile
+++ b/sys/src/cmd/ktrans/mkfile
@@ -8,3 +8,9 @@ OFILES=\
main.$O\
</sys/src/cmd/mkone
+
+$O.test: test.$O
+ $LD $LDFLAGS -o $target $prereq
+
+test:V: $O.test $O.out
+ $O.test $O.out
diff --git a/sys/src/cmd/ktrans/test.c b/sys/src/cmd/ktrans/test.c
new file mode 100644
index 000000000..77d416b0c
--- /dev/null
+++ b/sys/src/cmd/ktrans/test.c
@@ -0,0 +1,111 @@
+#include <u.h>
+#include <libc.h>
+
+struct {
+ char *input;
+ Rune *expect;
+} set[] = {
+ "n", L"ん",
+ " no", L"の",
+ " nno", L"んの",
+ " neko", L"猫",
+ " neko", L"ねこ",
+ " watashi", L"私",
+ " tanoShi", L"楽し",
+ " oreNO", L"俺の",
+
+ " watashiHAmainichi35 funijouaruIte,saraNI10 fundenshaNInoTtegakkouNIkayoImasu.\nkenkouNOijiNImoyakuDAtteimasuga,nakanakatanoshiImonodesu.\n",
+ L"私は毎日35分以上歩いて、更に10分電車に乗って学校に通います。\n健康の維持にも役だっていますが、なかなかたのしいものです。\n",
+};
+
+char*
+makemsg(char *s)
+{
+ char *out, *d;
+ int i, n;
+
+ n = strlen(s) + 1;
+ out = mallocz(n * 3, 1);
+ for(d = out, i = 0; i < n; i++){
+ *d++ = 'c';
+ if(i == n - 1)
+ *d++ = 1;
+ else
+ *d++ = s[i];
+ *d++ = '\0';
+ }
+ return out;
+}
+
+void
+main(int argc, char **argv)
+{
+ int io1[2], io2[2];
+ int i;
+ int n;
+ char *p, *e;
+ static char buf[256];
+ Rune r;
+ char *to;
+ char *bin;
+ static Rune stack[256];
+ static int nstack;
+
+ if(argc < 2)
+ sysfatal("usage: %s binary", argv[0]);
+
+ bin = argv[1];
+ pipe(io1);
+ pipe(io2);
+ if(fork() == 0){
+ dup(io1[0], 0);
+ dup(io2[0], 1);
+ close(io1[1]); close(io2[1]);
+ execl(bin, "ktrans", "-l", "jp", "-G", nil);
+ sysfatal("exec: %r");
+ }
+ close(io1[0]); close(io2[0]);
+ for(i = 0; i < nelem(set); i++){
+ nstack = 0;
+ stack[nstack] = 0;
+ to = makemsg(set[i].input);
+ for(;;){
+ write(io1[1], to, strlen(to) + 1);
+ if(to[1] == 1)
+ break;
+ to += strlen(to)+1;
+ }
+ for(;;) {
+ n = read(io2[1], buf, sizeof buf);
+ if(n <= 0)
+ break;
+ e = buf + n;
+ for(p = buf; p < e; p += (strlen(p)+1)){
+ assert(*p == 'c');
+ chartorune(&r, p+1);
+ switch(r){
+ case 1:
+ goto Verify;
+ case 8:
+ if(nstack == 0)
+ sysfatal("buffer underrun");
+ nstack--;
+ stack[nstack] = 0;
+ break;
+ default:
+ stack[nstack++] = r;
+ stack[nstack] = 0;
+ break;
+ }
+ }
+ }
+ Verify:
+ if(runestrcmp(set[i].expect, stack) != 0){
+ fprint(2, "%S != %S\n", stack, set[i].expect);
+ exits("fail");
+ }
+ }
+ close(io1[1]); close(io2[1]);
+ waitpid();
+ exits(nil);
+}