|
| 1 | +/* |
| 2 | + * test_diacritic.cpp |
| 3 | + * |
| 4 | + * Created on: 2026-02-23 |
| 5 | + * Author: automated-test |
| 6 | + */ |
| 7 | + |
| 8 | +#include "Debug.h" |
| 9 | +#include "UI/Components/LVGL/LvLabel.h" |
| 10 | +#include "test_utils/UiTestSuite.h" |
| 11 | +#include <cstring> |
| 12 | +#include <gtest/gtest.h> |
| 13 | +#include <string> |
| 14 | + |
| 15 | +using namespace UI; |
| 16 | + |
| 17 | +class TestDiacritic : public UiTestSuite |
| 18 | +{ |
| 19 | + public: |
| 20 | + TestDiacritic() {} |
| 21 | +}; |
| 22 | + |
| 23 | +TEST_F(TestDiacritic, CombinedVsCombining) |
| 24 | +{ |
| 25 | + // Create two labels on the test screen |
| 26 | + LvLabel label_precomposed("label_pre", screen); |
| 27 | + LvLabel label_decomposed("label_decomp", screen); |
| 28 | + |
| 29 | + // Examples: pairs of (precomposed, decomposed) |
| 30 | + // This list covers common diacritics used across European languages. |
| 31 | + struct Pair |
| 32 | + { |
| 33 | + const char* pre; |
| 34 | + const char* decomp; |
| 35 | + const char* desc; |
| 36 | + } pairs[] = { |
| 37 | + {"\u00E1", "a\u0301", "a + acute -> á"}, // á |
| 38 | + {"\u00E0", "a\u0300", "a + grave -> à"}, // à |
| 39 | + {"\u00E2", "a\u0302", "a + circumflex -> â"}, |
| 40 | + {"\u00E3", "a\u0303", "a + tilde -> ã"}, |
| 41 | + {"\u00E4", "a\u0308", "a + diaeresis -> ä"}, |
| 42 | + {"\u00E5", "a\u030A", "a + ring -> å"}, |
| 43 | + {"\u0105", "a\u0328", "a + ogonek -> ą"}, |
| 44 | + |
| 45 | + {"\u00E9", "e\u0301", "e + acute -> é"}, // é |
| 46 | + {"\u00E8", "e\u0300", "e + grave -> è"}, // è |
| 47 | + {"\u00EA", "e\u0302", "e + circumflex -> ê"}, |
| 48 | + {"\u00EB", "e\u0308", "e + diaeresis -> ë"}, |
| 49 | + {"\u0119", "e\u0328", "e + ogonek -> ę"}, |
| 50 | + {"\u011B", "e\u030C", "e + caron -> ě"}, |
| 51 | + |
| 52 | + {"\u00ED", "i\u0301", "i + acute -> í"}, |
| 53 | + {"\u00EC", "i\u0300", "i + grave -> ì"}, |
| 54 | + {"\u00EE", "i\u0302", "i + circumflex -> î"}, |
| 55 | + {"\u00EF", "i\u0308", "i + diaeresis -> ï"}, |
| 56 | + {"\u012B", "i\u0304", "i + macron -> ī"}, |
| 57 | + |
| 58 | + {"\u00F3", "o\u0301", "o + acute -> ó"}, |
| 59 | + {"\u00F2", "o\u0300", "o + grave -> ò"}, |
| 60 | + {"\u00F4", "o\u0302", "o + circumflex -> ô"}, |
| 61 | + {"\u00F5", "o\u0303", "o + tilde -> õ"}, |
| 62 | + {"\u00F6", "o\u0308", "o + diaeresis -> ö"}, |
| 63 | + {"\u00F8", "o\u0338", "o + stroke (approx) -> ø"}, |
| 64 | + |
| 65 | + {"\u00F1", "n\u0303", "n + tilde -> ñ"}, |
| 66 | + {"\u0144", "n\u0301", "n + acute -> ń"}, |
| 67 | + |
| 68 | + {"\u00E7", "c\u0327", "c + cedilla -> ç"}, |
| 69 | + {"\u0107", "c\u0301", "c + acute -> ć"}, |
| 70 | + {"\u010D", "c\u030C", "c + caron -> č"}, |
| 71 | + |
| 72 | + {"\u015B", "s\u0301", "s + acute -> ś"}, |
| 73 | + {"\u0161", "s\u030C", "s + caron -> š"}, |
| 74 | + |
| 75 | + {"\u017A", "z\u0301", "z + acute -> ź"}, |
| 76 | + {"\u017C", "z\u0307", "z + dot -> ż"}, |
| 77 | + {"\u017E", "z\u030C", "z + caron -> ž"}, |
| 78 | + |
| 79 | + {"\u0142", "l\u0335", "l + stroke (approx) -> ł"}, |
| 80 | + {"\u0159", "r\u030C", "r + caron -> ř"}, |
| 81 | + {"\u0165", "t\u030C", "t + caron -> ť"}, |
| 82 | + |
| 83 | + {"\u0117", "e\u0307", "e + dot -> ė"}, |
| 84 | + {"\u012F", "i\u0328", "i + ogonek -> į"}, |
| 85 | + {"\u0173", "u\u0328", "u + ogonek -> ų"}, |
| 86 | + |
| 87 | + {"\u00FC", "u\u0308", "u + diaeresis -> ü"}, |
| 88 | + {"\u016B", "u\u0304", "u + macron -> ū"}, |
| 89 | + }; |
| 90 | + |
| 91 | + // Create labels for each pair and verify the stored text matches what we set |
| 92 | + for (size_t i = 0; i < std::size(pairs); ++i) |
| 93 | + { |
| 94 | + std::string name_pre = std::string("pre_") + std::to_string(i); |
| 95 | + std::string name_de = std::string("de_") + std::to_string(i); |
| 96 | + |
| 97 | + LvLabel lp(name_pre, screen); |
| 98 | + LvLabel ld(name_de, screen); |
| 99 | + |
| 100 | + lp.setText(pairs[i].pre); |
| 101 | + ld.setText(pairs[i].decomp); |
| 102 | + |
| 103 | + ASSERT_STREQ(lp.getText(), pairs[i].pre) << "precomposed failed for " << pairs[i].desc; |
| 104 | + ASSERT_STREQ(ld.getText(), pairs[i].decomp) << "decomposed failed for " << pairs[i].desc; |
| 105 | + |
| 106 | + // Precomposed and decomposed byte lengths will commonly differ |
| 107 | + EXPECT_NE(std::strlen(lp.getText()), std::strlen(ld.getText())) << pairs[i].desc; |
| 108 | + } |
| 109 | + |
| 110 | + // Compose all pairs into single strings for a combined display on the two top-level labels |
| 111 | + std::string combined_pre; |
| 112 | + std::string combined_decomp; |
| 113 | + for (size_t i = 0; i < std::size(pairs); ++i) |
| 114 | + { |
| 115 | + if (!combined_pre.empty()) |
| 116 | + { |
| 117 | + combined_pre += " "; |
| 118 | + combined_decomp += " "; |
| 119 | + } |
| 120 | + combined_pre += pairs[i].pre; |
| 121 | + combined_decomp += pairs[i].decomp; |
| 122 | + } |
| 123 | + |
| 124 | + // Use the labels created at the top of the test to show the combined strings |
| 125 | + label_precomposed.setText(combined_pre); |
| 126 | + label_decomposed.setText(combined_decomp); |
| 127 | + |
| 128 | + EXPECT_EQUAL_SCREENSHOT("diacritic/combined_vs_combining.png"); |
| 129 | +} |
0 commit comments