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 "units_data.h"
9 #include "intltest.h"
10 
11 using namespace ::icu::units;
12 
13 class UnitsDataTest : public IntlTest {
14   public:
UnitsDataTest()15     UnitsDataTest() {}
16 
17     void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = NULL);
18 
19     void testGetUnitCategory();
20     void testGetAllConversionRates();
21     void testGetPreferencesFor();
22 };
23 
createUnitsDataTest()24 extern IntlTest *createUnitsDataTest() { return new UnitsDataTest(); }
25 
runIndexedTest(int32_t index,UBool exec,const char * & name,char *)26 void UnitsDataTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char * /*par*/) {
27     if (exec) { logln("TestSuite UnitsDataTest: "); }
28     TESTCASE_AUTO_BEGIN;
29     TESTCASE_AUTO(testGetUnitCategory);
30     TESTCASE_AUTO(testGetAllConversionRates);
31     TESTCASE_AUTO(testGetPreferencesFor);
32     TESTCASE_AUTO_END;
33 }
34 
testGetUnitCategory()35 void UnitsDataTest::testGetUnitCategory() {
36     struct TestCase {
37         const char *unit;
38         const char *expectedCategory;
39     } testCases[]{
40         {"kilogram-per-cubic-meter", "mass-density"},
41         {"cubic-meter-per-meter", "consumption"},
42         // TODO(CLDR-13787,hugovdm): currently we're treating
43         // consumption-inverse as a separate category. Once consumption
44         // preference handling has been clarified by CLDR-13787, this function
45         // should be fixed.
46         {"meter-per-cubic-meter", "consumption-inverse"},
47     };
48 
49     IcuTestErrorCode status(*this, "testGetUnitCategory");
50     for (const auto &t : testCases) {
51         CharString category = getUnitCategory(t.unit, status);
52         status.errIfFailureAndReset("getUnitCategory(%s)", t.unit);
53         assertEquals("category", t.expectedCategory, category.data());
54     }
55 }
56 
testGetAllConversionRates()57 void UnitsDataTest::testGetAllConversionRates() {
58     IcuTestErrorCode status(*this, "testGetAllConversionRates");
59     MaybeStackVector<ConversionRateInfo> conversionInfo;
60     getAllConversionRates(conversionInfo, status);
61 
62     // Convenience output for debugging
63     for (int i = 0; i < conversionInfo.length(); i++) {
64         ConversionRateInfo *cri = conversionInfo[i];
65         logln("* conversionInfo %d: source=\"%s\", baseUnit=\"%s\", factor=\"%s\", offset=\"%s\"", i,
66               cri->sourceUnit.data(), cri->baseUnit.data(), cri->factor.data(), cri->offset.data());
67         assertTrue("sourceUnit", cri->sourceUnit.length() > 0);
68         assertTrue("baseUnit", cri->baseUnit.length() > 0);
69         assertTrue("factor", cri->factor.length() > 0);
70     }
71 }
72 
73 class UnitPreferencesOpenedUp : public UnitPreferences {
74   public:
UnitPreferencesOpenedUp(UErrorCode & status)75     UnitPreferencesOpenedUp(UErrorCode &status) : UnitPreferences(status) {}
getInternalMetadata() const76     const MaybeStackVector<UnitPreferenceMetadata> *getInternalMetadata() const { return &metadata_; }
getInternalUnitPrefs() const77     const MaybeStackVector<UnitPreference> *getInternalUnitPrefs() const { return &unitPrefs_; }
78 };
79 
80 /**
81  * This test is dependent upon CLDR Data: when the preferences change, the test
82  * may fail: see the constants for expected Max/Min unit identifiers, for US and
83  * World, and for Roads and default lengths.
84  */
testGetPreferencesFor()85 void UnitsDataTest::testGetPreferencesFor() {
86     const char* USRoadMax = "mile";
87     const char* USRoadMin = "foot";
88     const char* USLenMax = "mile";
89     const char* USLenMin = "inch";
90     const char* WorldRoadMax = "kilometer";
91     const char* WorldRoadMin = "meter";
92     const char* WorldLenMax = "kilometer";
93     const char* WorldLenMin = "centimeter";
94     struct TestCase {
95         const char *name;
96         const char *category;
97         const char *usage;
98         const char *region;
99         const char *expectedBiggest;
100         const char *expectedSmallest;
101     } testCases[]{
102         {"US road", "length", "road", "US", USRoadMax, USRoadMin},
103         {"001 road", "length", "road", "001", WorldRoadMax, WorldRoadMin},
104         {"US lengths", "length", "default", "US", USLenMax, USLenMin},
105         {"001 lengths", "length", "default", "001", WorldLenMax, WorldLenMin},
106         {"XX road falls back to 001", "length", "road", "XX", WorldRoadMax, WorldRoadMin},
107         {"XX default falls back to 001", "length", "default", "XX", WorldLenMax, WorldLenMin},
108         {"Unknown usage US", "length", "foobar", "US", USLenMax, USLenMin},
109         {"Unknown usage 001", "length", "foobar", "XX", WorldLenMax, WorldLenMin},
110         {"Fallback", "length", "person-height-xyzzy", "DE", "meter-and-centimeter",
111          "meter-and-centimeter"},
112         {"Fallback twice", "length", "person-height-xyzzy-foo", "DE", "meter-and-centimeter",
113          "meter-and-centimeter"},
114         // Confirming results for some unitPreferencesTest.txt test cases
115         {"001 area", "area", "default", "001", "square-kilometer", "square-centimeter"},
116         {"GB area", "area", "default", "GB", "square-mile", "square-inch"},
117         {"001 area geograph", "area", "geograph", "001", "square-kilometer", "square-kilometer"},
118         {"GB area geograph", "area", "geograph", "GB", "square-mile", "square-mile"},
119         {"CA person-height", "length", "person-height", "CA", "foot-and-inch", "inch"},
120         {"AT person-height", "length", "person-height", "AT", "meter-and-centimeter",
121          "meter-and-centimeter"},
122     };
123     IcuTestErrorCode status(*this, "testGetPreferencesFor");
124     UnitPreferencesOpenedUp preferences(status);
125     auto *metadata = preferences.getInternalMetadata();
126     auto *unitPrefs = preferences.getInternalUnitPrefs();
127     assertTrue(UnicodeString("Metadata count: ") + metadata->length() + " > 200",
128                metadata->length() > 200);
129     assertTrue(UnicodeString("Preferences count: ") + unitPrefs->length() + " > 250",
130                unitPrefs->length() > 250);
131 
132     for (const auto &t : testCases) {
133         logln(t.name);
134         const UnitPreference *const *prefs;
135         int32_t prefsCount;
136         preferences.getPreferencesFor(t.category, t.usage, t.region, prefs, prefsCount, status);
137         if (status.errIfFailureAndReset("getPreferencesFor(\"%s\", \"%s\", \"%s\", ...", t.category,
138                                         t.usage, t.region)) {
139             continue;
140         }
141         if (prefsCount > 0) {
142             assertEquals(UnicodeString(t.name) + " - max unit", t.expectedBiggest,
143                          prefs[0]->unit.data());
144             assertEquals(UnicodeString(t.name) + " - min unit", t.expectedSmallest,
145                          prefs[prefsCount - 1]->unit.data());
146         } else {
147             errln(UnicodeString(t.name) + ": failed to find preferences");
148         }
149         status.errIfFailureAndReset("testCase '%s'", t.name);
150     }
151 }
152 
153 #endif /* #if !UCONFIG_NO_FORMATTING */
154