| /* ==================================================================== |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| ==================================================================== */ |
| |
| package org.apache.poi.ss.util; |
| |
| import junit.framework.AssertionFailedError; |
| import junit.framework.ComparisonFailure; |
| import junit.framework.TestCase; |
| |
| import java.util.Locale; |
| |
| import org.apache.poi.hssf.record.FormulaRecord; |
| import org.apache.poi.ss.formula.constant.ConstantValueParser; |
| import org.apache.poi.ss.formula.ptg.NumberPtg; |
| import org.apache.poi.ss.util.NumberToTextConversionExamples.ExampleConversion; |
| /** |
| * Tests for {@link NumberToTextConverter} |
| * |
| * @author Josh Micich |
| */ |
| public final class TestNumberToTextConverter extends TestCase { |
| |
| |
| /** |
| * Confirms that <tt>ExcelNumberToTextConverter.toText(d)</tt> produces the right results. |
| * As part of preparing this test class, the <tt>ExampleConversion</tt> instances should be set |
| * up to contain the rendering as produced by Excel. |
| */ |
| public void testAll() { |
| int failureCount = 0; |
| |
| ExampleConversion[] examples = NumberToTextConversionExamples.getExampleConversions(); |
| |
| for (int i = 0; i < examples.length; i++) { |
| ExampleConversion example = examples[i]; |
| try { |
| if (example.isNaN()) { |
| confirmNaN(example.getRawDoubleBits(), example.getExcelRendering()); |
| continue; |
| } |
| String actual = NumberToTextConverter.toText(example.getDoubleValue()); |
| if (!example.getExcelRendering().equals(actual)) { |
| failureCount++; |
| String msg = "Error rendering for examples[" + i + "] " |
| + formatExample(example) + " " |
| + " bad-result='" + actual + "' " |
| + new ComparisonFailure(null, example.getExcelRendering(), actual).getMessage(); |
| System.err.println(msg); |
| continue; |
| } |
| } catch (RuntimeException e) { |
| failureCount++; |
| System.err.println("Error in excel rendering for examples[" + i + "] " |
| + formatExample(example) + "':" + e.getMessage()); |
| e.printStackTrace(); |
| } |
| } |
| if (failureCount > 0) { |
| throw new AssertionFailedError(failureCount |
| + " error(s) in excel number to text conversion (see std-err)"); |
| } |
| } |
| |
| private static String formatExample(ExampleConversion example) { |
| String hexLong = Long.toHexString(example.getRawDoubleBits()).toUpperCase(Locale.ROOT); |
| String longRep = "0x" + "0000000000000000".substring(hexLong.length()) + hexLong+ "L"; |
| return "ec(" + longRep + ", \"" + example.getJavaRendering() + "\", \"" + example.getExcelRendering() + "\")"; |
| } |
| |
| /** |
| * Excel's abnormal rendering of NaNs is both difficult to test and even reproduce in java. In |
| * general, Excel does not attempt to use raw NaN in the IEEE sense. In {@link FormulaRecord}s, |
| * Excel uses the NaN bit pattern to flag non-numeric (text, boolean, error) cached results. |
| * If the formula result actually evaluates to raw NaN, Excel transforms it to <i>#NUM!</i>. |
| * In other places (e.g. {@link NumberRecord}, {@link NumberPtg}, array items (via {@link |
| * ConstantValueParser}), there seems to be no special NaN translation scheme. If a NaN bit |
| * pattern is somehow encoded into any of these places Excel actually attempts to render the |
| * values as a plain number. That is the unusual functionality that this method is testing.<p> |
| * |
| * There are multiple encodings (bit patterns) for NaN, and CPUs and applications can convert |
| * to a preferred NaN encoding (Java prefers <tt>0x7FF8000000000000L</tt>). Besides the |
| * special encoding in {@link FormulaRecord.SpecialCachedValue}, it is not known how/whether |
| * Excel attempts to encode NaN values. |
| * |
| * Observed NaN behaviour on HotSpot/Windows: |
| * <tt>Double.longBitsToDouble()</tt> will set one bit 51 (the NaN signaling flag) if it isn't |
| * already. <tt>Double.doubleToLongBits()</tt> will return a double with bit pattern |
| * <tt>0x7FF8000000000000L</tt> for any NaN bit pattern supplied.<br> |
| * Differences are likely to be observed with other architectures.<p> |
| * |
| * <p> |
| * The few test case examples calling this method represent functionality which may not be |
| * important for POI to support. |
| */ |
| private void confirmNaN(long l, String excelRep) { |
| double d = Double.longBitsToDouble(l); |
| assertEquals("NaN", Double.toString(d)); |
| |
| String strExcel = NumberToTextConverter.rawDoubleBitsToText(l); |
| |
| assertEquals(excelRep, strExcel); |
| } |
| |
| public void testSimpleRendering_bug56156() { |
| double dResult = 0.05+0.01; // values chosen to produce rounding anomaly |
| String actualText = NumberToTextConverter.toText(dResult); |
| String jdkText = Double.toString(dResult); |
| if (jdkText.equals(actualText)) { |
| // "0.060000000000000005" |
| throw new AssertionFailedError("Should not use default JDK IEEE double rendering"); |
| } |
| assertEquals("0.06", actualText); |
| } |
| } |