]> granicus.if.org Git - icu/commitdiff
ICU-7912 C wrapper for Formattable - UFormattable
authorSteven R. Loomis <srl@icu-project.org>
Wed, 26 Jun 2013 06:31:09 +0000 (06:31 +0000)
committerSteven R. Loomis <srl@icu-project.org>
Wed, 26 Jun 2013 06:31:09 +0000 (06:31 +0000)
X-SVN-Rev: 33849

icu4c/source/i18n/fmtable.cpp
icu4c/source/i18n/i18n.vcxproj
icu4c/source/i18n/unicode/fmtable.h
icu4c/source/i18n/unicode/uformattable.h [new file with mode: 0644]
icu4c/source/test/intltest/intltest.cpp
icu4c/source/test/intltest/intltest.h
icu4c/source/test/intltest/numfmtst.cpp
icu4c/source/test/intltest/numfmtst.h

index 274b3d782d069f3e1450efb866d2e32b496cb8f6..4e2eedbcf0446812aa67a52482e104e189da6a5c 100644 (file)
@@ -1,6 +1,6 @@
 /*
 *******************************************************************************
-* Copyright (C) 1997-2012, International Business Machines Corporation and    *
+* Copyright (C) 1997-2013, International Business Machines Corporation and    *
 * others. All Rights Reserved.                                                *
 *******************************************************************************
 *
@@ -22,6 +22,7 @@
 #include "unicode/ustring.h"
 #include "unicode/measure.h"
 #include "unicode/curramt.h"
+#include "unicode/uformattable.h"
 #include "charstr.h"
 #include "cmemory.h"
 #include "cstring.h"
@@ -695,46 +696,56 @@ StringPiece Formattable::getDecimalNumber(UErrorCode &status) {
         return "";
     }
     if (fDecimalStr != NULL) {
-        return fDecimalStr->toStringPiece();
+      return fDecimalStr->toStringPiece();
     }
 
-    if (fDecimalNum == NULL) {
+    CharString *decimalStr = internalGetCharString(status);
+    if(decimalStr == NULL) {
+      return ""; // getDecimalNumber returns "" for error cases
+    } else {
+      return decimalStr->toStringPiece();
+    }
+}
+
+CharString *Formattable::internalGetCharString(UErrorCode &status) {
+    if(fDecimalStr == NULL) {
+      if (fDecimalNum == NULL) {
         // No decimal number for the formattable yet.  Which means the value was
         // set directly by the user as an int, int64 or double.  If the value came
         // from parsing, or from the user setting a decimal number, fDecimalNum
         // would already be set.
         //
-      fDecimalNum = new DigitList; // TODO: use internal digit list
+        fDecimalNum = new DigitList; // TODO: use internal digit list
         if (fDecimalNum == NULL) {
-            status = U_MEMORY_ALLOCATION_ERROR;
-            return "";
+          status = U_MEMORY_ALLOCATION_ERROR;
+          return NULL;
         }
 
         switch (fType) {
         case kDouble:
-            fDecimalNum->set(this->getDouble());
-            break;
+          fDecimalNum->set(this->getDouble());
+          break;
         case kLong:
-            fDecimalNum->set(this->getLong());
-            break;
+          fDecimalNum->set(this->getLong());
+          break;
         case kInt64:
-            fDecimalNum->set(this->getInt64());
-            break;
+          fDecimalNum->set(this->getInt64());
+          break;
         default:
-            // The formattable's value is not a numeric type.
-            status = U_INVALID_STATE_ERROR;
-            return "";
+          // The formattable's value is not a numeric type.
+          status = U_INVALID_STATE_ERROR;
+          return NULL;
         }
-    }
+      }
 
-    fDecimalStr = new CharString;
-    if (fDecimalStr == NULL) {
+      fDecimalStr = new CharString;
+      if (fDecimalStr == NULL) {
         status = U_MEMORY_ALLOCATION_ERROR;
-        return "";
+        return NULL;
+      }
+      fDecimalNum->getDecimal(*fDecimalStr, status);
     }
-    fDecimalNum->getDecimal(*fDecimalStr, status);
-
-    return fDecimalStr->toStringPiece();
+    return fDecimalStr;
 }
 
 
@@ -882,6 +893,197 @@ FormattableStreamer::streamOut(ostream& stream, const Formattable& obj)
 
 #endif
 
+/* ---- UFormattable stuff ---- */
+
+
+U_DRAFT UFormattable* U_EXPORT2
+ufmt_open(UErrorCode *status) {
+  if( U_FAILURE(*status) ) {
+    return NULL;
+  }
+  UFormattable *fmt = (new Formattable())->toUFormattable();
+
+  if( fmt == NULL ) {
+    *status = U_MEMORY_ALLOCATION_ERROR;
+  }
+  return fmt;
+}
+
+U_DRAFT void U_EXPORT2
+ufmt_close(UFormattable *fmt) {
+  Formattable *obj = Formattable::fromUFormattable(fmt);
+
+  delete obj;
+}
+
+U_INTERNAL UFormattableType U_EXPORT2
+ufmt_getType(UFormattable *fmt, UErrorCode *status) {
+  if(U_FAILURE(*status)) {
+    return (UFormattableType)-1;
+  }
+  Formattable *obj = Formattable::fromUFormattable(fmt);
+  switch( obj->getType() ) {
+  case Formattable::kDate:
+    return UFMT_DATE;
+    break;
+  case Formattable::kDouble:
+    return UFMT_DOUBLE;
+    break;
+  case Formattable::kLong:
+    return UFMT_LONG;
+    break;
+  case Formattable::kString:
+    return UFMT_STRING;
+    break;
+  case Formattable::kArray:
+    return UFMT_ARRAY;
+    break;
+  case Formattable::kInt64:
+    return UFMT_INT64;
+    break;
+  case Formattable::kObject:
+    return UFMT_OBJECT;
+    break;
+  default:
+    *status = U_ILLEGAL_ARGUMENT_ERROR;
+    return (UFormattableType)-1; // invalid
+  }
+}
+
+
+U_INTERNAL UBool U_EXPORT2
+ufmt_isNumeric(UFormattable *fmt) {
+  Formattable *obj = Formattable::fromUFormattable(fmt);
+  return obj->isNumeric();
+}
+
+U_DRAFT UDate U_EXPORT2
+ufmt_getDate(UFormattable *fmt, UErrorCode *status) {
+  Formattable *obj = Formattable::fromUFormattable(fmt);
+
+  return obj->getDate(*status);
+}
+
+U_DRAFT double U_EXPORT2
+ufmt_getDouble(UFormattable *fmt, UErrorCode *status) {
+  Formattable *obj = Formattable::fromUFormattable(fmt);
+
+  return obj->getDouble(*status);
+}
+
+U_DRAFT int32_t U_EXPORT2
+ufmt_getLong(UFormattable *fmt, UErrorCode *status) {
+  Formattable *obj = Formattable::fromUFormattable(fmt);
+
+  return obj->getLong(*status);
+}
+
+
+U_DRAFT const void *U_EXPORT2
+ufmt_getObject(UFormattable *fmt, UErrorCode *status) {
+  Formattable *obj = Formattable::fromUFormattable(fmt);
+
+  const void *ret = obj->getObject();
+  if( ret==NULL &&
+      (obj->getType() != Formattable::kObject) &&
+      U_SUCCESS( *status )) {
+    *status = U_INVALID_FORMAT_ERROR;
+  }
+  return ret;
+}
+
+U_DRAFT const UChar* U_EXPORT2
+ufmt_getUChars(UFormattable *fmt, int32_t *len, UErrorCode *status) {
+  Formattable *obj = Formattable::fromUFormattable(fmt);
+
+  // avoid bogosity by checking the type first.
+  if( obj->getType() != Formattable::kString ) {
+    if( U_SUCCESS(*status) ){
+      *status = U_INVALID_FORMAT_ERROR;
+    }
+    return NULL;
+  }
+
+  // This should return a valid string
+  UnicodeString &str = obj->getString(*status);
+  if( U_SUCCESS(*status) && len != NULL ) {
+    *len = str.length();
+  }
+  return str.getTerminatedBuffer();
+}
+
+U_DRAFT int32_t U_EXPORT2
+ufmt_getArrayLength(UFormattable* fmt, UErrorCode *status) {
+  Formattable *obj = Formattable::fromUFormattable(fmt);
+
+  int32_t count;
+  (void)obj->getArray(count, *status);
+  return count;
+}
+
+U_DRAFT UFormattable * U_EXPORT2
+ufmt_getArrayItemByIndex(UFormattable* fmt, int32_t n, UErrorCode *status) {
+  Formattable *obj = Formattable::fromUFormattable(fmt);
+  int32_t count;
+  (void)obj->getArray(count, *status);
+  if(U_FAILURE(*status)) {
+    return NULL;
+  } else if(n<0 || n>=count) {
+    setError(*status, U_INDEX_OUTOFBOUNDS_ERROR);
+    return NULL;
+  } else {
+    return (*obj)[n].toUFormattable(); // returns non-const Formattable
+  }
+}
+
+U_DRAFT const char * U_EXPORT2
+ufmt_getDecNumChars(UFormattable *fmt, int32_t *len, UErrorCode *status) {
+  if(U_FAILURE(*status)) {
+    return "";
+  }
+  Formattable *obj = Formattable::fromUFormattable(fmt);
+  CharString *charString = obj->internalGetCharString(*status);
+  if(U_FAILURE(*status)) {
+    return "";
+  }
+  if(charString == NULL) {
+    *status = U_MEMORY_ALLOCATION_ERROR;
+    return "";
+  } else {
+    if(len!=NULL) {
+      *len = charString->length();
+    }
+    return charString->data();
+  }
+}
+
+// make-a-copy version
+// U_DRAFT int32_t U_EXPORT2
+// ufmt_getDecNumChars(UFormattable *fmt, char *buf, int32_t len, UErrorCode *status) {
+//   if(U_FAILURE(*status)) {
+//     return 0;
+//   }
+//   Formattable *obj = Formattable::fromUFormattable(fmt);
+//   CharString *charString = obj->internalGetCharString(*status);
+//   if(U_FAILURE(*status)) {
+//     return 0;
+//   }
+//   if(charString == NULL) {
+//     *status = U_MEMORY_ALLOCATION_ERROR;
+//     return 0;
+//   } else {
+//     return charString->extract(buf, len, *status);
+//   }
+// }
+
+
+U_DRAFT int64_t U_EXPORT2
+ufmt_getInt64(UFormattable *fmt, UErrorCode *status) {
+  Formattable *obj = Formattable::fromUFormattable(fmt);
+  return obj->getInt64(*status);
+}
+
+
 U_NAMESPACE_END
 
 #endif /* #if !UCONFIG_NO_FORMATTING */
index 0b3598e8f2175aec6a7645bf197e43a4015cc8c9..fc33d41529b013b290dde94cbb568e5729c11c06 100644 (file)
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>\r
+<?xml version="1.0" encoding="utf-8"?>\r
 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">\r
   <ItemGroup Label="ProjectConfigurations">\r
     <ProjectConfiguration Include="Debug|Win32">\r
 </Command>\r
       <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>\r
       <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode\r
+</Command>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>\r
+    </CustomBuild>\r
+    <CustomBuild Include="unicode\uformattable.h">\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">copy "%(FullPath)" ..\..\include\unicode\r
+</Command>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">copy "%(FullPath)" ..\..\include\unicode\r
+</Command>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">copy "%(FullPath)" ..\..\include\unicode\r
+</Command>\r
+      <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>\r
+      <Command Condition="'$(Configuration)|$(Platform)'=='Release|x64'">copy "%(FullPath)" ..\..\include\unicode\r
 </Command>\r
       <Outputs Condition="'$(Configuration)|$(Platform)'=='Release|x64'">..\..\include\unicode\%(Filename)%(Extension);%(Outputs)</Outputs>\r
     </CustomBuild>\r
index 7959d38b161a96c6b906d18dc1c648351e7d0d26..d4cfccc76f29510ea08376bb3da47b5a291275c5 100644 (file)
 #define FMTABLE_H
 
 #include "unicode/utypes.h"
-#include "unicode/unistr.h"
-#include "unicode/stringpiece.h"
 
 /**
- * \file 
- * \brief C++ API: Formattable is a thin wrapper for primitive numeric types.
+ * \file
+ * \brief C++ API: Formattable is a thin wrapper for primitive types used for formatting and parsing
  */
 
 #if !UCONFIG_NO_FORMATTING
 
+#include "unicode/unistr.h"
+#include "unicode/stringpiece.h"
+#include "unicode/uformattable.h"
+
 U_NAMESPACE_BEGIN
 
 class CharString;
@@ -84,7 +86,7 @@ public:
      * Creates a Formattable object with a UDate instance.
      * @param d the UDate instance.
      * @param flag the flag to indicate this is a date. Always set it to kIsDate
-     * @stable ICU 2.0  
+     * @stable ICU 2.0
      */
     Formattable(UDate d, ISDATE flag);
 
@@ -183,8 +185,8 @@ public:
      * @stable ICU 2.0
      */
     UBool          operator==(const Formattable &other) const;
-    
-    /** 
+
+    /**
      * Equality operator.
      * @param other    the object to be compared with.
      * @return        TRUE if other are unequal to this, FALSE otherwise.
@@ -193,7 +195,7 @@ public:
     UBool          operator!=(const Formattable& other) const
       { return !operator==(other); }
 
-    /** 
+    /**
      * Destructor.
      * @stable ICU 2.0
      */
@@ -212,7 +214,7 @@ public:
      */
     Formattable *clone() const;
 
-    /** 
+    /**
      * Selector for flavor of data type contained within a
      * Formattable object.  Formattable is a union of several
      * different types, and at any time contains exactly one type.
@@ -275,7 +277,7 @@ public:
      * @stable ICU 2.0
      */
     Type            getType(void) const;
-    
+
     /**
      * Returns TRUE if the data type of this Formattable object
      * is kDouble, kLong, kInt64 or kDecimalNumber.
@@ -283,13 +285,13 @@ public:
      * @stable ICU 3.0
      */
     UBool           isNumeric() const;
-    
+
     /**
      * Gets the double value of this object. If this object is not of type
      * kDouble then the result is undefined.
      * @return    the double value of this object.
      * @stable ICU 2.0
-     */ 
+     */
     double          getDouble(void) const { return fValue.fDouble; }
 
     /**
@@ -303,7 +305,7 @@ public:
      * @param status the error code
      * @return the double value of this object.
      * @stable ICU 3.0
-     */ 
+     */
     double          getDouble(UErrorCode& status) const;
 
     /**
@@ -311,7 +313,7 @@ public:
      * kLong then the result is undefined.
      * @return    the long value of this object.
      * @stable ICU 2.0
-     */ 
+     */
     int32_t         getLong(void) const { return (int32_t)fValue.fInt64; }
 
     /**
@@ -329,7 +331,7 @@ public:
      * @param status the error code
      * @return    the long value of this object.
      * @stable ICU 3.0
-     */ 
+     */
     int32_t         getLong(UErrorCode& status) const;
 
     /**
@@ -337,7 +339,7 @@ public:
      * kInt64 then the result is undefined.
      * @return    the int64 value of this object.
      * @stable ICU 2.8
-     */ 
+     */
     int64_t         getInt64(void) const { return fValue.fInt64; }
 
     /**
@@ -354,7 +356,7 @@ public:
      * @param status the error code
      * @return    the int64 value of this object.
      * @stable ICU 3.0
-     */ 
+     */
     int64_t         getInt64(UErrorCode& status) const;
 
     /**
@@ -362,7 +364,7 @@ public:
      * kDate then the result is undefined.
      * @return    the Date value of this object.
      * @stable ICU 2.0
-     */ 
+     */
     UDate           getDate() const { return fValue.fDate; }
 
     /**
@@ -372,7 +374,7 @@ public:
      * @param status the error code.
      * @return    the Date value of this object.
      * @stable ICU 3.0
-     */ 
+     */
      UDate          getDate(UErrorCode& status) const;
 
     /**
@@ -381,7 +383,7 @@ public:
      * @param result    Output param to receive the Date value of this object.
      * @return          A reference to 'result'.
      * @stable ICU 2.0
-     */ 
+     */
     UnicodeString&  getString(UnicodeString& result) const
       { result=*fValue.fString; return result; }
 
@@ -390,10 +392,10 @@ public:
      * string, status is set to U_INVALID_FORMAT_ERROR and a bogus
      * string is returned.
      * @param result    Output param to receive the Date value of this object.
-     * @param status    the error code. 
+     * @param status    the error code.
      * @return          A reference to 'result'.
      * @stable ICU 3.0
-     */ 
+     */
     UnicodeString&  getString(UnicodeString& result, UErrorCode& status) const;
 
     /**
@@ -427,7 +429,7 @@ public:
      * Gets a reference to the string value of this object. If the
      * type is not a string, status is set to U_INVALID_FORMAT_ERROR
      * and the result is a bogus string.
-     * @param status    the error code. 
+     * @param status    the error code.
      * @return   a reference to the string value of this object.
      * @stable ICU 3.0
      */
@@ -439,7 +441,7 @@ public:
      * @param count    fill-in with the count of this object.
      * @return         the array value of this object.
      * @stable ICU 2.0
-     */ 
+     */
     const Formattable* getArray(int32_t& count) const
       { count=fValue.fArrayAndCount.fCount; return fValue.fArrayAndCount.fArray; }
 
@@ -448,10 +450,10 @@ public:
      * not an array, status is set to U_INVALID_FORMAT_ERROR, count is
      * set to 0, and the result is NULL.
      * @param count    fill-in with the count of this object.
-     * @param status the error code. 
+     * @param status the error code.
      * @return         the array value of this object.
      * @stable ICU 3.0
-     */ 
+     */
     const Formattable* getArray(int32_t& count, UErrorCode& status) const;
 
     /**
@@ -463,7 +465,7 @@ public:
      * @stable ICU 2.0
      */
     Formattable&    operator[](int32_t index) { return fValue.fArrayAndCount.fArray[index]; }
-       
+
     /**
      * Returns a pointer to the UObject contained within this
      * formattable, or NULL if this object does not contain a UObject.
@@ -478,7 +480,7 @@ public:
      * For values obtained by parsing, the returned decimal number retains
      * the full precision and range of the original input, unconstrained by
      * the limits of a double floating point or a 64 bit int.
-     * 
+     *
      * This function is not thread safe, and therfore is not declared const,
      * even though it is logically const.
      *
@@ -497,7 +499,7 @@ public:
      * kDouble.
      * @param d    the new double value to be set.
      * @stable ICU 2.0
-     */ 
+     */
     void            setDouble(double d);
 
     /**
@@ -505,7 +507,7 @@ public:
      * kLong.
      * @param l    the new long value to be set.
      * @stable ICU 2.0
-     */ 
+     */
     void            setLong(int32_t l);
 
     /**
@@ -513,7 +515,7 @@ public:
      * kInt64.
      * @param ll    the new int64 value to be set.
      * @stable ICU 2.8
-     */ 
+     */
     void            setInt64(int64_t ll);
 
     /**
@@ -521,7 +523,7 @@ public:
      * kDate.
      * @param d    the new Date value to be set.
      * @stable ICU 2.0
-     */ 
+     */
     void            setDate(UDate d);
 
     /**
@@ -529,7 +531,7 @@ public:
      * kString.
      * @param stringToCopy    the new string value to be set.
      * @stable ICU 2.0
-     */ 
+     */
     void            setString(const UnicodeString& stringToCopy);
 
     /**
@@ -538,7 +540,7 @@ public:
      * @param array    the array value.
      * @param count    the number of array elements to be copied.
      * @stable ICU 2.0
-     */ 
+     */
     void            setArray(const Formattable* array, int32_t count);
 
     /**
@@ -546,16 +548,16 @@ public:
      * changes the type to kArray.
      * @param stringToAdopt    the new string value to be adopted.
      * @stable ICU 2.0
-     */ 
+     */
     void            adoptString(UnicodeString* stringToAdopt);
 
     /**
      * Sets and adopts the array value and count of this object and
      * changes the type to kArray.
      * @stable ICU 2.0
-     */ 
+     */
     void            adoptArray(Formattable* array, int32_t count);
-       
+
     /**
      * Sets and adopts the UObject value of this object and changes
      * the type to kObject.  After this call, the caller must not
@@ -567,7 +569,7 @@ public:
 
     /**
      * Sets the the numeric value from a decimal number string, and changes
-     * the type to to a numeric type appropriate for the number.  
+     * the type to to a numeric type appropriate for the number.
      * The syntax of the number is a "numeric string"
      * as defined in the Decimal Arithmetic Specification, available at
      * http://speleotrove.com/decimal
@@ -596,13 +598,29 @@ public:
      */
     static UClassID U_EXPORT2 getStaticClassID();
 
+    /**
+     * Convert the UFormattable to a Formattable.  Internally, this is a reinterpret_cast.
+     * @param fmt a valid UFormattable
+     * @return the UFormattable as a Formattable object pointer.  This is an alias to the original
+     * UFormattable, and so is only valid while the original argument remains in scope.
+     * @draft ICU 52
+     */
+    static inline Formattable *fromUFormattable(UFormattable *fmt);
+
+    /**
+     * Convert this object pointer to a UFormattable.
+     * @return this object as a UFormattable pointer.   This is an alias to the original UFormattable,
+     * and so is only valid while the original argument remains in scope.
+     */
+    inline UFormattable *toUFormattable();
+
 #ifndef U_HIDE_DEPRECATED_API
     /**
      * Deprecated variant of getLong(UErrorCode&).
      * @param status the error code
      * @return the long value of this object.
      * @deprecated ICU 3.0 use getLong(UErrorCode&) instead
-     */ 
+     */
     inline int32_t getLong(UErrorCode* status) const;
 #endif  /* U_HIDE_DEPRECATED_API */
 
@@ -629,6 +647,14 @@ public:
      *  @internal
      */
     void adoptDigitList(DigitList *dl);
+
+    /**
+     * Internal function to return the CharString pointer.
+     * @param status error code
+     * @return pointer to the CharString - may become invalid if the object is modified
+     */
+    CharString *internalGetCharString(UErrorCode &status);
+
 #endif  /* U_HIDE_INTERNAL_API */
 
 private:
@@ -689,6 +715,14 @@ inline int32_t Formattable::getLong(UErrorCode* status) const {
     return getLong(*status);
 }
 
+inline UFormattable* Formattable::toUFormattable() {
+  return (UFormattable*)(this);
+}
+
+inline Formattable* Formattable::fromUFormattable(UFormattable *fmt) {
+  return reinterpret_cast<Formattable *>(fmt);
+}
+
 
 U_NAMESPACE_END
 
diff --git a/icu4c/source/i18n/unicode/uformattable.h b/icu4c/source/i18n/unicode/uformattable.h
new file mode 100644 (file)
index 0000000..9107ec4
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+TODO
+* copy C++ apidoc concerning error codes to appropriate wrapper functions
+*/
+
+
+/*
+********************************************************************************
+* Copyright (C) 2013, International Business Machines Corporation and others.
+* All Rights Reserved.
+********************************************************************************
+*
+* File UFORMATTABLE.H
+*
+* Modification History:
+*
+*   Date        Name        Description
+*   2013 Jul 7  srl         New
+********************************************************************************
+*/
+
+/**
+ * \file
+ * \brief C API: UFormattable is a thin wrapper for primitive types used for formatting and parsing.
+ *
+ * This is a C interface to the icu::Formattable class. Static functions on this class convert
+ * to and from this interface (via reinterpret_cast).  Note that Formattables (and thus UFormattables)
+ * are mutable, and many operations (even getters) may actually modify the internal state. For this
+ * reason, UFormattables are not thread safe, and should not be shared between threads.
+ */
+
+#ifndef FORMATTABLE_H
+#define FORMATTABLE_H
+
+#include "unicode/utypes.h"
+
+#if !UCONFIG_NO_FORMATTING
+
+#include "unicode/localpointer.h"
+
+/**
+ * Enum designating the type of a UFormattable instance.
+ * Practically, this indicates which of the getters would return without conversion
+ * or error.
+ * @see icu::Formattable::Type
+ * @draft ICU 52
+ */
+typedef enum UFormattableType {
+  UFMT_DATE = 0, /**< ufmt_getDate() will return without conversion. */
+  UFMT_DOUBLE,   /**< ufmt_getDouble() will return without conversion. */
+  UFMT_LONG,     /**< ufmt_getLong() will return without conversion. */
+  UFMT_INT64,    /**< ufmt_getInt64() will return without conversion. */
+  UFMT_OBJECT,   /**< ufmt_getObject() will return without conversion. */
+  UFMT_STRING,   /**< ufmt_getUChars() will return without conversion. */
+  UFMT_ARRAY,    /**< ufmt_countArray() and ufmt_getArray() will return the value. */
+  UFMT_COUNT     /**< Count of defined UFormattableType values */
+} UFormattableType;
+
+
+/**
+ * Opaque type representing various types of data which may be used for formatting
+ * and parsing operations.
+ * @see icu::Formattable
+ * @draft ICU 52
+ */
+typedef void *UFormattable;
+
+/**
+ * Initialize a UFormattable, to type UNUM_LONG, value 0
+ * may return error if memory allocation failed.
+ * parameter status error code.
+ * @draft ICU 52
+ * @return the new UFormattable
+ */
+U_DRAFT UFormattable* U_EXPORT2
+ufmt_open(UErrorCode* status);
+
+/**
+ * Cleanup any additional memory allocated by this UFormattable.
+ * @draft ICU 52
+ */
+U_DRAFT void U_EXPORT2
+ufmt_close(UFormattable* fmt);
+
+#if U_SHOW_CPLUSPLUS_API
+
+U_NAMESPACE_BEGIN
+
+/**
+ * \class LocalUFormattablePointer
+ * "Smart pointer" class, closes a UFormattable via ufmt_close().
+ * For most methods see the LocalPointerBase base class.
+ *
+ * @see LocalPointerBase
+ * @see LocalPointer
+ * @draft ICU 52
+ */
+U_DEFINE_LOCAL_OPEN_POINTER(LocalUFormattablePointer, UFormattable, ufmt_close);
+
+U_NAMESPACE_END
+
+#endif
+
+/**
+ * Return the type of this object
+ * @param fmt the UFormattable object
+ * @status status code - U_ILLEGAL_ARGUMENT_ERROR is returned if the UFormattable contains data not supported by
+ * the API
+ * @return the value as a UFormattableType
+ * @internal
+ */
+U_INTERNAL UFormattableType U_EXPORT2
+ufmt_getType(UFormattable* fmt, UErrorCode *status);
+
+/**
+ * Return the type of this object
+ * @param fmt the UFormattable object
+ * @return true if the object is a double, long, or int64 value.
+ * @internal
+ */
+U_INTERNAL UBool U_EXPORT2
+ufmt_isNumeric(UFormattable* fmt);
+
+
+/**
+ * Get the value as a date, converting if need be.
+ * @param fmt the UFormattable object
+ * @param status the error code - any conversion or format errors
+ * @return the value
+ * @draft ICU 52
+ */
+U_DRAFT UDate U_EXPORT2
+ufmt_getDate(UFormattable* fmt, UErrorCode *status);
+
+/**
+ * Get the value as a double, converting if need be.
+ * @param fmt the UFormattable object
+ * @param status the error code - any conversion or format errors
+ * @return the value
+ * @draft ICU 52
+ */
+U_DRAFT double U_EXPORT2
+ufmt_getDouble(UFormattable* fmt, UErrorCode *status);
+
+/**
+ * Get the value as a int32_t, converting if need be.
+ * @param fmt the UFormattable object
+ * @param status the error code - any conversion or format errors
+ * @return the value
+ * @draft ICU 52
+ */
+U_DRAFT int32_t U_EXPORT2
+ufmt_getLong(UFormattable* fmt, UErrorCode *status);
+
+
+/**
+ * Get the value as a int64_t, converting if need be.
+ * @param fmt the UFormattable object
+ * @param status the error code - any conversion or format errors
+ * @return the value
+ * @draft ICU 52
+ */
+U_DRAFT int64_t U_EXPORT2
+ufmt_getInt64(UFormattable* fmt, UErrorCode *status);
+
+/**
+ * Get the value as an object.
+ * @param fmt the UFormattable object
+ * @param status the error code - any conversion or format errors
+ * @return the value as a const void*. It is a polymorphic C++ object.
+ * @draft ICU 52
+ */
+U_DRAFT const void *U_EXPORT2
+ufmt_getObject(UFormattable* fmt, UErrorCode *status);
+
+/**
+ * Get the value as UChar string, converting if need be.
+ * This function is not thread safe and may modify the UFormattable if need be to terminate the buffer.
+ * @param fmt the UFormattable object
+ * @param status the error code - any conversion or format errors
+ * @param len if non null, contains the string length on return
+ * @return the null terminated string value - must not be referenced after any other functions are called on this UFormattable.
+ * @draft ICU 52
+ */
+U_DRAFT const UChar* U_EXPORT2
+ufmt_getUChars(UFormattable* fmt, int32_t *len, UErrorCode *status);
+
+/**
+ * Get the number of array objects contained. Invalid if the object is not an array type.
+ * @param fmt the UFormattable object
+ * @param status the error code - any conversion or format errors. U_ILLEGAL_ARGUMENT_ERROR if not an array type.
+ * @return the number of array objects
+ * @draft ICU 52
+ */
+U_DRAFT int32_t U_EXPORT2
+ufmt_getArrayLength(UFormattable* fmt, UErrorCode *status);
+
+/**
+ * Get the specified value from the array of UFormattables. Invalid if the object is not an array type.
+ * @param fmt the UFormattable object
+ * #param n the number of the array to return (0 based).
+ * @param status the error code - any conversion or format errors. Returns an error if n is out of bounds.
+ * @return the nth array value, only valid while the containing UFormattable is valid
+ * @draft ICU 52
+ */
+U_DRAFT UFormattable * U_EXPORT2
+ufmt_getArrayItemByIndex(UFormattable* fmt, int32_t n, UErrorCode *status);
+
+/**
+ * Get the value as a C String, if it is a numeric type (isNumeric is true), or if is an Object
+ * with a numeric value. The returned string is not valid if any other function calls are made on this
+ * object, or if it is destroyed.
+ * @param fmt the UFormattable object
+ * @param len if non-null, on exit contains the string length (not including the terminating null)
+ * @param status the error code
+ * @return the character buffer, which is owned by the object and must not be accessed if any other functions are called on this object.
+ * @draft ICU 52
+ */
+U_DRAFT const char * U_EXPORT2
+ufmt_getDecNumChars(UFormattable *fmt, int32_t *len, UErrorCode *status);
+
+#endif
+
+#endif
index 345d058286a7ceb2c747052a226f968db750fafc..b53f7d646fe57a7ff30d8a1c15a691d7ddc85b4c 100644 (file)
@@ -120,6 +120,12 @@ operator+(const UnicodeString& left,
     return left + buffer;
 }
 
+UnicodeString
+operator+(const UnicodeString& left,
+          int64_t num) {
+  return left + Int64ToUnicodeString(num);
+}
+
 #if !UCONFIG_NO_FORMATTING
 
 /**
@@ -204,6 +210,12 @@ UnicodeString toString(int32_t n) {
     return UnicodeString() + (long)n;
 }
 
+
+
+UnicodeString toString(UBool b) {
+  return b ? UnicodeString("TRUE"):UnicodeString("false");
+}
+
 // stephen - cleaned up 05/05/99
 UnicodeString operator+(const UnicodeString& left, char num)
 { return left + (long)num; }
@@ -1768,6 +1780,40 @@ UBool IntlTest::assertEquals(const char* message,
     return TRUE;
 }
 
+UBool IntlTest::assertEquals(const char* message,
+                             int64_t expected,
+                             int64_t actual) {
+    if (expected != actual) {
+        errln((UnicodeString)"FAIL: " + message + "; got " +
+              actual + 
+              "; expected " + expected );
+        return FALSE;
+    }
+#ifdef VERBOSE_ASSERTIONS
+    else {
+        logln((UnicodeString)"Ok: " + message + "; got " + actual);
+    }
+#endif
+    return TRUE;
+}
+
+UBool IntlTest::assertEquals(const char* message,
+                             UBool expected,
+                             UBool actual) {
+    if (expected != actual) {
+        errln((UnicodeString)"FAIL: " + message + "; got " +
+              toString(actual) +
+              "; expected " + toString(expected));
+        return FALSE;
+    }
+#ifdef VERBOSE_ASSERTIONS
+    else {
+      logln((UnicodeString)"Ok: " + message + "; got " + toString(actual));
+    }
+#endif
+    return TRUE;
+}
+
 #if !UCONFIG_NO_FORMATTING
 UBool IntlTest::assertEquals(const char* message,
                              const Formattable& expected,
@@ -1820,6 +1866,21 @@ UBool IntlTest::assertEquals(const UnicodeString& message,
                              const char* actual) {
     return assertEquals(extractToAssertBuf(message), expected, actual);
 }
+UBool IntlTest::assertEquals(const UnicodeString& message,
+                             UBool expected,
+                             UBool actual) {
+    return assertEquals(extractToAssertBuf(message), expected, actual);
+}
+UBool IntlTest::assertEquals(const UnicodeString& message,
+                             int32_t expected,
+                             int32_t actual) {
+    return assertEquals(extractToAssertBuf(message), expected, actual);
+}
+UBool IntlTest::assertEquals(const UnicodeString& message,
+                             int64_t expected,
+                             int64_t actual) {
+    return assertEquals(extractToAssertBuf(message), expected, actual);
+}
 //--------------------------------------------------------------------
 // Time bomb - allows temporary behavior that expires at a given
 //             release
index e71576d259bbbcadea294ccaf0329e436fde8610..2b5e01d490bcddcb582269dfd72a580334ab46e7 100644 (file)
@@ -51,21 +51,23 @@ U_NAMESPACE_USE
 //string-concatenation operator (moved from findword test by rtg)
 UnicodeString UCharToUnicodeString(UChar c);
 UnicodeString Int64ToUnicodeString(int64_t num);
-//UnicodeString operator+(const UnicodeString& left, int64_t num); // Some compilers don't allow this because of the long type.
+UnicodeString operator+(const UnicodeString& left, int64_t num);
 UnicodeString operator+(const UnicodeString& left, long num);
 UnicodeString operator+(const UnicodeString& left, unsigned long num);
 UnicodeString operator+(const UnicodeString& left, double num);
-UnicodeString operator+(const UnicodeString& left, char num); 
-UnicodeString operator+(const UnicodeString& left, short num);  
-UnicodeString operator+(const UnicodeString& left, int num);      
-UnicodeString operator+(const UnicodeString& left, unsigned char num);  
-UnicodeString operator+(const UnicodeString& left, unsigned short num);  
-UnicodeString operator+(const UnicodeString& left, unsigned int num);      
+UnicodeString operator+(const UnicodeString& left, char num);
+UnicodeString operator+(const UnicodeString& left, short num);
+UnicodeString operator+(const UnicodeString& left, int num);
+UnicodeString operator+(const UnicodeString& left, unsigned char num);
+UnicodeString operator+(const UnicodeString& left, unsigned short num);
+UnicodeString operator+(const UnicodeString& left, unsigned int num);
 UnicodeString operator+(const UnicodeString& left, float num);
 #if !UCONFIG_NO_FORMATTING
 UnicodeString toString(const Formattable& f); // liu
 UnicodeString toString(int32_t n);
 #endif
+UnicodeString toString(UBool b);
+
 //-----------------------------------------------------------------------------
 
 // Use the TESTCASE macro in subclasses of IntlTest.  Define the
@@ -178,6 +180,13 @@ public:
     void errln(const char *fmt, ...);
     void dataerr(const char *fmt, ...);
     void dataerrln(const char *fmt, ...);
+
+    /**
+     * logs an error (even if status==U_ZERO_ERROR), but
+     * calls dataerrln() or errln() depending on the type of error.
+     * Does not report the status code.
+     * @param status parameter for selecting whether errln or dataerrln is called.
+     */
     void errcheckln(UErrorCode status, const char *fmt, ...);
 
     // Print ALL named errors encountered so far
@@ -236,12 +245,19 @@ protected:
     /* JUnit-like assertions. Each returns TRUE if it succeeds. */
     UBool assertTrue(const char* message, UBool condition, UBool quiet=FALSE, UBool possibleDataError=FALSE, const char *file=NULL, int line=0);
     UBool assertFalse(const char* message, UBool condition, UBool quiet=FALSE);
+    /**
+     * @param possibleDataError - if TRUE, use dataerrln instead of errcheckln on failure
+     * @return TRUE on success, FALSE on failure.
+     */
     UBool assertSuccess(const char* message, UErrorCode ec, UBool possibleDataError=FALSE);
     UBool assertEquals(const char* message, const UnicodeString& expected,
                        const UnicodeString& actual, UBool possibleDataError=FALSE);
     UBool assertEquals(const char* message, const char* expected,
                        const char* actual);
+    UBool assertEquals(const char* message, UBool expected,
+                       UBool actual);
     UBool assertEquals(const char* message, int32_t expected, int32_t actual);
+    UBool assertEquals(const char* message, int64_t expected, int64_t actual);
 #if !UCONFIG_NO_FORMATTING
     UBool assertEquals(const char* message, const Formattable& expected,
                        const Formattable& actual);
@@ -255,6 +271,9 @@ protected:
                        const UnicodeString& actual);
     UBool assertEquals(const UnicodeString& message, const char* expected,
                        const char* actual);
+    UBool assertEquals(const UnicodeString& message, UBool expected, UBool actual);
+    UBool assertEquals(const UnicodeString& message, int32_t expected, int32_t actual);
+    UBool assertEquals(const UnicodeString& message, int64_t expected, int64_t actual);
 
     virtual void runIndexedTest( int32_t index, UBool exec, const char* &name, char* par = NULL ); // overide !
 
index b909303c6052ef1660504e1445cbddee0f783c15..37c7d5da18d3870f645f59d4f456362b834cacac 100644 (file)
@@ -121,6 +121,7 @@ void NumberFormatTest::runIndexedTest( int32_t index, UBool exec, const char* &n
   TESTCASE_AUTO(Test9087);
   TESTCASE_AUTO(TestFormatFastpaths);
   TESTCASE_AUTO(TestFormattableSize);
+  TESTCASE_AUTO(TestUFormattable);
   TESTCASE_AUTO(TestSignificantDigits);
   TESTCASE_AUTO(TestShowZero);
   TESTCASE_AUTO(TestCompatibleCurrencies);
@@ -6789,6 +6790,226 @@ void NumberFormatTest::TestFormattableSize(void) {
   }
 }
 
+UBool NumberFormatTest::testFormattableAsUFormattable(const char *file, int line, Formattable &f) {
+  UnicodeString fileLine = UnicodeString(file)+UnicodeString(":")+line+UnicodeString(": ");
+
+  UFormattable *u = f.toUFormattable();
+  logln();
+  if (u == NULL) {
+    errln("%s:%d: Error: f.toUFormattable() retuned NULL.");
+    return FALSE;
+  }
+  logln("%s:%d: comparing Formattable with UFormattable", file, line);
+  logln(fileLine + toString(f));
+
+  UErrorCode status = U_ZERO_ERROR;
+  UErrorCode valueStatus = U_ZERO_ERROR;
+  UFormattableType expectUType = UFMT_COUNT; // invalid
+
+  UBool triedExact = FALSE; // did we attempt an exact comparison?
+  UBool exactMatch = FALSE; // was the exact comparison true?
+
+  switch( f.getType() ) {
+  case Formattable::kDate:
+    expectUType = UFMT_DATE;
+    exactMatch = (f.getDate()==ufmt_getDate(u, &valueStatus));
+    triedExact = TRUE;
+    break;
+  case Formattable::kDouble:
+    expectUType = UFMT_DOUBLE;
+    exactMatch = (f.getDouble()==ufmt_getDouble(u, &valueStatus));
+    triedExact = TRUE;
+    break;
+  case Formattable::kLong:
+    expectUType = UFMT_LONG;
+    exactMatch = (f.getLong()==ufmt_getLong(u, &valueStatus));
+    triedExact = TRUE;
+    break;
+  case Formattable::kString:
+    expectUType = UFMT_STRING;
+    {
+      UnicodeString str;
+      f.getString(str);
+      int32_t len;
+      const UChar* uch = ufmt_getUChars(u, &len, &valueStatus);
+      if(U_SUCCESS(valueStatus)) {
+        UnicodeString str2(uch, len);
+        exactMatch = (str == str2);
+      }
+      triedExact = TRUE;
+    }
+    break;
+  case Formattable::kArray:
+    expectUType = UFMT_ARRAY;
+    triedExact = TRUE;
+    {
+      int32_t count = ufmt_getArrayLength(u, &valueStatus);
+      int32_t count2;
+      const Formattable *array2 = f.getArray(count2);
+      exactMatch = assertEquals(fileLine + " array count", count, count2);
+
+      if(exactMatch) {
+        for(int i=0;U_SUCCESS(valueStatus) && i<count;i++) {
+          UFormattable *uu = ufmt_getArrayItemByIndex(u, i, &valueStatus);
+          if(*Formattable::fromUFormattable(uu) != (array2[i])) {
+            errln("%s:%d: operator== did not match at index[%d] - %p vs %p", file, line, i,
+                  (const void*)Formattable::fromUFormattable(uu), (const void*)&(array2[i]));
+            exactMatch = FALSE;
+          } else {
+            if(!testFormattableAsUFormattable("(sub item)",i,*Formattable::fromUFormattable(uu))) {
+              exactMatch = FALSE;
+            }
+          }
+        }
+      }
+    }
+    break;
+  case Formattable::kInt64:
+    expectUType = UFMT_INT64;
+    exactMatch = (f.getInt64()==ufmt_getInt64(u, &valueStatus));
+    triedExact = TRUE;
+    break;
+  case Formattable::kObject:
+    expectUType = UFMT_OBJECT;
+    exactMatch = (f.getObject()==ufmt_getObject(u, &valueStatus));
+    triedExact = TRUE;
+    break;
+  }
+  UFormattableType uType = ufmt_getType(u, &status);
+
+  if(U_FAILURE(status)) {
+    errln("%s:%d: Error calling ufmt_getType - %s", file, line, u_errorName(status));
+    return FALSE;
+  }
+
+  if(uType != expectUType) {
+    errln("%s:%d: got type (%d) expected (%d) from ufmt_getType", file, line, (int) uType, (int) expectUType);
+  }
+
+  if(triedExact) {
+    if(U_FAILURE(valueStatus)) {
+      errln("%s:%d: got err %s trying to ufmt_get...() for exact match check", file, line, u_errorName(valueStatus));
+    } else if(!exactMatch) {
+     errln("%s:%d: failed exact match for the Formattable type", file, line);
+    } else {
+      logln("%s:%d: exact match OK", file, line);
+    }
+  } else {
+    logln("%s:%d: note, did not attempt exact match for this formattable type", file, line);
+  }
+
+  if( assertEquals(fileLine + " isNumeric()", f.isNumeric(), ufmt_isNumeric(u))
+      && f.isNumeric()) {
+    UErrorCode convStatus = U_ZERO_ERROR;
+    assertTrue(fileLine + " as doubles ==", f.getDouble(convStatus)==ufmt_getDouble(u, &convStatus));
+
+    if( assertSuccess(fileLine + " (numeric conversion status)", convStatus) ) {
+      StringPiece fDecNum = f.getDecimalNumber(convStatus);
+#if 1
+      int32_t len;
+      const char *decNumChars = ufmt_getDecNumChars(u, &len, &convStatus);
+#else
+      // copy version
+      char decNumChars[200];
+      int32_t len = ufmt_getDecNumChars(u, decNumChars, 200, &convStatus);
+#endif
+
+      if( assertSuccess(fileLine + " (decNumbers conversion)", convStatus) ) {
+        logln(fileLine + decNumChars);
+        assertEquals(fileLine + " decNumChars length==", len, fDecNum.length());
+        assertEquals(fileLine + " decNumChars digits", decNumChars, fDecNum.data());
+      }
+
+      UErrorCode int64ConversionF = U_ZERO_ERROR;
+      int64_t l = f.getInt64(int64ConversionF);
+      UErrorCode int64ConversionU = U_ZERO_ERROR;
+      int64_t r = ufmt_getInt64(u, &int64ConversionU);
+
+      if( (l==r) 
+          && ( uType != UFMT_INT64 ) // int64 better not overflow
+          && (U_INVALID_FORMAT_ERROR==int64ConversionU) 
+          && (U_INVALID_FORMAT_ERROR==int64ConversionF) ) {
+        logln("%s:%d: OK: 64 bit overflow", file, line);
+      } else {
+        assertEquals(fileLine + " as int64 ==", l, r);
+        assertSuccess(fileLine + " Formattable.getnt64()", int64ConversionF);
+        assertSuccess(fileLine + " ufmt_getInt64()", int64ConversionU);
+      }
+    }
+  }
+  return exactMatch || !triedExact;
+}
+
+void NumberFormatTest::TestUFormattable(void) {
+  {
+    // test that a default formattable is equal to Formattable()
+    UErrorCode status = U_ZERO_ERROR;
+    LocalUFormattablePointer defaultUFormattable(ufmt_open(&status));
+    assertSuccess("calling umt_open", status);
+    Formattable defaultFormattable;
+    assertTrue((UnicodeString)"comparing ufmt_open() with Formattable()",
+               (defaultFormattable
+                == *(Formattable::fromUFormattable(defaultUFormattable.getAlias()))));
+    assertTrue((UnicodeString)"comparing ufmt_open() with Formattable()",
+               (defaultFormattable
+                == *(Formattable::fromUFormattable(defaultUFormattable.getAlias()))));
+    assertTrue((UnicodeString)"comparing Formattable() round tripped through UFormattable",
+               (defaultFormattable
+                == *(Formattable::fromUFormattable(defaultFormattable.toUFormattable()))));
+    assertTrue((UnicodeString)"comparing &Formattable() round tripped through UFormattable",
+               ((&defaultFormattable)
+                == Formattable::fromUFormattable(defaultFormattable.toUFormattable())));
+    assertFalse((UnicodeString)"comparing &Formattable() with ufmt_open()",
+               ((&defaultFormattable)
+                == Formattable::fromUFormattable(defaultUFormattable.getAlias())));
+    testFormattableAsUFormattable(__FILE__, __LINE__, defaultFormattable);
+  }
+  // test some random Formattables
+  {
+    Formattable f(ucal_getNow(), Formattable::kIsDate);
+    testFormattableAsUFormattable(__FILE__, __LINE__,  f);
+  }
+  {
+    Formattable f((double)1.61803398874989484820); // golden ratio
+    testFormattableAsUFormattable(__FILE__, __LINE__,  f);
+  }
+  {
+    Formattable f((int64_t)80994231587905127LL); // weight of the moon, in kilotons http://solarsystem.nasa.gov/planets/profile.cfm?Display=Facts&Object=Moon
+    testFormattableAsUFormattable(__FILE__, __LINE__,  f);
+  }
+  {
+    Formattable f((int32_t)4); // random number, source: http://www.xkcd.com/221/
+    testFormattableAsUFormattable(__FILE__, __LINE__,  f);
+  }
+  {
+    Formattable f("Hello world."); // should be invariant?
+    testFormattableAsUFormattable(__FILE__, __LINE__,  f);
+  }
+  {
+    UErrorCode status2 = U_ZERO_ERROR;
+    Formattable f(StringPiece("73476730924573500000000.0"), status2); // weight of the moon, kg
+    assertSuccess("Constructing a StringPiece", status2);
+    testFormattableAsUFormattable(__FILE__, __LINE__,  f);
+  }
+  {
+    UErrorCode status2 = U_ZERO_ERROR;
+    UObject *obj = new Locale();
+    Formattable f(obj);
+    assertSuccess("Constructing a Formattable from a default constructed Locale()", status2);
+    testFormattableAsUFormattable(__FILE__, __LINE__,  f);
+  }
+  {
+    const Formattable array[] = {
+      Formattable(ucal_getNow(), Formattable::kIsDate),
+      Formattable((int32_t)4),
+      Formattable((double)1.234),
+    };
+
+    Formattable fa(array, 3);
+    testFormattableAsUFormattable(__FILE__, __LINE__, fa);
+  }
+}
+
 void NumberFormatTest::TestSignificantDigits(void) {
   double input[] = {
         0, 0,
index ada6f8418ea89b954a78d44fd6eae6afe2a8e496..48649b929ac6f975409fb05b37b3d53cc149d396 100644 (file)
@@ -160,6 +160,8 @@ class NumberFormatTest: public CalendarTimeZoneTest {
 
     void TestFormattableSize();
 
+    void TestUFormattable();
+
     void TestEnumSet();
 
     void TestSignificantDigits();
@@ -169,6 +171,8 @@ class NumberFormatTest: public CalendarTimeZoneTest {
     void TestBug9936();
 
  private:
+    UBool testFormattableAsUFormattable(const char *file, int line, Formattable &f);
+
     void expectParseCurrency(const NumberFormat &fmt, const UChar* currency, double amount, const char *text);
 
     static UBool equalValue(const Formattable& a, const Formattable& b);