/* ==================================================================== 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.formula.functions; import org.apache.poi.hssf.usermodel.HSSFFormulaEvaluator; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.formula.eval.StringEval; import org.apache.poi.ss.formula.eval.ValueEval; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.CellValue; import org.apache.poi.ss.usermodel.FormulaEvaluator; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.xssf.usermodel.XSSFFormulaEvaluator; import org.apache.poi.xssf.usermodel.XSSFWorkbook; import junit.framework.AssertionFailedError; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; public final class TestProper { private Cell cell11; private FormulaEvaluator evaluator; @Test public void testValidHSSF() { HSSFWorkbook wb = new HSSFWorkbook(); evaluator = new HSSFFormulaEvaluator(wb); confirm(wb); } @Test public void testValidXSSF() { XSSFWorkbook wb = new XSSFWorkbook(); evaluator = new XSSFFormulaEvaluator(wb); confirm(wb); } private void confirm(Workbook wb) { Sheet sheet = wb.createSheet("new sheet"); cell11 = sheet.createRow(0).createCell(0); cell11.setCellType(CellType.FORMULA); confirm("PROPER(\"hi there\")", "Hi There"); //simple case confirm("PROPER(\"what's up\")", "What'S Up"); //apostrophes are treated as word breaks confirm("PROPER(\"I DON'T TH!NK SO!\")", "I Don'T Th!Nk So!"); //capitalization is ignored, special punctuation is treated as a word break confirm("PROPER(\"dr\u00dcb\u00f6'\u00e4 \u00e9lo\u015f|\u00eb\u00e8 \")", "Dr\u00fcb\u00f6'\u00c4 \u00c9lo\u015f|\u00cb\u00e8 "); confirm("PROPER(\"hi123 the123re\")", "Hi123 The123Re"); //numbers are treated as word breaks confirm("PROPER(\"-\")", "-"); //nothing happens with ascii punctuation that is not upper or lower case confirm("PROPER(\"!\u00a7$\")", "!\u00a7$"); //nothing happens with unicode punctuation (section sign) that is not upper or lower case confirm("PROPER(\"/&%\")", "/&%"); //nothing happens with ascii punctuation that is not upper or lower case confirm("PROPER(\"Apache POI\")", "Apache Poi"); //acronyms are not special confirm("PROPER(\" hello world\")", " Hello World"); //leading whitespace is ignored final String scharfes = "\u00df"; //German lowercase eszett, scharfes s, sharp s confirm("PROPER(\"stra"+scharfes+"e\")", "Stra"+scharfes+"e"); assertTrue(Character.isLetter(scharfes.charAt(0))); // CURRENTLY FAILS: result: "SSUnd"+scharfes // LibreOffice 5.0.3.2 behavior: "Sund"+scharfes // Excel 2013 behavior: ??? confirm("PROPER(\""+scharfes+"und"+scharfes+"\")", "SSund"+scharfes); // also test longer string StringBuilder builder = new StringBuilder("A"); StringBuilder expected = new StringBuilder("A"); for(int i = 1;i < 254;i++) { builder.append((char)(65 + (i % 26))); expected.append((char)(97 + (i % 26))); } confirm("PROPER(\"" + builder + "\")", expected.toString()); } private void confirm(String formulaText, String expectedResult) { cell11.setCellFormula(formulaText); evaluator.clearAllCachedResultValues(); CellValue cv = evaluator.evaluate(cell11); if (cv.getCellTypeEnum() != CellType.STRING) { throw new AssertionFailedError("Wrong result type: " + cv.formatAsString()); } String actualValue = cv.getStringValue(); assertEquals(expectedResult, actualValue); } @Test public void test() { checkProper("", ""); checkProper("a", "A"); checkProper("abc", "Abc"); checkProper("abc abc", "Abc Abc"); checkProper("abc/abc", "Abc/Abc"); checkProper("ABC/ABC", "Abc/Abc"); checkProper("aBc/ABC", "Abc/Abc"); checkProper("aBc@#$%^&*()_+=-ABC", "Abc@#$%^&*()_+=-Abc"); checkProper("aBc25aerg/ABC", "Abc25Aerg/Abc"); checkProper("aBc/\u00C4\u00F6\u00DF\u00FC/ABC", "Abc/\u00C4\u00F6\u00DF\u00FC/Abc"); // Some German umlauts with uppercase first letter is not changed checkProper("\u00FC", "\u00DC"); checkProper("\u00DC", "\u00DC"); checkProper("\u00DF", "SS"); // German "scharfes s" is uppercased to "SS" checkProper("\u00DFomesing", "SSomesing"); // German "scharfes s" is uppercased to "SS" checkProper("aBc/\u00FC\u00C4\u00F6\u00DF\u00FC/ABC", "Abc/\u00DC\u00E4\u00F6\u00DF\u00FC/Abc"); // Some German umlauts with lowercase first letter is changed to uppercase } @Test public void testMicroBenchmark() { ValueEval strArg = new StringEval("some longer text that needs a number of replacements to check for runtime of different implementations"); long start = System.currentTimeMillis(); for(int i = 0;i < 300000;i++) { final ValueEval ret = TextFunction.PROPER.evaluate(new ValueEval[]{strArg}, 0, 0); assertEquals("Some Longer Text That Needs A Number Of Replacements To Check For Runtime Of Different Implementations", ((StringEval)ret).getStringValue()); } // Took aprox. 600ms on a decent Laptop in July 2016 System.out.println("Took: " + (System.currentTimeMillis() - start) + "ms"); } private void checkProper(String input, String expected) { ValueEval strArg = new StringEval(input); final ValueEval ret = TextFunction.PROPER.evaluate(new ValueEval[]{strArg}, 0, 0); assertEquals(expected, ((StringEval)ret).getStringValue()); } }