OSDN Git Service

Merge release/v3.120.2 release-3.120.2
authorOlyutorskii <olyutorskii@users.osdn.me>
Tue, 4 Jun 2019 13:32:31 +0000 (22:32 +0900)
committerOlyutorskii <olyutorskii@users.osdn.me>
Tue, 4 Jun 2019 13:32:31 +0000 (22:32 +0900)
13 files changed:
CHANGELOG.txt
config/checkstyle/checkstyle-suppressions.xml
config/checkstyle/checkstyle.xml
pom.xml
src/main/java/jp/sfjp/mikutoga/xml/AbstractXmlExporter.java
src/main/java/jp/sfjp/mikutoga/xml/DatatypeIo.java [new file with mode: 0644]
src/main/java/jp/sfjp/mikutoga/xml/DomNsUtils.java
src/main/java/jp/sfjp/mikutoga/xml/DomUtils.java
src/main/java/jp/sfjp/mikutoga/xml/SaxAttr.java
src/test/java/jp/sfjp/mikutoga/math/MkQuatTest.java
src/test/java/jp/sfjp/mikutoga/xml/BasicXmlExporterTest.java [new file with mode: 0644]
src/test/java/jp/sfjp/mikutoga/xml/DatatypeIoTest.java [new file with mode: 0644]
src/test/java/jp/sfjp/mikutoga/xml/DomUtilsTest.java [new file with mode: 0644]

index 6124e11..0b2a6f3 100644 (file)
@@ -4,6 +4,9 @@
 TogaGem 変更履歴
 
 
+3.120.2 (2019-06-04)
+    ・replacing JAXB DatatypeConverter.
+
 3.101.106 (2019-06-02)
     ・必須環境をJavaSE8に引き上げ。
     ・Mercurial(3.102.4)からGit(3.101.105-SNAPSHOT)へSCMを移行。
index 1086722..9b0570a 100644 (file)
     <suppress files="" checks="ImportControl" />
 
     <!-- Javadoc Comments -->
+    <suppress files="" checks="JavadocParagraph" />
+    <suppress files="" checks="JavadocTagContinuationIndentation" />
     <suppress files="" checks="SummaryJavadocCheck" />
 
     <!-- Miscellaneous -->
     <suppress files="" checks="FinalParameters" />
     <suppress files="" checks="TrailingComment" />
 
+    <!-- Modifier -->
+    <suppress files="" checks="InterfaceMemberImpliedModifier" />
+
     <!-- Whitespace -->
     <suppress files="" checks="SingleSpaceSeparator" />
 
index 8080bd3..7d19930 100644 (file)
@@ -6,7 +6,7 @@
 
 <!--
     Checkstyle modules
-    for Checkstyle 8.20 or later
+    for Checkstyle 8.21 or later
 
     [ https://checkstyle.org/ ]
 
     <property name="localeCountry" value="JP" />
     <property name="localeLanguage" value="en" />
     <!--property name="localeLanguage" value="ja" /-->
-    <property name="fileExtensions" value="java, xml, properties" />
+    <property name="fileExtensions" value="java, properties, xml, xsd, md, txt" />
     <property name="severity" value="error" />
 
 
     <!-- Filters -->
+
     <module name="SeverityMatchFilter" />
     <!--module name="SuppressionFilter" /-->
     <module name="SuppressWarningsFilter" />
@@ -32,6 +33,7 @@
 
 
     <!-- Headers -->
+
     <module name="Header">
         <property name="header" value="&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&gt;" />
         <property name="fileExtensions" value="xml" />
 
 
     <!-- Javadoc Comments -->
+
     <module name="JavadocPackage" />
 
 
     <!-- Miscellaneous -->
+
     <module name="NewlineAtEndOfFile">
-        <property name="fileExtensions" value="java" />
+        <property name="fileExtensions" value="java, properties, xml, xsd, md, txt" />
     </module>
     <module name="Translation" />
     <module name="UniqueProperties" />
 
 
     <!-- Regexp -->
+
     <module name="RegexpMultiline">
         <property name="format" value="[\u000b\f\u001a]" />
     </module>
 
 
     <!-- Size Violations -->
+
     <module name="FileLength" />
 
 
     <!-- Whitespace -->
+
     <module name="FileTabCharacter" />
 
 
         <module name="SuperClone" />
         <module name="SuperFinalize" />
         <module name="UnnecessaryParentheses" />
-        <module name="VariableDeclarationUsageDistance" />
+        <module name="VariableDeclarationUsageDistance">
+            <property name="allowedDistance" value="5"/>
+        </module>
 
 
     <!-- Imports -->
         <module name="JavadocVariable">
             <property name="scope" value="protected" />
         </module>
+        <module name="MissingJavadocMethod" />
+        <module name="MissingJavadocType" />
         <module name="NonEmptyAtclauseDescription" />
         <module name="SingleLineJavadoc" />
         <module name="SummaryJavadocCheck" />
         <module name="NoWhitespaceAfter" />
         <module name="NoWhitespaceBefore" />
         <module name="OperatorWrap" />
-        <module name="ParenPad" />
-        <module name="SeparatorWrap" />
+        <module name="ParenPad">
+            <property name="option" value="nospace" />
+            <property
+                name="tokens"
+                value="CTOR_CALL, METHOD_CALL, SUPER_CTOR_CALL"
+            />
+        </module>
+        <module name="SeparatorWrap">
+            <property name="tokens" value="DOT"/>
+            <property name="option" value="nl"/>
+        </module>
         <module name="SingleSpaceSeparator" />
         <module name="TypecastParenPad" />
         <module name="WhitespaceAfter" >
diff --git a/pom.xml b/pom.xml
index bc24dff..ec2404a 100644 (file)
--- a/pom.xml
+++ b/pom.xml
@@ -16,7 +16,7 @@
     <groupId>jp.sourceforge.mikutoga</groupId>
     <artifactId>togagem</artifactId>
 
-    <version>3.101.106</version>
+    <version>3.120.2</version>
 
     <packaging>jar</packaging>
     <name>TogaGem</name>
         <detectJavaApiLink>false</detectJavaApiLink>
 
         <surefire-plugin.version>3.0.0-M3</surefire-plugin.version>
-        <jacoco-plugin.version>0.8.3</jacoco-plugin.version>
+        <jacoco-plugin.version>0.8.4</jacoco-plugin.version>
 
-        <checkstyle-plugin.version>3.0.0</checkstyle-plugin.version>
-        <checkstyleruntime.version>8.20</checkstyleruntime.version>
+        <checkstyle-plugin.version>3.1.0</checkstyle-plugin.version>
+        <checkstyleruntime.version>8.21</checkstyleruntime.version>
         <checkstyle.config.location>${project.basedir}/config/checkstyle/checkstyle.xml</checkstyle.config.location>
         <checkstyle.suppressions.location>${project.basedir}/config/checkstyle/checkstyle-suppressions.xml</checkstyle.suppressions.location>
         <checkstyle.enable.rss>false</checkstyle.enable.rss>
 
         <pmd-plugin.version>3.12.0</pmd-plugin.version>
-        <pmd.analysisCache>true</pmd.analysisCache>
 
         <spotbugs-plugin.version>3.1.11</spotbugs-plugin.version>
         <spotbugs.effort>Max</spotbugs.effort>
                                     <version>[3.3.9,)</version>
                                 </requireMavenVersion>
                                 <requireJavaVersion>
-                                    <!-- JAXB -->
-                                    <version>1.8</version>
+                                    <version>[1.8,)</version>
                                 </requireJavaVersion>
                             </rules>
                         </configuration>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-compiler-plugin</artifactId>
-                <version>3.8.0</version>
+                <version>3.8.1</version>
                 <configuration>
                     <source>1.8</source>  <!-- for NetBeans IDE -->
                     <target>1.8</target>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-jar-plugin</artifactId>
-                <version>3.1.1</version>
+                <version>3.1.2</version>
                 <configuration>
                     <archive>
                         <manifest>
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>
                 <artifactId>maven-source-plugin</artifactId>
-                <version>3.0.1</version>
+                <version>3.1.0</version>
                 <configuration>
                     <includePom>true</includePom>
                     <archive>
index 9f8c342..a6c1c0e 100644 (file)
@@ -8,9 +8,6 @@
 package jp.sfjp.mikutoga.xml;
 
 import java.io.IOException;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import javax.xml.bind.DatatypeConverter;
 
 /**
  * Appendable実装に依存したXMLエクスポータの半実装。
@@ -35,9 +32,6 @@ abstract class AbstractXmlExporter implements XmlExporter{
     private static final String COMM_START = "<!--";
     private static final String COMM_END   =   "-->";
 
-    private static final Pattern NUM_FUZZY =
-            Pattern.compile("([^.]*\\.[0-9][0-9]*?)0+");
-
     private static final String REF_HEX = "&#x";
     private static final int HEX_EXP = 4;    // 2 ** 4 == 16
     private static final int MASK_1HEX = (1 << HEX_EXP) - 1;  // 0b00001111
@@ -84,28 +78,6 @@ abstract class AbstractXmlExporter implements XmlExporter{
         return false;
     }
 
-    /**
-     * 冗長な実数出力を抑止する。
-     * <p>DatatypeConverterにおけるJDK1.6系と1.7系の仕様変更を吸収する。
-     * <p>0.001fは"0.0010"ではなく"0.001"と出力される。
-     * <p>指数表記での冗長桁は無視する。
-     * @param numTxt 実数表記
-     * @return 冗長桁が抑止された実数表記
-     * @see javax.xml.bind.DatatypeConverter
-     */
-    protected static String chopFuzzyZero(String numTxt){
-        String result;
-
-        Matcher matcher = NUM_FUZZY.matcher(numTxt);
-        if(matcher.matches()){
-            result = matcher.group(1);
-        }else{
-            result = numTxt;
-        }
-
-        return result;
-    }
-
 
     /**
      * {@inheritDoc}
@@ -617,7 +589,7 @@ abstract class AbstractXmlExporter implements XmlExporter{
      */
     @Override
     public XmlExporter putXsdInt(int iVal) throws IOException{
-        String value = DatatypeConverter.printInt(iVal);
+        String value = DatatypeIo.printInt(iVal);
         putRawText(value);
         return this;
     }
@@ -630,8 +602,7 @@ abstract class AbstractXmlExporter implements XmlExporter{
      */
     @Override
     public XmlExporter putXsdFloat(float fVal) throws IOException{
-        String value = DatatypeConverter.printFloat(fVal);
-        value = chopFuzzyZero(value);
+        String value = DatatypeIo.printFloat(fVal);
         putRawText(value);
         return this;
     }
diff --git a/src/main/java/jp/sfjp/mikutoga/xml/DatatypeIo.java b/src/main/java/jp/sfjp/mikutoga/xml/DatatypeIo.java
new file mode 100644 (file)
index 0000000..b451fe7
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * XML Schema datatypes input/output
+ *
+ * License : The MIT License
+ * Copyright(c) 2019 MikuToga Partners
+ */
+
+package jp.sfjp.mikutoga.xml;
+
+/**
+ * XSD datatypes I/O utilities.
+ *
+ * <p>This class replaces javax.xml.bind.DatatypeConverter(JAXB) subset.
+ * JAXB is not part of JDK9 or later.
+ *
+ * @see <a href="https://www.w3.org/TR/xmlschema-2/">
+ * XML Schema Part 2: Datatypes Second Edition
+ * </a>
+ * @see <a href="https://docs.oracle.com/javase/8/docs/api/javax/xml/bind/DatatypeConverter.html">
+ * JavaSE8:DatatypeConverter
+ * </a>
+ */
+final class DatatypeIo {
+
+    /**
+     * Hidden constructor.
+     */
+    private DatatypeIo(){
+        assert false;
+    }
+
+    /**
+     * Converts an int value into a string as xsd:int.
+     *
+     * @param iVal int value
+     * @return xsd:int type text
+     */
+    public static String printInt(int iVal){
+        String result;
+        result = String.valueOf(iVal);
+        return result;
+    }
+
+    /**
+     * Converts an float value into a string as xsd:float.
+     *
+     * <p>Infinite value will be "INF".
+     *
+     * @param fVal float value
+     * @return xsd:float type text
+     */
+    public static String printFloat(float fVal){
+        String result;
+
+        if(fVal == Float.POSITIVE_INFINITY){
+            result = "INF";
+        }else if(fVal == Float.NEGATIVE_INFINITY){
+            result = "-INF";
+        }else{
+            result = String.valueOf(fVal);
+        }
+
+        return result;
+    }
+
+    /**
+     * trimming whitespace around XSD datatypes value.
+     *
+     * @param txt XSD value
+     * @return trimmed text
+     */
+    public static CharSequence xsdTrim(CharSequence txt){
+        int length = txt.length();
+        int startPos = 0;
+        int endPos = length;
+
+        for(int pt = 0; pt < length; pt++){
+            char ch = txt.charAt(pt);
+            if(!isXsdWhitespace(ch)){
+                startPos = pt;
+                break;
+            }
+        }
+
+        for(int pt = length - 1; pt >= 0; pt--){
+            char ch = txt.charAt(pt);
+            if(!isXsdWhitespace(ch)){
+                endPos = pt + 1;
+                break;
+            }
+        }
+
+        CharSequence result = txt.subSequence(startPos, endPos);
+
+        return result;
+    }
+
+    /**
+     * checking whitespace character around XSD datattypes.
+     *
+     * <p>\n, \r, \t, and &#x5c;0020 are whitespace.
+     *
+     * @param ch character
+     * @return true if whitespace
+     */
+    public static boolean isXsdWhitespace(char ch){
+        boolean result;
+
+        switch(ch){
+        case '\n':
+        case '\r':
+        case '\t':
+        case '\u0020':
+            result = true;
+            break;
+        default:
+            result = false;
+            break;
+        }
+
+        return result;
+    }
+
+    /**
+     * Converts the xsd:boolean string argument into a boolean value.
+     *
+     * <p>{"true", "1"} is true. {"false", "0"} is false.
+     *
+     * @param xsdVal xsd:boolean string
+     * @return true if true
+     * @throws IllegalArgumentException illegal xsd:boolean string
+     */
+    public static boolean parseBoolean(CharSequence xsdVal)
+            throws IllegalArgumentException{
+        boolean result;
+
+        CharSequence trimmed = xsdTrim(xsdVal);
+
+        if("true".contentEquals(trimmed)){
+            result = true;
+        }else if("false".contentEquals(trimmed)){
+            result = false;
+        }else if("0".contentEquals(trimmed)){
+            result = false;
+        }else if("1".contentEquals(trimmed)){
+            result = true;
+        }else{
+            throw new IllegalArgumentException(trimmed.toString());
+        }
+
+        return result;
+    }
+
+    /**
+     * Converts the xsd:byte string argument into a byte value.
+     *
+     * @param xsdVal xsd:byte string
+     * @return byte value
+     * @throws NumberFormatException illegal xsd:byte
+     */
+    public static byte parseByte(CharSequence xsdVal)
+            throws NumberFormatException{
+        CharSequence trimmed = xsdTrim(xsdVal);
+
+        int iVal;
+        iVal = Integer.parseInt(trimmed.toString());
+
+        if(iVal < -128 || 127 < iVal){
+            throw new NumberFormatException(xsdVal.toString());
+        }
+
+        byte result;
+        result = (byte)iVal;
+
+        return result;
+    }
+
+    /**
+     * Converts the xsd:int string argument into a int value.
+     *
+     * @param xsdVal xsd:int string
+     * @return int value
+     * @throws NumberFormatException illegal xsd:int
+     */
+    public static int parseInt(CharSequence xsdVal)
+            throws NumberFormatException{
+        CharSequence trimmed = xsdTrim(xsdVal);
+        int result;
+        result = Integer.parseInt(trimmed.toString());
+        return result;
+    }
+
+    /**
+     * Converts the xsd:float string argument into a float value.
+     *
+     * @param xsdVal xsd:float string
+     * @return float value
+     * @throws NumberFormatException illegal xsd:float
+     */
+    public static float parseFloat(CharSequence xsdVal)
+            throws NumberFormatException{
+        String trimmed = xsdTrim(xsdVal).toString();
+
+        float result;
+        if("INF".equals(trimmed)){
+            result = Float.POSITIVE_INFINITY;
+        }else if("-INF".equals(trimmed)){
+            result = Float.NEGATIVE_INFINITY;
+        }else if(trimmed.endsWith("Infinity")){
+            throw new NumberFormatException(trimmed);
+        }else if(trimmed.contains("x") || trimmed.contains("X")){
+            // HexFloatingPointLiteral
+            throw new NumberFormatException(trimmed);
+        }else{
+            // zero will happen when underflow.
+            // infinite will happen when overflow.
+            // NaN is NaN.
+            // -0 is minus zero.
+            result = Float.parseFloat(trimmed);
+        }
+
+        return result;
+    }
+
+}
index 649b542..0bda046 100644 (file)
@@ -9,7 +9,6 @@ package jp.sfjp.mikutoga.xml;
 
 import java.text.MessageFormat;
 import java.util.Iterator;
-import javax.xml.bind.DatatypeConverter;
 import org.w3c.dom.DOMException;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
@@ -223,7 +222,7 @@ public final class DomNsUtils {
 
         boolean result;
         try{
-            result = DatatypeConverter.parseBoolean(value);
+            result = DatatypeIo.parseBoolean(value);
         }catch(IllegalArgumentException e){
             String message = MessageFormat.format(ERRMSG_INVATTR,
                                                   localName,
@@ -250,7 +249,7 @@ public final class DomNsUtils {
 
         int result;
         try{
-            result = DatatypeConverter.parseInt(value);
+            result = DatatypeIo.parseInt(value);
         }catch(NumberFormatException e){
             String message = MessageFormat.format(ERRMSG_INVATTR,
                                                   localName,
@@ -277,7 +276,7 @@ public final class DomNsUtils {
 
         float result;
         try{
-            result = DatatypeConverter.parseFloat(value);
+            result = DatatypeIo.parseFloat(value);
         }catch(NumberFormatException e){
             String message = MessageFormat.format(ERRMSG_INVATTR,
                                                   localName,
index 1463e8d..465c3f5 100644 (file)
@@ -11,7 +11,6 @@ import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.NoSuchElementException;
-import javax.xml.bind.DatatypeConverter;
 import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 
@@ -72,7 +71,7 @@ public final class DomUtils {
 
         boolean result;
         try{
-            result = DatatypeConverter.parseBoolean(value);
+            result = DatatypeIo.parseBoolean(value);
         }catch(IllegalArgumentException e){
             String message =
                     "Invalid boolean attribute form "
@@ -96,7 +95,7 @@ public final class DomUtils {
 
         int result;
         try{
-            result = DatatypeConverter.parseInt(value);
+            result = DatatypeIo.parseInt(value);
         }catch(IllegalArgumentException e){
             String message =
                     "Invalid integer attribute form "
@@ -120,7 +119,7 @@ public final class DomUtils {
 
         float result;
         try{
-            result = DatatypeConverter.parseFloat(value);
+            result = DatatypeIo.parseFloat(value);
         }catch(IllegalArgumentException e){
             String message =
                     "Invalid float attribute form "
index 6f55e5e..617aad5 100644 (file)
@@ -7,7 +7,6 @@
 
 package jp.sfjp.mikutoga.xml;
 
-import javax.xml.bind.DatatypeConverter;
 import org.xml.sax.Attributes;
 
 /**
@@ -57,7 +56,7 @@ public final class SaxAttr {
             throws IllegalArgumentException{
         String attrVal = attr.getValue(name);
         boolean bVal;
-        bVal = DatatypeConverter.parseBoolean(attrVal);
+        bVal = DatatypeIo.parseBoolean(attrVal);
         return bVal;
     }
 
@@ -77,7 +76,7 @@ public final class SaxAttr {
         if(attrVal == null) return def;
 
         boolean bVal;
-        bVal = DatatypeConverter.parseBoolean(attrVal);
+        bVal = DatatypeIo.parseBoolean(attrVal);
 
         return bVal;
     }
@@ -93,7 +92,7 @@ public final class SaxAttr {
             throws NumberFormatException{
         String attrVal = attr.getValue(name);
         byte bVal;
-        bVal = DatatypeConverter.parseByte(attrVal);
+        bVal = DatatypeIo.parseByte(attrVal);
         return bVal;
     }
 
@@ -108,7 +107,7 @@ public final class SaxAttr {
             throws NumberFormatException {
         String attrVal = attr.getValue(name);
         float fVal;
-        fVal = DatatypeConverter.parseFloat(attrVal);
+        fVal = DatatypeIo.parseFloat(attrVal);
         return fVal;
     }
 
@@ -123,7 +122,7 @@ public final class SaxAttr {
             throws NumberFormatException {
         String attrVal = attr.getValue(name);
         int iVal;
-        iVal = DatatypeConverter.parseInt(attrVal);
+        iVal = DatatypeIo.parseInt(attrVal);
         return iVal;
     }
 
index 85cd7cc..216c3ec 100644 (file)
@@ -41,12 +41,22 @@ public strictfp class MkQuatTest {
     public void tearDown() {
     }
 
-    private void assert0UlpEquals(double expected, double result){
+    /**
+     * StrictMath.toRadians(6) results are not same between JDK8 & JDK9.
+     */
+    private static double toRadians(double deg){
+        double result = deg * 0.01745329251994329576924;
+//        assert StrictMath.toRadians(6) == 0.10471975511965977; //JDK8
+//        assert StrictMath.toRadians(6) == 0.10471975511965978; //JDK9
+        return result;
+    }
+
+    private static void assert0UlpEquals(double expected, double result){
         assertUlpEquals(expected, result, 0);
         return;
     }
 
-    private void assertUlpEquals(double expected, double result, int ulpNum){
+    private static void assertUlpEquals(double expected, double result, int ulpNum){
         double ulpExpected = StrictMath.ulp(expected);
         double ulpResult   = StrictMath.ulp(result);
         double ulp = StrictMath.max(ulpExpected, ulpResult);
@@ -434,14 +444,14 @@ public strictfp class MkQuatTest {
         double yRad;
         double zRad;
 
-        xRad = StrictMath.toRadians(95);
-        yRad = StrictMath.toRadians(0);
-        zRad = StrictMath.toRadians(0);
+        xRad = toRadians(95);
+        yRad = toRadians(0);
+        zRad = toRadians(0);
         qq.setEulerYXZ(xRad, yRad, zRad);
         qq.toEulerYXZ(eu, yRad);
-        assertUlpEquals(StrictMath.toRadians(85), eu.getXRot(), 1);
-        assertUlpEquals(StrictMath.toRadians(180), eu.getYRot(), 0);
-        assertUlpEquals(StrictMath.toRadians(180), eu.getZRot(), 0);
+        assertUlpEquals(toRadians(85), eu.getXRot(), 1);
+        assertUlpEquals(toRadians(180), eu.getYRot(), 0);
+        assertUlpEquals(toRadians(180), eu.getZRot(), 0);
 
         return;
     }
@@ -462,9 +472,9 @@ public strictfp class MkQuatTest {
         qq = new MkQuat();
         eu = new EulerYXZ();
 
-        xRad = StrictMath.toRadians(89);
-        yRad = StrictMath.toRadians(80);
-        zRad = StrictMath.toRadians(41);
+        xRad = toRadians(89);
+        yRad = toRadians(80);
+        zRad = toRadians(41);
         qq.setEulerYXZ(xRad, yRad, zRad);
         qq.toEulerYXZ(eu, 0.0);
         assertUlpEquals(xRad, eu.getXRot(), 164);
@@ -472,23 +482,23 @@ public strictfp class MkQuatTest {
         assertUlpEquals(zRad, eu.getZRot(), 211);
 
         // ジンバルロック判定境界ケース
-        xRad = StrictMath.toRadians(90);
-        yRad = StrictMath.toRadians(6);
-        zRad = StrictMath.toRadians(7);
+        xRad = toRadians(90);
+        yRad = toRadians(6);
+        zRad = toRadians(7);
         qq.setEulerYXZ(xRad, yRad, zRad);
         qq.toEulerYXZ(eu, yRad);
         assert0UlpEquals(xRad, eu.getXRot());
         assert0UlpEquals(yRad, eu.getYRot());
-        assert0UlpEquals(zRad, eu.getZRot());
+        assertUlpEquals(zRad, eu.getZRot(), 1);
 
-        xRad = StrictMath.toRadians(89.999);
-        yRad = StrictMath.toRadians(89.999);
-        zRad = StrictMath.toRadians(89.999);
+        xRad = toRadians(89.999);
+        yRad = toRadians(89.999);
+        zRad = toRadians(89.999);
         qq.setEulerYXZ(xRad, yRad, zRad);
         qq.toEulerYXZ(eu, yRad);
         assertUlpEquals(xRad, eu.getXRot(), 83029);
-        assertUlpEquals(yRad, eu.getYRot(), 80108);
-        assertUlpEquals(zRad, eu.getZRot(), 80108);
+        assertUlpEquals(yRad, eu.getYRot(), 91782);
+        assertUlpEquals(zRad, eu.getZRot(), 91782);
 
         return;
     }
@@ -668,9 +678,9 @@ public strictfp class MkQuatTest {
         qq = new MkQuat();
         result = new EulerYXZ();
 
-        double xRad = StrictMath.toRadians(ix);
-        double yRad = StrictMath.toRadians(iy);
-        double zRad = StrictMath.toRadians(iz);
+        double xRad = toRadians(ix);
+        double yRad = toRadians(iy);
+        double zRad = toRadians(iz);
 
         qq.setEulerYXZ(xRad, yRad, zRad);
         qq.toEulerYXZ(result, yRad);
diff --git a/src/test/java/jp/sfjp/mikutoga/xml/BasicXmlExporterTest.java b/src/test/java/jp/sfjp/mikutoga/xml/BasicXmlExporterTest.java
new file mode 100644 (file)
index 0000000..61edcc4
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+ */
+
+package jp.sfjp.mikutoga.xml;
+
+import java.io.IOException;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class BasicXmlExporterTest {
+
+    public BasicXmlExporterTest() {
+    }
+
+    @BeforeClass
+    public static void setUpClass() {
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+    }
+
+    @Before
+    public void setUp() {
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    /**
+     * Test of append method, of class BasicXmlExporter.
+     */
+    @Test
+    public void testAppend() {
+        System.out.println("setAppendable");
+
+        BasicXmlExporter instance;
+        Appendable app;
+        StringBuffer buf;
+        
+        instance = new BasicXmlExporter();
+
+        try{
+            instance.append(null);
+            fail();
+        }catch(NullPointerException e){
+            assert true;
+        }catch(IOException e){
+            fail();
+        }
+
+        buf = new StringBuffer();
+        app = buf;
+
+        instance.setAppendable(app);
+
+        try{
+            instance.append("abc");
+            instance.append('d');
+            instance.append("abcdef", 4, 5);
+        }catch(IOException e){
+            fail();
+        }
+
+        assertEquals("abcde", buf.toString());
+
+        try{
+            instance.flush();
+            instance.close();
+        }catch(IOException e){
+            fail();
+        }
+
+        return;
+    }
+
+    @Test
+    public void testPutXsdInt() throws IOException{
+        System.out.println("putXsdInt");
+
+        BasicXmlExporter instance;
+        StringBuffer buf;
+
+        instance = new BasicXmlExporter();
+
+        buf = new StringBuffer();
+        instance.setAppendable(buf);
+        instance.putXsdInt(-1).putCh(',').putXsdInt(0).putCh(',').putXsdInt(1);
+        assertEquals("-1,0,1", buf.toString());
+
+        buf = new StringBuffer();
+        instance.setAppendable(buf);
+        instance.putXsdInt(-999).putCh(',').putXsdInt(9999);
+        assertEquals("-999,9999", buf.toString());
+
+        buf = new StringBuffer();
+        instance.setAppendable(buf);
+        instance.putXsdInt(Integer.MIN_VALUE).putCh(',').putXsdInt(Integer.MAX_VALUE);
+        assertEquals("-2147483648,2147483647", buf.toString());
+
+        return;
+    }
+
+    @Test
+    public void testPutXsdFloat() throws IOException{
+        System.out.println("putXsdFloat");
+
+        BasicXmlExporter instance;
+        StringBuffer buf;
+
+        instance = new BasicXmlExporter();
+
+        buf = new StringBuffer();
+        instance.setAppendable(buf);
+        instance.putXsdFloat(-1.0f).putCh(',')
+                .putXsdFloat(-0.0f).putCh(',')
+                .putXsdFloat(0.0f).putCh(',')
+                .putXsdFloat(1.0f);
+        assertEquals("-1.0,-0.0,0.0,1.0", buf.toString());
+
+        buf = new StringBuffer();
+        instance.setAppendable(buf);
+        instance.putXsdFloat(Float.NEGATIVE_INFINITY).putCh(',')
+                .putXsdFloat(Float.POSITIVE_INFINITY).putCh(',')
+                .putXsdFloat(Float.NaN);
+        assertEquals("-INF,INF,NaN", buf.toString());
+
+        buf = new StringBuffer();
+        instance.setAppendable(buf);
+        instance.putXsdFloat(Float.MIN_VALUE).putCh(',')
+                .putXsdFloat(Float.MIN_NORMAL).putCh(',')
+                .putXsdFloat(Float.MAX_VALUE);
+        assertEquals("1.4E-45,1.17549435E-38,3.4028235E38", buf.toString());
+
+        buf = new StringBuffer();
+        instance.setAppendable(buf);
+        instance.putXsdFloat(0.001f);
+        assertEquals("0.001", buf.toString()); // fuzzy "0.0010" on JDK1.6
+
+        buf = new StringBuffer();
+        instance.setAppendable(buf);
+        instance.putXsdFloat(StrictMath.nextDown(0.001f));
+        assertEquals("9.999999E-4", buf.toString());
+
+        buf = new StringBuffer();
+        instance.setAppendable(buf);
+        instance.putXsdFloat(10000000.0f);
+        assertEquals("1.0E7", buf.toString());
+
+        buf = new StringBuffer();
+        instance.setAppendable(buf);
+        instance.putXsdFloat(StrictMath.nextDown(10000000.0f));
+        assertEquals("9999999.0", buf.toString());
+
+        buf = new StringBuffer();
+        instance.setAppendable(buf);
+        instance.putXsdFloat((float)StrictMath.E).putCh(',')
+                .putXsdFloat((float)StrictMath.PI);
+        assertEquals("2.7182817,3.1415927", buf.toString());
+
+        return;
+    }
+
+}
diff --git a/src/test/java/jp/sfjp/mikutoga/xml/DatatypeIoTest.java b/src/test/java/jp/sfjp/mikutoga/xml/DatatypeIoTest.java
new file mode 100644 (file)
index 0000000..13f1edc
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ */
+package jp.sfjp.mikutoga.xml;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ */
+public class DatatypeIoTest {
+
+    public DatatypeIoTest() {
+    }
+
+    @BeforeClass
+    public static void setUpClass() {
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+    }
+
+    @Before
+    public void setUp() {
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    /**
+     * Test of printInt method, of class DatatypeIo.
+     */
+    @Test
+    public void testPrintInt() {
+        System.out.println("printInt");
+
+        CharSequence result;
+
+        result = DatatypeIo.printInt(0);
+        assertEquals("0", result.toString());
+
+        result = DatatypeIo.printInt(1);
+        assertEquals("1", result.toString());
+
+        result = DatatypeIo.printInt(-1);
+        assertEquals("-1", result.toString());
+
+        result = DatatypeIo.printInt(999);
+        assertEquals("999", result.toString());
+
+        result = DatatypeIo.printInt(-9999);
+        assertEquals("-9999", result.toString());
+
+        result = DatatypeIo.printInt(Integer.MIN_VALUE);
+        assertEquals("-2147483648", result.toString());
+
+        result = DatatypeIo.printInt(Integer.MAX_VALUE);
+        assertEquals("2147483647", result.toString());
+
+        return;
+    }
+
+    /**
+     * Test of printFloat method, of class DatatypeIo.
+     */
+    @Test
+    public void testPrintFloat() {
+        System.out.println("printFloat");
+
+        CharSequence result;
+
+        result = DatatypeIo.printFloat(0.0f);
+        assertEquals("0.0", result.toString());
+
+        result = DatatypeIo.printFloat(-0.0f);
+        assertEquals("-0.0", result.toString());
+
+        result = DatatypeIo.printFloat(1.0f);
+        assertEquals("1.0", result.toString());
+
+        result = DatatypeIo.printFloat(-1.0f);
+        assertEquals("-1.0", result.toString());
+
+        result = DatatypeIo.printFloat((float)StrictMath.E);
+        assertEquals("2.7182817", result.toString());
+
+        result = DatatypeIo.printFloat((float)StrictMath.PI);
+        assertEquals("3.1415927", result.toString());
+
+        result = DatatypeIo.printFloat(0.001f);
+        assertEquals("0.001", result.toString());
+
+        result = DatatypeIo.printFloat(StrictMath.nextDown(0.001f));
+        assertEquals("9.999999E-4", result.toString());
+
+        result = DatatypeIo.printFloat(10_000_000.0f);
+        assertEquals("1.0E7", result.toString());
+
+        result = DatatypeIo.printFloat(StrictMath.nextDown(10_000_000.0f));
+        assertEquals("9999999.0", result.toString());
+
+        result = DatatypeIo.printFloat(Float.POSITIVE_INFINITY);
+        assertEquals("INF", result.toString());
+
+        result = DatatypeIo.printFloat(Float.NEGATIVE_INFINITY);
+        assertEquals("-INF", result.toString());
+
+        result = DatatypeIo.printFloat(Float.NaN);
+        assertEquals("NaN", result.toString());
+
+        result = DatatypeIo.printFloat(Float.MIN_VALUE);
+        assertEquals("1.4E-45", result.toString());
+
+        result = DatatypeIo.printFloat(Float.MIN_NORMAL);
+        assertEquals("1.17549435E-38", result.toString());
+
+        result = DatatypeIo.printFloat(Float.MAX_VALUE);
+        assertEquals("3.4028235E38", result.toString());
+
+        return;
+    }
+
+    /**
+     * Test of parseBoolean method, of class DatatypeIo.
+     */
+    @Test
+    public void testParseBoolean() {
+        System.out.println("parseBoolean");
+
+        assertFalse(DatatypeIo.parseBoolean("0"));
+        assertFalse(DatatypeIo.parseBoolean("false"));
+        assertTrue(DatatypeIo.parseBoolean("1"));
+        assertTrue(DatatypeIo.parseBoolean("true"));
+
+        assertTrue(DatatypeIo.parseBoolean("\n\rtrue\u0020\t"));
+
+        try{
+            DatatypeIo.parseBoolean("yes");
+            fail();
+        }catch(IllegalArgumentException e){
+            assert true;
+        }
+
+        try{
+            DatatypeIo.parseBoolean("");
+            fail();
+        }catch(IllegalArgumentException e){
+            assert true;
+        }
+
+        return;
+    }
+
+    /**
+     * Test of parseInt method, of class DatatypeIo.
+     */
+    @Test
+    public void testParseInt() {
+        System.out.println("parseInt");
+
+        int result;
+
+        result = DatatypeIo.parseInt("0");
+        assertEquals(0, result);
+
+        result = DatatypeIo.parseInt("+0");
+        assertEquals(0, result);
+
+        result = DatatypeIo.parseInt("-0");
+        assertEquals(0, result);
+
+        result = DatatypeIo.parseInt("1");
+        assertEquals(1, result);
+
+        result = DatatypeIo.parseInt("+1");
+        assertEquals(1, result);
+
+        result = DatatypeIo.parseInt("-1");
+        assertEquals(-1, result);
+
+        result = DatatypeIo.parseInt("999");
+        assertEquals(999, result);
+
+        result = DatatypeIo.parseInt("-9999");
+        assertEquals(-9999, result);
+
+        result = DatatypeIo.parseInt("-2147483648");
+        assertEquals(Integer.MIN_VALUE, result);
+
+        result = DatatypeIo.parseInt("2147483647");
+        assertEquals(Integer.MAX_VALUE, result);
+
+        result = DatatypeIo.parseInt("\n\r999\u0020\t");
+        assertEquals(999, result);
+
+        try{
+            DatatypeIo.parseInt("?");
+            fail();
+        }catch(NumberFormatException e){
+            assert true;
+        }
+
+        try{
+            DatatypeIo.parseInt("-2147483649");
+            fail();
+        }catch(NumberFormatException e){
+            assert true;
+        }
+
+        try{
+            DatatypeIo.parseInt("2147483648");
+            fail();
+        }catch(NumberFormatException e){
+            assert true;
+        }
+
+        try{
+            DatatypeIo.parseInt("3.14");
+            fail();
+        }catch(NumberFormatException e){
+            assert true;
+        }
+
+        return;
+    }
+
+    /**
+     * Test of parseFloat method, of class DatatypeIo.
+     */
+    @Test
+    public void testParseFloat() {
+        System.out.println("parseFloat");
+
+        float result;
+
+        result = DatatypeIo.parseFloat("0.0");
+        assertEquals(0.0f, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("+0.0");
+        assertEquals(0.0f, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("-0.0");
+        assertEquals(-0.0f, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("-123.45");
+        assertEquals(-123.45f, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("654.32");
+        assertEquals(654.32f, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("2.718281828459045");
+        assertEquals((float)StrictMath.E, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("3.141592653589793");
+        assertEquals((float)StrictMath.PI, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("1.401298464324817E-45");
+        assertEquals(Float.MIN_VALUE, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("1.1754943508222875E-38");
+        assertEquals(Float.MIN_NORMAL, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("3.4028234663852886E38");
+        assertEquals(Float.MAX_VALUE, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("2E3");
+        assertEquals(2000.0f, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("2.3E4");
+        assertEquals(23000.0f, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("2.3e4");
+        assertEquals(23000.0f, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("2.3E+4");
+        assertEquals(23000.0f, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("2.3E-4");
+        assertEquals(0.00023f, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("INF");
+        assertEquals(Float.POSITIVE_INFINITY, result, 0.0f);
+
+        result = DatatypeIo.parseFloat("-INF");
+        assertEquals(Float.NEGATIVE_INFINITY, result, 0.0f);
+
+        try{
+            DatatypeIo.parseFloat("+INF");
+            fail();
+        }catch(NumberFormatException e){
+            assert true;
+        }
+
+        try{
+            DatatypeIo.parseFloat("Infinity");
+            fail();
+        }catch(NumberFormatException e){
+            assert true;
+        }
+
+        result = DatatypeIo.parseFloat("NaN");
+        assertTrue(Float.isNaN(result));
+
+        result = DatatypeIo.parseFloat("\n\r1.2\u0020\t");
+        assertEquals(1.2f, result, 0.0f);
+
+        try{
+            DatatypeIo.parseFloat("?");
+            fail();
+        }catch(NumberFormatException e){
+            assert true;
+        }
+
+        try{
+            DatatypeIo.parseFloat("0x1.0p0");
+            fail();
+        }catch(NumberFormatException e){
+            assert true;
+        }
+
+        return;
+    }
+
+    /**
+     * Test of trim method, of class DatatypeIo.
+     */
+    @Test
+    public void testTrim() {
+        System.out.println("trim");
+
+        CharSequence txt;
+        CharSequence result;
+
+        txt = "abc";
+        result = DatatypeIo.xsdTrim(txt);
+        assertEquals("abc", result.toString());
+
+        txt = "";
+        result = DatatypeIo.xsdTrim(txt);
+        assertEquals("", result.toString());
+
+        txt = "  abc   ";
+        result = DatatypeIo.xsdTrim(txt);
+        assertEquals("abc", result.toString());
+
+        txt = "  abc";
+        result = DatatypeIo.xsdTrim(txt);
+        assertEquals("abc", result.toString());
+
+        txt = "abc  ";
+        result = DatatypeIo.xsdTrim(txt);
+        assertEquals("abc", result.toString());
+
+        txt = " a b c ";
+        result = DatatypeIo.xsdTrim(txt);
+        assertEquals("a b c", result.toString());
+
+        txt = "\n\rabc\u0020\t";
+        result = DatatypeIo.xsdTrim(txt);
+        assertEquals("abc", result.toString());
+
+        return;
+    }
+
+    /**
+     * Test of isWhitespace method, of class DatatypeIo.
+     */
+    @Test
+    public void testIsWhitespace() {
+        System.out.println("isWhitespace");
+
+        assertTrue(DatatypeIo.isXsdWhitespace('\u0020'));
+        assertTrue(DatatypeIo.isXsdWhitespace('\n'));
+        assertTrue(DatatypeIo.isXsdWhitespace('\r'));
+        assertTrue(DatatypeIo.isXsdWhitespace('\t'));
+        assertFalse(DatatypeIo.isXsdWhitespace('X'));
+        assertFalse(DatatypeIo.isXsdWhitespace('\u0001'));
+
+        return;
+    }
+
+}
diff --git a/src/test/java/jp/sfjp/mikutoga/xml/DomUtilsTest.java b/src/test/java/jp/sfjp/mikutoga/xml/DomUtilsTest.java
new file mode 100644 (file)
index 0000000..f319a31
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+@see https://www.w3.org/TR/xmlschema-2/
+ */
+
+package jp.sfjp.mikutoga.xml;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+/**
+ *
+ */
+public class DomUtilsTest {
+
+    private static final DocumentBuilderFactory FACTORY =
+            DocumentBuilderFactory.newInstance();
+    private static final DocumentBuilder BUILDER;
+
+    private static final String TESTELEM = "testelem";
+    private static final String TESTATTR = "testattr";
+
+    private static Element getTestAttredElem(String attrVal){
+        Document doc = BUILDER.newDocument();
+        Element elem = doc.createElement(TESTELEM);
+        elem.setAttribute(TESTATTR, attrVal);
+        return elem;
+    }
+
+    static{
+        try{
+            BUILDER = FACTORY.newDocumentBuilder();
+        }catch(ParserConfigurationException e){
+            throw new ExceptionInInitializerError(e);
+        }
+    }
+
+    public DomUtilsTest() {
+    }
+
+    @BeforeClass
+    public static void setUpClass() throws ParserConfigurationException{
+    }
+
+    @AfterClass
+    public static void tearDownClass() {
+    }
+
+    @Before
+    public void setUp() {
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    /**
+     * Test of getBooleanAttr method, of class DomUtils.
+     */
+    @Test
+    public void testGetBooleanAttr() throws Exception {
+        System.out.println("getBooleanAttr");
+
+        boolean result;
+        Element elem;
+
+        elem = getTestAttredElem("true");
+        result = DomUtils.getBooleanAttr(elem, TESTATTR);
+        assertTrue(result);
+
+        elem = getTestAttredElem("false");
+        result = DomUtils.getBooleanAttr(elem, TESTATTR);
+        assertFalse(result);
+
+        elem = getTestAttredElem("0");
+        result = DomUtils.getBooleanAttr(elem, TESTATTR);
+        assertFalse(result);
+
+        elem = getTestAttredElem("1");
+        result = DomUtils.getBooleanAttr(elem, TESTATTR);
+        assertTrue(result);
+
+        elem = getTestAttredElem("\n\rtrue\u0020\t");
+        result = DomUtils.getBooleanAttr(elem, TESTATTR);
+        assertTrue(result);
+
+        elem = getTestAttredElem("?");
+        try{
+            DomUtils.getBooleanAttr(elem, TESTATTR);
+            fail();
+        }catch(TogaXmlException e){
+            assert true;
+        }
+
+        return;
+    }
+
+    /**
+     * Test of getIntegerAttr method, of class DomUtils.
+     */
+    @Test
+    public void testGetIntegerAttr() throws TogaXmlException {
+        System.out.println("getIntegerAttr");
+
+        int result;
+        Element elem;
+
+        elem = getTestAttredElem("0");
+        result = DomUtils.getIntegerAttr(elem, TESTATTR);
+        assertEquals(0, result);
+
+        elem = getTestAttredElem("1");
+        result = DomUtils.getIntegerAttr(elem, TESTATTR);
+        assertEquals(1, result);
+
+        elem = getTestAttredElem("-1");
+        result = DomUtils.getIntegerAttr(elem, TESTATTR);
+        assertEquals(-1, result);
+
+        elem = getTestAttredElem("999");
+        result = DomUtils.getIntegerAttr(elem, TESTATTR);
+        assertEquals(999, result);
+
+        elem = getTestAttredElem("-9999");
+        result = DomUtils.getIntegerAttr(elem, TESTATTR);
+        assertEquals(-9999, result);
+
+        elem = getTestAttredElem("\n\r999\u0020\t");
+        result = DomUtils.getIntegerAttr(elem, TESTATTR);
+        assertEquals(999, result);
+
+        elem = getTestAttredElem("?");
+        try{
+            result = DomUtils.getIntegerAttr(elem, TESTATTR);
+            fail();
+        }catch(TogaXmlException e){
+            assert true;
+        }
+
+        return;
+    }
+
+    /**
+     * Test of getFloatAttr method, of class DomUtils.
+     */
+    @Test
+    public void testGetFloatAttr() throws TogaXmlException {
+        System.out.println("getFloatAttr");
+
+        float result;
+        Element elem;
+
+        elem = getTestAttredElem("0.0");
+        result = DomUtils.getFloatAttr(elem, TESTATTR);
+        assertEquals(0.0f, result, 0.0f);
+
+        elem = getTestAttredElem("-0.0");
+        result = DomUtils.getFloatAttr(elem, TESTATTR);
+        assertEquals(0.0f, result, 0.0f);
+        assertEquals("-0.0", Float.toString(result));
+
+        elem = getTestAttredElem("-123.456");
+        result = DomUtils.getFloatAttr(elem, TESTATTR);
+        assertEquals(-123.456f, result, 0.0f);
+
+        elem = getTestAttredElem("654.321");
+        result = DomUtils.getFloatAttr(elem, TESTATTR);
+        assertEquals(654.321f, result, 0.0f);
+
+        elem = getTestAttredElem("2.3E4");
+        result = DomUtils.getFloatAttr(elem, TESTATTR);
+        assertEquals(23000.0f, result, 0.0f);
+
+        elem = getTestAttredElem("INF");
+        result = DomUtils.getFloatAttr(elem, TESTATTR);
+        assertEquals(Float.POSITIVE_INFINITY, result, 0.0f);
+
+        elem = getTestAttredElem("+INF");
+        try{
+            DomUtils.getFloatAttr(elem, TESTATTR);
+            fail();
+        }catch(TogaXmlException e){
+            assert true;
+        }
+
+        elem = getTestAttredElem("NaN");
+        result = DomUtils.getFloatAttr(elem, TESTATTR);
+        assertTrue(Float.isNaN(result));
+
+        elem = getTestAttredElem("\n\r123.456\u0020\t");
+        result = DomUtils.getFloatAttr(elem, TESTATTR);
+        assertEquals(123.456f, result, 0.0f);
+
+        elem = getTestAttredElem("?");
+        try{
+            DomUtils.getFloatAttr(elem, TESTATTR);
+            fail();
+        }catch(TogaXmlException e){
+            assert true;
+        }
+
+        return;
+    }
+
+}