Home | History | Annotate | Download | only in cintltst
      1 /********************************************************************
      2  * COPYRIGHT:
      3  * Copyright (c) 2009, International Business Machines Corporation and
      4  * others. All Rights Reserved.
      5  ********************************************************************/
      6 /********************************************************************************
      7 *
      8 * File spooftest.c
      9 *
     10 *********************************************************************************/
     11 /*C API TEST for the uspoof Unicode Indentifier Spoofing and Security API */
     12 /**
     13 *   This is an API test for ICU spoof detection in plain C.  It doesn't test very many cases, and doesn't
     14 *   try to test the full functionality.  It just calls each function and verifies that it
     15 *   works on a basic level.
     16 *
     17 *   More complete testing of spoof detection functionality is done with the C++ tests.
     18 **/
     19 
     20 #include "unicode/utypes.h"
     21 #if !UCONFIG_NO_REGULAR_EXPRESSIONS && !UCONFIG_NO_NORMALIZATION
     22 
     23 #include <stdlib.h>
     24 #include <stdio.h>
     25 #include <string.h>
     26 #include "unicode/uspoof.h"
     27 #include "unicode/ustring.h"
     28 #include "unicode/uset.h"
     29 #include "cintltst.h"
     30 
     31 #define TEST_ASSERT_SUCCESS(status) {if (U_FAILURE(status)) { \
     32     log_err_status(status, "Failure at file %s, line %d, error = %s\n", __FILE__, __LINE__, u_errorName(status));}}
     33 
     34 #define TEST_ASSERT(expr) {if ((expr)==FALSE) { \
     35 log_err("Test Failure at file %s, line %d: \"%s\" is false.\n", __FILE__, __LINE__, #expr);};}
     36 
     37 #define TEST_ASSERT_EQ(a, b) { if ((a) != (b)) { \
     38     log_err("Test Failure at file %s, line %d: \"%s\" (%d) != \"%s\" (%d) \n", \
     39              __FILE__, __LINE__, #a, (a), #b, (b)); }}
     40 
     41 #define TEST_ASSERT_NE(a, b) { if ((a) == (b)) { \
     42     log_err("Test Failure at file %s, line %d: \"%s\" (%d) == \"%s\" (%d) \n", \
     43              __FILE__, __LINE__, #a, (a), #b, (b)); }}
     44 
     45 
     46 /*
     47  *   TEST_SETUP and TEST_TEARDOWN
     48  *         macros to handle the boilerplate around setting up test case.
     49  *         Put arbitrary test code between SETUP and TEARDOWN.
     50  *         "sc" is the ready-to-go  SpoofChecker for use in the tests.
     51  */
     52 #define TEST_SETUP {  \
     53     UErrorCode status = U_ZERO_ERROR; \
     54     USpoofChecker *sc;     \
     55     sc = uspoof_open(&status);  \
     56     TEST_ASSERT_SUCCESS(status);   \
     57     if (U_SUCCESS(status)){
     58 
     59 #define TEST_TEARDOWN  \
     60     }  \
     61     TEST_ASSERT_SUCCESS(status);  \
     62     uspoof_close(sc);  \
     63 }
     64 
     65 
     66 static void TestUSpoofCAPI(void);
     67 
     68 void addUSpoofTest(TestNode** root);
     69 
     70 void addUSpoofTest(TestNode** root)
     71 {
     72 #if !UCONFIG_NO_FILE_IO
     73     addTest(root, &TestUSpoofCAPI, "uspoof/TestUSpoofCAPI");
     74 #endif
     75 }
     76 
     77 /*
     78  *  Identifiers for verifying that spoof checking is minimally alive and working.
     79  */
     80 const UChar goodLatin[] = {(UChar)0x75, (UChar)0x77, 0};    /* "uw", all ASCII             */
     81                                                             /*   (not confusable)          */
     82 const UChar scMixed[]  = {(UChar)0x73, (UChar)0x0441, 0};   /* "sc", with Cyrillic 'c'     */
     83                                                             /*   (mixed script, confusable */
     84 
     85 const UChar scLatin[]  = {(UChar)0x73,  (UChar)0x63, 0};    /* "sc", plain ascii.        */
     86 const UChar goodCyrl[] = {(UChar)0x438, (UChar)0x43B, 0};   /* Plain lower case Cyrillic letters,
     87                                                                no latin confusables         */
     88 
     89 const UChar goodGreek[]   = {(UChar)0x3c0, (UChar)0x3c6, 0};   /* Plain lower case Greek letters */
     90 
     91 const UChar lll_Latin_a[] = {(UChar)0x6c, (UChar)0x49, (UChar)0x31, 0};   /* lI1, all ASCII */
     92 
     93                              /*  Full-width I, Small Roman Numeral fifty, Latin Cap Letter IOTA*/
     94 const UChar lll_Latin_b[] = {(UChar)0xff29, (UChar)0x217c, (UChar)0x196, 0};
     95 
     96 const UChar lll_Cyrl[]    = {(UChar)0x0406, (UChar)0x04C0, (UChar)0x31, 0};
     97 
     98 /* The skeleton transform for all of thes 'lll' lookalikes is all ascii digit 1. */
     99 const UChar lll_Skel[]    = {(UChar)0x31, (UChar)0x31, (UChar)0x31, 0};
    100 
    101 /* Provide better code coverage */
    102 const char goodLatinUTF8[]    = {0x75, 0x77, 0};
    103 /*
    104  *   Spoof Detction C API Tests
    105  */
    106 static void TestUSpoofCAPI(void) {
    107 
    108     /*
    109      *  basic uspoof_open().
    110      */
    111     {
    112         USpoofChecker *sc;
    113         UErrorCode  status = U_ZERO_ERROR;
    114         sc = uspoof_open(&status);
    115         TEST_ASSERT_SUCCESS(status);
    116         if (U_FAILURE(status)) {
    117             /* If things are so broken that we can't even open a default spoof checker,  */
    118             /*   don't even try the rest of the tests.  They would all fail.             */
    119             return;
    120         }
    121         uspoof_close(sc);
    122     }
    123 
    124 
    125 
    126     /*
    127      *  Test Open from source rules.
    128     */
    129     TEST_SETUP
    130     const char *dataSrcDir;
    131     char       *fileName;
    132     char       *confusables;
    133     int         confusablesLength;
    134     char       *confusablesWholeScript;
    135     int         confusablesWholeScriptLength;
    136     FILE       *f;
    137     UParseError pe;
    138     int32_t     errType;
    139     USpoofChecker *rsc;
    140 
    141     dataSrcDir = ctest_dataSrcDir();
    142     fileName = malloc(strlen(dataSrcDir) + 100);
    143     strcpy(fileName, dataSrcDir);
    144     strcat(fileName, U_FILE_SEP_STRING "unidata" U_FILE_SEP_STRING "confusables.txt");
    145     f = fopen(fileName, "r");
    146     TEST_ASSERT_NE(f, NULL);
    147     confusables = malloc(3000000);
    148     confusablesLength = fread(confusables, 1, 3000000, f);
    149     fclose(f);
    150 
    151 
    152     strcpy(fileName, dataSrcDir);
    153     strcat(fileName, U_FILE_SEP_STRING "unidata" U_FILE_SEP_STRING "confusablesWholeScript.txt");
    154     f = fopen(fileName, "r");
    155     TEST_ASSERT_NE(f, NULL);
    156     confusablesWholeScript = malloc(1000000);
    157     confusablesWholeScriptLength = fread(confusablesWholeScript, 1, 1000000, f);
    158     fclose(f);
    159 
    160     rsc = uspoof_openFromSource(confusables, confusablesLength,
    161                                               confusablesWholeScript, confusablesWholeScriptLength,
    162                                               &errType, &pe, &status);
    163     TEST_ASSERT_SUCCESS(status);
    164 
    165     free(confusablesWholeScript);
    166     free(confusables);
    167     free(fileName);
    168     uspoof_close(rsc);
    169     /*  printf("ParseError Line is %d\n", pe.line);  */
    170     TEST_TEARDOWN;
    171 
    172 
    173     /*
    174      * openFromSerialized and serialize
    175     */
    176     TEST_SETUP
    177         int32_t        serializedSize = 0;
    178         int32_t        actualLength = 0;
    179         char           *buf;
    180         USpoofChecker  *sc2;
    181         int32_t         checkResults;
    182 
    183 
    184         serializedSize = uspoof_serialize(sc, NULL, 0, &status);
    185         TEST_ASSERT_EQ(status, U_BUFFER_OVERFLOW_ERROR);
    186         TEST_ASSERT(serializedSize > 0);
    187 
    188         /* Serialize the default spoof checker */
    189         status = U_ZERO_ERROR;
    190         buf = (char *)malloc(serializedSize + 10);
    191         TEST_ASSERT(buf != NULL);
    192         buf[serializedSize] = 42;
    193         uspoof_serialize(sc, buf, serializedSize, &status);
    194         TEST_ASSERT_SUCCESS(status);
    195         TEST_ASSERT_EQ(42, buf[serializedSize]);
    196 
    197         /* Create a new spoof checker from the freshly serialized data */
    198         sc2 = uspoof_openFromSerialized(buf, serializedSize+10, &actualLength, &status);
    199         TEST_ASSERT_SUCCESS(status);
    200         TEST_ASSERT_NE(NULL, sc2);
    201         TEST_ASSERT_EQ(serializedSize, actualLength);
    202 
    203         /* Verify that the new spoof checker at least wiggles */
    204         checkResults = uspoof_check(sc2, goodLatin, -1, NULL, &status);
    205         TEST_ASSERT_SUCCESS(status);
    206         TEST_ASSERT_EQ(0, checkResults);
    207 
    208         checkResults = uspoof_check(sc2, scMixed, -1, NULL, &status);
    209         TEST_ASSERT_SUCCESS(status);
    210         TEST_ASSERT_EQ(USPOOF_SINGLE_SCRIPT | USPOOF_MIXED_SCRIPT_CONFUSABLE, checkResults);
    211 
    212         uspoof_close(sc2);
    213         free(buf);
    214     TEST_TEARDOWN;
    215 
    216 
    217 
    218     /*
    219      * Set & Get Check Flags
    220     */
    221     TEST_SETUP
    222         int32_t t;
    223         uspoof_setChecks(sc, USPOOF_ALL_CHECKS, &status);
    224         TEST_ASSERT_SUCCESS(status);
    225         t = uspoof_getChecks(sc, &status);
    226         TEST_ASSERT_EQ(t, USPOOF_ALL_CHECKS);
    227 
    228         uspoof_setChecks(sc, 0, &status);
    229         TEST_ASSERT_SUCCESS(status);
    230         t = uspoof_getChecks(sc, &status);
    231         TEST_ASSERT_EQ(0, t);
    232 
    233         uspoof_setChecks(sc,
    234                         USPOOF_WHOLE_SCRIPT_CONFUSABLE | USPOOF_MIXED_SCRIPT_CONFUSABLE | USPOOF_ANY_CASE,
    235                         &status);
    236         TEST_ASSERT_SUCCESS(status);
    237         t = uspoof_getChecks(sc, &status);
    238         TEST_ASSERT_SUCCESS(status);
    239         TEST_ASSERT_EQ(USPOOF_WHOLE_SCRIPT_CONFUSABLE | USPOOF_MIXED_SCRIPT_CONFUSABLE | USPOOF_ANY_CASE, t);
    240     TEST_TEARDOWN;
    241 
    242     /*
    243     * get & setAllowedChars
    244     */
    245     TEST_SETUP
    246         USet *us;
    247         const USet *uset;
    248 
    249         uset = uspoof_getAllowedChars(sc, &status);
    250         TEST_ASSERT_SUCCESS(status);
    251         TEST_ASSERT(uset_isFrozen(uset));
    252         us = uset_open((UChar32)0x41, (UChar32)0x5A);   /*  [A-Z]  */
    253         uspoof_setAllowedChars(sc, us, &status);
    254         TEST_ASSERT_SUCCESS(status);
    255         TEST_ASSERT_NE(us, uspoof_getAllowedChars(sc, &status));
    256         TEST_ASSERT(uset_equals(us, uspoof_getAllowedChars(sc, &status)));
    257         TEST_ASSERT_SUCCESS(status);
    258         uset_close(us);
    259     TEST_TEARDOWN;
    260 
    261     /*
    262     *  clone()
    263     */
    264 
    265     TEST_SETUP
    266         USpoofChecker *clone1 = NULL;
    267         USpoofChecker *clone2 = NULL;
    268         int32_t        checkResults = 0;
    269 
    270         clone1 = uspoof_clone(sc, &status);
    271         TEST_ASSERT_SUCCESS(status);
    272         TEST_ASSERT_NE(clone1, sc);
    273 
    274         clone2 = uspoof_clone(clone1, &status);
    275         TEST_ASSERT_SUCCESS(status);
    276         TEST_ASSERT_NE(clone2, clone1);
    277 
    278         uspoof_close(clone1);
    279 
    280         /* Verify that the cloned spoof checker is alive */
    281         checkResults = uspoof_check(clone2, goodLatin, -1, NULL, &status);
    282         TEST_ASSERT_SUCCESS(status);
    283         TEST_ASSERT_EQ(0, checkResults);
    284 
    285         checkResults = uspoof_check(clone2, scMixed, -1, NULL, &status);
    286         TEST_ASSERT_SUCCESS(status);
    287         TEST_ASSERT_EQ(USPOOF_SINGLE_SCRIPT | USPOOF_MIXED_SCRIPT_CONFUSABLE, checkResults);
    288         uspoof_close(clone2);
    289     TEST_TEARDOWN;
    290 
    291     /*
    292      *  get & set Checks
    293     */
    294     TEST_SETUP
    295         int32_t   checks;
    296         int32_t   checks2;
    297         int32_t   checkResults;
    298 
    299         checks = uspoof_getChecks(sc, &status);
    300         TEST_ASSERT_SUCCESS(status);
    301         TEST_ASSERT_EQ(USPOOF_ALL_CHECKS, checks);
    302 
    303         checks &= ~(USPOOF_SINGLE_SCRIPT | USPOOF_MIXED_SCRIPT_CONFUSABLE);
    304         uspoof_setChecks(sc, checks, &status);
    305         TEST_ASSERT_SUCCESS(status);
    306         checks2 = uspoof_getChecks(sc, &status);
    307         TEST_ASSERT_EQ(checks, checks2);
    308 
    309         /* The checks that were disabled just above are the same ones that the "scMixed" test fails.
    310             So with those tests gone checking that Identifier should now succeed */
    311         checkResults = uspoof_check(sc, scMixed, -1, NULL, &status);
    312         TEST_ASSERT_SUCCESS(status);
    313         TEST_ASSERT_EQ(0, checkResults);
    314     TEST_TEARDOWN;
    315 
    316     /*
    317      *  AllowedLoacles
    318      */
    319 
    320     TEST_SETUP
    321         const char  *allowedLocales;
    322         int32_t  checkResults;
    323 
    324         /* Default allowed locales list should be empty */
    325         allowedLocales = uspoof_getAllowedLocales(sc, &status);
    326         TEST_ASSERT_SUCCESS(status);
    327         TEST_ASSERT(strcmp("", allowedLocales) == 0)
    328 
    329         /* Allow en and ru, which should enable Latin and Cyrillic only to pass */
    330         uspoof_setAllowedLocales(sc, "en, ru_RU", &status);
    331         TEST_ASSERT_SUCCESS(status);
    332         allowedLocales = uspoof_getAllowedLocales(sc, &status);
    333         TEST_ASSERT_SUCCESS(status);
    334         TEST_ASSERT(strstr(allowedLocales, "en") != NULL);
    335         TEST_ASSERT(strstr(allowedLocales, "ru") != NULL);
    336 
    337         /* Limit checks to USPOOF_CHAR_LIMIT.  Some of the test data has whole script confusables also,
    338          * which we don't want to see in this test. */
    339         uspoof_setChecks(sc, USPOOF_CHAR_LIMIT, &status);
    340         TEST_ASSERT_SUCCESS(status);
    341 
    342         checkResults = uspoof_check(sc, goodLatin, -1, NULL, &status);
    343         TEST_ASSERT_SUCCESS(status);
    344         TEST_ASSERT_EQ(0, checkResults);
    345 
    346         checkResults = uspoof_check(sc, goodGreek, -1, NULL, &status);
    347         TEST_ASSERT_SUCCESS(status);
    348         TEST_ASSERT_EQ(USPOOF_CHAR_LIMIT, checkResults);
    349 
    350         checkResults = uspoof_check(sc, goodCyrl, -1, NULL, &status);
    351         TEST_ASSERT_SUCCESS(status);
    352         TEST_ASSERT_EQ(0, checkResults);
    353 
    354         /* Reset with an empty locale list, which should allow all characters to pass */
    355         uspoof_setAllowedLocales(sc, " ", &status);
    356         TEST_ASSERT_SUCCESS(status);
    357 
    358         checkResults = uspoof_check(sc, goodGreek, -1, NULL, &status);
    359         TEST_ASSERT_SUCCESS(status);
    360         TEST_ASSERT_EQ(0, checkResults);
    361     TEST_TEARDOWN;
    362 
    363     /*
    364      * AllowedChars   set/get the USet of allowed characters.
    365      */
    366     TEST_SETUP
    367         const USet  *set;
    368         USet        *tmpSet;
    369         int32_t      checkResults;
    370 
    371         /* By default, we should see no restriction; the USet should allow all characters. */
    372         set = uspoof_getAllowedChars(sc, &status);
    373         TEST_ASSERT_SUCCESS(status);
    374         tmpSet = uset_open(0, 0x10ffff);
    375         TEST_ASSERT(uset_equals(tmpSet, set));
    376 
    377         /* Setting the allowed chars should enable the check. */
    378         uspoof_setChecks(sc, USPOOF_ALL_CHECKS & ~USPOOF_CHAR_LIMIT, &status);
    379         TEST_ASSERT_SUCCESS(status);
    380 
    381         /* Remove a character that is in our good Latin test identifier from the allowed chars set. */
    382         uset_remove(tmpSet, goodLatin[1]);
    383         uspoof_setAllowedChars(sc, tmpSet, &status);
    384         TEST_ASSERT_SUCCESS(status);
    385         uset_close(tmpSet);
    386 
    387         /* Latin Identifier should now fail; other non-latin test cases should still be OK */
    388         checkResults = uspoof_check(sc, goodLatin, -1, NULL, &status);
    389         TEST_ASSERT_SUCCESS(status);
    390         TEST_ASSERT_EQ(USPOOF_CHAR_LIMIT, checkResults);
    391 
    392         checkResults = uspoof_check(sc, goodGreek, -1, NULL, &status);
    393         TEST_ASSERT_SUCCESS(status);
    394         TEST_ASSERT_EQ(USPOOF_WHOLE_SCRIPT_CONFUSABLE, checkResults);
    395     TEST_TEARDOWN;
    396 
    397     /*
    398      * check UTF-8
    399      */
    400     TEST_SETUP
    401         char    utf8buf[200];
    402         int32_t checkResults;
    403         int32_t position;
    404 
    405         u_strToUTF8(utf8buf, sizeof(utf8buf), NULL, goodLatin, -1, &status);
    406         TEST_ASSERT_SUCCESS(status);
    407         position = 666;
    408         checkResults = uspoof_checkUTF8(sc, utf8buf, -1, &position, &status);
    409         TEST_ASSERT_SUCCESS(status);
    410         TEST_ASSERT_EQ(0, checkResults);
    411         TEST_ASSERT_EQ(666, position);
    412 
    413         u_strToUTF8(utf8buf, sizeof(utf8buf), NULL, goodCyrl, -1, &status);
    414         TEST_ASSERT_SUCCESS(status);
    415         checkResults = uspoof_checkUTF8(sc, utf8buf, -1, &position, &status);
    416         TEST_ASSERT_SUCCESS(status);
    417         TEST_ASSERT_EQ(0, checkResults);
    418 
    419         u_strToUTF8(utf8buf, sizeof(utf8buf), NULL, scMixed, -1, &status);
    420         TEST_ASSERT_SUCCESS(status);
    421         position = 666;
    422         checkResults = uspoof_checkUTF8(sc, utf8buf, -1, &position, &status);
    423         TEST_ASSERT_SUCCESS(status);
    424         TEST_ASSERT_EQ(USPOOF_MIXED_SCRIPT_CONFUSABLE | USPOOF_SINGLE_SCRIPT , checkResults);
    425         TEST_ASSERT_EQ(2, position);
    426 
    427     TEST_TEARDOWN;
    428 
    429     /*
    430      * uspoof_areConfusable()
    431      */
    432     TEST_SETUP
    433         int32_t  checkResults;
    434 
    435         checkResults = uspoof_areConfusable(sc, scLatin, -1, scMixed, -1, &status);
    436         TEST_ASSERT_SUCCESS(status);
    437         TEST_ASSERT_EQ(USPOOF_MIXED_SCRIPT_CONFUSABLE, checkResults);
    438 
    439         checkResults = uspoof_areConfusable(sc, goodGreek, -1, scLatin, -1, &status);
    440         TEST_ASSERT_SUCCESS(status);
    441         TEST_ASSERT_EQ(0, checkResults);
    442 
    443         checkResults = uspoof_areConfusable(sc, lll_Latin_a, -1, lll_Latin_b, -1, &status);
    444         TEST_ASSERT_SUCCESS(status);
    445         TEST_ASSERT_EQ(USPOOF_SINGLE_SCRIPT_CONFUSABLE, checkResults);
    446 
    447     TEST_TEARDOWN;
    448 
    449     /*
    450      * areConfusableUTF8
    451      */
    452     TEST_SETUP
    453         int32_t checkResults;
    454         char s1[200];
    455         char s2[200];
    456 
    457 
    458         u_strToUTF8(s1, sizeof(s1), NULL, scLatin, -1, &status);
    459         u_strToUTF8(s2, sizeof(s2), NULL, scMixed, -1, &status);
    460         TEST_ASSERT_SUCCESS(status);
    461         checkResults = uspoof_areConfusableUTF8(sc, s1, -1, s2, -1, &status);
    462         TEST_ASSERT_SUCCESS(status);
    463         TEST_ASSERT_EQ(USPOOF_MIXED_SCRIPT_CONFUSABLE, checkResults);
    464 
    465         u_strToUTF8(s1, sizeof(s1), NULL, goodGreek, -1, &status);
    466         u_strToUTF8(s2, sizeof(s2), NULL, scLatin, -1, &status);
    467         TEST_ASSERT_SUCCESS(status);
    468         checkResults = uspoof_areConfusableUTF8(sc, s1, -1, s2, -1, &status);
    469         TEST_ASSERT_SUCCESS(status);
    470         TEST_ASSERT_EQ(0, checkResults);
    471 
    472         u_strToUTF8(s1, sizeof(s1), NULL, lll_Latin_a, -1, &status);
    473         u_strToUTF8(s2, sizeof(s2), NULL, lll_Latin_b, -1, &status);
    474         TEST_ASSERT_SUCCESS(status);
    475         checkResults = uspoof_areConfusableUTF8(sc, s1, -1, s2, -1, &status);
    476         TEST_ASSERT_SUCCESS(status);
    477         TEST_ASSERT_EQ(USPOOF_SINGLE_SCRIPT_CONFUSABLE, checkResults);
    478 
    479     TEST_TEARDOWN;
    480 
    481 
    482   /*
    483    * getSkeleton
    484    */
    485 
    486     TEST_SETUP
    487         UChar dest[100];
    488         int32_t   skelLength;
    489 
    490         skelLength = uspoof_getSkeleton(sc, USPOOF_ANY_CASE, lll_Latin_a, -1, dest, sizeof(dest)/sizeof(UChar), &status);
    491         TEST_ASSERT_SUCCESS(status);
    492         TEST_ASSERT_EQ(0, u_strcmp(lll_Skel, dest));
    493         TEST_ASSERT_EQ(u_strlen(lll_Skel), skelLength);
    494 
    495         skelLength = uspoof_getSkeletonUTF8(sc, USPOOF_ANY_CASE, goodLatinUTF8, -1, dest, sizeof(dest)/sizeof(UChar), &status);
    496         TEST_ASSERT_SUCCESS(status);
    497 
    498         skelLength = uspoof_getSkeleton(sc, USPOOF_ANY_CASE, lll_Latin_a, -1, NULL, 0, &status);
    499         TEST_ASSERT_EQ(U_BUFFER_OVERFLOW_ERROR, status);
    500         TEST_ASSERT_EQ(3, skelLength);
    501         status = U_ZERO_ERROR;
    502 
    503     TEST_TEARDOWN;
    504 }
    505 
    506 #endif  /* UCONFIG_NO_REGULAR_EXPRESSIONS */
    507