#include "unicode_config.h" #include "courier-unicode.h" #include #include #include #include #include #include #include #include #include std::vector testcase; FILE *DEBUGDUMP; int main(int argc, char **argv) { if (argc > 1) { char32_t c=atoi(argv[1]); unicode_bidi_bracket_type_t bt; std::cout << unicode_bidi_mirror(c) << " " << unicode_bidi_bracket_type(c, &bt) << " "; std::cout << (char)bt << std::endl; exit (0); } DEBUGDUMP=fopen("/dev/null", "w"); if (!DEBUGDUMP) { perror("/dev/null"); exit(1); } std::ifstream fp("BidiTest.txt"); if (!fp.is_open()) { std::cerr << "Cannot open BidiTest.txt" << std::endl; exit(1); } size_t linenum=0; size_t nextlogline=0; std::string logmsg; std::string buf; std::vector expected_levels; std::vector expected_reorder; while (1) { buf.clear(); bool iseof=std::getline(fp, buf).eof() && buf.empty(); if (iseof || ++linenum >= nextlogline) { alarm(300); std::cout << logmsg; std::ostringstream o; o << std::setw(6) << linenum << " lines processed... "; logmsg=o.str(); std::cout << logmsg << std::flush; std::fill(logmsg.begin(), logmsg.end(), '\b'); nextlogline += 20000; } if (iseof) break; buf.erase(std::find(buf.begin(), buf.end(), '#'), buf.end()); if (buf.substr(0, 8) == "@Levels:") { expected_levels.clear(); std::istringstream i(buf); std::string word; i >> word; while (i >> word) { int n; std::stringstream words(word); if (words >> n) { expected_levels.push_back(n); } else { expected_levels .push_back(UNICODE_BIDI_SKIP); } } continue; } if (buf.substr(0, 9) == "@Reorder:") { expected_reorder.clear(); std::istringstream i(buf); std::string word; i >> word; size_t n; while (i >> n) { expected_reorder.push_back(n); } continue; } if (buf.substr(0, 1) == "@") continue; size_t semicolon=buf.find(';'); if (semicolon == buf.npos) continue; testcase.clear(); { std::istringstream i(buf.substr(0, semicolon)); std::string word; while (i >> word) testcase.push_back(word); } int n; { std::istringstream i(buf.substr(semicolon+1)); if (!(i >> n)) { std::cerr << "Cannot parse paragraph bitset: " << buf.substr(semicolon+1) << " on line " << linenum << std::endl; abort(); } } //if (linenum != 98950) // continue; std::vector actual_levels; std::u32string dummy_input; dummy_input.resize(testcase.size()); static const unicode_bidi_level_t level_0=0; static const unicode_bidi_level_t level_1=1; static const unicode_bidi_level_t *levels[3]= {0, &level_0, &level_1}; for (auto level:levels) { if (n & 1) { auto ret=level ? unicode::bidi_calc(dummy_input,*level) : unicode::bidi_calc(dummy_input); actual_levels=std::get<0>(ret); int matched=0; if (actual_levels.size() == expected_levels.size()) { size_t i=0; matched=1; for (i=0; i actual_reorder; actual_reorder.resize(testcase.size()); std::iota(actual_reorder.begin(), actual_reorder.end(), 0); unicode::bidi_reorder (dummy_input, actual_levels, [&] (size_t s, size_t cnt) { auto *b=&actual_reorder[s]; auto *e=b+cnt; while (b < e) { --e; std::swap(*b, *e); ++b; } }); auto b=actual_reorder.begin(), p=b, e=actual_reorder.end(); auto q=actual_levels.begin(); while (b != e) { if (*q != UNICODE_BIDI_SKIP) { *p=*b; ++p; } ++b; ++q; } actual_reorder.erase(p, e); if (actual_reorder != expected_reorder) { fclose(DEBUGDUMP); DEBUGDUMP=stderr; std::cout << std::endl << std::flush; unicode_bidi_calc(&dummy_input[0], testcase.size(), &actual_levels[0], level); std::cerr << "Regression, line " << linenum; if (!level) { std::cerr << ", auto"; } else { std::cerr << (*level ? ", RTL" : ", LTR"); } std::cerr << ": expected reorder"; for (auto o:expected_reorder) { std::cerr << " " << o; } std::cerr << std::endl << "Moved: "; for (auto o:actual_reorder) { std::cerr << " " << o; } std::cerr << std::endl; exit(1); } } n >>= 1; } } std::cout << std::endl; return 0; } #define UNICODE_BIDI_TEST(i) (buf[i]=fudge_unicode_bidi(i)) #define BIDI_DEBUG extern "C" { #if 0 } #endif #include "unicode_bidi.c" enum_bidi_type_t fudge_unicode_bidi(size_t i) { if (i >= testcase.size()) { std::cerr << "Test case:"; for (auto &n:testcase) std::cerr << " " << n; std::cerr << ": no value #" << i << std::endl; abort(); } for (const auto &cn:bidiclassnames) { if (testcase[i] == cn.classname) { return cn.classenum; } } std::cerr << "Test case:"; for (auto &n:testcase) std::cerr << " " << n; std::cerr << ": unknown value: " << testcase[i]; abort(); } #if 0 { #endif }