blob: d86a0f13b6ac127c5485de77941e37aa34eaeadc [file] [log] [blame]
/* liblouis Braille Translation and Back-Translation Library
Copyright (C) 2008 Eitan Isaacson <eitan@ascender.com>
Copyright (C) 2012 James Teh <jamie@nvaccess.org>
Copyright (C) 2012 Bert Frees <bertfrees@gmail.com>
Copyright (C) 2014 Mesar Hameed <mesar.hameed@gmail.com>
Copyright (C) 2015 Mike Gray <mgray@aph.org>
Copyright (C) 2010-2016 Swiss Library for the Blind, Visually Impaired and Print
Disabled
Copyright (C) 2016-2017 Davy Kager <mail@davykager.nl>
Copying and distribution of this file, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without any warranty.
*/
#include <config.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "liblouis.h"
#include "internal.h"
#include "brl_checks.h"
#include "unistr.h"
int
check_full(const char *tableList, const char *str, const formtype *typeform,
const char *expected, int mode, const int *cursorPos, int direction,
int diagnostics);
void
print_int_array(const char *prefix, int *pos_list, int len) {
int i;
fprintf(stderr, "%s ", prefix);
for (i = 0; i < len; i++) fprintf(stderr, "%d ", pos_list[i]);
fprintf(stderr, "\n");
}
void
print_typeform(const formtype *typeform, int len) {
int i;
fprintf(stderr, "Typeform: ");
for (i = 0; i < len; i++) fprintf(stderr, "%hi", typeform[i]);
fprintf(stderr, "\n");
}
void
print_widechars(widechar *buffer, int length) {
uint8_t *result_buf;
size_t result_len;
#ifdef WIDECHARS_ARE_UCS4
result_buf = u32_to_u8(buffer, length, NULL, &result_len);
#else
result_buf = u16_to_u8(buffer, length, NULL, &result_len);
#endif
fprintf(stderr, "%.*s", (int)result_len, result_buf);
free(result_buf);
}
/* Helper function to convert a typeform string of '0's, '1's, '2's etc.
* to the required format, which is an array of 0s, 1s, 2s, etc.
* For example, "0000011111000" is converted to {0,0,0,0,0,1,1,1,1,1,0,0,0}
* The caller is responsible for freeing the returned array. */
formtype *
convert_typeform(const char *typeform_string) {
int len = strlen(typeform_string);
formtype *typeform = malloc(len * sizeof(formtype));
int i;
for (i = 0; i < len; i++) typeform[i] = typeform_string[i] - '0';
return typeform;
}
void
update_typeform(const char *typeform_string, formtype *typeform, const typeforms kind) {
int len = strlen(typeform_string);
int i;
for (i = 0; i < len; i++)
if (typeform_string[i] != ' ') typeform[i] |= kind;
}
/* Check if a string is translated as expected. Return 0 if the
* translation is as expected and 1 otherwise. */
int
check_translation(const char *tableList, const char *str, const formtype *typeform,
const char *expected) {
return check_translation_full(tableList, str, typeform, expected, 0, 0);
}
/* Check if a string is translated as expected. Return 0 if the
* translation is as expected and 1 otherwise. */
int
check_translation_with_mode(const char *tableList, const char *str,
const formtype *typeform, const char *expected, int mode) {
return check_translation_full(tableList, str, typeform, expected, mode, 0);
}
/* Check if a string is translated as expected. Return 0 if the
* translation is as expected and 1 otherwise. */
int
check_translation_with_cursorpos(const char *tableList, const char *str,
const formtype *typeform, const char *expected, const int *cursorPos) {
return check_translation_full(tableList, str, typeform, expected, 0, cursorPos);
}
/* Check if a string is translated as expected. Return 0 if the
* translation is as expected and 1 otherwise. */
int
check_translation_full(const char *tableList, const char *str, const formtype *typeform,
const char *expected, int mode, const int *cursorPos) {
return check_full(tableList, str, typeform, expected, mode, cursorPos, 0, 1);
}
/* Check if a string is backtranslated as expected. Return 0 if the
* backtranslation is as expected and 1 otherwise. */
int
check_backtranslation(const char *tableList, const char *str, const formtype *typeform,
const char *expected) {
return check_backtranslation_full(tableList, str, typeform, expected, 0, 0);
}
/* Check if a string is backtranslated as expected. Return 0 if the
* backtranslation is as expected and 1 otherwise. */
int
check_backtranslation_with_mode(const char *tableList, const char *str,
const formtype *typeform, const char *expected, int mode) {
return check_backtranslation_full(tableList, str, typeform, expected, mode, 0);
}
/* Check if a string is backtranslated as expected. Return 0 if the
* backtranslation is as expected and 1 otherwise. */
int
check_backtranslation_with_cursorpos(const char *tableList, const char *str,
const formtype *typeform, const char *expected, const int *cursorPos) {
return check_backtranslation_full(tableList, str, typeform, expected, 0, cursorPos);
}
/* Check if a string is backtranslated as expected. Return 0 if the
* backtranslation is as expected and 1 otherwise. */
int
check_backtranslation_full(const char *tableList, const char *str,
const formtype *typeform, const char *expected, int mode, const int *cursorPos) {
return check_full(tableList, str, typeform, expected, mode, cursorPos, 1, 1);
}
/* direction, 0=forward, otherwise backwards. If diagnostics is 1 then
* print diagnostics in case where the translation is not as
* expected */
int
check_full(const char *tableList, const char *str, const formtype *typeform,
const char *expected, int mode, const int *cursorPos, int direction,
int diagnostics) {
widechar *inbuf, *outbuf, *expectedbuf;
int inlen = strlen(str);
int outlen = inlen * 10;
int expectedlen = strlen(expected);
int i, retval = 0;
int funcStatus = 0;
formtype *typeformbuf = NULL;
int *cursorPosbuf = NULL;
inbuf = malloc(sizeof(widechar) * inlen);
outbuf = malloc(sizeof(widechar) * outlen);
expectedbuf = malloc(sizeof(widechar) * expectedlen);
if (typeform != NULL) {
typeformbuf = malloc(outlen * sizeof(formtype));
memcpy(typeformbuf, typeform, outlen * sizeof(formtype));
}
if (cursorPos != NULL) {
cursorPosbuf = malloc(sizeof(int));
memcpy(cursorPosbuf, cursorPos, sizeof(int));
}
inlen = _lou_extParseChars(str, inbuf);
if (!inlen) {
fprintf(stderr, "Cannot parse input string.\n");
retval = 1;
goto fail;
}
if (direction == 0) {
funcStatus = lou_translate(tableList, inbuf, &inlen, outbuf, &outlen, typeformbuf,
NULL, NULL, NULL, cursorPosbuf, mode);
} else {
funcStatus = lou_backTranslate(tableList, inbuf, &inlen, outbuf, &outlen,
typeformbuf, NULL, NULL, NULL, cursorPosbuf, mode);
}
if (!funcStatus) {
fprintf(stderr, "Translation failed.\n");
retval = 1;
goto fail;
}
expectedlen = _lou_extParseChars(expected, expectedbuf);
for (i = 0; i < outlen && i < expectedlen && expectedbuf[i] == outbuf[i]; i++)
;
if (i < outlen || i < expectedlen) {
retval = 1;
if (diagnostics) {
outbuf[outlen] = 0;
fprintf(stderr, "Input: '%s'\n", str);
/* Print the original typeform not the typeformbuf, as the
* latter has been modified by the translation and contains some
* information about outbuf */
if (typeform != NULL) print_typeform(typeform, inlen);
if (cursorPos != NULL) fprintf(stderr, "Cursor: %d\n", *cursorPos);
fprintf(stderr, "Expected: '%s' (length %d)\n", expected, expectedlen);
fprintf(stderr, "Received: '");
print_widechars(outbuf, outlen);
fprintf(stderr, "' (length %d)\n", outlen);
uint8_t *expected_utf8;
uint8_t *out_utf8;
size_t expected_utf8_len;
size_t out_utf8_len;
#ifdef WIDECHARS_ARE_UCS4
expected_utf8 = u32_to_u8(&expectedbuf[i], 1, NULL, &expected_utf8_len);
out_utf8 = u32_to_u8(&outbuf[i], 1, NULL, &out_utf8_len);
#else
expected_utf8 = u16_to_u8(&expectedbuf[i], 1, NULL, &expected_utf8_len);
out_utf8 = u16_to_u8(&outbuf[i], 1, NULL, &out_utf8_len);
#endif
if (i < outlen && i < expectedlen) {
fprintf(stderr,
"Diff: Expected '%.*s' but received '%.*s' in index %d\n",
(int)expected_utf8_len, expected_utf8, (int)out_utf8_len,
out_utf8, i);
} else if (i < expectedlen) {
fprintf(stderr,
"Diff: Expected '%.*s' but received nothing in index %d\n",
(int)expected_utf8_len, expected_utf8, i);
} else {
fprintf(stderr,
"Diff: Expected nothing but received '%.*s' in index %d\n",
(int)out_utf8_len, out_utf8, i);
}
free(expected_utf8);
free(out_utf8);
}
}
fail:
free(inbuf);
free(outbuf);
free(expectedbuf);
free(typeformbuf);
free(cursorPosbuf);
return retval;
}
int
check_inpos(const char *tableList, const char *str, const int *expected_poslist) {
widechar *inbuf;
widechar *outbuf;
int *inpos;
int inlen;
int outlen;
int i, retval = 0;
inlen = strlen(str) * 2;
outlen = inlen;
inbuf = malloc(sizeof(widechar) * inlen);
outbuf = malloc(sizeof(widechar) * outlen);
inpos = malloc(sizeof(int) * inlen);
for (i = 0; i < inlen; i++) {
inbuf[i] = str[i];
}
if (!lou_translate(tableList, inbuf, &inlen, outbuf, &outlen, NULL, NULL, NULL, inpos,
NULL, 0)) {
fprintf(stderr, "Translation failed.\n");
retval = 1;
goto fail;
}
for (i = 0; i < outlen; i++) {
if (expected_poslist[i] != inpos[i]) {
if (!retval) // Print only once
fprintf(stderr, "Inpos failure:\n");
fprintf(stderr, "Expected %d, received %d in index %d\n", expected_poslist[i],
inpos[i], i);
retval = 1;
}
}
fail:
free(inbuf);
free(outbuf);
free(inpos);
return retval;
}
int
check_outpos(const char *tableList, const char *str, const int *expected_poslist) {
widechar *inbuf;
widechar *outbuf;
int *inpos, *outpos;
int origInlen, inlen;
int outlen;
int i, retval = 0;
origInlen = inlen = strlen(str);
outlen = inlen * 2;
inbuf = malloc(sizeof(widechar) * inlen);
outbuf = malloc(sizeof(widechar) * outlen);
/* outputPos can be affected by inputPos, so pass inputPos as well. */
inpos = malloc(sizeof(int) * outlen);
outpos = malloc(sizeof(int) * inlen);
for (i = 0; i < inlen; i++) {
inbuf[i] = str[i];
}
if (!lou_translate(tableList, inbuf, &inlen, outbuf, &outlen, NULL, NULL, outpos,
inpos, NULL, 0)) {
fprintf(stderr, "Translation failed.\n");
retval = 1;
goto fail;
}
if (inlen != origInlen) {
fprintf(stderr, "original inlen %d and returned inlen %d differ\n", origInlen,
inlen);
}
for (i = 0; i < inlen; i++) {
if (expected_poslist[i] != outpos[i]) {
if (!retval) // Print only once
fprintf(stderr, "Outpos failure:\n");
fprintf(stderr, "Expected %d, received %d in index %d\n", expected_poslist[i],
outpos[i], i);
retval = 1;
}
}
fail:
free(inbuf);
free(outbuf);
free(inpos);
free(outpos);
return retval;
}
int
check_cursor_pos(const char *tableList, const char *str, const int *expected_pos) {
widechar *inbuf;
widechar *outbuf;
int *inpos, *outpos;
int inlen = strlen(str);
int outlen = inlen;
int cursor_pos;
int i, retval = 0;
inbuf = malloc(sizeof(widechar) * inlen);
outbuf = malloc(sizeof(widechar) * inlen);
inpos = malloc(sizeof(int) * inlen);
outpos = malloc(sizeof(int) * inlen);
inlen = _lou_extParseChars(str, inbuf);
for (i = 0; i < inlen; i++) {
cursor_pos = i;
if (!lou_translate(tableList, inbuf, &inlen, outbuf, &outlen, NULL, NULL, NULL,
NULL, &cursor_pos, compbrlAtCursor)) {
fprintf(stderr, "Translation failed.\n");
retval = 1;
goto fail;
}
if (expected_pos[i] != cursor_pos) {
if (!retval) // Print only once
fprintf(stderr, "Cursorpos failure:\n");
fprintf(stderr,
"string='%s' cursor=%d ('%c') expected=%d received=%d ('%c')\n", str,
i, str[i], expected_pos[i], cursor_pos, (char)outbuf[cursor_pos]);
retval = 1;
}
}
fail:
free(inbuf);
free(outbuf);
free(inpos);
free(outpos);
return retval;
}
/* Check if a string is hyphenated as expected. Return 0 if the
* hyphenation is as expected and 1 otherwise. */
int
check_hyphenation(const char *tableList, const char *str, const char *expected) {
widechar *inbuf;
char *hyphens = NULL;
int inlen = strlen(str);
int retval = 0;
inbuf = malloc(sizeof(widechar) * inlen);
inlen = _lou_extParseChars(str, inbuf);
if (!inlen) {
fprintf(stderr, "Cannot parse input string.\n");
retval = 1;
goto fail;
}
hyphens = calloc(inlen + 1, sizeof(char));
if (!lou_hyphenate(tableList, inbuf, inlen, hyphens, 0)) {
fprintf(stderr, "Hyphenation failed.\n");
retval = 1;
goto fail;
}
if (strcmp(expected, hyphens)) {
fprintf(stderr, "Input: '%s'\n", str);
fprintf(stderr, "Expected: '%s'\n", expected);
fprintf(stderr, "Received: '%s'\n", hyphens);
retval = 1;
}
fail:
free(inbuf);
free(hyphens);
return retval;
}