]> granicus.if.org Git - icu/commitdiff
Checkpoint
authorShane F. Carr <shane@unicode.org>
Wed, 15 Jan 2020 15:08:53 +0000 (16:08 +0100)
committerShane F. Carr <shane@unicode.org>
Fri, 17 Jan 2020 16:14:19 +0000 (17:14 +0100)
icu4c/source/i18n/measunit.cpp
icu4c/source/i18n/measunit_extra.cpp
icu4c/source/i18n/unicode/measunit.h
icu4c/source/test/intltest/measfmttest.cpp

index 22f877a95b8e2152fbc2b0abd1b423bbdfa60ea3..c575c53745be249238a988d13fa112aafb161426 100644 (file)
@@ -2083,10 +2083,10 @@ const char *MeasureUnit::getSubtype() const {
     if (fTypeId == -1) {
         return "";
     }
-    return toString();
+    return getIdentifier();
 }
 
-const char *MeasureUnit::toString() const {
+const char *MeasureUnit::getIdentifier() const {
     return fId ? fId : gSubTypes[getOffset()];
 }
 
@@ -2098,7 +2098,7 @@ UBool MeasureUnit::operator==(const UObject& other) const {
         return FALSE;
     }
     const MeasureUnit &rhs = static_cast<const MeasureUnit&>(other);
-    return uprv_strcmp(toString(), rhs.toString()) == 0;
+    return uprv_strcmp(getIdentifier(), rhs.getIdentifier()) == 0;
 }
 
 int32_t MeasureUnit::getIndex() const {
index 86453302b1e4074b6c5205416360d0270ded4ba6..83257fbcf56969011ea2b7603e157f5499b9e737 100644 (file)
@@ -88,6 +88,7 @@ const struct SIPrefixStrings {
 
 // FIXME: Get this list from data
 const char16_t* const gSimpleUnits[] = {
+    u"one", // note: expected to be index 0
     u"100kilometer",
     u"acre",
     u"ampere",
@@ -262,6 +263,7 @@ public:
         TYPE_SI_PREFIX,
         TYPE_COMPOUND_PART,
         TYPE_POWER_PART,
+        TYPE_ONE,
         TYPE_SIMPLE_UNIT,
     };
 
@@ -274,6 +276,8 @@ public:
             return TYPE_COMPOUND_PART;
         } else if (fMatch < kSimpleUnitOffset) {
             return TYPE_POWER_PART;
+        } else if (fMatch == kSimpleUnitOffset) {
+            return TYPE_ONE;
         } else {
             return TYPE_SIMPLE_UNIT;
         }
@@ -285,14 +289,17 @@ public:
     }
 
     int32_t getMatch() const {
+        U_ASSERT(getType() == TYPE_COMPOUND_PART);
         return fMatch;
     }
 
     int8_t getPower() const {
+        U_ASSERT(getType() == TYPE_POWER_PART);
         return static_cast<int8_t>(fMatch - kPowerPartOffset);
     }
 
     int32_t getSimpleUnitOffset() const {
+        U_ASSERT(getType() == TYPE_SIMPLE_UNIT);
         return fMatch - kSimpleUnitOffset;
     }
 
@@ -302,11 +309,10 @@ private:
 
 struct PowerUnit {
     int8_t power = 0;
-    bool plus = false;
     UMeasureSIPrefix siPrefix = UMEASURE_SI_PREFIX_ONE;
     StringPiece id;
 
-    void toString(CharString& builder, UErrorCode& status) {
+    void appendTo(CharString& builder, UErrorCode& status) {
         if (power == 0) {
             // no-op
         } else if (power == 1) {
@@ -348,50 +354,22 @@ struct PowerUnit {
 class UnitIdentifierParser {
 public:
     static UnitIdentifierParser from(StringPiece source, UErrorCode& status) {
+        if (U_FAILURE(status)) {
+            return UnitIdentifierParser();
+        }
         umtx_initOnce(gUnitExtrasInitOnce, &initUnitExtras, status);
         if (U_FAILURE(status)) {
             return UnitIdentifierParser();
         }
         return UnitIdentifierParser(source);
     }
-    
-    Token nextToken(UErrorCode& status) {
-        fTrie.reset();
-        int32_t match = -1;
-        int32_t previ = -1;
-        do {
-            fTrie.next(fSource.data()[fIndex++]);
-            if (fTrie.current() == USTRINGTRIE_NO_MATCH) {
-                break;
-            } else if (fTrie.current() == USTRINGTRIE_NO_VALUE) {
-                continue;
-            } else if (fTrie.current() == USTRINGTRIE_FINAL_VALUE) {
-                match = fTrie.getValue();
-                previ = fIndex;
-                break;
-            } else if (fTrie.current() == USTRINGTRIE_INTERMEDIATE_VALUE) {
-                match = fTrie.getValue();
-                previ = fIndex;
-                continue;
-            } else {
-                UPRV_UNREACHABLE;
-            }
-        } while (fIndex < fSource.length());
-
-        if (match < 0) {
-            // TODO: Make a new status code?
-            status = U_ILLEGAL_ARGUMENT_ERROR;
-        } else {
-            fIndex = previ;
-        }
-        return Token(match);
-    }
 
     bool hasNext() const {
         return fIndex < fSource.length();
     }
 
-    PowerUnit nextUnit(UErrorCode& status) {
+    PowerUnit nextUnit(bool& sawPlus, UErrorCode& status) {
+        sawPlus = false;
         PowerUnit retval;
         if (U_FAILURE(status)) {
             return retval;
@@ -405,7 +383,7 @@ public:
         int32_t previ = fIndex;
 
         // Maybe read a compound part
-        if (!fExpectingUnit) {
+        if (fIndex != 0) {
             Token token = nextToken(status);
             if (U_FAILURE(status)) {
                 return retval;
@@ -425,7 +403,7 @@ public:
                     break;
 
                 case COMPOUND_PART_PLUS:
-                    retval.plus = true;
+                    sawPlus = true;
                     fAfterPer = false;
                     break;
             }
@@ -461,10 +439,11 @@ public:
                     state = 2;
                     break;
 
+                case Token::TYPE_ONE:
+                    // Skip "one" and go to the next unit
+                    return nextUnit(sawPlus, status);
+
                 case Token::TYPE_SIMPLE_UNIT:
-                    if (state > 2) {
-                        goto fail;
-                    }
                     retval.id = fSource.substr(previ, fIndex - previ);
                     return retval;
 
@@ -473,14 +452,24 @@ public:
             }
         }
 
-    fail:
-        // TODO: Make a new status code?
-        status = U_ILLEGAL_ARGUMENT_ERROR;
-        return retval;
+        fail:
+            // TODO: Make a new status code?
+            status = U_ILLEGAL_ARGUMENT_ERROR;
+            return retval;
     }
 
-    int32_t currentIndex() const {
-        return fIndex;
+    PowerUnit getOnlyUnit(UErrorCode& status) {
+        bool sawPlus;
+        PowerUnit retval = nextUnit(sawPlus, status);
+        if (U_FAILURE(status)) {
+            return retval;
+        }
+        if (sawPlus || hasNext()) {
+            // Expected to find only one unit in the string
+            status = U_ILLEGAL_ARGUMENT_ERROR;
+            return retval;
+        }
+        return retval;
     }
 
 private:
@@ -489,12 +478,43 @@ private:
     UCharsTrie fTrie;
 
     bool fAfterPer = false;
-    bool fExpectingUnit = true;
 
     UnitIdentifierParser() : fSource(""), fTrie(u"") {}
 
     UnitIdentifierParser(StringPiece source)
         : fSource(source), fTrie(kSerializedUnitExtrasStemTrie) {}
+
+    Token nextToken(UErrorCode& status) {
+        fTrie.reset();
+        int32_t match = -1;
+        int32_t previ = -1;
+        do {
+            fTrie.next(fSource.data()[fIndex++]);
+            if (fTrie.current() == USTRINGTRIE_NO_MATCH) {
+                break;
+            } else if (fTrie.current() == USTRINGTRIE_NO_VALUE) {
+                continue;
+            } else if (fTrie.current() == USTRINGTRIE_FINAL_VALUE) {
+                match = fTrie.getValue();
+                previ = fIndex;
+                break;
+            } else if (fTrie.current() == USTRINGTRIE_INTERMEDIATE_VALUE) {
+                match = fTrie.getValue();
+                previ = fIndex;
+                continue;
+            } else {
+                UPRV_UNREACHABLE;
+            }
+        } while (fIndex < fSource.length());
+
+        if (match < 0) {
+            // TODO: Make a new status code?
+            status = U_ILLEGAL_ARGUMENT_ERROR;
+        } else {
+            fIndex = previ;
+        }
+        return Token(match);
+    }
 };
 
 } // namespace
@@ -507,62 +527,71 @@ MeasureUnit MeasureUnit::forIdentifier(const char* identifier, UErrorCode& statu
         return MeasureUnit();
     }
 
+    CharString builder;
+    bool afterPer = false;
     while (parser.hasNext()) {
-        parser.nextToken(status);
+        bool sawPlus;
+        PowerUnit powerUnit = parser.nextUnit(sawPlus, status);
         if (U_FAILURE(status)) {
             // Invalid syntax
             return MeasureUnit();
         }
+
+        if (sawPlus) {
+            builder.append('+', status);
+            afterPer = false;
+        }
+        if (powerUnit.power < 0 && !afterPer) {
+            if (builder.length() == 0 || sawPlus) {
+                builder.append("one", status);
+            }
+            builder.append("-per-", status);
+            powerUnit.power *= -1;
+        }
+        powerUnit.appendTo(builder, status);
     }
 
     // Success
-    return MeasureUnit(uprv_strdup(identifier));
+    return MeasureUnit(builder.cloneData(status));
 }
 
-UMeasureSIPrefix MeasureUnit::getSIPrefix() const {
-    ErrorCode status;
-    const char* id = toString();
-    return UnitIdentifierParser::from(id, status).nextUnit(status).siPrefix;
+UMeasureSIPrefix MeasureUnit::getSIPrefix(UErrorCode& status) const {
+    const char* id = getIdentifier();
+    return UnitIdentifierParser::from(id, status).getOnlyUnit(status).siPrefix;
 }
 
-MeasureUnit MeasureUnit::withSIPrefix(UMeasureSIPrefix prefix) const {
-    ErrorCode status;
-    const char* id = toString();
-    UnitIdentifierParser parser = UnitIdentifierParser::from(id, status);
-    PowerUnit powerUnit = parser.nextUnit(status);
-    if (status.isFailure()) {
+MeasureUnit MeasureUnit::withSIPrefix(UMeasureSIPrefix prefix, UErrorCode& status) const {
+    const char* id = getIdentifier();
+    PowerUnit powerUnit = UnitIdentifierParser::from(id, status).getOnlyUnit(status);
+    if (U_FAILURE(status)) {
         return *this;
     }
 
     powerUnit.siPrefix = prefix;
     CharString builder;
-    powerUnit.toString(builder, status);
+    powerUnit.appendTo(builder, status);
     return MeasureUnit(builder.cloneData(status));
 }
 
-int8_t MeasureUnit::getPower() const {
-    ErrorCode status;
-    const char* id = toString();
-    return UnitIdentifierParser::from(id, status).nextUnit(status).power;
+int8_t MeasureUnit::getPower(UErrorCode& status) const {
+    const char* id = getIdentifier();
+    return UnitIdentifierParser::from(id, status).getOnlyUnit(status).power;
 }
 
-MeasureUnit MeasureUnit::withPower(int8_t power) const {
-    if (power < 0) {
-        // Don't know how to handle this yet
-        U_ASSERT(FALSE);
-    }
-
-    ErrorCode status;
-    const char* id = toString();
-    UnitIdentifierParser parser = UnitIdentifierParser::from(id, status);
-    PowerUnit powerUnit = parser.nextUnit(status);
-    if (status.isFailure()) {
+MeasureUnit MeasureUnit::withPower(int8_t power, UErrorCode& status) const {
+    const char* id = getIdentifier();
+    PowerUnit powerUnit = UnitIdentifierParser::from(id, status).getOnlyUnit(status);
+    if (U_FAILURE(status)) {
         return *this;
     }
 
-    powerUnit.power = power;
     CharString builder;
-    powerUnit.toString(builder, status);
+    if (power < 0) {
+        builder.append("one-per-", status);
+        power *= -1;
+    }
+    powerUnit.power = power;
+    powerUnit.appendTo(builder, status);
     return MeasureUnit(builder.cloneData(status));
 }
 
index 466460b02a06eb5baf3fd5e4bbb96e70d89f4a57..8ed893190ab9193b28860f4d806b57ee05ec0d56 100644 (file)
@@ -293,7 +293,7 @@ class U_I18N_API MeasureUnit: public UObject {
      * @return The string form of this unit, owned by this MeasureUnit.
      * @draft ICU 67
      */
-    const char* toString() const;
+    const char* getIdentifier() const;
 
     /**
      * Creates a MeasureUnit which is this MeasureUnit augmented with the specified SI prefix.
@@ -301,14 +301,14 @@ class U_I18N_API MeasureUnit: public UObject {
      *
      * There is sufficient locale data to format all standard SI prefixes.
      *
-     * If the MeasureUnit is composed of multiple simple units, only the first simple unit is
-     * modified. For example, starting at "meter-kilogram-per-second", if you set the SI prefix
-     * to "centi", then you get "centimeter-kilogram-per-second".
+     * This method only works if the MeasureUnit is composed of only one simple unit. An error
+     * will be set if called on a MeasureUnit containing multiple units.
      *
      * @param prefix The SI prefix, from UMeasureSIPrefix.
+     * @param status ICU error code
      * @return A new MeasureUnit.
      */
-    MeasureUnit withSIPrefix(UMeasureSIPrefix prefix) const;
+    MeasureUnit withSIPrefix(UMeasureSIPrefix prefix, UErrorCode& status) const;
 
     /**
      * Gets the current SI prefix of this MeasureUnit. For example, if the unit has the SI prefix
@@ -320,20 +320,20 @@ class U_I18N_API MeasureUnit: public UObject {
      *
      * @return The SI prefix of the first simple unit, from UMeasureSIPrefix.
      */
-    UMeasureSIPrefix getSIPrefix() const;
+    UMeasureSIPrefix getSIPrefix(UErrorCode& status) const;
 
     /**
      * Creates a MeasureUnit which is this MeasureUnit augmented with the specified power. For
      * example, if power is 2, the unit will be squared.
      *
-     * If the MeasureUnit is composed of multiple simple units, only the first simple unit is
-     * modified. For example, starting at "meter-kilogram-per-second", if you set the power to 2,
-     * then you get "square-meter-kilogram-per-second".
+     * This method only works if the MeasureUnit is composed of only one simple unit. An error
+     * will be set if called on a MeasureUnit containing multiple units.
      *
      * @param power The power.
+     * @param status ICU error code
      * @return A new MeasureUnit.
      */
-    MeasureUnit withPower(int8_t power) const;
+    MeasureUnit withPower(int8_t power, UErrorCode& status) const;
 
     /**
      * Gets the power of this MeasureUnit. For example, if the unit is square, then 2 is returned.
@@ -343,7 +343,7 @@ class U_I18N_API MeasureUnit: public UObject {
      *
      * @return The power of the first simple unit.
      */
-    int8_t getPower() const;
+    int8_t getPower(UErrorCode& status) const;
 
     /**
      * Gets the reciprocal of the unit, with the numerator and denominator flipped.
@@ -352,7 +352,7 @@ class U_I18N_API MeasureUnit: public UObject {
      *
      * @return The reciprocal of the target unit.
      */
-    MeasureUnit reciprocal() const;
+    MeasureUnit reciprocal(UErrorCode& status) const;
 
     /**
      * Gets the product of this unit with another unit. This is a way to build units from
@@ -365,7 +365,7 @@ class U_I18N_API MeasureUnit: public UObject {
      *
      * @return The product of the target unit with the provided unit.
      */
-    MeasureUnit product(const MeasureUnit& other) const;
+    MeasureUnit product(const MeasureUnit& other, UErrorCode& status) const;
 
     /**
      * Gets the number of constituent simple units.
@@ -375,7 +375,7 @@ class U_I18N_API MeasureUnit: public UObject {
      *
      * @return The number of constituent units.
      */
-    size_t getSimpleUnitCount() const;
+    size_t getSimpleUnitCount(UErrorCode& status) const;
 
     /**
      * Gets the constituent unit at the given index.
@@ -394,7 +394,7 @@ class U_I18N_API MeasureUnit: public UObject {
      * @param index Zero-based index. If out of range, the dimensionless unit is returned.
      * @return The constituent simple unit at the specified position.
      */
-    MeasureUnit simpleUnitAt(size_t index) const;
+    MeasureUnit simpleUnitAt(size_t index, UErrorCode& status) const;
 
     /**
      * Composes this unit with a super unit.
@@ -413,7 +413,7 @@ class U_I18N_API MeasureUnit: public UObject {
      * @param other The super unit to compose with the target unit.
      * @return The composition of the given super unit with this unit.
      */
-    MeasureUnit withSuperUnit(const MeasureUnit& other) const;
+    MeasureUnit withSuperUnit(const MeasureUnit& other, UErrorCode& status) const;
 
     /**
      * Gets the number of super units in the receiver.
@@ -422,7 +422,7 @@ class U_I18N_API MeasureUnit: public UObject {
      *
      * @return The number of super units.
      */
-    size_t getSuperUnitCount() const;
+    size_t getSuperUnitCount(UErrorCode& status) const;
 
     /**
      * Gets the super unit at the given index.
@@ -440,7 +440,7 @@ class U_I18N_API MeasureUnit: public UObject {
      *
      * @return The super unit at the specified position.
      */
-    MeasureUnit superUnitAt(size_t index) const;
+    MeasureUnit superUnitAt(size_t index, UErrorCode& status) const;
 
     /**
      * getAvailable gets all of the available units.
index 94a499e73a4d30e0aca2d6a8b387d0faa6c596ac..27ed41b9590dfe734cdba16bff46eff7d9118b52 100644 (file)
@@ -188,6 +188,7 @@ void MeasureFormatTest::runIndexedTest(
     TESTCASE_AUTO(Test20332_PersonUnits);
     TESTCASE_AUTO(TestNumericTime);
     TESTCASE_AUTO(TestNumericTimeSomeSpecialFormats);
+    TESTCASE_AUTO(TestCompoundUnitOperations);
     TESTCASE_AUTO_END;
 }
 
@@ -3224,64 +3225,69 @@ void MeasureFormatTest::TestNumericTimeSomeSpecialFormats() {
 void MeasureFormatTest::TestCompoundUnitOperations() {
     IcuTestErrorCode status(*this, "TestCompoundUnitOperations");
 
+    MeasureUnit::forIdentifier("kilometer-per-second-joule", status);
+
     MeasureUnit kilometer = MeasureUnit::getKilometer();
-    MeasureUnit meter = kilometer.withSIPrefix(UMEASURE_SI_PREFIX_ONE);
-    MeasureUnit centimeter1 = kilometer.withSIPrefix(UMEASURE_SI_PREFIX_CENTI);
-    MeasureUnit centimeter2 = meter.withSIPrefix(UMEASURE_SI_PREFIX_CENTI);
+    MeasureUnit cubicMeter = MeasureUnit::getCubicMeter();
+    MeasureUnit meter = kilometer.withSIPrefix(UMEASURE_SI_PREFIX_ONE, status);
+    MeasureUnit centimeter1 = kilometer.withSIPrefix(UMEASURE_SI_PREFIX_CENTI, status);
+    MeasureUnit centimeter2 = meter.withSIPrefix(UMEASURE_SI_PREFIX_CENTI, status);
+    MeasureUnit cubicDecimeter = cubicMeter.withSIPrefix(UMEASURE_SI_PREFIX_DECI, status);
 
     verifyUnitParts(kilometer, UMEASURE_SI_PREFIX_KILO, 0, "kilometer");
     verifyUnitParts(meter, UMEASURE_SI_PREFIX_ONE, 0, "meter");
     verifyUnitParts(centimeter1, UMEASURE_SI_PREFIX_CENTI, 0, "centimeter");
     verifyUnitParts(centimeter2, UMEASURE_SI_PREFIX_CENTI, 0, "centimeter");
+    verifyUnitParts(cubicDecimeter, UMEASURE_SI_PREFIX_DECI, 3, "cubic-decimeter");
 
     assertTrue("centimeter equality", centimeter1 == centimeter2);
     assertTrue("kilometer inequality", centimeter1 != kilometer);
 
-    MeasureUnit squareMeter = meter.withPower(2);
-    MeasureUnit overCubicCentimeter = centimeter1.withPower(-3);
-    MeasureUnit quarticKilometer = kilometer.withPower(4);
-    MeasureUnit overQuarticKilometer1 = kilometer.withPower(-4);
+    MeasureUnit squareMeter = meter.withPower(2, status);
+    MeasureUnit overCubicCentimeter = centimeter1.withPower(-3, status);
+    MeasureUnit quarticKilometer = kilometer.withPower(4, status);
+    MeasureUnit overQuarticKilometer1 = kilometer.withPower(-4, status);
 
     verifyUnitParts(squareMeter, UMEASURE_SI_PREFIX_ONE, 2, "square-meter");
-    verifyUnitParts(overCubicCentimeter, UMEASURE_SI_PREFIX_CENTI, 2, "one-per-cubic-centimeter");
-    verifyUnitParts(quarticKilometer, UMEASURE_SI_PREFIX_ONE, 2, "p4-kilometer");
-    verifyUnitParts(overQuarticKilometer1, UMEASURE_SI_PREFIX_ONE, 2, "one-per-p4-kilometer");
-
-    assertTrue("power inequality", quarticKilometer != overQuarticKilometer1);
-
-    MeasureUnit overQuarticKilometer2 = overQuarticKilometer1.reciprocal();
-    MeasureUnit overQuarticKilometer3 = kilometer.product(kilometer).product(kilometer)
-        .product(kilometer).reciprocal();
-
-    verifyUnitParts(overQuarticKilometer2, UMEASURE_SI_PREFIX_ONE, 2, "one-per-p4-kilometer");
-    verifyUnitParts(overQuarticKilometer3, UMEASURE_SI_PREFIX_ONE, 2, "one-per-p4-kilometer");
-
-    assertTrue("reciprocal equality", overQuarticKilometer1 == overQuarticKilometer2);
-    assertTrue("reciprocal equality", overQuarticKilometer1 == overQuarticKilometer3);
-
-    MeasureUnit kiloSquareSecond = MeasureUnit::getSecond()
-        .withPower(2).withSIPrefix(UMEASURE_SI_PREFIX_KILO);
-    MeasureUnit meterSecond = meter.product(kiloSquareSecond);
-    MeasureUnit cubicMeterSecond1 = meter.withPower(3).product(kiloSquareSecond);
-    MeasureUnit cubicMeterSecond2 = meterSecond.withPower(3);
-    MeasureUnit centimeterSecond1 = meter.withSIPrefix(UMEASURE_SI_PREFIX_CENTI).product(kiloSquareSecond);
-    MeasureUnit centimeterSecond2 = meterSecond.withSIPrefix(UMEASURE_SI_PREFIX_CENTI);
-    MeasureUnit secondCubicMeter = kiloSquareSecond.product(meter.withPower(3));
-    MeasureUnit secondCentimeter = kiloSquareSecond.product(meter.withSIPrefix(UMEASURE_SI_PREFIX_CENTI));
-
-    verifyUnitParts(kiloSquareSecond, UMEASURE_SI_PREFIX_KILO, 2, "square-kilosecond");
-    verifyUnitParts(meterSecond, UMEASURE_SI_PREFIX_ONE, 0, "meter-square-kilosecond");
-    verifyUnitParts(cubicMeterSecond1, UMEASURE_SI_PREFIX_ONE, 2, "cubic-meter-square-kilosecond");
-    verifyUnitParts(cubicMeterSecond2, UMEASURE_SI_PREFIX_ONE, 2, "cubic-meter-square-kilosecond");
-    verifyUnitParts(centimeterSecond1, UMEASURE_SI_PREFIX_CENTI, 0, "centimeter-square-kilosecond");
-    verifyUnitParts(centimeterSecond2, UMEASURE_SI_PREFIX_CENTI, 0, "centimeter-square-kilosecond");
-    verifyUnitParts(secondCubicMeter, UMEASURE_SI_PREFIX_KILO, 2, "square-kilosecond-cubic-meter");
-    verifyUnitParts(secondCentimeter, UMEASURE_SI_PREFIX_KILO, 2, "square-kilosecond-centimeter");
-
-    assertTrue("multipart power equality", cubicMeterSecond1 == cubicMeterSecond2);
-    assertTrue("multipart SI prefix equality", centimeterSecond1 == centimeterSecond2);
-    assertTrue("order matters inequality", cubicMeterSecond1 != secondCubicMeter);
-    assertTrue("additional simple units inequality", secondCubicMeter != secondCentimeter);
+    verifyUnitParts(overCubicCentimeter, UMEASURE_SI_PREFIX_CENTI, -3, "one-per-cubic-centimeter");
+    verifyUnitParts(quarticKilometer, UMEASURE_SI_PREFIX_KILO, 4, "p4-kilometer");
+    verifyUnitParts(overQuarticKilometer1, UMEASURE_SI_PREFIX_KILO, -4, "one-per-p4-kilometer");
+
+    // assertTrue("power inequality", quarticKilometer != overQuarticKilometer1);
+
+    // MeasureUnit overQuarticKilometer2 = overQuarticKilometer1.reciprocal();
+    // MeasureUnit overQuarticKilometer3 = kilometer.product(kilometer).product(kilometer)
+    //     .product(kilometer).reciprocal();
+
+    // verifyUnitParts(overQuarticKilometer2, UMEASURE_SI_PREFIX_KILO, 2, "one-per-p4-kilometer");
+    // verifyUnitParts(overQuarticKilometer3, UMEASURE_SI_PREFIX_KILO, 2, "one-per-p4-kilometer");
+
+    // assertTrue("reciprocal equality", overQuarticKilometer1 == overQuarticKilometer2);
+    // assertTrue("reciprocal equality", overQuarticKilometer1 == overQuarticKilometer3);
+
+    // MeasureUnit kiloSquareSecond = MeasureUnit::getSecond()
+    //     .withPower(2).withSIPrefix(UMEASURE_SI_PREFIX_KILO);
+    // MeasureUnit meterSecond = meter.product(kiloSquareSecond);
+    // MeasureUnit cubicMeterSecond1 = meter.withPower(3).product(kiloSquareSecond);
+    // MeasureUnit cubicMeterSecond2 = meterSecond.withPower(3);
+    // MeasureUnit centimeterSecond1 = meter.withSIPrefix(UMEASURE_SI_PREFIX_CENTI).product(kiloSquareSecond);
+    // MeasureUnit centimeterSecond2 = meterSecond.withSIPrefix(UMEASURE_SI_PREFIX_CENTI);
+    // MeasureUnit secondCubicMeter = kiloSquareSecond.product(meter.withPower(3));
+    // MeasureUnit secondCentimeter = kiloSquareSecond.product(meter.withSIPrefix(UMEASURE_SI_PREFIX_CENTI));
+
+    // verifyUnitParts(kiloSquareSecond, UMEASURE_SI_PREFIX_KILO, 2, "square-kilosecond");
+    // verifyUnitParts(meterSecond, UMEASURE_SI_PREFIX_ONE, 0, "meter-square-kilosecond");
+    // verifyUnitParts(cubicMeterSecond1, UMEASURE_SI_PREFIX_ONE, 2, "cubic-meter-square-kilosecond");
+    // verifyUnitParts(cubicMeterSecond2, UMEASURE_SI_PREFIX_ONE, 2, "cubic-meter-square-kilosecond");
+    // verifyUnitParts(centimeterSecond1, UMEASURE_SI_PREFIX_CENTI, 0, "centimeter-square-kilosecond");
+    // verifyUnitParts(centimeterSecond2, UMEASURE_SI_PREFIX_CENTI, 0, "centimeter-square-kilosecond");
+    // verifyUnitParts(secondCubicMeter, UMEASURE_SI_PREFIX_KILO, 2, "square-kilosecond-cubic-meter");
+    // verifyUnitParts(secondCentimeter, UMEASURE_SI_PREFIX_KILO, 2, "square-kilosecond-centimeter");
+
+    // assertTrue("multipart power equality", cubicMeterSecond1 == cubicMeterSecond2);
+    // assertTrue("multipart SI prefix equality", centimeterSecond1 == centimeterSecond2);
+    // assertTrue("order matters inequality", cubicMeterSecond1 != secondCubicMeter);
+    // assertTrue("additional simple units inequality", secondCubicMeter != secondCentimeter);
 }
 
 
@@ -3361,10 +3367,17 @@ void MeasureFormatTest::verifyUnitParts(
         int8_t power,
         const char* identifier) {
     IcuTestErrorCode status(*this, "verifyUnitParts");
-    assertEquals(UnicodeString(identifier) + ": SI prefix", siPrefix, unit.getSIPrefix());
-    assertEquals(UnicodeString(identifier) + ": Power", power, unit.getPower());
-    assertEquals(UnicodeString(identifier) + ": Identifier", identifier, unit.toString());
-    assertTrue(UnicodeString(identifier) + ": Constructor", unit == MeasureUnit::forIdentifier(identifier, status));
+    assertEquals(UnicodeString(identifier) + ": SI prefix",
+        siPrefix,
+        unit.getSIPrefix(status));
+    assertEquals(UnicodeString(identifier) + ": Power",
+        static_cast<int32_t>(power),
+        static_cast<int32_t>(unit.getPower(status)));
+    assertEquals(UnicodeString(identifier) + ": Identifier",
+        identifier,
+        unit.getIdentifier());
+    assertTrue(UnicodeString(identifier) + ": Constructor",
+        unit == MeasureUnit::forIdentifier(identifier, status));
 }
 
 extern IntlTest *createMeasureFormatTest() {