spiegel-keyman/core/tests/unit/ldml/transforms.tests.cpp

1288 lines
49 KiB
C++

#include "../../../src/ldml/ldml_markers.hpp"
#include "../../../src/ldml/ldml_transforms.hpp"
#include "../../../src/util_regex.hpp"
#include "kmx/kmx_plus.h"
#include "kmx/kmx_xstring.h"
#include "test_color.h"
#include <iostream>
#include <string>
#include <test_assert.h>
#include "../../../src/util_regex.hpp"
// TODO-LDML: normal asserts wern't working, so using some hacks.
// #include "ldml_test_utils.hpp"
// #include <test_assert.h>
// #include "debuglog.h"
#ifndef zassert_string_equal
#define zassert_string_equal(actual, expected) \
{ \
if (actual != expected) { \
std::wcerr << __FILE__ << ":" << __LINE__ << ": " << console_color::fg(console_color::BRIGHT_RED) << "got: " << actual \
<< " " << km::core::kmx::Debug_UnicodeString(actual, 0) << " expected " << expected << " " \
<< km::core::kmx::Debug_UnicodeString(expected, 1) << console_color::reset() << std::endl; \
return EXIT_FAILURE; \
} \
}
#endif
#ifndef zassert_equal
#define zassert_equal(actual, expected) \
{ \
if (actual != expected) { \
std::wcerr << __FILE__ << ":" << __LINE__ << ": " << console_color::fg(console_color::BRIGHT_RED) << "got: " << actual \
<< " expected " << expected << console_color::reset() << std::endl; \
return EXIT_FAILURE; \
} \
}
#endif
// needed for streaming operators
#include "utfcodec.hpp"
using namespace km::core::ldml;
using namespace km::core::kmx;
void
prepend_hex_oct(std::u32string &str, char32_t x) {
for (auto i = 0; i < 8; i++) {
KMX_DWORD remainder = x & 0xF; // get the last nibble
const char32_t ch = remainder < 0xA ? U'0' + remainder : U'A' + (remainder - 0xA);
str.insert(0, 1, ch); // prepend
x >>= 4;
}
}
std::u32string
marker_map_to_string(const marker_map &m) {
std::u32string s;
for (auto i = m.rbegin(); i < m.rend(); i++) {
if (i->end) {
s.insert(0, U"<END>");
}
if (i->processed) {
s.insert(0, U"<PROCESSED?>");
}
if (i->ch == MARKER_BEFORE_EOT) {
s.insert(0, U"<EOT>");
} else {
prepend_hex_oct(s, i->ch);
s.insert(0, U"=U+");
}
if (i->marker != LDML_MARKER_NO_INDEX) {
prepend_hex_quad(s, i->marker);
s.insert(0, U" \\m0x");
}
}
return s;
}
bool
_assert_marker_map_equal(const char *f, int l, const marker_map orig, const marker_map x) {
marker_map a;
// copy everything but 'end' entries
std::copy_if(
orig.begin(), orig.end(), std::back_inserter(a), [](const marker_entry &m) { return m.marker != LDML_MARKER_NO_INDEX; });
// now check equality
if (a == x) {
return true;
}
// Not equal. Print out why.
std::wcerr << f << ":" << l << ": " << console_color::fg(console_color::BRIGHT_RED);
std::wcerr << "got: " << marker_map_to_string(a);
std::wcerr << " expected: " << marker_map_to_string(x);
std::wcerr << console_color::reset() << std::endl;
return false;
}
#define assert_marker_map_equal(actual, expected) \
if (!_assert_marker_map_equal(__FILE__, __LINE__, (actual), (expected))) \
return EXIT_FAILURE;
// using km::core::kmx::u16cmp;
int
test_transforms() {
std::cout << "== " << __FUNCTION__ << std::endl;
std::cout << __FILE__ << ":" << __LINE__ << " - basic " << std::endl;
{
// start with one
transform_entry te(std::u32string(U"e\\^"), std::u32string(U"E")); // keep it simple
// OK now make a group do it
transforms tr(false);
transform_group st;
st.push_back(te);
tr.addGroup(st);
// see if we can match the same
{
std::u32string src(U"barQ^");
bool res = tr.apply(src);
zassert_equal(res, false);
zassert_string_equal(src, std::u32string(U"barQ^")); // no change
}
{
std::u32string src(U"fooe^");
bool res = tr.apply(src);
zassert_equal(res, true);
zassert_string_equal(src, std::u32string(U"fooE"));
}
}
std::cout << __FILE__ << ":" << __LINE__ << " - more complex " << std::endl;
{
transforms tr(false);
// setup
{
transform_group st;
st.emplace_back(std::u32string(U"za"), std::u32string(U"c"));
st.emplace_back(std::u32string(U"a"), std::u32string(U"bb"));
tr.addGroup(st);
}
{
transform_group st;
st.emplace_back(std::u32string(U"bb"), std::u32string(U"ccc"));
tr.addGroup(st);
}
{
transform_group st;
st.emplace_back(std::u32string(U"cc"), std::u32string(U"d"));
tr.addGroup(st);
}
{
transform_group st;
st.emplace_back(std::u32string(U"tcd"), std::u32string(U"e"));
tr.addGroup(st);
}
// now test
// see if we can match the same
{
std::u32string src(U"ta");
bool res = tr.apply(src);
// pipe (|) symbol shows where the 'output' is delineated
// t|a --> t|bb --> t|ccc --> t|cd --> |e
zassert_string_equal(src, std::u32string(U"e"));
zassert_equal(res, true);
}
{
std::u32string src(U"qza");
bool res = tr.apply(src);
// pipe (|) symbol shows where the 'output' is delineated
// q|za -> q|c
zassert_string_equal(src, std::u32string(U"qc"));
zassert_equal(res, true);
}
{
std::u32string src(U"qa");
bool res = tr.apply(src);
zassert_string_equal(src, std::u32string(U"qcd"));
zassert_equal(res, true);
}
{
std::u32string src(U"tb");
bool res = tr.apply(src);
zassert_string_equal(src, std::u32string(U"tb"));
zassert_equal(res, false);
}
}
std::cout << __FILE__ << ":" << __LINE__ << " - hindi example " << std::endl;
{
transforms tr(false);
{
transform_group st;
st.emplace_back(std::u32string(U"िह"), std::u32string(U"हि"));
tr.addGroup(st);
}
{
std::u32string src(U"िह");
bool res = tr.apply(src);
zassert_string_equal(src, std::u32string(U"हि"));
zassert_equal(res, true);
}
}
return EXIT_SUCCESS;
}
int
test_reorder_standalone() {
std::cout << "== " << __FUNCTION__ << std::endl;
std::cout << __FILE__ << ":" << __LINE__ << " - element API test " << std::endl;
// element API test - not a real element, just here for testing
{
element es(U'a', 0xF4500000 | LDML_ELEM_FLAGS_PREBASE | LDML_ELEM_FLAGS_TERTIARY_BASE); // tertiary -12, primary 80
std::cout << "es flags" << std::hex << es.get_flags() << std::dec << std::endl;
// verify element metadata
test_assert_equal(es.is_uset(), false);
test_assert_equal(es.get_order(), 0x50);
test_assert_equal(es.get_tertiary(), -12);
test_assert_equal(es.is_prebase(), true);
test_assert_equal(es.is_tertiary_base(), true);
// verify element matching
test_assert_equal(es.matches(U'a'), true);
test_assert_equal(es.matches(U'b'), false);
}
std::cout << __FILE__ << ":" << __LINE__ << " - nod-Lana " << std::endl;
{
const std::u32string roasts[] = {
// from the spec
U"\u1A21\u1A60\u1A45\u1A6B\u1A76", // 'ideal'
U"\u1A21\u1A6B\u1A76\u1A60\u1A45", // vowel first
U"\u1A21\u1A6B\u1A60\u1A76\u1A45", // vowel first, NFC
U"\u1A21\u1A6B\u1A60\u1A45\u1A76", // tone after lower
};
/** we expect this is what comes out the other side */
const std::u32string expect = roasts[0];
// now setup the rules
const COMP_KMXPLUS_USET_RANGE ranges[] = {// 0
COMP_KMXPLUS_USET_RANGE(0x1A75, 0x1A79)};
const COMP_KMXPLUS_USET_USET usets[] = {{0, 1, 0xFFFFFFFF}};
const COMP_KMXPLUS_USET_USET &toneMarksUset = usets[0];
const SimpleUSet toneMarks(&ranges[toneMarksUset.range], toneMarksUset.count);
// validate that the range [1A75, 1A79] matches
test_assert_equal(toneMarks.contains(0x1A76), true);
test_assert_equal(toneMarks.contains(0x1A60), false);
std::cout << __FILE__ << ":" << __LINE__ << " - element API test " << std::endl;
// element test
{
element es(U'a', (80 << LDML_ELEM_FLAGS_ORDER_BITSHIFT) | LDML_ELEM_FLAGS_PREBASE); // tertiary -12, primary 80
std::cout << "es flags" << std::hex << es.get_flags() << std::dec << std::endl;
// verify element metadata
test_assert_equal(es.is_uset(), false);
test_assert_equal(es.get_order(), 0x50);
test_assert_equal(es.get_tertiary(), 0);
test_assert_equal(es.is_prebase(), true);
test_assert_equal(es.is_tertiary_base(), false);
// verify element matching
test_assert_equal(es.matches(U'a'), true);
test_assert_equal(es.matches(U'b'), false);
element eu(toneMarks, 0x37F40000);
// element metadata
std::cout << "eu flags" << std::hex << eu.get_flags() << std::dec << std::endl;
test_assert_equal(eu.is_uset(), true);
std::cout << "order" << (int)eu.get_order() << std::endl;
test_assert_equal(eu.get_order(), -12);
test_assert_equal(eu.get_tertiary(), 55);
test_assert_equal(eu.is_prebase(), false);
test_assert_equal(eu.is_tertiary_base(), false);
// element matching
test_assert_equal(eu.matches(U'a'), false);
test_assert_equal(eu.matches(U'\u1A76'), true);
test_assert_equal(eu.matches(U'\u1A75'), true);
element_list l; // '[tones]a'
l.emplace_back(es);
l.emplace_back(eu);
std::cout << __FILE__ << ":" << __LINE__ << " - list test " << std::endl;
test_assert_equal(l.match_end(U"asdfasdf"), 0); // no match
test_assert_equal(l.match_end(U"a"), 0); // partial substring, fastpath because it's short
test_assert_equal(l.match_end(U"\u1A76"), 0); // partial substring, fastpath because it's short
test_assert_equal(l.match_end(U"a\u1A76"), 2); // Match
test_assert_equal(l.match_end(U"a\u1A75"), 2); // Match
test_assert_equal(l.match_end(U"SomethingSomethingSomethinga\u1A76"), 2); // Sub-Match
// generate sort keys
std::cout << __FILE__ << ":" << __LINE__ << " - get_sort_key test " << std::endl;
std::u32string str = U"a\u1A78";
// get the baseline sortkey
auto keylist = reorder_sort_key::from(str);
std::cout << __FILE__ << ":" << __LINE__ << " baseline sortkey" << std::endl;
for (auto i = keylist.begin(); i < keylist.end(); i++) {
i->dump();
}
// make sure it matches
test_assert_equal(l.match_end(str), 2);
// update the keylist with these elements.
l.update_sort_key(0, keylist);
std::cout << __FILE__ << ":" << __LINE__ << " updated sortkey" << std::endl;
test_assert_equal(keylist.size(), 2);
reorder_weight secondary = 0;
for (auto i = keylist.begin(); i < keylist.end(); i++) {
i->dump();
test_assert_equal(i->secondary, secondary);
test_assert_equal(i->quaternary, secondary);
secondary++;
}
std::cout << std::endl;
// spot check first sortkey
test_assert_equal(keylist.begin()->primary, 80);
test_assert_equal(keylist.begin()->tertiary, 0);
test_assert_equal(keylist.begin()->ch, 0x61);
std::cout << __FILE__ << ":" << __LINE__ << " sorted sortkey" << std::endl;
// now sort them
std::sort(keylist.begin(), keylist.end());
for (auto i = keylist.begin(); i < keylist.end(); i++) {
i->dump();
}
std::cout << std::endl;
// spot check first sort key
test_assert_equal(keylist.begin()->primary, -12);
test_assert_equal(keylist.begin()->tertiary, 55);
test_assert_equal(keylist.begin()->ch, 0x1A78);
}
std::cout << __FILE__ << ":" << __LINE__ << " - key test " << std::endl;
{
// can we sort an array of reorder sort keys?
reorder_sort_key keys0[] = {
{U'\u1A21', 0, 0, 0, 0},
{U'\u1A6B', 42, 1, 0, 1},
{U'\u1A76', 55, 2, 0, 2},
{U'\u1A60', 10, 3, 0, 3},
{U'\u1A45', 10, 4, 0, 3}};
// add it to a list
std::deque<reorder_sort_key> keylist;
for (size_t i = 0; i < sizeof(keys0) / sizeof(keys0[0]); i++) {
keylist.emplace_back(keys0[i]);
// print it out
keys0[i].dump();
}
// now sort it
std::cout << __FILE__ << ":" << __LINE__ << " sort" << std::endl;
std::sort(keylist.begin(), keylist.end());
std::u32string sorted;
for (auto i = keylist.begin(); i < keylist.end(); i++) {
i->dump();
sorted.append(1, i->ch);
}
// did the roast come out?
zassert_string_equal(sorted, expect);
}
std::cout << "now prepare the reorder elements" << std::endl;
transforms tr(false);
{
reorder_group rg;
// <reorder from="\u1A60" order="127" />
element_list e0;
e0.emplace_back(U'\u1A60', 127 << LDML_ELEM_FLAGS_ORDER_BITSHIFT);
rg.list.emplace_back(e0);
// <reorder from="\u1A6B" order="42" />
element_list e1;
e1.emplace_back(U'\u1A6B', 42 << LDML_ELEM_FLAGS_ORDER_BITSHIFT);
rg.list.emplace_back(e1);
// <reorder from="[\u1A75-\u1A79]" order="55" />
element_list e2;
e2.emplace_back(toneMarks, 55 << LDML_ELEM_FLAGS_ORDER_BITSHIFT);
rg.list.emplace_back(e2);
// <reorder before="\u1A6B" from="\u1A60\u1A45" order="10" />
element_list e3;
e3.emplace_back(U'\u1A60', 10 << LDML_ELEM_FLAGS_ORDER_BITSHIFT);
e3.emplace_back(U'\u1A45', 10 << LDML_ELEM_FLAGS_ORDER_BITSHIFT);
element_list e3before;
e3before.emplace_back(U'\u1A6B', 0);
rg.list.emplace_back(e3, e3before);
// <reorder before="\u1A6B[\u1A75-\u1A79]" from="\u1A60\u1A45" order="10" />
element_list e4;
e4.emplace_back(U'\u1A60', 10 << LDML_ELEM_FLAGS_ORDER_BITSHIFT);
e4.emplace_back(U'\u1A45', 10 << LDML_ELEM_FLAGS_ORDER_BITSHIFT);
element_list e4before;
e4before.emplace_back(U'\u1A6B', 0);
e4before.emplace_back(toneMarks, 0);
rg.list.emplace_back(e4, e4before);
// <reorder before="\u1A6B" from="\u1A60[\u1A75-\u1A79]\u1A45" order="10 55 10" />
element_list e5;
e5.emplace_back(U'\u1A60', 10 << LDML_ELEM_FLAGS_ORDER_BITSHIFT);
e5.emplace_back(toneMarks, 55 << LDML_ELEM_FLAGS_ORDER_BITSHIFT);
e5.emplace_back(U'\u1A45', 10 << LDML_ELEM_FLAGS_ORDER_BITSHIFT);
element_list e5before;
e5before.emplace_back(U'\u1A6B', 0);
rg.list.emplace_back(e5, e5before);
tr.addGroup(rg);
}
// now actually test it
std::cout << __FILE__ << ":" << __LINE__ << " - back to nod-Lana " << std::endl;
// TODO-LDML: move this into test code perhaps
for (size_t r = 0; r < sizeof(roasts) / sizeof(roasts[0]); r++) {
const auto &roast = roasts[r];
std::cout << __FILE__ << ":" << __LINE__ << " - trying roast #" << r << "=" << roast << std::endl;
// try apply with string
{
std::cout << "- try apply(text, output)" << std::endl;
std::u32string text = roast;
std::u32string output;
size_t len = tr.apply(text, output);
if (len == 0) {
std::cout << " (did not apply)" << std::endl;
} else {
std::cout << " applied, matchLen= " << len << std::endl;
text.resize(text.size() - len); // shrink
text.append(output);
std::cout << " = " << text << std::endl;
}
zassert_string_equal(text, expect);
}
// try all-at-once
{
std::cout << "- try apply(text)" << std::endl;
std::u32string text = roast;
if (!tr.apply(text)) {
std::cout << " (did not apply)" << std::endl;
} else if (text == roast) {
std::cout << " (suboptimal: apply returned true but made no change)" << std::endl;
} else {
std::cout << " changed to " << text;
}
zassert_string_equal(text, expect);
std::cout << " matched (converting all at once)!" << std::endl;
}
// simulate typing this one char at a time;
{
std::cout << "- try key-at-a-time" << std::endl;
std::u32string text;
for (auto ch = roast.begin(); ch < roast.end(); ch++) {
// append the string
text.append(1, *ch);
std::cout << "-: " << text << std::endl;
if (!tr.apply(text)) {
std::cout << " (did not apply)" << std::endl;
}
}
// now the moment of truth
zassert_string_equal(text, expect);
std::cout << " matched! (converting char at a time)" << std::endl;
std::cout << std::endl;
}
}
// special test
{
std::cout << __FILE__ << ":" << __LINE__ << " - special test " << std::endl;
const std::u32string expect = U"\u1A21\u1A60\u1A45"; // this string shouldn't mutate at all.
{
std::u32string text = expect;
tr.apply(text);
zassert_string_equal(text, expect);
}
{
// try submatch
std::u32string text = expect;
std::u32string output;
size_t len = tr.apply(text, output);
zassert_string_equal(output, U"");
test_assert_equal(len, 0);
}
}
}
return EXIT_SUCCESS;
}
// this test case is also in XML form under 'k_201_*'
int
test_reorder_esk() {
std::cout << "== " << __FUNCTION__ << std::endl;
std::cout << __FILE__ << ":" << __LINE__ << " - k_201_reorder_esk (tertiary reordering) " << std::endl;
{
// now setup the rules
// rules are a little bit simplified, having only the vowel 'a'
std::cout << "now prepare the reorder elements" << std::endl;
transforms tr(false);
{
reorder_group rg;
// <reorder from="a" order="0" tertiaryBase="true" />
{
element_list e;
e.emplace_back(U'a', (0 << LDML_ELEM_FLAGS_ORDER_BITSHIFT) | LDML_ELEM_FLAGS_TERTIARY_BASE);
rg.list.emplace_back(e);
}
// <reorder from="[\u{0332}]" tertiary="1" />
{
element_list e;
e.emplace_back(0x0332, (1 << LDML_ELEM_FLAGS_TERTIARY_BITSHIFT));
rg.list.emplace_back(e);
}
// <reorder from="[\u{0305}\u{0302}]" tertiary="2" />
{
element_list e;
e.emplace_back(0x305, (2 << LDML_ELEM_FLAGS_TERTIARY_BITSHIFT));
// (should be a unicodeset, but for simplicity we're dropping the U+302)
// e.emplace_back(0x302, (2 << LDML_ELEM_FLAGS_TERTIARY_BITSHIFT));
rg.list.emplace_back(e);
}
// <reorder from="x" order="1" />
{
element_list e;
e.emplace_back(U'x', (1 << LDML_ELEM_FLAGS_ORDER_BITSHIFT));
rg.list.emplace_back(e);
}
// <reorder from="y" order="2" />
{
element_list e;
e.emplace_back(U'y', (2 << LDML_ELEM_FLAGS_ORDER_BITSHIFT));
rg.list.emplace_back(e);
}
// <reorder from="z" order="3" />
{
element_list e;
e.emplace_back(U'z', (3 << LDML_ELEM_FLAGS_ORDER_BITSHIFT));
rg.list.emplace_back(e);
}
tr.addGroup(rg);
}
// now actually test it
std::cout << __FILE__ << ":" << __LINE__ << " - cases " << std::endl;
const std::u32string orig_expect[] = {
// 1short
U"ax\u0305", // orig
U"a\u0305x", // expect
// 2longer
U"az\u0305x\u0332", // orig
U"a\u0332\u0305xz", // expect
};
// TODO-LDML: move this into test code perhaps
for (size_t r = 0; r < sizeof(orig_expect) / sizeof(orig_expect[0]); r += 2) {
const auto &orig = orig_expect[r + 0];
const auto &expect = orig_expect[r + 1];
std::cout << __FILE__ << ":" << __LINE__ << " - trying str #" << r + 1 << "=" << orig << std::endl;
// try apply with string
{
std::cout << "- try apply(text, output)" << std::endl;
std::u32string text = orig;
std::u32string output;
size_t len = tr.apply(text, output);
if (len == 0) {
std::cout << " (did not apply)" << std::endl;
} else {
std::cout << " applied, matchLen= " << len << std::endl;
text.resize(text.size() - len); // shrink
text.append(output);
std::cout << " = " << text << std::endl;
}
zassert_string_equal(text, expect);
}
// try all-at-once
{
std::cout << "- try apply(text)" << std::endl;
std::u32string text = orig;
if (!tr.apply(text)) {
std::cout << " (did not apply)" << std::endl;
} else if (text == orig) {
std::cout << " (suboptimal: apply returned true but made no change)" << std::endl;
} else {
std::cout << " changed to " << text;
}
zassert_string_equal(text, expect);
std::cout << " matched (converting all at once)!" << std::endl;
}
// simulate typing this one char at a time;
{
std::cout << "- try key-at-a-time" << std::endl;
std::u32string text;
for (auto ch = orig.begin(); ch < orig.end(); ch++) {
// append the string
text.append(1, *ch);
std::cout << "-: " << text << std::endl;
if (!tr.apply(text)) {
std::cout << " (did not apply)" << std::endl;
}
}
// now the moment of truth
zassert_string_equal(text, expect);
std::cout << " matched! (converting char at a time)" << std::endl;
std::cout << std::endl;
}
}
}
return EXIT_SUCCESS;
}
int
test_map() {
std::cout << "== " << __FUNCTION__ << std::endl;
std::cout << __FILE__ << ":" << __LINE__ << " transform_entry::findIndex" << std::endl;
{
std::deque<std::u32string> list;
test_assert_equal(km::core::util::km_regex::findIndex(U"Does Not Exist", list), -1);
list.emplace_back(U"0th");
list.emplace_back(U"First");
list.emplace_back(U"Second");
test_assert_equal(km::core::util::km_regex::findIndex(U"First", list), 1);
test_assert_equal(km::core::util::km_regex::findIndex(U"0th", list), 0);
test_assert_equal(km::core::util::km_regex::findIndex(U"Second", list), 2);
test_assert_equal(km::core::util::km_regex::findIndex(U"Nowhere", list), -1);
}
return EXIT_SUCCESS;
}
int
test_strutils() {
std::cout << "== " << __FUNCTION__ << std::endl;
std::cout << __FILE__ << ":" << __LINE__ << " * remove_markers" << std::endl;
{
std::cout << __FILE__ << ":" << __LINE__ << " - basic test0" << std::endl;
const std::u32string src = U"abc";
const std::u32string dst = remove_markers(src);
zassert_string_equal(dst, src); // unchanged
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - basic test" << std::endl;
const std::u32string src = U"abc";
const std::u32string dst = remove_markers(src, map);
zassert_string_equal(dst, src); // unchanged
test_assert_equal(count_markers(map), 0);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - marker test" << std::endl;
const std::u32string src = U"6\U0000ffff\U00000008\U00000001e";
const std::u32string dst = remove_markers(src, map);
const std::u32string expect = U"6e";
zassert_string_equal(dst, expect);
marker_map expm = {{U'e', 0x1L}};
assert_marker_map_equal(map, expm); // marker 1 @ e
test_assert_equal(count_markers(map), 1);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - bad0" << std::endl;
const std::u32string src = U"6\U0000ffff\U00000008"; // missing trailing marker #
const std::u32string dst = remove_markers(src, map);
const std::u32string expect = src;
zassert_string_equal(dst, expect);
test_assert_equal(count_markers(map), 0);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - bad1" << std::endl;
const std::u32string src = U"6\U0000ffffq"; // missing sentinel subtype
const std::u32string dst = remove_markers(src, map);
const std::u32string expect = src; // 'q' removed
zassert_string_equal(dst, expect);
test_assert_equal(count_markers(map), 0);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - bad1b" << std::endl;
const std::u32string src = U"6\U0000ffff"; // missing code
const std::u32string dst = remove_markers(src, map);
const std::u32string expect = src;
zassert_string_equal(dst, expect);
test_assert_equal(count_markers(map), 0);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - bad1c" << std::endl;
const std::u32string src = U"6\U0000ffffzz"; // missing code
const std::u32string dst = remove_markers(src, map);
const std::u32string expect = src;
zassert_string_equal(dst, expect);
test_assert_equal(count_markers(map), 0);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - marker end test" << std::endl;
const std::u32string src = U"6\U0000ffff\U00000008\U00000001";
const std::u32string dst = remove_markers(src, map);
const std::u32string expect = U"6";
zassert_string_equal(dst, expect);
marker_map expm({{MARKER_BEFORE_EOT, 0x1L}});
assert_marker_map_equal(map, expm);
test_assert_equal(count_markers(map), 1);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - complex test" << std::endl;
const std::u32string src =
U"6\U0000ffff\U00000008\U00000001e\U0000ffff\U00000008\U00000002\U00000320\U0000ffff\U00000008\U00000003\U00000300"
U"\U0000ffff\U00000008\U00000004";
const std::u32string dst = remove_markers(src, map);
const std::u32string expect = U"6e\U00000320\U00000300";
zassert_string_equal(dst, expect);
marker_map expm({{U'e', 0x1L}, {0x0320, 0x2L}, {0x0300, 0x3L}, {MARKER_BEFORE_EOT, 0x4L}});
assert_marker_map_equal(map, expm);
test_assert_equal(count_markers(map), 4);
}
{
std::cout << __FILE__ << ":" << __LINE__ << " - prepend hex quad" << std::endl;
{
std::u32string dst;
prepend_hex_quad(dst, 0x0001);
zassert_string_equal(dst, U"0001");
}
{
std::u32string dst;
prepend_hex_quad(dst, 0xCAFE);
zassert_string_equal(dst, U"CAFE");
}
{
std::u32string dst;
prepend_hex_quad(dst, 0xFFFF);
zassert_string_equal(dst, U"FFFF");
}
}
{
std::cout << __FILE__ << ":" << __LINE__ << " - parse hex quad" << std::endl;
test_assert_equal(parse_hex_quad(U"0001"), 0x0001);
test_assert_equal(parse_hex_quad(U"CAFE"), 0xCAFE);
test_assert_equal(parse_hex_quad(U"D00d"), 0xD00D);
test_assert_equal(parse_hex_quad(U"FFFF"), 0xFFFF);
test_assert_equal(parse_hex_quad(U"zzzz"), 0); // err
}
return EXIT_SUCCESS;
}
int
test_normalize() {
std::cout << "== " << __FUNCTION__ << std::endl;
std::cout << __FILE__ << ":" << __LINE__ << " * normalize_nfd_markers" << std::endl;
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - noop test" << std::endl;
const std::u32string src = U"6e\U00000320\U00000300"; // already NFD
const std::u32string expect = src;
std::u32string dst = src;
test_assert(normalize_nfd_markers_segment(dst, map));
zassert_string_equal(dst, expect);
test_assert_equal(count_markers(map), 0);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - medium test" << std::endl;
const std::u32string src = U"6e\U00000300\U00000320"; // swapped
const std::u32string expect = U"6e\U00000320\U00000300"; // correct NFD
std::u32string dst = src;
test_assert(normalize_nfd_markers_segment(dst, map));
zassert_string_equal(dst, expect);
test_assert_equal(count_markers(map), 0);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - noop test w markers" << std::endl;
const std::u32string src =
U"6\U0000ffff\U00000008\U00000001e\U0000ffff\U00000008\U00000002\U00000320\U0000ffff\U00000008\U00000003\U00000300"
U"\U0000ffff\U00000008\U00000004";
const std::u32string expect = src;
std::u32string dst = src;
test_assert(normalize_nfd_markers_segment(dst, map));
zassert_string_equal(dst, expect);
marker_map expm({{U'e', 0x1L}, {0x320, 0x2L}, {0x300, 0x3L}, {MARKER_BEFORE_EOT, 0x4L}});
assert_marker_map_equal(map, expm);
test_assert_equal(count_markers(map), 4);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - complex test" << std::endl;
const std::u32string src = // already in order: 320+300
U"6\U0000ffff\U00000008\U00000001e\U0000ffff\U00000008\U00000002\U00000320\U0000ffff\U00000008\U00000003\U00000300"
U"\U0000ffff\U00000008\U00000004";
const std::u32string expect = src;
std::u32string dst = src;
test_assert(normalize_nfd_markers_segment(dst, map));
zassert_string_equal(dst, expect);
marker_map expm({{U'e', 0x1L}, {0x320, 0x2L}, {0x300, 0x3L}, {MARKER_BEFORE_EOT, 0x4L}});
assert_marker_map_equal(map, expm);
test_assert_equal(count_markers(map), 4);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - complex test2" << std::endl;
const std::u32string src = // out of order, 300-320
U"6\U0000ffff\U00000008\U00000001e\U0000ffff\U00000008\U00000002\U00000300\U0000ffff\U00000008\U00000003\U00000320"
U"\U0000ffff\U00000008\U00000004";
const std::u32string expect =
U"6\U0000ffff\U00000008\U00000001e\U0000ffff\U00000008\U00000003\U00000320\U0000ffff\U00000008\U00000002\U00000300"
U"\U0000ffff\U00000008\U00000004";
std::u32string dst = src;
test_assert(normalize_nfd_markers_segment(dst, map));
if (dst != expect) {
std::cout << "dst: " << Debug_UnicodeString(dst) << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect) << std::endl;
}
zassert_string_equal(dst, expect);
marker_map expm({{U'e', 0x1L}, {0x300, 0x2L}, {0x320, 0x3L}, {MARKER_BEFORE_EOT, 0x4L}});
assert_marker_map_equal(map, expm);
test_assert_equal(count_markers(map), 4);
}
{
// u"4è\U0000ffff\u0008\U00000001̠"
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - complex test 4a" << std::endl;
const std::u32string src = U"4e\u0300\uFFFF\u0008\u0001\u0320";
const std::u32string expect = U"4e\uFFFF\u0008\u0001\u0320\u0300";
std::u32string dst = src;
test_assert(normalize_nfd_markers_segment(dst, map));
if (dst != expect) {
std::cout << "dst: " << Debug_UnicodeString(dst) << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect) << std::endl;
}
zassert_string_equal(dst, expect);
marker_map expm({{0x320, 0x1L}});
assert_marker_map_equal(map, expm);
test_assert_equal(count_markers(map), 1);
}
{
// from tests
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - complex test 9c" << std::endl;
const std::u32string src = U"9ce\u0300\uFFFF\u0008\u0002\u0320\uFFFF\u0008\u0001";
const std::u32string expect = U"9ce\uFFFF\u0008\u0002\u0320\u0300\uFFFF\u0008\u0001";
std::u32string dst = src;
test_assert(normalize_nfd_markers_segment(dst, map));
if (dst != expect) {
std::cout << "dst: " << Debug_UnicodeString(dst) << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect) << std::endl;
}
zassert_string_equal(dst, expect);
marker_map expm({{0x320, 0x2L}, {MARKER_BEFORE_EOT, 0x1L}});
assert_marker_map_equal(map, expm);
test_assert_equal(count_markers(map), 2);
}
{
// from tests - regex edition
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - complex test 9c+regex" << std::endl;
const std::u32string src = U"9ce\u0300\\uffff\\u0008\\u0002\u0320\\uffff\\u0008\\u0001";
const std::u32string expect = U"9ce\\uffff\\u0008\\u0002\u0320\u0300\\uffff\\u0008\\u0001";
std::u32string dst = src;
test_assert(normalize_nfd_markers_segment(dst, map, regex_sentinel));
if (dst != expect) {
std::cout << "dst: " << Debug_UnicodeString(dst) << std::endl;
std::cout << " " << dst << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect) << std::endl;
std::cout << " " << expect << std::endl;
}
zassert_string_equal(dst, expect);
marker_map expm({{0x320, 0x2L}, {MARKER_BEFORE_EOT, 0x1L}});
assert_marker_map_equal(map, expm);
test_assert_equal(count_markers(map), 2);
}
{
// from tests - regex edition
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - complex test \\m{.}" << std::endl;
const std::u32string src = U"9ce\u0300\\uffff\\u0008[\\u0001-\\ud7fe]\u0320\\uffff\\u0008\\u0001";
const std::u32string expect = U"9ce\\uffff\\u0008[\\u0001-\\ud7fe]\u0320\u0300\\uffff\\u0008\\u0001";
std::u32string dst = src;
test_assert(normalize_nfd_markers_segment(dst, map, regex_sentinel));
if (dst != expect) {
std::cout << "dst: " << Debug_UnicodeString(dst) << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect) << std::endl;
}
zassert_string_equal(dst, expect);
marker_map expm({{0x320, LDML_MARKER_ANY_INDEX}, {MARKER_BEFORE_EOT, 0x1L}});
assert_marker_map_equal(map, expm);
test_assert_equal(count_markers(map), 2);
}
{
// from tests
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - complex test 10 stack o' 2x2" << std::endl;
const std::u32string src = U"9ce\u0300\uFFFF\u0008\u0002\uFFFF\u0008\u0002\u0320";
const std::u32string expect = U"9ce\uFFFF\u0008\u0002\uFFFF\u0008\u0002\u0320\u0300";
std::u32string dst = src;
test_assert(normalize_nfd_markers_segment(dst, map));
if (dst != expect) {
std::cout << "dst: " << Debug_UnicodeString(dst) << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect) << std::endl;
}
zassert_string_equal(dst, expect);
marker_map expm({{0x320, 0x2L}, {0x320, 0x2L}});
assert_marker_map_equal(map, expm);
test_assert_equal(count_markers(map), 2);
}
{
// from tests
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - complex test 10 stack o' 2x1x2" << std::endl;
const std::u32string src = U"9ce\u0300\uFFFF\u0008\u0002\uFFFF\u0008\u0001\uFFFF\u0008\u0003\u0320";
const std::u32string expect = U"9ce\uFFFF\u0008\u0002\uFFFF\u0008\u0001\uFFFF\u0008\u0003\u0320\u0300";
std::u32string dst = src;
test_assert(normalize_nfd_markers_segment(dst, map));
if (dst != expect) {
std::cout << "dst: " << Debug_UnicodeString(dst) << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect) << std::endl;
}
zassert_string_equal(dst, expect);
marker_map expm({{0x320, 0x2L}, {0x320, 0x1L}, {0x320, 0x3L}});
assert_marker_map_equal(map, expm);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - dup-char test" << std::endl;
const std::u32string src = U"a\uFFFF\u0008\u0001\u0300e\uFFFF\u0008\u0002\u0300";
const std::u32string dst = remove_markers(src, map);
const std::u32string expect = U"a\u0300e\u0300"; // U+0300 twice! This should be removed in 2 segments
zassert_string_equal(dst, expect);
marker_map expm({{0x300, 0x1L}, {0x300, 0x2L}});
assert_marker_map_equal(map, expm);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - support 2-segment markers " << std::endl;
// e\m{1}`\m{2}_E\m{3}`\m{4}_
const std::u32string src =
U"e\uFFFF\u0008\u0001\u0300\uFFFF\u0008\u0002\u0320E\uFFFF\u0008\u0003\u0300\uFFFF\u0008\u0004\u0320";
// e\m{2}_\m{1}`E\m{4}_\m{3}`
const std::u32string expect_rem =
U"e\u0300\u0320E\u0300\u0320";
const std::u32string expect_nfd =
U"e\uFFFF\u0008\u0002\u0320\uFFFF\u0008\u0001\u0300E\uFFFF\u0008\u0004\u0320\uFFFF\u0008\u0003\u0300";
auto dst_rem = remove_markers(src, &map); // note: this is bigger than a single segment. so it is a degenerate test case.
marker_map expm({{0x300, 0x1L}, {0x320, 0x2L}, {0x300, 0x3L}, {0x320, 0x4L}});
assert_marker_map_equal(map, expm);
zassert_string_equal(dst_rem, expect_rem);
std::u32string dst_nfd = src;
test_assert(normalize_nfd_markers(dst_nfd));
if (dst_nfd != expect_nfd) {
std::cout << "dst: " << Debug_UnicodeString(dst_nfd) << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect_nfd) << std::endl;
}
zassert_string_equal(dst_nfd, expect_nfd);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - marker-before-NFC " << std::endl;
// KA \m O -> KA \m E AA
const std::u32string src = U"\u0995\uFFFF\u0008\u0001\u09CB";
const std::u32string expect_rem = U"\u0995\u09CB";
const std::u32string expect_nfd = U"\u0995\uFFFF\u0008\u0001\u09C7\u09BE";
auto dst_rem = remove_markers(src, &map);
marker_map expm({{0x09C7, 0x1L}});
zassert_string_equal(dst_rem, expect_rem);
std::u32string dst_nfd = src;
test_assert(normalize_nfd_markers(dst_nfd));
if (dst_nfd != expect_nfd) {
std::cout << "dst: " << Debug_UnicodeString(dst_nfd) << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect_nfd) << std::endl;
}
zassert_string_equal(dst_nfd, expect_nfd);
assert_marker_map_equal(map, expm);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - marker-before-NFC " << std::endl;
const std::u32string src = U"\u0995\u09BE\uFFFF\u0008\u0001\u09C7";
const std::u32string expect_rem = U"\u0995\u09BE\u09C7";
const std::u32string expect_nfd = src; // does not get reordered
auto dst_rem = remove_markers(src, &map);
marker_map expm({{0x09C7, 0x1L}});
zassert_string_equal(dst_rem, expect_rem);
std::u32string dst_nfd = src;
test_assert(normalize_nfd_markers(dst_nfd));
if (dst_nfd != expect_nfd) {
std::cout << "dst: " << Debug_UnicodeString(dst_nfd) << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect_nfd) << std::endl;
}
zassert_string_equal(dst_nfd, expect_nfd);
assert_marker_map_equal(map, expm);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - marker-before-NFC " << std::endl;
const std::u32string src = U"\u0995\u09BE\uFFFF\u0008\u0001\u09C7";
const std::u32string expect_rem = U"\u0995\u09BE\u09C7";
const std::u32string expect_nfd = src; // does not get reordered
auto dst_rem = remove_markers(src, &map);
marker_map expm({{0x09C7, 0x1L}});
zassert_string_equal(dst_rem, expect_rem);
std::u32string dst_nfd = src;
test_assert(normalize_nfd_markers(dst_nfd));
if (dst_nfd != expect_nfd) {
std::cout << "dst: " << Debug_UnicodeString(dst_nfd) << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect_nfd) << std::endl;
}
zassert_string_equal(dst_nfd, expect_nfd);
assert_marker_map_equal(map, expm);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - marker-before-greek " << std::endl;
const std::u32string src = U"\u03B5\uFFFF\u0008\u0001\u0344";
const std::u32string expect_rem = U"\u03B5\u0344";
const std::u32string expect_nfd = U"\u03B5\uFFFF\u0008\u0001\u0308\u0301";
auto dst_rem = remove_markers(src, &map);
marker_map expm({{0x0308, 0x1L}});
zassert_string_equal(dst_rem, expect_rem);
std::u32string dst_nfd = src;
test_assert(normalize_nfd_markers(dst_nfd));
if (dst_nfd != expect_nfd) {
std::cout << "dst: " << Debug_UnicodeString(dst_nfd) << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect_nfd) << std::endl;
}
zassert_string_equal(dst_nfd, expect_nfd);
assert_marker_map_equal(map, expm);
}
// doubled markers tests
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - doubled marker1 " << std::endl;
const std::u32string src = U"e\uffff\u0008\u0001\u0300\u0320\u0300";
const std::u32string expect_rem = U"e\u0300\u0320\u0300";
const std::u32string expect_nfd = U"e\u0320\uffff\u0008\u0001\u0300\u0300";
auto dst_rem = remove_markers(src, &map);
marker_map expm({{0x0300, 0x1L}});
zassert_string_equal(dst_rem, expect_rem);
std::u32string dst_nfd = src;
test_assert(normalize_nfd_markers(dst_nfd));
if (dst_nfd != expect_nfd) {
std::cout << "dst: " << Debug_UnicodeString(dst_nfd) << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect_nfd) << std::endl;
}
zassert_string_equal(dst_nfd, expect_nfd);
assert_marker_map_equal(map, expm);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - doubled unchanged marker " << std::endl;
const std::u32string src = U"e\u0320\uffff\u0008\u0001\u0300\u0300";
const std::u32string expect_rem = U"e\u0320\u0300\u0300";
const std::u32string expect_nfd = src;
auto dst_rem = remove_markers(src, &map);
marker_map expm({{0x300, 0x1L}});
zassert_string_equal(dst_rem, expect_rem);
std::u32string dst_nfd = src;
test_assert(normalize_nfd_markers(dst_nfd));
if (dst_nfd != expect_nfd) {
std::cout << "dst: " << Debug_UnicodeString(dst_nfd) << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect_nfd) << std::endl;
}
zassert_string_equal(dst_nfd, expect_nfd);
assert_marker_map_equal(map, expm);
}
{
marker_map map;
std::cout << __FILE__ << ":" << __LINE__ << " - marker-before-double-greek " << std::endl;
const std::u32string src = U"\u03B5\uFFFF\u0008\u0001\u0344\uFFFF\u0008\u0002\u0344\uFFFF\u0008\u0003";
const std::u32string expect_rem = U"\u03B5\u0344\u0344";
const std::u32string expect_nfd = U"\u03B5\uFFFF\u0008\u0001\u0308\u0301\uFFFF\u0008\u0002\u0308\u0301\uFFFF\u0008\u0003";
auto dst_rem = remove_markers(src, &map);
marker_map expm({{0x0308, 0x1L},{0x0308, 0x2L},{MARKER_BEFORE_EOT, 0x3L}});
zassert_string_equal(dst_rem, expect_rem);
std::u32string dst_nfd = src;
test_assert(normalize_nfd_markers(dst_nfd));
if (dst_nfd != expect_nfd) {
std::cout << "dst: " << Debug_UnicodeString(dst_nfd) << std::endl;
std::cout << "exp: " << Debug_UnicodeString(expect_nfd) << std::endl;
}
zassert_string_equal(dst_nfd, expect_nfd);
assert_marker_map_equal(map, expm);
}
// macro for moving tests from test-pattern-parser.ts
#define TEST_NFD_PLAIN(x, y) \
{ \
marker_map map; \
std::cout << __FILE__ << ":" << __LINE__ << ": nfd test " << std::endl; \
const std::u32string src = x; \
const std::u32string expect_nfd = y; \
std::u32string dst_nfd = src; \
test_assert(normalize_nfd_markers(dst_nfd)); \
if (dst_nfd != expect_nfd) { \
std::cout << "dst: " << Debug_UnicodeString(dst_nfd) << std::endl; \
std::cout << "exp: " << Debug_UnicodeString(expect_nfd) << std::endl; \
} \
zassert_string_equal(dst_nfd, expect_nfd); \
}
// double marker - in front of second, no change
TEST_NFD_PLAIN(U"e\u0320\u0300\uffff\u0008\u0001\u0300", U"e\u0320\u0300\uffff\u0008\u0001\u0300")
// double marker - in front of second, with segment reordering
TEST_NFD_PLAIN(U"e\u0300\u0320\uffff\u0008\u0001\u0300", U"e\u0320\u0300\uffff\u0008\u0001\u0300")
// double marker - alternate pattern with reordering needed
TEST_NFD_PLAIN(U"e\u0300\uffff\u0008\u0001\u0300\u0320", U"e\u0320\u0300\uffff\u0008\u0001\u0300")
// triple diacritic + marker - reordering needed
TEST_NFD_PLAIN(U"e\u0300\uffff\u0008\u0001\u0300\u0320\u0300", U"e\u0320\u0300\uffff\u0008\u0001\u0300\u0300")
return EXIT_SUCCESS;
}
/** test for the util_regex.hpp functions */
int
test_util_regex() {
std::cout << "== " << __FUNCTION__ << std::endl;
{
std::cout << __FILE__ << ":" << __LINE__ << " * util_regex.hpp null tests" << std::endl;
km::core::util::km_regex r;
test_assert(!r.valid()); // not valid because of an empty string
}
{
std::cout << __FILE__ << ":" << __LINE__ << " * util_regex.hpp simple tests" << std::endl;
km::core::util::km_regex r(U"ion");
test_assert(r.valid());
const std::u32string to(U"ivity");
const std::deque<std::u32string> fromList;
const std::deque<std::u32string> toList;
std::u32string output;
auto apply0 = r.apply(U"not present", output, to, fromList, toList);
test_assert_equal(apply0, 0); // not found
const std::u32string input(U"action");
auto apply1 = r.apply(input, output, to, fromList, toList);
test_assert_equal(apply1, 3); // matched last 3 codepoints
std::u32string expect(U"ivity");
zassert_string_equal(output, expect)
}
{
std::cout << __FILE__ << ":" << __LINE__ << " * util_regex.hpp wide tests" << std::endl;
km::core::util::km_regex r(U"e𐒻");
test_assert(r.valid());
const std::u32string to(U"𐓏");
const std::deque<std::u32string> fromList;
const std::deque<std::u32string> toList;
std::u32string output;
const std::u32string input(U":e𐒻");
auto apply1 = r.apply(input, output, to, fromList, toList);
test_assert_equal(apply1, 2); // matched last 2 codepoints
std::u32string expect(U"𐓏");
zassert_string_equal(output, expect)
}
{
std::cout << __FILE__ << ":" << __LINE__ << " * util_regex.hpp simple map tests" << std::endl;
km::core::util::km_regex r(U"(A|B|C)");
test_assert(r.valid());
const std::u32string to(U"$[1:alpha2]"); // ignored
std::deque<std::u32string> fromList;
fromList.emplace_back(U"A");
fromList.emplace_back(U"B");
fromList.emplace_back(U"C");
std::deque<std::u32string> toList;
toList.emplace_back(U"N");
toList.emplace_back(U"O");
toList.emplace_back(U"P");
std::u32string output;
auto apply0 = r.apply(U"not present", output, to, fromList, toList);
test_assert_equal(apply0, 0); // not found
const std::u32string input(U"WHOA");
auto apply1 = r.apply(input, output, to, fromList, toList);
test_assert_equal(apply1, 1); // matched last 1 codepoint
std::u32string expect(U"N");
zassert_string_equal(output, expect)
}
{
std::cout << __FILE__ << ":" << __LINE__ << " * util_regex.hpp wide map tests" << std::endl;
km::core::util::km_regex r(U"(𐒷|𐒻|𐓏𐓏|x)");
test_assert(r.valid());
const std::u32string to(U"$[1:alpha2]"); // ignored
std::deque<std::u32string> fromList;
fromList.emplace_back(U"𐒷");
fromList.emplace_back(U"𐒻");
fromList.emplace_back(U"𐓏𐓏");
fromList.emplace_back(U"x");
std::deque<std::u32string> toList;
toList.emplace_back(U"x");
toList.emplace_back(U"𐒷");
toList.emplace_back(U"𐒻");
toList.emplace_back(U"𐓏");
std::u32string output;
auto apply0 = r.apply(U"not present", output, to, fromList, toList);
test_assert_equal(apply0, 0); // not found
test_assert_equal(r.apply(U"WHO𐓏𐒷", output, to, fromList, toList), 1);
zassert_string_equal(output, U"x");
test_assert_equal(r.apply(U"WHO𐓏x", output, to, fromList, toList), 1);
zassert_string_equal(output, U"𐓏");
test_assert_equal(r.apply(U"WHO𐓏𐓏", output, to, fromList, toList), 2); // 2 codepoints
zassert_string_equal(output, U"𐒻");
}
return EXIT_SUCCESS;
}
int
main(int argc, const char *argv[]) {
int rc = EXIT_SUCCESS;
bool arg_color = false;
int first_arg = 1;
if (first_arg < argc) {
arg_color = std::string(argv[first_arg]) == "--color";
if (arg_color) {
first_arg++;
}
}
console_color::enabled = console_color::isaterminal() || arg_color;
if (test_util_regex() != EXIT_SUCCESS) {
rc = EXIT_FAILURE;
}
if (test_transforms() != EXIT_SUCCESS) {
rc = EXIT_FAILURE;
}
if (test_reorder_standalone() != EXIT_SUCCESS) {
rc = EXIT_FAILURE;
}
if (test_reorder_esk() != EXIT_SUCCESS) {
rc = EXIT_FAILURE;
}
if (test_map() != EXIT_SUCCESS) {
rc = EXIT_FAILURE;
}
if (test_strutils() != EXIT_SUCCESS) {
rc = EXIT_FAILURE;
}
if (test_normalize() != EXIT_SUCCESS) {
rc = EXIT_FAILURE;
}
if (rc == EXIT_FAILURE) {
std::cout << "== FAILURE" << std::endl;
} else {
std::cout << "== PASS" << std::endl;
}
return rc;
}