blob: a20b83eb7a2659edc953417193d73500ae65d9de [file] [edit]
/* liblouis Braille Translation and Back-Translation Library
Copyright (C) 2014 ViewPlus Technologies, Inc. www.viewplus.com
and the liblouis team. http://liblouis.org
All rights reserved
This file is free software; you can redistribute it and/or modify
it under the terms of the Lesser or Library GNU General Public
License as published by the Free Software Foundation; either
version 3, or (at your option) any later version.
This file is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Library GNU General Public License for more details.
You should have received a copy of the Library GNU General Public
License along with this program; see the file COPYING. If not,
write to the Free Software Foundation, 51 Franklin Street, Fifth
Floor, Boston, MA 02110-1301, USA.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "liblouis.h"
#include "louis.h"
#include "brl_checks.h"
#include "unistr.h"
int check_with_mode(const char *tableList, const char *str,
const formtype *typeform, const char *expected, int mode,
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_with_mode(tableList, str, typeform, expected, 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_with_mode(tableList, str, typeform, expected, mode, 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_with_mode(tableList, str, typeform, expected, 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_with_mode(tableList, str, typeform, expected, mode, 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_with_mode(const char *tableList, const char *str,
const formtype *typeform, const char *expected, int mode,
int direction, int diagnostics) {
widechar *inbuf, *outbuf, *expectedbuf;
int inlen;
int outlen;
int i, rv = 0;
int funcStatus = 0;
formtype *typeformbuf = NULL;
int expectedlen = strlen(expected);
inlen = strlen(str);
outlen = inlen * 10;
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));
}
inlen = extParseChars(str, inbuf);
if (!inlen) {
fprintf(stderr, "Cannot parse input string.\n");
return 1;
}
if (direction == 0) {
funcStatus = lou_translate(tableList, inbuf, &inlen, outbuf, &outlen,
typeformbuf, NULL, NULL, NULL, NULL, mode);
} else {
funcStatus = lou_backTranslate(tableList, inbuf, &inlen, outbuf, &outlen,
typeformbuf, NULL, NULL, NULL, NULL, mode);
}
if (!funcStatus) {
fprintf(stderr, "Translation failed.\n");
return 1;
}
expectedlen = extParseChars(expected, expectedbuf);
for (i = 0; i < outlen && i < expectedlen && expectedbuf[i] == outbuf[i]; i++)
;
if (i < outlen || i < expectedlen) {
rv = 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);
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);
}
}
free(inbuf);
free(outbuf);
free(expectedbuf);
free(typeformbuf);
return rv;
}
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, rv = 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");
return 1;
}
for (i = 0; i < outlen; i++) {
if (expected_poslist[i] != inpos[i]) {
rv = 1;
fprintf(stderr, "Expected %d, received %d in index %d\n",
expected_poslist[i], inpos[i], i);
}
}
free(inbuf);
free(outbuf);
free(inpos);
return rv;
}
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, rv = 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");
return 1;
}
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]) {
rv = 1;
fprintf(stderr, "Expected %d, received %d in index %d\n",
expected_poslist[i], outpos[i], i);
}
}
free(inbuf);
free(outbuf);
free(inpos);
free(outpos);
return rv;
}
int check_cursor_pos(const char *tableList, const char *str,
const int *expected_pos) {
widechar *inbuf;
widechar *outbuf;
int *inpos, *outpos;
int inlen;
int outlen;
int cursor_pos;
int i, rv = 0;
inlen = strlen(str);
outlen = inlen;
inbuf = malloc(sizeof(widechar) * inlen);
outbuf = malloc(sizeof(widechar) * inlen);
inpos = malloc(sizeof(int) * inlen);
outpos = malloc(sizeof(int) * inlen);
inlen = 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");
return 1;
}
if (expected_pos[i] != cursor_pos) {
rv = 1;
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]);
}
}
free(inbuf);
free(outbuf);
free(inpos);
free(outpos);
return rv;
}
/* 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;
int inlen;
int rv = 0;
inlen = strlen(str);
inbuf = malloc(sizeof(widechar) * inlen);
inlen = extParseChars(str, inbuf);
if (!inlen) {
fprintf(stderr, "Cannot parse input string.\n");
return 1;
}
hyphens = calloc(inlen + 1, sizeof(char));
if (!lou_hyphenate(tableList, inbuf, inlen, hyphens, 0)) {
fprintf(stderr, "Hyphenation failed.\n");
return 1;
}
if (strcmp(expected, hyphens)) {
fprintf(stderr, "Input: '%s'\n", str);
fprintf(stderr, "Expected: '%s'\n", expected);
fprintf(stderr, "Received: '%s'\n", hyphens);
rv = 1;
}
free(inbuf);
free(hyphens);
lou_free();
return rv;
}