xref: /aosp_15_r20/external/icu/icu4c/source/test/intltest/units_data_test.cpp (revision 0e209d3975ff4a8c132096b14b0e9364a753506e)
1 // © 2020 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html#License
3 
4 #include "unicode/utypes.h"
5 
6 #if !UCONFIG_NO_FORMATTING
7 
8 #include "cstring.h"
9 #include "measunit_impl.h"
10 #include "unicode/locid.h"
11 #include "units_data.h"
12 
13 #include "intltest.h"
14 
15 using namespace ::icu::units;
16 
17 // These test are no in ICU4J. TODO: consider porting them to Java?
18 class UnitsDataTest : public IntlTest {
19   public:
UnitsDataTest()20     UnitsDataTest() {}
21 
22     void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = nullptr) override;
23 
24     void testGetUnitCategory();
25     // This is a sanity check that only exists in ICU4C.
26     void testGetAllConversionRates();
27     void testGetPreferencesFor();
28 };
29 
createUnitsDataTest()30 extern IntlTest *createUnitsDataTest() { return new UnitsDataTest(); }
31 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)32 void UnitsDataTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char * /*par*/) {
33     if (exec) { logln("TestSuite UnitsDataTest: "); }
34     TESTCASE_AUTO_BEGIN;
35     TESTCASE_AUTO(testGetUnitCategory);
36     TESTCASE_AUTO(testGetAllConversionRates);
37     TESTCASE_AUTO(testGetPreferencesFor);
38     TESTCASE_AUTO_END;
39 }
40 
testGetUnitCategory()41 void UnitsDataTest::testGetUnitCategory() {
42     struct TestCase {
43         const char *unit;
44         const char *expectedCategory;
45     } testCases[]{
46         {"kilogram-per-cubic-meter", "mass-density"},
47         {"cubic-meter-per-kilogram", "specific-volume"},
48         {"meter-per-second", "speed"},
49         {"second-per-meter", "speed"},
50         // TODO: add this test cases once the `getUnitCategory` accepts any `MeasureUnit` and not only
51         // base units.
52         // Tests are:
53         // {"liter-per-100-kilometer", "consumption"},
54         // {"mile-per-gallon", "consumption"},
55         // {"knot", "speed"},
56         // {"beaufort", "speed"},
57         {"cubic-meter-per-meter", "consumption"},
58         {"meter-per-cubic-meter", "consumption"},
59         {"kilogram-meter-per-square-meter-square-second", "pressure"},
60     };
61 
62     IcuTestErrorCode status(*this, "testGetUnitCategory");
63     for (const auto &t : testCases) {
64         CharString category = getUnitQuantity(MeasureUnitImpl::forIdentifier(t.unit, status), status);
65         if (!status.errIfFailureAndReset("getUnitCategory(%s)", t.unit)) {
66             assertEquals("category", t.expectedCategory, category.data());
67         }
68     }
69 }
70 
testGetAllConversionRates()71 void UnitsDataTest::testGetAllConversionRates() {
72     IcuTestErrorCode status(*this, "testGetAllConversionRates");
73     MaybeStackVector<ConversionRateInfo> conversionInfo;
74     getAllConversionRates(conversionInfo, status);
75 
76     // Convenience output for debugging
77     for (int i = 0; i < conversionInfo.length(); i++) {
78         ConversionRateInfo *cri = conversionInfo[i];
79         logln("* conversionInfo %d: source=\"%s\", baseUnit=\"%s\", factor=\"%s\", offset=\"%s\"", i,
80               cri->sourceUnit.data(), cri->baseUnit.data(), cri->factor.data(), cri->offset.data());
81         assertTrue("sourceUnit", cri->sourceUnit.length() > 0);
82         assertTrue("baseUnit", cri->baseUnit.length() > 0);
83         assertTrue("factor || special", cri->factor.length() > 0 || cri->specialMappingName.length() > 0);
84     }
85 }
86 
87 class UnitPreferencesOpenedUp : public UnitPreferences {
88   public:
UnitPreferencesOpenedUp(UErrorCode & status)89     UnitPreferencesOpenedUp(UErrorCode &status) : UnitPreferences(status) {}
getInternalMetadata() const90     const MaybeStackVector<UnitPreferenceMetadata> *getInternalMetadata() const { return &metadata_; }
getInternalUnitPrefs() const91     const MaybeStackVector<UnitPreference> *getInternalUnitPrefs() const { return &unitPrefs_; }
92 };
93 
94 /**
95  * This test is dependent upon CLDR Data: when the preferences change, the test
96  * may fail: see the constants for expected Max/Min unit identifiers, for US and
97  * World, and for Roads and default lengths.
98  */
testGetPreferencesFor()99 void UnitsDataTest::testGetPreferencesFor() {
100     const char* USRoadMax = "mile";
101     const char* USRoadMin = "foot";
102     const char* USLenMax = "mile";
103     const char* USLenMin = "inch";
104     const char* WorldRoadMax = "kilometer";
105     const char* WorldRoadMin = "meter";
106     const char* WorldLenMax = "kilometer";
107     const char* WorldLenMin = "centimeter";
108     struct TestCase {
109         const char *name;
110         const char *category;
111         const char *usage;
112         const char *region;
113         const char *expectedBiggest;
114         const char *expectedSmallest;
115     } testCases[]{
116         {"US road", "length", "road", "US", USRoadMax, USRoadMin},
117         {"001 road", "length", "road", "001", WorldRoadMax, WorldRoadMin},
118         {"US lengths", "length", "default", "US", USLenMax, USLenMin},
119         {"001 lengths", "length", "default", "001", WorldLenMax, WorldLenMin},
120         {"XX road falls back to 001", "length", "road", "XX", WorldRoadMax, WorldRoadMin},
121         {"XX default falls back to 001", "length", "default", "XX", WorldLenMax, WorldLenMin},
122         {"Unknown usage US", "length", "foobar", "US", USLenMax, USLenMin},
123         {"Unknown usage 001", "length", "foobar", "XX", WorldLenMax, WorldLenMin},
124         {"Fallback", "length", "person-height-xyzzy", "DE", "centimeter", "centimeter"},
125         {"Fallback twice", "length", "person-height-xyzzy-foo", "DE", "centimeter", "centimeter"},
126         // Confirming results for some unitPreferencesTest.txt test cases
127         {"001 area", "area", "default", "001", "square-kilometer", "square-centimeter"},
128         {"GB area", "area", "default", "GB", "square-mile", "square-inch"},
129         {"001 area geograph", "area", "geograph", "001", "square-kilometer", "square-kilometer"},
130         {"GB area geograph", "area", "geograph", "GB", "square-mile", "square-mile"},
131         {"CA person-height", "length", "person-height", "CA", "foot-and-inch", "inch"},
132         {"AT person-height", "length", "person-height", "AT", "meter-and-centimeter",
133          "meter-and-centimeter"},
134     };
135     IcuTestErrorCode status(*this, "testGetPreferencesFor");
136     UnitPreferencesOpenedUp preferences(status);
137     const auto* metadata = preferences.getInternalMetadata();
138     const auto* unitPrefs = preferences.getInternalUnitPrefs();
139     assertTrue(UnicodeString("Metadata count: ") + metadata->length() + " > 200",
140                metadata->length() > 200);
141     assertTrue(UnicodeString("Preferences count: ") + unitPrefs->length() + " > 250",
142                unitPrefs->length() > 250);
143 
144     for (const auto &t : testCases) {
145         logln(t.name);
146         CharString localeID;
147         localeID.append("und-", status); // append undefined language.
148         localeID.append(t.region, status);
149         Locale locale(localeID.data());
150         auto unitPrefs = preferences.getPreferencesFor(t.category, t.usage, locale, status);
151         if (status.errIfFailureAndReset("getPreferencesFor(\"%s\", \"%s\", \"%s\", ...", t.category,
152                                         t.usage, t.region)) {
153             continue;
154         }
155         if (unitPrefs.length() > 0) {
156             assertEquals(UnicodeString(t.name) + " - max unit", t.expectedBiggest,
157                          unitPrefs[0]->unit.data());
158             assertEquals(UnicodeString(t.name) + " - min unit", t.expectedSmallest,
159                          unitPrefs[unitPrefs.length() - 1]->unit.data());
160         } else {
161             errln(UnicodeString(t.name) + ": failed to find preferences");
162         }
163         status.errIfFailureAndReset("testCase '%s'", t.name);
164     }
165 }
166 
167 #endif /* #if !UCONFIG_NO_FORMATTING */
168