Windows: Tests for afsd modules
authorAsanka Herath <asanka@secure-endpoints.com>
Sun, 26 Jul 2009 14:16:33 +0000 (10:16 -0400)
committerJeffrey Altman <jaltman@openafs.org>
Sun, 26 Jul 2009 14:20:30 +0000 (07:20 -0700)
Add test routines for internationalization routines.

LICENSE MIT

Reviewed-on: http://gerrit.openafs.org/218
Tested-by: Jeffrey Altman <jaltman@openafs.org>
Reviewed-by: Jeffrey Altman <jaltman@openafs.org>

src/WINNT/afsd/NTMakefile
src/WINNT/afsd/test/btreetest.c [new file with mode: 0644]
src/WINNT/afsd/test/convtest.c [new file with mode: 0644]
src/WINNT/afsd/test/stricmptest.c [new file with mode: 0644]

index 5a59510..4db2f54 100644 (file)
@@ -514,3 +514,26 @@ clean::
        $(DEL) $(LOGON_DLLFILE)
 
 mkdir:
+
+############################################################################
+# Tests
+
+{test}.c{$(OUT)\}.obj:
+       $(C2OBJ) $<
+
+test::
+
+test:: btreetest
+
+btreetest: "$(OUT)\btreetest.exe"
+       "$(OUT)\btreetest.exe"
+
+$(OUT)\btreetest.exe: \
+               $(OUT)\btreetest.obj \
+               $(OUT)\cm_btree.obj \
+               $(OUT)\cm_nls.obj \
+               $(OUT)\cm_utils.obj \
+               $(DESTDIR)\lib\libosi.lib
+       $(EXECONLINK)
+       $(_VC_MANIFEST_EMBED_EXE)
+       $(EXEPREP)
diff --git a/src/WINNT/afsd/test/btreetest.c b/src/WINNT/afsd/test/btreetest.c
new file mode 100644 (file)
index 0000000..ebe1e13
--- /dev/null
@@ -0,0 +1,258 @@
+#include<windows.h>
+#include<stdio.h>
+#include<wchar.h>
+#include<strsafe.h>
+
+#include "..\afsd.h"
+
+#define paste(a,b) a ## b
+#define _L(a) paste(L,a)
+
+#define TRACE1 wprintf
+
+/* Setup and Fakery ... */
+osi_log_t * afsd_logp;
+
+void cm_SetFid(cm_fid_t *fidp, afs_uint32 cell, afs_uint32 volume, afs_uint32 vnode, afs_uint32 unique)
+{
+    fidp->cell = cell;
+    fidp->volume = volume;
+    fidp->vnode = vnode;
+    fidp->unique = unique;
+    fidp->hash = ((cell & 0xF) << 28) | ((volume & 0x3F) << 22) | ((vnode & 0x7FF) << 11) | (unique & 0x7FF);
+}
+
+cm_scache_t *cm_FindSCache(cm_fid_t *fidp)
+{
+    return NULL;
+}
+
+void cm_ReleaseSCache(cm_scache_t *scp)
+{
+}
+
+
+long cm_ApplyDir(cm_scache_t *scp, cm_DirFuncp_t funcp, void *parmp,
+                 osi_hyper_t *startOffsetp, cm_user_t *userp, cm_req_t *reqp,
+                 cm_scache_t **retscp)
+{
+    return 0;
+}
+
+void
+afsi_log(char *pattern, ...)
+{
+    char s[256], t[100], d[100], u[512];
+    va_list ap;
+    va_start(ap, pattern);
+
+    StringCbVPrintfA(s, sizeof(s), pattern, ap);
+    GetTimeFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, t, sizeof(t));
+    GetDateFormat(LOCALE_SYSTEM_DEFAULT, 0, NULL, NULL, d, sizeof(d));
+    StringCbPrintfA(u, sizeof(u), "%s %s: %s\r\n", d, t, s);
+    printf("%s", u);
+}
+
+
+static int initialize_tests(void)
+{
+    osi_Init();
+    cm_InitNormalization();
+
+    if (!cm_InitBPlusDir()) {
+        TRACE1(L"Can't initialize BPlusDir\n");
+        return 1;
+    }
+
+    afsd_logp = osi_LogCreate("fakelog", 100);
+
+    return 0;
+}
+
+int n_succeeded = 0;
+int n_failed = 0;
+
+int n_subSucceeded = 0;
+int n_subFailed = 0;
+
+static int runtest(wchar_t * testname, int (*f)(void))
+{
+    int rv = 0;
+
+    n_subSucceeded = 0;
+    n_subFailed = 0;
+
+    TRACE1(L"Begin test %s\n", testname);
+    f();
+    TRACE1(L"End test %s\n", testname);
+    TRACE1(L"Subtests Succeeded %d, Failed %d\n", n_subSucceeded, n_subFailed);
+
+    if (n_subFailed)
+        n_failed++;
+    else
+        n_succeeded++;
+
+    return rv;
+}
+
+#define RUNTEST(f) runtest(_L(#f), f)
+
+#define IS_NOT_NULL(v) (((v) != NULL)? n_subSucceeded++: (TRACE1(L"Failed %s\n", _L(#v)), n_subFailed++))
+#define IS(e) ((e)? n_subSucceeded++ : (TRACE1(L"Failed %s\n", _L(#e)), n_subFailed++))
+#define CHECK_IF(e) do { if (e) { n_subSucceeded++; } else { TRACE1(L"Failed %s\n", _L(#e)); n_subFailed++; return 1; }} while (0)
+
+/**************************************************************/
+/* Actual tests */
+
+struct strings {
+    const fschar_t * str;
+    const clientchar_t * lookup;
+    int rc;
+};
+
+struct strings simple[] = {
+    {"abc", L"ABC", CM_ERROR_INEXACT_MATCH},
+    {"A", L"A", 0},
+    {".", L".", 0},
+    {"567", L"567", 0},
+    {"b", L"B", CM_ERROR_INEXACT_MATCH},
+    {"d", L"D", CM_ERROR_INEXACT_MATCH},
+    {"àáâ", L"\x00c0\x00c1\x00c2", CM_ERROR_INEXACT_MATCH},
+    {"Ŷ", L"\x0177", CM_ERROR_INEXACT_MATCH},
+    {"a\xef\xac\xb4",L"a\xfb34",0},
+    {"b\xd7\x94\xd6\xbc",L"b\xfb34",0},
+    {"c\xef\xac\xb4",L"c\x05d4\x05bc",0},
+    {"d\xd7\x94\xd6\xbc",L"d\x05d4\x05bc",0},
+};
+
+void init_scache(cm_scache_t * scp, cm_fid_t * fidp)
+{
+    memset(scp, 0, sizeof(cm_scache_t));
+    scp->magic = CM_SCACHE_MAGIC;
+    lock_InitializeRWLock(&scp->rw, "cm_scache_t rw");
+    lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock");
+    lock_InitializeRWLock(&scp->dirlock, "cm_scache_t dirlock");
+    scp->serverLock = -1;
+    scp->fid = *fidp;
+    scp->refCount = 1;
+}
+
+int simple_test(void)
+{
+    Tree * t;
+    int i;
+
+    t = initBtree(64, MAX_FANOUT, cm_BPlusCompareNormalizedKeys);
+    CHECK_IF(t != NULL);
+
+    for (i=0; i < lengthof(simple); i++) {
+        normchar_t * norm;
+        keyT key;
+        dataT data;
+
+        norm = cm_FsStringToNormStringAlloc(simple[i].str, -1, NULL);
+        CHECK_IF(norm != NULL);
+
+        key.name = norm;
+
+        data.cname = cm_FsStringToClientStringAlloc(simple[i].str, -1, NULL);
+        data.fsname = cm_FsStrDup(simple[i].str);
+        data.shortform = FALSE;
+        cm_SetFid(&data.fid, 1, 2, i, 4);
+
+        insert(t, key, data);
+
+        if (!cm_Is8Dot3(data.cname)) {
+            wchar_t wshortName[13];
+            cm_dirFid_t dfid;
+
+            dfid.vnode = i;
+            dfid.unique = 0;
+
+            cm_Gen8Dot3NameIntW(data.cname, &dfid, wshortName, NULL);
+
+            key.name = wshortName;
+            data.cname = cm_FsStringToClientStringAlloc(simple[i].str, -1, NULL);
+            data.fsname = cm_FsStrDup(simple[i].str);
+            data.shortform = TRUE;
+
+            insert(t, key, data);
+        }
+
+        free(norm);
+    }
+
+    for (i=0; i < lengthof(simple); i++) {
+        int rc = EINVAL;
+        normchar_t * entry = NULL;
+        keyT key = {NULL};
+        Nptr leafNode = NONODE;
+        cm_fid_t fid;
+        cm_fid_t * cfid = &fid;
+
+        TRACE1(L"Test row %d\n", i);
+
+        entry = cm_ClientStringToNormStringAlloc(simple[i].lookup, -1, NULL);
+        key.name = entry;
+
+        leafNode = bplus_Lookup(t, key);
+        if (leafNode != NONODE) {
+            int         slot;
+            Nptr        firstDataNode, dataNode, nextDataNode;
+            int         exact = 0;
+            int         count = 0;
+
+            slot = getSlot(t, leafNode);
+            if (slot <= BTERROR) {
+                rc = (slot == BTERROR ? EINVAL : ENOENT);
+                goto done;
+            }
+            firstDataNode = getnode(leafNode, slot);
+
+            for ( dataNode = firstDataNode; dataNode; dataNode = nextDataNode) {
+                count++;
+                if (!comparekeys(t)(key, getdatakey(dataNode), EXACT_MATCH) ) {
+                    exact = 1;
+                    break;
+                }
+                nextDataNode = getdatanext(dataNode);
+            }
+
+            if (exact) {
+                *cfid = getdatavalue(dataNode).fid;
+                rc = 0;
+            } else if (count == 1) {
+                *cfid = getdatavalue(firstDataNode).fid;
+                rc = CM_ERROR_INEXACT_MATCH;
+            } else {
+                rc = CM_ERROR_AMBIGUOUS_FILENAME;
+            } 
+        } else {
+            rc = ENOENT;
+        }
+
+    done:
+        if (entry)
+            free(entry);
+
+        IS(rc == simple[i].rc);
+        if (rc == simple[i].rc)
+            IS(fid.vnode == i);
+    }
+}
+
+
+int wmain(int argc, wchar_t ** argv)
+{
+    TRACE1(L"\n\nRunning BPLUS tests...\n\n");
+    if (initialize_tests())
+        return 1;
+
+    RUNTEST(simple_test);
+
+    TRACE1(L"\nDone\n");
+    TRACE1(L"# of test Succeeded: %d\n", n_succeeded);
+    TRACE1(L"# of test Failed: %d\n", n_failed);
+
+    return 0;
+}
diff --git a/src/WINNT/afsd/test/convtest.c b/src/WINNT/afsd/test/convtest.c
new file mode 100644 (file)
index 0000000..f30f061
--- /dev/null
@@ -0,0 +1,339 @@
+#include<stdio.h>
+#include<wchar.h>
+#include "..\cm_nls.h"
+
+#define elements_in(a) (sizeof(a)/sizeof(a[0]))
+
+struct norm_pair {
+    const cm_unichar_t * left;
+    const cm_normchar_t * right;
+};
+
+struct norm_pair normalization_pairs[] = {
+    { L"abcdefghijklmnopq", L"abcdefghijklmnopq" },
+    { L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234",
+
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234"
+      L"abcdefghijklmnopqrstuvwxyz1234" },
+    { L"12839481flalfoo_)()(*&#@(*&",
+      L"12839481flalfoo_)()(*&#@(*&" }
+};
+
+void dumputf8(const unsigned char * s) {
+    while (*s) {
+        printf("%02X ", (int) *s++);
+    }
+}
+
+void dumpunicode(const wchar_t * s) {
+    while (*s) {
+        printf("%04X ", (int) *s++);
+    }
+}
+
+int cm_NormalizeStringAllocTest(void)
+{
+    int i;
+
+    for (i=0; i < elements_in(normalization_pairs); i++) {
+        cm_normchar_t * nstr;
+        int cchdest = 0;
+
+        printf ("Test #%d:", i);
+
+        nstr = cm_NormalizeStringAlloc(normalization_pairs[i].left, -1, &cchdest);
+
+        if (nstr == NULL) {
+            printf ("FAILED! returned a NULL\n");
+            return 1;
+        }
+
+        if (wcscmp(nstr, normalization_pairs[i].right)) {
+            printf ("FAILED: Expected [");
+            dumpunicode(normalization_pairs[i].right);
+            printf ("] Received [");
+            dumpunicode(nstr);
+            printf ("]\n");
+            return 1;
+        }
+
+        if (wcslen(nstr) != cchdest - 1) {
+            printf ("FAILED: Length is wrong\n");
+            return 1;
+        }
+
+        printf ("PASS\n");
+
+        free (nstr);
+    }
+
+    return 0;
+}
+
+typedef struct norm_test_entry {
+    const wchar_t * str;
+    const wchar_t * nfc;
+    const wchar_t * nfd;
+    const wchar_t * nfkc;
+    const wchar_t * nfkd;
+} norm_test_entry;
+
+extern norm_test_entry norm_tests[];
+extern int n_norm_tests;
+
+int cm_NormalizeStringTest(void)
+{
+    int i;
+    int n_failed = 0;
+
+    for (i=0; i < n_norm_tests; i++) {
+        cm_normchar_t * nfc;
+
+        nfc = cm_NormalizeStringAlloc(norm_tests[i].nfd, -1, NULL);
+        if (nfc == NULL) {
+            printf ("FAILED: returned a NULL\n");
+            return 1;
+        }
+
+        if (wcscmp(nfc, norm_tests[i].nfc)) {
+            printf ("FAILED: Expected [");
+            dumpunicode(norm_tests[i].nfc);
+            printf ("] Received [");
+            dumpunicode(nfc);
+            printf ("]\n");
+            n_failed ++;
+        }
+
+        free(nfc);
+    }
+
+    if (n_failed)
+        printf ("Number of failed tests: %d\n", n_failed);
+
+    return 0;
+}
+
+typedef struct conv_test_entry {
+    const cm_utf8char_t * str;
+    const cm_unichar_t  * wstr;
+} conv_test_entry;
+
+#define CTEST(a) { a, L ## a }
+
+conv_test_entry conv_tests[] = {
+    CTEST(""),
+    CTEST("a"),
+    CTEST("abcdefghijkl"),
+    CTEST("osidfja*(2312835"),
+    {"\xee\x80\x80", L"\xe000"},
+    {"\xef\xbf\xbd", L"\xfffd"},
+    {"\xf0\x9f\xbf\xbf", L"\xd83f\xdfff"}, /* Surrogates */
+    {"\xF1\x9F\xBF\xBE", L"\xD93F\xDFFE"},
+    {"\xf0\x90\x80\x80", L"\xd800\xdc00"},
+};
+
+int cm_Utf16ToUtf8AllocTest(void)
+{
+    int i;
+
+    for (i=0; i < sizeof(conv_tests)/sizeof(conv_tests[0]); i++) {
+        cm_utf8char_t * c;
+        int len = 0;
+
+        printf ("Test #%d:", i);
+
+        c = cm_Utf16ToUtf8Alloc(conv_tests[i].wstr, -1, &len);
+
+        if (c == NULL) {
+            printf ("FAILED: returned NULL\n");
+            return 1;
+        }
+
+        if (strlen(c) + 1 != len) {
+            printf ("FAILED: Returned wrong length [%d]. Actual length [%d]\n", len,
+                    strlen(c) + 1);
+            return 1;
+        }
+
+        if (strcmp(c, conv_tests[i].str)) {
+            printf ("FAILED: Expected [");
+            dumputf8(conv_tests[i].str);
+            printf ("]. Returned [");
+            dumputf8(c);
+            printf ("]\n");
+            return 1;
+        }
+
+        printf("PASS\n");
+
+        free(c);
+    }
+
+    return 0;
+}
+
+int cm_Utf16ToUtf8Test(void)
+{
+    int i;
+    cm_utf8char_t c[1024];
+
+    for (i=0; i < sizeof(conv_tests)/sizeof(conv_tests[0]); i++) {
+        int len;
+
+        printf ("Test #%d:", i);
+
+        len = cm_Utf16ToUtf8(conv_tests[i].wstr, -1, c, sizeof(c)/sizeof(c[0]));
+
+        if (len == 0) {
+            printf ("FAILED: returned 0\n");
+            return 1;
+        }
+
+        if (strlen(c) + 1 != len) {
+            printf ("FAILED: Returned wrong length [%d]. Actual length [%d]\n", len,
+                    strlen(c) + 1);
+            return 1;
+        }
+
+        if (strcmp(c, conv_tests[i].str)) {
+            printf ("FAILED: Expected [%s]. Returned [%s]\n", conv_tests[i].str, c);
+            return 1;
+        }
+
+        printf("PASS\n");
+    }
+
+    return 0;
+}
+
+int cm_Utf8ToUtf16AllocTest(void)
+{
+    int i;
+
+    for (i=0; i < sizeof(conv_tests)/sizeof(conv_tests[0]); i++) {
+        cm_unichar_t * c;
+        int len = 0;
+
+        printf ("Test #%d:", i);
+
+        c = cm_Utf8ToUtf16Alloc(conv_tests[i].str, -1, &len);
+
+        if (c == NULL) {
+            printf ("FAILED: returned NULL\n");
+            return 1;
+        }
+
+        if (wcslen(c) + 1 != len) {
+            printf ("FAILED: Returned wrong length [%d]. Actual length [%d]\n", len,
+                    wcslen(c) + 1);
+            return 1;
+        }
+
+        if (wcscmp(c, conv_tests[i].wstr)) {
+            printf ("FAILED: Expected [");
+            dumpunicode(conv_tests[i].wstr);
+            printf ("]. Returned [");
+            dumpunicode(c);
+            printf ("]\n");
+            return 1;
+        }
+
+        printf("PASS\n");
+
+        free(c);
+    }
+
+    return 0;
+}
+
+int cm_Utf8ToUtf16Test(void)
+{
+    int i;
+    cm_unichar_t c[1024];
+
+    for (i=0; i < sizeof(conv_tests)/sizeof(conv_tests[0]); i++) {
+        int len = 0;
+
+        printf ("Test #%d:", i);
+
+        len = cm_Utf8ToUtf16(conv_tests[i].str, -1, c, sizeof(c)/sizeof(c[0]));
+
+        if (len == 0) {
+            printf ("FAILED: returned 0\n");
+            return 1;
+        }
+
+        if (wcslen(c) + 1 != len) {
+            printf ("FAILED: Returned wrong length [%d]. Actual length [%d]\n", len,
+                    wcslen(c) + 1);
+            return 1;
+        }
+
+        if (wcscmp(c, conv_tests[i].wstr)) {
+            printf ("FAILED: Expected [");
+            dumpunicode(conv_tests[i].wstr);
+            printf ("]. Returned [");
+            dumpunicode(c);
+            printf ("]\n");
+            return 1;
+        }
+
+        printf("PASS\n");
+    }
+
+    return 0;
+}
+
+int main(int argc, char ** argv)
+{
+    int trv;
+
+    cm_InitNormalization();
+
+#define RUNTEST(f) printf("Begin " #f "\n"); trv = f(); printf ("End " #f "\n\n"); if (trv != 0) return trv;
+
+    RUNTEST(cm_NormalizeStringAllocTest);
+    RUNTEST(cm_NormalizeStringTest);
+    RUNTEST(cm_Utf16ToUtf8AllocTest);
+    RUNTEST(cm_Utf16ToUtf8Test);
+    RUNTEST(cm_Utf8ToUtf16AllocTest);
+    RUNTEST(cm_Utf8ToUtf16Test);
+    return 0;
+}
diff --git a/src/WINNT/afsd/test/stricmptest.c b/src/WINNT/afsd/test/stricmptest.c
new file mode 100644 (file)
index 0000000..1f13d79
--- /dev/null
@@ -0,0 +1,102 @@
+#include<windows.h>
+#include<wchar.h>
+#include<strsafe.h>
+#include "..\cm_nls.h"
+
+typedef struct wtest_pair {
+    const wchar_t * str1;
+    const wchar_t * str2;
+    int comparison_result;
+} wtest_pair;
+
+wtest_pair wtest_pairs[] = {
+    { L"abc", L"aBc", 0 },
+    { L"Abc", L"Acb", -1 },
+    { L"", L"", 0 },
+    { L"", L"", 0 },
+    { L"", L"", 0 },
+    { L"", L"", 0 },
+    { L"", L"", 0 },
+    { L"", L"", 0 },
+};
+
+typedef struct utf8test_pair {
+    const char * str1;
+    const char * str2;
+    int comparison_result;
+} utf8test_pair;
+
+utf8test_pair utf8test_pairs[] = {
+    {"abc", "abc", 0},
+    {"abc", "AbC", 0},
+    {"abc", "ABC", 0},
+    {"ÆOn", "æoN", 0},
+    {"Ǽaaa", "ǽaaa", 0},
+    {"Ằ  ", "ằ  ", 0},
+    {"Ĺ378", "ĺ378", 0},
+    {"Abc", "Acb", -1},
+    {"ǼaEa", "ǽaaa", 1},
+    {"ùÒz±", "ÙòZ±", 0},
+    {"ÀÁÂÃÄÅÆÇÈÉÊË", "àáâãäåæçèéêë", 0},
+    {"", "", 0},
+    {"", "", 0},
+};
+
+int wmain(int argc, wchar_t ** argv)
+{
+
+    int i;
+
+    printf("Starting test--\n");
+    for (i=0; i<sizeof(utf8test_pairs)/sizeof(utf8test_pairs[0]); i++) {
+        printf("Comparing [%s] and [%s]:", utf8test_pairs[i].str1, utf8test_pairs[i].str2);
+        printf("strcmp=%d, stricmp=%d, cm_stricmp_utf=%d, expected=%d\n",
+               strcmp(utf8test_pairs[i].str1, utf8test_pairs[i].str2),
+               stricmp(utf8test_pairs[i].str1, utf8test_pairs[i].str2),
+               cm_stricmp_utf8(utf8test_pairs[i].str1, utf8test_pairs[i].str2),
+               utf8test_pairs[i].comparison_result);
+    }
+    printf("End of test\n");
+
+    printf("String navigation test\n");
+    {
+        char * str="abcdefghijklДڰ١╚☼ﮓﮚﻂﺧﱞ⅔";
+        /*                    1111111111222*/
+        /*          01234567890123456789012 */
+        char * strend;
+        char * p;
+        int i;
+
+        strend = str + strlen(str);
+
+        printf ("Forward direction:\n");
+
+        for (i=0, p=str; *p && p <= strend; p = char_next_utf8(p)) {
+            printf ("Char %d at offset %d\n", i++, p-str);
+        }
+
+        printf ("Reverse direction:\n");
+
+        for (i=23,p=strend; p >= str; p = char_prev_utf8(p)) {
+            printf ("Char %d at offset %d\n", i--, p-str);
+        }
+
+    }
+    printf("End of test\n");
+
+    printf("Strupr test\n");
+    for (i=0; i<sizeof(utf8test_pairs)/sizeof(utf8test_pairs[0]); i++) {
+        char tbuf[MAX_PATH];
+
+        strcpy(tbuf, utf8test_pairs[i].str1);
+        strupr_utf8(tbuf, sizeof(tbuf));
+        printf("Original [%s]->[%s]", utf8test_pairs[i].str1, tbuf);
+
+        strcpy(tbuf, utf8test_pairs[i].str2);
+        strupr_utf8(tbuf, sizeof(tbuf));
+        printf(" [%s]->[%s]\n", utf8test_pairs[i].str2, tbuf);
+    }
+    printf("End of test\n");
+
+    return 0;
+}