This is an automated email from the ASF dual-hosted git repository.
gtchaboussie pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git
The following commit(s) were added to refs/heads/trunk by this push:
new e3d73ac143 Improved: FlexibleStringExpander tests rewrite (OFBIZ-13336)
e3d73ac143 is described below
commit e3d73ac143e1ec9481f4b89df228eead47aaa879
Author: Gaetan <[email protected]>
AuthorDate: Fri Jan 30 09:41:17 2026 +0100
Improved: FlexibleStringExpander tests rewrite (OFBIZ-13336)
- Rewrote the FlexibleStringExpander in groovy.
- Simplified the reading by splitting the tests into two distinct
classes : Parser, and actual FSE test.
- Actual tests are now grouped by theme.
- Small tool classes that were used are now dedicated classes.
- Also removed the explicit groovy test sources, no longer required,
with the added useJunit()
config to allow this behavior
(#939)
Thanks Jacques for the review
---
build.gradle | 4 +-
.../FlexibleStringExpanderParserTests.groovy | 87 ++++++
.../util/string/FlexibleStringExpanderTests.groovy | 246 +++++++++++++++
.../base/util/string/tool/SpecialNumber.groovy | 30 ++
.../base/util/string/tool/TestException.groovy | 32 ++
.../ofbiz/base/util/string/tool/TestNpe.groovy | 31 ++
.../util/string/FlexibleStringExpanderTests.java | 342 ---------------------
7 files changed, 427 insertions(+), 345 deletions(-)
diff --git a/build.gradle b/build.gradle
index 3f7ff5a68c..84aabfc0b1 100644
--- a/build.gradle
+++ b/build.gradle
@@ -305,9 +305,6 @@ sourceSets {
// If a groovy test is supposed to be tested this way, it can be added
here.
groovy {
srcDirs = getDirectoryInActiveComponentsIfExists('src/test/groovy')
- include 'org/apache/ofbiz/service/ModelServiceTest.groovy'
- include
'org/apache/ofbiz/base/util/string/FlexibleStringExpanderBaseCodeTests.groovy'
- include 'org/apache/ofbiz/base/util/FileUtilTests.groovy'
}
resources {
srcDirs =
getDirectoryInActiveComponentsIfExists('src/test/resources')
@@ -374,6 +371,7 @@ eclipse.classpath.file.whenMerged { classpath ->
tasks.eclipse.dependsOn(cleanEclipse)
test {
+ useJUnit()
jvmArgs "-javaagent:${classpath.find { it.name.contains('jmockit')
}.absolutePath}"
}
diff --git
a/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/FlexibleStringExpanderParserTests.groovy
b/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/FlexibleStringExpanderParserTests.groovy
new file mode 100644
index 0000000000..e36ae9c613
--- /dev/null
+++
b/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/FlexibleStringExpanderParserTests.groovy
@@ -0,0 +1,87 @@
+/*******************************************************************************
+ * 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.ofbiz.base.util.string
+
+import org.junit.Test
+
+/* codenarc-disable GStringExpressionWithinString,
JUnitTestMethodWithoutAssert */
+
+/**
+ * ./gradlew test --tests '*GroovyFlexibleStringExpander*'
+ */
+class FlexibleStringExpanderParserTests {
+
+ @Test
+ void testSimpleParserIntegrity() {
+ List<String> stringsToTest = [
+ '${\'Hello ${var}\'}!',
+ 'Hello ${${groovy:' + FlexibleStringExpanderParserTests +
'.staticReturnNull()}}World!',
+ '${${throwException.value}}',
+ '${a${}${}',
+ '',
+ '${groovy:}',
+ '\\${}',
+ 'a\\${}',
+ '\\${groovy:}',
+ '${',
+ '${a${}',
+ '${a${${}',
+ '\\${',
+ 'a\\${',
+ '${?currency(',
+ '${?currency()',
+ '${price?currency(',
+ '${price?currency()',
+ '${?currency(usd',
+ '${?currency(usd)',
+ '${price?currency(usd',
+ '${price?currency(usd)',
+ '${?currency(}',
+ '${?currency()}',
+ '${?currency(usd}',
+ '${?currency(usd)}',
+ '${price?currency(}',
+ '${price?currency()}',
+ '${price?currency(usd}',
+ '${price?currency(usd)}',
+ 'a${price?currency(usd)}b']
+ for (String stringToTest in stringsToTest) {
+ doParserIntegrityTest(stringToTest)
+ }
+ }
+
+ @Test
+ void testParserIntegrityWithNullInput() {
+ doParserIntegrityTest(null, '')
+ }
+
+ @Test
+ void testParserIntegrityWithSingleCharInput() {
+ doParserIntegrityTest('a', 'a', false)
+ }
+
+ private static void doParserIntegrityTest(String input, String toString =
input, boolean checkCache = true) {
+ assert toString == FlexibleStringExpander.getInstance(input,
false).toString()
+ assert toString == FlexibleStringExpander.getInstance(input,
true).toString()
+ if (checkCache) {
+ assert FlexibleStringExpander.getInstance(input, true) ===
FlexibleStringExpander.getInstance(input, true)
+ }
+ }
+
+}
diff --git
a/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/FlexibleStringExpanderTests.groovy
b/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/FlexibleStringExpanderTests.groovy
new file mode 100644
index 0000000000..4dc83ad0a0
--- /dev/null
+++
b/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/FlexibleStringExpanderTests.groovy
@@ -0,0 +1,246 @@
+/*******************************************************************************
+ * 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.ofbiz.base.util.string
+
+import junit.framework.TestCase
+import org.apache.ofbiz.base.util.string.tool.SpecialNumber
+import org.apache.ofbiz.base.util.string.tool.TestNpe
+import org.apache.ofbiz.base.util.string.tool.TestException
+import org.junit.Test
+
+/* codenarc-disable GStringExpressionWithinString,
JUnitTestMethodWithoutAssert, UnnecessaryBigDecimalInstantiation */
+
+/**
+ * Test Class for FlexibleStringExpander object
+ */
+class FlexibleStringExpanderTests extends TestCase {
+
+ private static final Locale LOCALE_TO_TEST = new Locale('en', 'US')
+ private static final Locale OTHER_LOCALE = new Locale('fr')
+ private static final TimeZone TIME_ZONE_TO_TEST =
TimeZone.getTimeZone('PST')
+ private static final TimeZone OTHER_TIME_ZONE = TimeZone.getTimeZone('GMT')
+
+ // Required to avoid ambiguous method calls. And makes tests easier to
read as a bonus.
+ private static final Map NULL_CONTEXT = null
+ private static final Locale NULL_LOCALE = null
+ private static final TimeZone NULL_TIMEZONE = null
+ private static final Object NULL_OBJECT = null
+
+ @Test
+ void testEmptyFSE() {
+ doEmptyFseTest(null, NULL_CONTEXT, NULL_TIMEZONE, NULL_LOCALE, '')
+ doEmptyFseTest(null, [foo: 'bar'], NULL_TIMEZONE, NULL_LOCALE, '')
+ doEmptyFseTest(null, [foo: 'bar'], TIME_ZONE_TO_TEST, LOCALE_TO_TEST,
'')
+ doEmptyFseTest('', [foo: 'bar'], null, null, '')
+ }
+
+ @Test
+ void testFSECommonCases() {
+ doFseTest('Hello World!', NULL_CONTEXT, NULL_TIMEZONE, NULL_LOCALE,
'Hello World!', NULL_OBJECT)
+ doFseTest('Hello World!', [foo: 'bar'], 'Hello World!')
+ doFseTest('Hello ${var}!', [var: 'World'], 'Hello World!')
+ doFseTest('${\'Hello ${var}\'}!', [var: 'World'], 'Hello World!')
+ doFseTest('${\'Hel${blank}lo ${var}\'}!', [var: 'World', blank: ''],
'Hello World!')
+ }
+
+ @Test
+ void testFSEUelExceptionIntegration() {
+ Map baseCtx = [exception: new TestException()]
+ doFseTest('${exception.value}', [*: baseCtx], NULL_TIMEZONE,
NULL_LOCALE, '', NULL_OBJECT)
+ doFseEmptyExpandTest('${${exception.value}}', [*: baseCtx])
+ doFseEmptyExpandTest('${excep${var}.value}', [*: baseCtx, var: 'tion'])
+ doFseEmptyExpandTest('${exception${var}.value}', [*: baseCtx, var: ''])
+ doFseTest('${npe.value}', [npe: new TestNpe()], NULL_TIMEZONE,
NULL_LOCALE, '', NULL_OBJECT)
+ doFseTest('The total is ${exception.value?currency(${usd})}.', [*:
baseCtx], 'The total is .')
+ }
+
+ @Test
+ void testFSEUelIntegrationOnNullOrEmpty() {
+ Map baseCtx = [nullVar: null]
+ doFseEmptyExpandTest('${${nu${nullVar}ll}}', [*: baseCtx])
+ doFseEmptyExpandTest('${${nullVar.noProp}}', [*: baseCtx])
+ doFseEmptyExpandTest('${${unknonL${nullVar}ist[0]}}', [nullVar: null])
+ doFseTest('${null}', [:], NULL_TIMEZONE, NULL_LOCALE, '', NULL_OBJECT)
+ doFseTest('${nullVar.noProp}', [*: baseCtx], NULL_TIMEZONE,
NULL_LOCALE, '', NULL_OBJECT)
+ doFseTest('${noList[0]}', [:], NULL_TIMEZONE, NULL_LOCALE, '',
NULL_OBJECT)
+ doFseTest('The total is ${map.missing?currency(${usd})}.', [map: [:]],
NULL_TIMEZONE, LOCALE_TO_TEST,
+ 'The total is .', 'The total is .')
+ doFseTest('The total is ${noList[0]?currency(${usd})}.', [noList: []],
NULL_TIMEZONE, LOCALE_TO_TEST,
+ 'The total is .', 'The total is .')
+ doFseTest('${${nullVar}}!', [*: baseCtx], '!')
+ }
+
+ @Test
+ void testFSEUelIntegration() {
+ doFseTest('Hello ${testMap.var}!', [testMap: [var: 'World']], 'Hello
World!')
+ doFseTest('Hello ${testMap.blank}World!', [testMap: [var: '']], 'Hello
World!')
+ doFseTest('Hello ${testList[0]}!', [testList: ['World']], 'Hello
World!')
+ doFseTestWithLocaleAndTimezone('${amount}', [amount: new
BigDecimal('1234567.89')], NULL_TIMEZONE,
+ LOCALE_TO_TEST, '1,234,567.89', new BigDecimal('1234567.89'))
+ doFseTestWithLocaleAndTimezone('${a${\'moun\'}t}', [amount: new
BigDecimal('1234567.89')], NULL_TIMEZONE,
+ LOCALE_TO_TEST, '1,234,567.89', new BigDecimal('1234567.89'))
+ }
+
+ /* codenarc-disable NoJavaUtilDate */
+
+ @Test
+ void testFSEDate() {
+ Date firstOfbizCommit = new Date(1154466300000)
+ doFseTestWithLocaleAndTimezone('The date is ${date}.', [date:
firstOfbizCommit], TIME_ZONE_TO_TEST,
+ LOCALE_TO_TEST, 'The date is 2006-08-01 14:05:00.000.', 'The
date is 2006-08-01 14:05:00.000.')
+ }
+ /* codenarc-enable NoJavaUtilDate */
+
+ @Test
+ void testMisformedFSE() {
+ doFseTest('${foobar', [:], '${foobar')
+ doFseTest('Hello${foobar', [:], 'Hello${foobar')
+ doFseTest('Hello ${var}${foobar', [var: 'World'], 'Hello
World${foobar')
+ }
+
+ @Test
+ void testCurrencyFSE() {
+ Map baseCtx = [usd: 'USD', amount: new BigDecimal('1234567.89')]
+ doFseTestWithLocaleAndTimezone('${amount?currency(${usd})}', [*:
baseCtx], NULL_TIMEZONE, LOCALE_TO_TEST,
+ '$1,234,567.89', '$1,234,567.89')
+ doFseTestWithLocaleAndTimezone('The total is
${amount?currency(${usd})}.', [*: baseCtx], NULL_TIMEZONE,
+ LOCALE_TO_TEST, 'The total is $1,234,567.89.', 'The total is
$1,234,567.89.')
+ }
+
+ @Test
+ void testGroovyScriptFSE() {
+ Map baseCtx = [var: 'World',
+ exception: new TestException(),
+ specialNumber: new SpecialNumber('1.00')]
+ doFseTest('${groovy: return \'Hello \' + var + \'!\'}', [*: baseCtx],
'Hello World!')
+ doFseTest('${groovy: return null}!', [*: baseCtx], '!')
+ doFseTest('${groovy: return noList[0]}', [*: baseCtx], NULL_OBJECT)
+ doFseTest('${groovy: return exception.value}!', [*: baseCtx], '!')
+ doFseTest('${groovy: return specialNumber}!', [*: baseCtx], '1!')
+ doFseTest('This is a groovy ${groovy: if (true) {return \'bracket\'}}
expression', [:],
+ 'This is a groovy bracket expression')
+ doFseTest('This is a groovy ${groovy: if (true) {if (true) {return
\'with 2 brackets\'}}} expression',
+ [:], 'This is a groovy with 2 brackets expression')
+ doFseTestWithLocaleAndTimezone('${groovy: return amount}', [amount:
new BigDecimal('1234567.89')],
+ NULL_TIMEZONE, LOCALE_TO_TEST, '1,234,567.89', new
BigDecimal('1234567.89'))
+ }
+
+ @Test
+ void testGroovyScriptFSESecurity() {
+ doFseTest('${groovy: java.util.Map.of(\'key\', \'value\')}!', [:], '!')
+ doFseTest('${groovy: \'ls /\'.execute()}!', [:], '!')
+ doFseTest('${groovy: new File(\'/etc/passwd\').getText()}!', [:], '!')
+ doFseTest('${groovy: (new File \'/etc/passwd\') .getText()}!', [:],
'!')
+ doFseTest('${groovy: Eval.me(\'1\')}!', [:], '!')
+ doFseTest('${groovy: Eval . me(\'1\')}!', [:], '!')
+ doFseTest('${groovy: System.properties[\'ofbiz.home\']}!', [:], '!')
+ doFseTest('${groovy: new
groovyx.net.http.HTTPBuilder(\'https://XXXX.XXXX.com:443\')}!', [:], '!')
+ }
+
+ @Test
+ void testFSEEscape() {
+ doFseTest('This is an \\${escaped} expression', [:], 'This is an
${escaped} expression')
+ doFseTest('This is an \\${groovy:escaped} expression', [:], 'This is
an ${groovy:escaped} expression')
+ }
+
+ private static void doFseBaseTest(String input, Map<String, Object>
context, TimeZone timeZone, Locale locale,
+ String expandedString, Object
expandedObj, boolean isEmpty) {
+ FlexibleStringExpander fse = FlexibleStringExpander.getInstance(input)
+ assert isEmpty == fse.isEmpty()
+
+ assert (input ?: '') == fse.getOriginal()
+ assert (input ?: '') == fse.toString()
+ expandedString = expandedString ?: ''
+
+ assert expandedString == FlexibleStringExpander.expandString(input,
context)
+ assert expandedString == FlexibleStringExpander.expandString(input,
context, locale)
+ assert expandedString == FlexibleStringExpander.expandString(input,
context, timeZone, locale)
+
+ assert expandedString == fse.expandString(context)
+ assert expandedString == fse.expandString(context as Map, locale as
Locale)
+ assert expandedString == fse.expandString(context as Map, timeZone as
TimeZone, locale as Locale)
+
+ assert expandedObj == fse.expand(context)
+ assert expandedObj == fse.expand(context as Map, locale as Locale)
+ assert expandedObj == fse.expand(context as Map, timeZone as TimeZone,
locale as Locale)
+ }
+
+ private static void doEmptyFseTest(String input, Map<String, Object>
context, TimeZone timeZone, Locale locale,
+ String expandedString, Object
expandedObj = NULL_OBJECT) {
+ doFseBaseTest(input, context, timeZone, locale, expandedString,
expandedObj, true)
+ }
+
+ private static void doFseTest(String input, Map<String, Object> context,
String expandedString) {
+ doFseBaseTest(input, context, NULL_TIMEZONE, NULL_LOCALE,
expandedString, expandedString, false)
+ }
+
+ private static void doFseEmptyExpandTest(String input, Map<String, Object>
context) {
+ doFseBaseTest(input, context, NULL_TIMEZONE, NULL_LOCALE, '', '',
false)
+ }
+
+ private static void doFseTest(String input, Map<String, Object> context,
TimeZone timeZone, Locale locale,
+ String expandedString, Object expandedObj =
NULL_OBJECT) {
+ doFseBaseTest(input, context, timeZone, locale, expandedString,
expandedObj, false)
+ }
+
+ /* codenarc-disable LocaleSetDefault */
+
+ private static void doFseTestWithLocaleAndTimezone(String input,
Map<String, Object> context, TimeZone timeZone,
+ Locale locale, String
expandedString, Object expandedObj) {
+ // Test with only default locale
+ Locale.setDefault(locale)
+ TimeZone.setDefault(timeZone)
+ doFseBaseTest(input, context, NULL_TIMEZONE, NULL_LOCALE,
expandedString, expandedObj, false)
+ Locale.setDefault(OTHER_LOCALE)
+ TimeZone.setDefault(OTHER_TIME_ZONE)
+ doFseNotEqualsTest(input, context, expandedString, expandedObj)
+
+ // Test with only autoUserLogin
+ context << [autoUserLogin: [
+ lastLocale: locale ? locale.toString() : null,
+ lastTimeZone: timeZone ? timeZone.getID() : null
+ ]]
+ doFseBaseTest(input, context, NULL_TIMEZONE, NULL_LOCALE,
expandedString, expandedObj, false)
+ context.autoUserLogin = [
+ lastLocale: OTHER_LOCALE.toString(),
+ lastTimeZone: OTHER_TIME_ZONE.getID()
+ ]
+ doFseNotEqualsTest(input, context, expandedString, expandedObj)
+
+ // Test with only context
+ context.put('locale', locale)
+ context.put('timeZone', timeZone)
+ doFseBaseTest(input, context, timeZone, locale, expandedString,
expandedObj, false)
+ context.put('locale', OTHER_LOCALE)
+ context.put('timeZone', OTHER_TIME_ZONE)
+ doFseNotEqualsTest(input, context, expandedString, expandedObj)
+ }
+ /* codenarc-enable LocaleSetDefault */
+
+ private static void doFseNotEqualsTest(String input, Map<String, Object>
context, String expandedString,
+ Object expandedObj) {
+ FlexibleStringExpander fse = FlexibleStringExpander.getInstance(input)
+ assert expandedString != FlexibleStringExpander.expandString(input,
context)
+ assert expandedString != fse.expandString(context)
+ if (expandedObj instanceof String) {
+ assert expandedObj != fse.expand(context)
+ }
+ }
+
+}
diff --git
a/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/tool/SpecialNumber.groovy
b/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/tool/SpecialNumber.groovy
new file mode 100644
index 0000000000..f21cdd7f46
--- /dev/null
+++
b/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/tool/SpecialNumber.groovy
@@ -0,0 +1,30 @@
+/*******************************************************************************
+ * 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.ofbiz.base.util.string.tool
+
+/**
+ * Class used in testing
+ */
+public class SpecialNumber extends BigDecimal {
+
+ public SpecialNumber(String value) {
+ super(value)
+ }
+
+}
diff --git
a/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/tool/TestException.groovy
b/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/tool/TestException.groovy
new file mode 100644
index 0000000000..ceebc60704
--- /dev/null
+++
b/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/tool/TestException.groovy
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * 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.ofbiz.base.util.string.tool
+
+/**
+ * Exception used in testing
+ */
+public class TestException extends Exception {
+
+ /* codenarc-disable ThrowException */
+
+ Object getValue() throws Exception {
+ throw new Exception()
+ }
+
+}
diff --git
a/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/tool/TestNpe.groovy
b/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/tool/TestNpe.groovy
new file mode 100644
index 0000000000..b6f06de0dc
--- /dev/null
+++
b/framework/base/src/test/groovy/org/apache/ofbiz/base/util/string/tool/TestNpe.groovy
@@ -0,0 +1,31 @@
+/*******************************************************************************
+ * 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.ofbiz.base.util.string.tool
+
+/**
+ * Test NPE used in testing
+ */
+public class TestNpe {
+
+ /* codenarc-disable ThrowNullPointerException */
+ Object getValue() throws NullPointerException {
+ throw new NullPointerException()
+ }
+
+}
diff --git
a/framework/base/src/test/java/org/apache/ofbiz/base/util/string/FlexibleStringExpanderTests.java
b/framework/base/src/test/java/org/apache/ofbiz/base/util/string/FlexibleStringExpanderTests.java
deleted file mode 100644
index aa50f1b046..0000000000
---
a/framework/base/src/test/java/org/apache/ofbiz/base/util/string/FlexibleStringExpanderTests.java
+++ /dev/null
@@ -1,342 +0,0 @@
-/*******************************************************************************
- * 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.ofbiz.base.util.string;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotSame;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.TimeZone;
-
-import org.apache.ofbiz.base.conversion.AbstractConverter;
-import org.apache.ofbiz.base.conversion.ConversionException;
-import org.junit.Test;
-
-public class FlexibleStringExpanderTests {
- private static final Locale LOCALE_TO_TEST = new Locale("en", "US");
- private static final Locale BAD_LOCALE = new Locale("fr");
- private static final TimeZone TIME_ZONE_TO_TEST =
TimeZone.getTimeZone("PST");
- private static final TimeZone BAD_TIME_ZONE = TimeZone.getTimeZone("GMT");
-
- private static void parserTest(String label, String input, boolean
checkCache, String toString) {
- FlexibleStringExpander fse = FlexibleStringExpander.getInstance(input,
false);
- assertEquals(label + ":toString(no-cache)", toString, fse.toString());
- fse = FlexibleStringExpander.getInstance(input, true);
- assertEquals(label + ":toString(cache)", toString, fse.toString());
- if (checkCache) {
- assertEquals(label + ":same-cache", fse,
FlexibleStringExpander.getInstance(input, true));
- }
- }
-
- @Test
- /**
- * Test parsing.
- */
- public void testParsing() {
- parserTest("visible nested replacement", "${'Hello ${var}'}!", true,
"${'Hello ${var}'}!");
- parserTest("hidden (runtime) nested null callreplacement", "Hello
${${groovy:" + FlexibleStringExpanderTests.class.getName()
- + ".staticReturnNull()}}World!", true, "Hello ${${groovy:" +
FlexibleStringExpanderTests.class.getName()
- + ".staticReturnNull()}}World!");
- parserTest("UEL integration(nested): throw Exception",
"${${throwException.value}}", true, "${${throwException.value}}");
- parserTest("nested-constant-emptynest-emptynest", "${a${}${}", true,
"${a${}${}");
- parserTest("null", null, true, "");
- parserTest("empty", "", true, "");
- parserTest("constant-only", "a", false, "a");
- parserTest("nested-constant-emptynest-emptynest", "${a${}${}", true,
"${a${}${}");
- parserTest("groovy", "${groovy:}", true, "${groovy:}");
-
- parserTest("escaped", "\\${}", true, "\\${}");
- parserTest("constant-escaped", "a\\${}", true, "a\\${}");
- parserTest("escaped-groovy", "\\${groovy:}", true, "\\${groovy:}");
-
- parserTest("missing-}", "${", true, "${");
- parserTest("nested-constant-missing-}", "${a${}", true, "${a${}");
- parserTest("nested-constant-nested-nested-missing-}", "${a${${}",
true, "${a${${}");
- parserTest("escaped-missing-}", "\\${", true, "\\${");
- parserTest("constant-escaped-missing-}", "a\\${", true, "a\\${");
-
- parserTest("currency", "${?currency(", true, "${?currency(");
- parserTest("currency", "${?currency()", true, "${?currency()");
- parserTest("currency", "${price?currency(", true, "${price?currency(");
- parserTest("currency", "${price?currency()", true,
"${price?currency()");
- parserTest("currency", "${?currency(usd", true, "${?currency(usd");
- parserTest("currency", "${?currency(usd)", true, "${?currency(usd)");
- parserTest("currency", "${price?currency(usd", true,
"${price?currency(usd");
- parserTest("currency", "${price?currency(usd)", true,
"${price?currency(usd)");
- parserTest("currency", "${?currency(}", true, "${?currency(}");
- parserTest("currency", "${?currency()}", true, "${?currency()}");
- parserTest("currency", "${?currency(usd}", true, "${?currency(usd}");
- parserTest("currency", "${?currency(usd)}", true, "${?currency(usd)}");
- parserTest("currency", "${price?currency(}", true,
"${price?currency(}");
- parserTest("currency", "${price?currency()}", true,
"${price?currency()}");
- parserTest("currency", "${price?currency(usd}", true,
"${price?currency(usd}");
- parserTest("currency", "${price?currency(usd)}", true,
"${price?currency(usd)}");
- parserTest("currency", "a${price?currency(usd)}b", true,
"a${price?currency(usd)}b");
- }
-
- private static void fseTest(String label, String input, Map<String,
Object> context, String compare, boolean isEmpty) {
- fseTest(label, input, context, null, null, compare, isEmpty);
- }
-
- private static void doFseTest(String label, String input,
FlexibleStringExpander fse, Map<String, Object> context, TimeZone timeZone,
- Locale locale, String compare, Object
expand, boolean isEmpty) {
- assertEquals("isEmpty:" + label, isEmpty, fse.isEmpty());
- if (input == null) {
- assertEquals("getOriginal():" + label, "", fse.getOriginal());
- assertEquals("toString():" + label, "", fse.toString());
- assertEquals("expandString(null):" + label, "",
fse.expandString(null));
- assertEquals("expand(null):" + label, null, fse.expand(null));
- if (timeZone == null) {
- assertEquals("expandString(null):" + label, "",
fse.expandString(null, locale));
- assertEquals("expand(null):" + label, null, fse.expand(null,
locale));
- } else {
- assertEquals("expandString(null):" + label, "",
fse.expandString(null, timeZone, locale));
- assertEquals("expand(null):" + label, null, fse.expand(null,
timeZone, locale));
- }
- } else {
- assertEquals("getOriginal():" + label, input, fse.getOriginal());
- assertEquals("toString():" + label, input, fse.toString());
- assertEquals("expandString(null):" + label, input,
fse.expandString(null));
- assertEquals("expand(null):" + label, null, fse.expand(null));
- if (timeZone == null) {
- assertEquals("expandString(null):" + label, input,
fse.expandString(null, locale));
- assertEquals("expand(null):" + label, null, fse.expand(null,
locale));
- } else {
- assertEquals("expandString(null):" + label, input,
fse.expandString(null, timeZone, locale));
- assertEquals("expand(null):" + label, null, fse.expand(null,
timeZone, locale));
- }
- }
- if (locale == null) {
- assertEquals(label, compare, fse.expandString(context));
- assertEquals("expand:" + label, expand, fse.expand(context));
- } else {
- Locale defaultLocale = Locale.getDefault();
- TimeZone defaultTimeZone = TimeZone.getDefault();
- try {
- Locale.setDefault(locale);
- TimeZone.setDefault(timeZone);
- context.put("locale", locale);
- context.put("timeZone", timeZone);
- assertEquals(label, compare, fse.expandString(context, null,
null));
- assertEquals(label, expand, fse.expand(context, null, null));
- Locale.setDefault(BAD_LOCALE);
- TimeZone.setDefault(BAD_TIME_ZONE);
- assertNotSame(label, compare, fse.expandString(context, null,
null));
- if (input != null) {
- assertNotSame(label, expand, fse.expand(context, null,
null));
- }
- Map<String, Object> autoUserLogin = new HashMap<>();
- autoUserLogin.put("lastLocale", locale.toString());
- autoUserLogin.put("lastTimeZone", timeZone == null ? null :
timeZone.getID());
- context.put("autoUserLogin", autoUserLogin);
- assertEquals(label, compare, fse.expandString(context, null,
null));
- assertEquals(label, expand, fse.expand(context, null, null));
- autoUserLogin.put("lastLocale", BAD_LOCALE.toString());
- autoUserLogin.put("lastTimeZone", BAD_TIME_ZONE.getID());
- assertNotSame(label, compare, fse.expandString(context, null,
null));
- if (input != null) {
- assertNotSame(label, expand, fse.expand(context, null,
null));
- }
- context.remove("autoUserLogin");
- assertEquals(label, compare, fse.expandString(context, null,
null));
- assertEquals(label, expand, fse.expand(context, null, null));
- context.put("locale", BAD_LOCALE);
- context.put("timeZone", BAD_TIME_ZONE);
- assertNotSame(label, compare, fse.expandString(context, null,
null));
- if (input != null) {
- assertNotSame(label, expand, fse.expand(context, null,
null));
- }
- context.remove("locale");
- context.remove("timeZone");
- assertEquals(label, compare, fse.expandString(context,
timeZone, locale));
- assertEquals(label, expand, fse.expand(context, timeZone,
locale));
- assertNotSame(label, compare, fse.expandString(context,
BAD_TIME_ZONE, BAD_LOCALE));
- if (input != null) {
- assertNotSame(label, expand, fse.expand(context,
BAD_TIME_ZONE, BAD_LOCALE));
- }
- } finally {
- Locale.setDefault(defaultLocale);
- TimeZone.setDefault(defaultTimeZone);
- }
- }
- }
-
- private static void fseTest(String label, String input, Map<String,
Object> context, TimeZone timeZone, Locale locale,
- String compare, boolean isEmpty) {
- fseTest(label, input, context, timeZone, locale, compare, compare,
isEmpty);
- }
-
- private static void fseTest(String label, String input, Map<String,
Object> context, TimeZone timeZone, Locale locale, String compare,
- Object expand, boolean isEmpty) {
- FlexibleStringExpander fse = FlexibleStringExpander.getInstance(input);
- doFseTest(label, input, fse, context, timeZone, locale, compare,
expand, isEmpty);
- assertEquals("static expandString:" + label, compare,
FlexibleStringExpander.expandString(input, context, timeZone, locale));
- if (input == null) {
- assertEquals("static expandString(null, null):" + label, "",
FlexibleStringExpander.expandString(input, null));
- assertEquals("static expandString(null, null):" + label, "",
FlexibleStringExpander.expandString(input, null, locale));
- } else {
- assertEquals("static expandString(input, null):" + label, input,
FlexibleStringExpander.expandString(input, null));
- assertEquals("static expandString(input, null):" + label, input,
FlexibleStringExpander.expandString(input, null, locale));
- }
- if (!fse.isEmpty()) {
- fse = FlexibleStringExpander.getInstance(input, false);
- doFseTest(label, input, fse, context, timeZone, locale, compare,
expand, isEmpty);
- }
- }
-
- public static String staticReturnNull() {
- return null;
- }
-
- @SuppressWarnings("serial")
- public static class ThrowException extends Exception {
- /**
- * Gets value.
- * @return the value
- * @throws Exception the exception
- */
- public Object getValue() throws Exception {
- throw new Exception();
- }
- }
-
- public static class ThrowNPE {
- /**
- * Gets value.
- * @return the value
- */
- public Object getValue() {
- throw new NullPointerException();
- }
- }
-
- public static class SpecialNumberToString extends
AbstractConverter<SpecialNumber, String> {
- public SpecialNumberToString() {
- super(SpecialNumber.class, String.class);
- }
-
- @Override
- public String convert(SpecialNumber obj) throws ConversionException {
- throw new NullPointerException();
- }
- }
-
- @SuppressWarnings("serial")
- public static class SpecialNumber extends BigDecimal {
- public SpecialNumber(String value) {
- super(value);
- }
-
- @Override
- public String toString() {
- return getClass().getName();
- }
- }
-
- @Test
- public void testEverything() {
- Map<String, Object> testMap = new HashMap<>();
- testMap.put("date", new java.util.Date(1234567890));
- testMap.put("usd", "USD");
- testMap.put("amount", new BigDecimal("1234567.89"));
- testMap.put("blank", "");
- testMap.put("exc", "Exception");
- testMap.put("nullVar", null);
- testMap.put("throwException", new ThrowException());
- testMap.put("throwNPE", new ThrowNPE());
- testMap.put("var", "World");
- testMap.put("nested", "Hello ${var}");
- testMap.put("testMap", testMap);
- testMap.put("nestedNull", "Hello ${nullVar}${var}");
- testMap.put("specialNumber", new SpecialNumber("1.00"));
- List<String> testList = new ArrayList<>();
- testList.add("World");
- testMap.put("testList", testList);
- fseTest("null FlexibleStringExpander, null map", null, null, null,
null, "", null, true);
- fseTest("null FlexibleStringExpander", null, testMap, null, null, "",
null, true);
- fseTest("null context", "Hello World!", null, null, null, "Hello
World!", null, false);
- fseTest("plain string", "Hello World!", testMap, null, null, "Hello
World!", "Hello World!", false);
- fseTest("simple replacement", "Hello ${var}!", testMap, "Hello
World!", false);
- fseTest("null FlexibleStringExpander with timeZone/locale", null,
testMap, TIME_ZONE_TO_TEST, LOCALE_TO_TEST, "", null, true);
- fseTest("empty FlexibleStringExpander", "", testMap, null, null, "",
null, true);
- fseTest("UEL integration(nested): throw Exception",
"${${throwException.value}}", testMap, "", false);
- fseTest("UEL integration: throw Exception", "${throwException.value}",
testMap, null, null, "", null, false);
- fseTest("UEL integration(nested): throw Exception",
"${throw${exc}.value}", testMap, "", false);
- fseTest("UEL integration(nested): throw NPE",
"${throwNPE${blank}.value}", testMap, "", false);
- fseTest("visible nested replacement", "${'Hello ${var}'}!", testMap,
"Hello World!", false);
- fseTest("blank nested replacement", "${'Hel${blank}lo ${var}'}!",
testMap, "Hello World!", false);
- fseTest("UEL integration(nested): null", "${${nu${nullVar}ll}}",
testMap, "", false);
- fseTest("UEL integration(nested): NPE", "${${nullVar.noProp}}",
testMap, "", false);
- fseTest("UEL integration(nested): missing",
"${${noL${nullVar}ist[0]}}", testMap, "", false);
- fseTest("date w/ timezone", "The date is ${date}.", testMap,
TIME_ZONE_TO_TEST, LOCALE_TO_TEST, "The date is 1970-01-14 22:56:07.890.",
- "The date is 1970-01-14 22:56:07.890.", false);
- fseTest("just bad", "${foobar", testMap, "${foobar", false);
- fseTest("constant and bad", "Hello${foobar", testMap, "Hello${foobar",
false);
- fseTest("good and bad", "Hello ${var}${foobar", testMap, "Hello
World${foobar", false);
- fseTest("plain-currency(USD)", "${amount?currency(${usd})}", testMap,
null, LOCALE_TO_TEST, "$1,234,567.89", false);
- fseTest("currency(USD)", "The total is ${amount?currency(${usd})}.",
testMap, null, LOCALE_TO_TEST, "The total is $1,234,567.89.", false);
- fseTest("currency(USD): null", "The total is
${testMap.missing?currency(${usd})}.", testMap, null, LOCALE_TO_TEST, "The
total is .", false);
- fseTest("currency(USD): missing", "The total is
${noList[0]?currency(${usd})}.", testMap, null, LOCALE_TO_TEST, "The total is
.", false);
- fseTest("currency(USD): exception", "The total is
${throwException.value?currency(${usd})}.", testMap, null, LOCALE_TO_TEST,
- "The total is .", false);
- fseTest("null nested", "${${nullVar}}!", testMap, "!", false);
- fseTest("groovy: script", "${groovy:return \"Hello \" + var +
\"!\";}", testMap, "Hello World!", false);
- fseTest("groovy: null", "${groovy:return null;}!", testMap, "!",
false);
- fseTest("groovy missing property", "${groovy: return noList[0]}",
testMap, null, null, "", null, false);
- fseTest("groovy: throw Exception", "${groovy:return
throwException.value;}!", testMap, "!", false);
- fseTest("groovy: generate security issue", "${groovy:
java.util.Map.of('key', 'value')}!", testMap, "!", false);
- fseTest("groovy: another generate security issue 1", "${groovy: 'ls
/'.execute()}!", testMap, "!", false);
- fseTest("groovy: another generate security issue 2", "${groovy: new
File('/etc/passwd').getText()}!", testMap, "!", false);
- fseTest("groovy: another generate security issue 3", "${groovy: (new
File '/etc/passwd') .getText()}!", testMap, "!", false);
- fseTest("groovy: another generate security issue 4", "${groovy:
Eval.me('1')}!", testMap, "!", false);
- fseTest("groovy: another generate security issue 5", "${groovy: Eval .
me('1')}!", testMap, "!", false);
- fseTest("groovy: another generate security issue 6", "${groovy:
System.properties['ofbiz.home']}!", testMap, "!", false);
- fseTest("groovy: another generate security issue 7", "${groovy: new
groovyx.net.http.HTTPBuilder('https://XXXX.XXXX.com:443')}!",
- testMap, "!", false);
- fseTest("groovy: converter exception", "${groovy:return
specialNumber;}!", testMap, "1!", false);
- fseTest("UEL integration: Map", "Hello ${testMap.var}!", testMap,
"Hello World!", false);
- fseTest("UEL integration: blank", "Hello ${testMap.blank}World!",
testMap, "Hello World!", false);
- fseTest("UEL integration: List", "Hello ${testList[0]}!", testMap,
"Hello World!", false);
- fseTest("UEL integration: null", "${null}", testMap, null, null, "",
null, false);
- fseTest("UEL integration: null dereference", "${nullVar.noProp}",
testMap, null, null, "", null, false);
- fseTest("UEL integration: throw NPE", "${" +
FlexibleStringExpanderTests.class.getName() + ".ThrowNPE.noProp}", testMap,
null, null, "",
- null, false);
- fseTest("UEL integration: missing", "${noList[0]}", testMap, null,
null, "", null, false);
- fseTest("Escaped expression", "This is an \\${escaped} expression",
testMap, "This is an ${escaped} expression", false);
- fseTest("Escaped(groovy) expression", "This is an \\${groovy:escaped}
expression", testMap, "This is an ${groovy:escaped} expression", false);
- fseTest("Bracket en groovy", "This is a groovy ${groovy: if (true)
{return 'bracket'}} expression", testMap,
- "This is a groovy bracket expression", false);
- fseTest("Bracket en groovy again", "This is a groovy ${groovy: if
(true) {if (true) {return 'with 2 brackets'}}} expression", testMap,
- "This is a groovy with 2 brackets expression", false);
-
- // TODO: Find a better way to setup or handle the big decimal value.
If new ones are not instantiated in the test
- // it fails because of the comparison between object pointers..
- fseTest("nested UEL integration(return BigDecimal)", "${a${'moun'}t}",
testMap, null, LOCALE_TO_TEST,
- "1,234,567.89", new BigDecimal("1234567.89"), false);
- fseTest("UEL integration(return BigDecimal)", "${amount}", testMap,
null, LOCALE_TO_TEST,
- "1,234,567.89", new BigDecimal("1234567.89"), false);
- fseTest("groovy: return BigDecimal", "${groovy: return amount;}",
testMap, null, LOCALE_TO_TEST,
- "1,234,567.89", new BigDecimal("1234567.89"), false);
- }
-}