(root)/
fribidi-1.0.13/
test/
unicode-conformance/
BidiCharacterTest.c
       1  /*
       2   * Copyright (C) 2015, 2017 Dov Grobgeld
       3   *
       4   * This library is free software; you can redistribute it and/or
       5   * modify it under the terms of the GNU Lesser General Public
       6   * License as published by the Free Software Foundation; either
       7   * version 2.1 of the License, or (at your option) any later version.
       8   *
       9   * This library is distributed in the hope that it will be useful,
      10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12   * Lesser General Public License for more details.
      13   *
      14   * You should have received a copy of the GNU Lesser General Public License
      15   * along with this library, in a file named COPYING; if not, write to the
      16   * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
      17   * Boston, MA 02110-1301, USA
      18   */
      19  
      20  #include "fribidi.h"
      21  #include <stdio.h>
      22  #include <stdlib.h>
      23  #include <stdarg.h>
      24  #include <string.h>
      25  #include <ctype.h>
      26  #include <errno.h>
      27  
      28  #define FALSE 0
      29  #define TRUE 1
      30  #define LINE_SIZE 2048 /* Size of biggest line in test file */
      31  
      32  /* Glib like arrays */
      33  typedef struct {
      34    int capacity;
      35    int len;
      36    int *data;
      37  } int_array_t;
      38  
      39  typedef struct {
      40    int capacity;
      41    int len;
      42    char *data;
      43  } char_array_t;
      44  
      45  #define ARRAY_CHUNK_SIZE 32
      46  int_array_t *new_int_array()
      47  {
      48    int_array_t *arr = (int_array_t*)malloc(sizeof(int_array_t));
      49    arr->len = 0;
      50    arr->capacity = ARRAY_CHUNK_SIZE;
      51    arr->data = (int*)malloc(arr->capacity * sizeof(int));
      52  
      53    return arr;
      54  }
      55  
      56  void int_array_add(int_array_t *arr, int val)
      57  {
      58    if (arr->len == arr->capacity)
      59      {
      60        arr->capacity += ARRAY_CHUNK_SIZE;
      61        arr->data = (int*)realloc(arr->data, arr->capacity*sizeof(int));
      62      }
      63    arr->data[arr->len++] = val;
      64  }
      65  
      66  int *int_array_free(int_array_t *arr, int free_data)
      67  {
      68    int *data = arr->data;
      69    if (free_data) {
      70      data = NULL;
      71      free(arr->data);
      72    }
      73    free(arr);
      74    return data;
      75  }
      76  
      77  char_array_t *new_char_array()
      78  {
      79    char_array_t *arr = (char_array_t*)malloc(sizeof(char_array_t));
      80    arr->len = 0;
      81    arr->capacity = ARRAY_CHUNK_SIZE;
      82    arr->data = (char*)malloc(arr->capacity);
      83  
      84    return arr;
      85  }
      86  
      87  void char_array_add(char_array_t *arr, char val)
      88  {
      89    if (arr->len == arr->capacity)
      90      {
      91        arr->capacity += ARRAY_CHUNK_SIZE;
      92        arr->data = (char*)realloc(arr->data, arr->capacity * sizeof(char));
      93      }
      94    arr->data[arr->len++] = val;
      95  }
      96  
      97  char *char_array_free(char_array_t *arr, int free_data)
      98  {
      99    char *data = arr->data;
     100    if (free_data) {
     101      data = NULL;
     102      free(arr->data);
     103    }
     104    free(arr);
     105    return data;
     106  }
     107  
     108  static void die(const char *fmt, ...)
     109  {
     110    va_list ap;
     111    va_start(ap,fmt);
     112  
     113    vfprintf(stderr, fmt, ap);
     114    exit(-1);
     115  }
     116  
     117  static
     118  FriBidiChar parse_uni_char(const char *start, int len)
     119  {
     120    return strtoul(start, NULL, 16);
     121  }
     122  
     123  static
     124  void parse_test_line (char *line,
     125                        int line_no,
     126                        FriBidiChar **code_points,      /* Field 0 */
     127                        int *code_points_len,
     128                        int *paragraph_dir,    /* Field 1 */
     129                        int *resolved_paragraph_embedding_level,   /* Field 2 */
     130                        FriBidiLevel **resolved_levels,   /* Field 3 */
     131                        int **visual_ordering,    /* Field 4 */
     132                        int *visual_ordering_len
     133                        )
     134  {
     135    int_array_t *code_points_array, *visual_ordering_array;
     136    char_array_t *levels_array;
     137    char *end;
     138    int level;
     139  
     140    code_points_array = new_int_array ();
     141    levels_array = new_char_array ();
     142  
     143    /* Field 0. Code points */
     144    for(;;)
     145      {
     146        FriBidiChar c;
     147        while (isspace (*line))
     148          line++;
     149        end = line;
     150        while (isxdigit (*end))
     151          end++;
     152        if (line == end)
     153          break;
     154  
     155        c = parse_uni_char (line, end - line);
     156        int_array_add(code_points_array, c);
     157  
     158        line = end;
     159      }
     160  
     161    *code_points_len = code_points_array->len;
     162    *code_points = (FriBidiChar *) int_array_free (code_points_array, FALSE);
     163  
     164    if (*line == ';')
     165      line++;
     166    else
     167      die("Oops! Didn't find expected ;\n");
     168  
     169    /* Field 1. Paragraph direction */
     170    end = line;
     171    while (isdigit (*end))
     172      end++;
     173    *paragraph_dir = atoi(line);
     174    line = end;
     175  
     176    if (*line == ';')
     177      line++;
     178    else
     179      die("Oops! Didn't find expected ;\n");
     180  
     181    /* Field 2. resolved paragraph_dir */
     182    end = line;
     183    while (isdigit (*end))
     184      end++;
     185    *resolved_paragraph_embedding_level = atoi(line);
     186    line = end;
     187  
     188    if (*line == ';')
     189      line++;
     190    else
     191      die("Oops! Didn't find expected ; at line %d\n", line_no);
     192  
     193    while (*line)
     194      {
     195        FriBidiLevel level;
     196        char *end;
     197  
     198        errno = 0;
     199        level = strtol (line, &end, 10);
     200        if (errno != EINVAL && line != end)
     201          {
     202            char_array_add (levels_array, level);
     203            line = end;
     204            continue;
     205          }
     206  
     207        while (isspace (*line))
     208          line++;
     209  
     210        if (*line == 'x')
     211          {
     212            level = (FriBidiLevel) -1;
     213            char_array_add (levels_array, level);
     214            line++;
     215            continue;
     216          }
     217  
     218        if (*line == ';')
     219          break;
     220  
     221        die("Oops! I shouldn't be here!\n");
     222      }
     223  
     224    if (levels_array->len != *code_points_len)
     225      die("Oops! Different lengths for levels and codepoints at line %d!\n", line_no);
     226  
     227    *resolved_levels = (FriBidiLevel*)char_array_free (levels_array, FALSE);
     228  
     229    if (*line == ';')
     230      line++;
     231    else
     232      die("Oops! Didn't find expected ; at line %d\n", line_no);
     233  
     234    /* Field 4 - resulting visual ordering */
     235    visual_ordering_array = new_int_array ();
     236    for(; errno = 0, level = strtol (line, &end, 10), line != end && errno != EINVAL; line = end) {
     237      int_array_add (visual_ordering_array, level);
     238    }
     239  
     240    *visual_ordering_len = visual_ordering_array->len;
     241    *visual_ordering = (int*)int_array_free (visual_ordering_array, FALSE);
     242  }
     243  
     244  int
     245  main (int argc, char **argv)
     246  {
     247    int next_arg;
     248    FILE *channel;
     249    const char *filename;
     250    char line[LINE_SIZE];
     251    int numerrs = 0;
     252    int line_no = 0;
     253    FriBidiChar *code_points = NULL;
     254    int code_points_len = 0;
     255    int expected_ltor_len = 0;
     256    int paragraph_dir = 0;
     257    FriBidiLevel *expected_levels = NULL;
     258    int *expected_ltor = NULL;
     259    int resolved_paragraph_embedding_level;
     260    FriBidiLevel *levels = NULL;
     261    FriBidiCharType *types = NULL;
     262    FriBidiBracketType *bracket_types = NULL;
     263    FriBidiStrIndex *ltor = NULL;
     264    int ltor_len;
     265    int debug = FALSE;
     266  
     267    if (argc < 2)
     268      {
     269        fprintf (stderr, "usage: %s [--debug] test-file-name\n", argv[0]);
     270        exit (1);
     271      }
     272  
     273    next_arg = 1;
     274    while(next_arg < argc && argv[next_arg][0]=='-')
     275      {
     276        const char *arg = argv[next_arg++];
     277        if (strcmp(arg, "--debug")==0)
     278          {
     279            debug=TRUE;
     280            continue;
     281          }
     282        die("Unknown option %s!\n", arg);
     283      }
     284  
     285      filename = argv[next_arg++];
     286  
     287      channel = fopen(filename, "r");
     288      if (!channel) 
     289  	die ("Failed opening %s\n", filename);
     290  
     291      while (!feof(channel)) {
     292        int len;
     293        fgets(line, LINE_SIZE, channel);
     294        len = strlen(line);
     295        if (len == LINE_SIZE-1)
     296          die("LINE_SIZE=%d too small at line %d!\n", LINE_SIZE, line_no);
     297  
     298        line_no++;
     299  
     300        if (line[0] == '#' || line[0] == '\n')
     301          continue;
     302  
     303        free (code_points);
     304        free (expected_levels);
     305        free (expected_ltor);
     306        free (bracket_types);
     307        free (types);
     308        free (levels);
     309        free (ltor);
     310  
     311        parse_test_line (line,
     312                         line_no,
     313                         &code_points,      /* Field 0 */
     314                         &code_points_len,
     315                         &paragraph_dir,    /* Field 1 */
     316                         &resolved_paragraph_embedding_level,   /* Field 2 */
     317                         &expected_levels,   /* Field 3 */
     318                         &expected_ltor,    /* Field 4 */
     319                         &expected_ltor_len
     320                         );
     321  
     322        /* Test it */
     323        bracket_types = malloc ( sizeof(FriBidiBracketType) * code_points_len);
     324        types = malloc ( sizeof(FriBidiCharType) * code_points_len);
     325        levels = malloc (sizeof (FriBidiLevel) * code_points_len);
     326        ltor = malloc (sizeof (FriBidiStrIndex) * code_points_len);
     327  
     328  
     329        {
     330          FriBidiParType base_dir;
     331          int i, j;
     332          int matches;
     333          int types_len = code_points_len;
     334          int levels_len = types_len;
     335          FriBidiBracketType NoBracket = FRIBIDI_NO_BRACKET;
     336  
     337          for (i=0; i<code_points_len; i++)
     338            {
     339              types[i] = fribidi_get_bidi_type(code_points[i]);
     340  
     341              /* Note the optimization that a bracket is always
     342                 of type neutral */
     343              if (types[i] == FRIBIDI_TYPE_ON)
     344                  bracket_types[i] = fribidi_get_bracket(code_points[i]);
     345              else
     346                  bracket_types[i] = NoBracket;
     347            }
     348  
     349          switch (paragraph_dir)
     350            {
     351            case 0: base_dir = FRIBIDI_PAR_LTR; break;
     352            case 1: base_dir = FRIBIDI_PAR_RTL; break;
     353            case 2: base_dir = FRIBIDI_PAR_ON;  break;
     354            }
     355  
     356          if (fribidi_get_par_embedding_levels_ex (types,
     357                                                   bracket_types,
     358                                                   types_len,
     359                                                   &base_dir,
     360                                                   levels))
     361          {}
     362  
     363          for (i = 0; i < types_len; i++)
     364            ltor[i] = i;
     365  
     366          if (fribidi_reorder_line (0 /*FRIBIDI_FLAG_REORDER_NSM*/,
     367                                    types, types_len,
     368                                    0, base_dir,
     369                                    levels,
     370                                    NULL,
     371                                    ltor))
     372          {}
     373  
     374          j = 0;
     375          for (i = 0; i < types_len; i++)
     376            if (!FRIBIDI_IS_EXPLICIT_OR_BN (types[ltor[i]]))
     377              ltor[j++] = ltor[i];
     378          ltor_len = j;
     379  
     380          /* Compare */
     381          matches = TRUE;
     382          if (matches)
     383            for (i = 0; i < code_points_len; i++)
     384              if (levels[i] != expected_levels[i] &&
     385                  expected_levels[i] != (FriBidiLevel) -1) {
     386                matches = FALSE;
     387                break;
     388              }
     389  
     390          if (ltor_len != expected_ltor_len)
     391            matches = FALSE;
     392          if (matches)
     393            for (i = 0; i < ltor_len; i++)
     394              if (ltor[i] != expected_ltor[i]) {
     395                matches = FALSE;
     396                break;
     397              }
     398  
     399          if (!matches)
     400            {
     401              numerrs++;
     402  
     403              fprintf (stderr, "failure on line %d\n", line_no);
     404              fprintf (stderr, "input is: %s\n", line);
     405              fprintf (stderr, "base dir: %s\n", paragraph_dir==0 ? "LTR"
     406                          : paragraph_dir==1 ? "RTL" : "AUTO");
     407  
     408              fprintf (stderr, "expected levels:");
     409              for (i = 0; i < code_points_len; i++)
     410                if (expected_levels[i] == (FriBidiLevel) -1)
     411                  fprintf (stderr, " x");
     412                else
     413                  fprintf (stderr, " %d", expected_levels[i]);
     414              fprintf (stderr, "\n");
     415              fprintf (stderr, "returned levels:");
     416              for (i = 0; i < levels_len; i++)
     417                fprintf (stderr, " %d", levels[i]);
     418              fprintf (stderr, "\n");
     419  
     420              fprintf (stderr, "expected order:");
     421              for (i = 0; i < expected_ltor_len; i++)
     422                fprintf (stderr, " %d", expected_ltor[i]);
     423              fprintf (stderr, "\n");
     424              fprintf (stderr, "returned order:");
     425              for (i = 0; i < ltor_len; i++)
     426                fprintf (stderr, " %d", ltor[i]);
     427              fprintf (stderr, "\n");
     428  
     429              if (debug)
     430                {
     431                  fribidi_set_debug (1);
     432  
     433                  if (fribidi_get_par_embedding_levels_ex (types,
     434                                                           bracket_types,
     435                                                           types_len,
     436                                                           &base_dir,
     437                                                           levels))
     438                  {}
     439  
     440                  fribidi_set_debug (0);
     441                }
     442  
     443              fprintf (stderr, "\n");
     444            }
     445        }
     446      }
     447  
     448    if (numerrs)
     449      fprintf (stderr, "%d errors\n", numerrs);
     450    else
     451      printf("No errors found! :-)\n");
     452  
     453    free (code_points);
     454    free (expected_levels);
     455    free (expected_ltor);
     456    free (bracket_types);
     457    free (types);
     458    free (levels);
     459    free (ltor);
     460  
     461    return numerrs;
     462  }