This is an automated email from the ASF dual-hosted git repository.
ashishvijaywargiya 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 dc80d7f434 Migrate UEL unit tests (Date/Math/String/Misc) from JUnit3
testdef to Jupiter(JUnit5) (#1516)
dc80d7f434 is described below
commit dc80d7f434a3b985cb5a0a1becc975d9c65e44eb
Author: Ashish Vijaywargiya <[email protected]>
AuthorDate: Thu Jul 30 11:14:42 2026 +0530
Migrate UEL unit tests (Date/Math/String/Misc) from JUnit3 testdef to
Jupiter(JUnit5) (#1516)
UEL Unit Test Migration
1) I migrated the four UEL unit tests (Date, Math, String, Misc) from
the old JUnit3 testdef XML format to plain JUnit5/Jupiter tests so they
run through a fast gradlew test instead of the full OFBiz test
container.
2) UelFunctions.FUNCTION_MAPPER is built once per JVM by scanning
ComponentConfig, and ComponentConfig is normally only populated by
ComponentContainer during a real OFBiz boot, so these lightweight
Jupiter tests needed their own way to trigger just that piece.
3) Added ComponentContainerTestSupport.java as a test-only bridge class
living in the same package as ComponentContainer, so it can call its
package-private init(String, Path) method without widening that method's
visibility in production code.
4) Added UelTestSupport.groovy as the idempotent helper that checks
whether components are already loaded and triggers the bootstrap through
ComponentContainerTestSupport exactly once per JVM.
5) Added UelFunctionsBootstrapListener.groovy, registered via
META-INF/services as a JUnit Platform LauncherSessionListener, so the
bootstrap runs once before any test in the JVM is discovered, regardless
of which test class Gradle happens to run first.
6) That listener now loads the real, full component tree into the
JVM-wide ComponentConfig cache for every test run, so we renamed the
ComponentContainerTest fixture components from order/accounting to
test-order/test-accounting to avoid name collisions with the real
components.
7) Updated ComponentContainerTest.java to filter its assertions down to
just its own fixture names so the test stays a genuine check of
dependency sorting regardless of what else is loaded into the shared
cache.
8) Removed the four uel-*-tests test-cases from
framework/base/testdef/basetests.xml since they no longer run through
the old JUnit3 testtools container.
9) Added the junit-platform-launcher dependency to dependencies.gradle
since that library is what actually discovers and invokes the new
LauncherSessionListener.
10) I also verified the branch with gradlew test for the UEL and base
packages, checkstyleTest and codenarcTest, and both a scoped and a full
testIntegration run, with all suites passing.
---
dependencies.gradle | 1 +
.../apache/ofbiz/base/test/uel/DateUelTest.groovy | 118 -------------------
.../apache/ofbiz/base/test/uel/MathUelTest.groovy | 90 --------------
.../ofbiz/base/test/uel/StringUelTest.groovy | 70 -----------
.../apache/ofbiz/base/test/uel/DateUelTest.groovy | 131 +++++++++++++++++++++
.../apache/ofbiz/base/test/uel/MathUelTest.groovy | 106 +++++++++++++++++
.../apache/ofbiz/base/test/uel/MiscUelTest.groovy | 25 ++--
.../ofbiz/base/test/uel/StringUelTest.groovy | 84 +++++++++++++
.../test/uel/UelFunctionsBootstrapListener.groovy | 58 +++++++++
.../ofbiz/base/test/uel/UelTestSupport.groovy | 59 ++++++++++
.../base/container/ComponentContainerTest.java | 14 ++-
.../container/ComponentContainerTestSupport.java | 37 ++++++
...junit.platform.launcher.LauncherSessionListener | 1 +
.../ofbiz-component.xml | 4 +-
.../{order => test-order}/ofbiz-component.xml | 2 +-
framework/base/testdef/basetests.xml | 13 --
16 files changed, 508 insertions(+), 305 deletions(-)
diff --git a/dependencies.gradle b/dependencies.gradle
index 03303d97ae..5b945852f8 100644
--- a/dependencies.gradle
+++ b/dependencies.gradle
@@ -96,6 +96,7 @@ dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:6.1.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:6.1.0'
testImplementation 'org.junit.jupiter:junit-jupiter-params:6.1.0'
+ testImplementation 'org.junit.platform:junit-platform-launcher:6.1.0'
testImplementation 'org.hamcrest:hamcrest-library:2.2'
testImplementation 'org.mockito:mockito-core:5.23.0'
testImplementation 'org.jmockit:jmockit:1.50'
diff --git
a/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/DateUelTest.groovy
b/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/DateUelTest.groovy
deleted file mode 100644
index 69359c8fd5..0000000000
---
a/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/DateUelTest.groovy
+++ /dev/null
@@ -1,118 +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.test.uel
-
-import org.apache.ofbiz.base.util.UtilDateTime
-import org.apache.ofbiz.base.util.string.FlexibleStringExpander
-import org.apache.ofbiz.base.util.string.UelFunctions
-import org.apache.ofbiz.service.testtools.OFBizTestCase
-
-import java.sql.Timestamp
-
-/**
- * ./gradlew 'ofbiz -t component=base -t suitename=basetests'
- */
-/* codenarc-disable GStringExpressionWithinString,ClosureAsLastMethodParameter
*/
-class DateUelTest extends OFBizTestCase {
-
- DateUelTest(String name) {
- super(name)
- }
-
- void testDateUel() { // codenarc-disable JUnitTestMethodWithoutAssert
- doUelDateTest('${date:second(now, timeZone, locale)}', { Timestamp now
->
- UtilDateTime.getSecond(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:minute(now, timeZone, locale)}', { Timestamp now
->
- UtilDateTime.getMinute(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:hour(now, timeZone, locale)}', { Timestamp now ->
- UtilDateTime.getHour(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:dayOfMonth(now, timeZone, locale)}', { Timestamp
now ->
- UtilDateTime.getDayOfMonth(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:dayOfWeek(now, timeZone, locale)}', { Timestamp
now ->
- UtilDateTime.getDayOfWeek(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:dayOfYear(now, timeZone, locale)}', { Timestamp
now ->
- UtilDateTime.getDayOfYear(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:week(now, timeZone, locale)}', { Timestamp now ->
- UtilDateTime.getWeek(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:month(now, timeZone, locale)}', { Timestamp now
->
- UtilDateTime.getMonth(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:year(now, timeZone, locale)}', { Timestamp now ->
- UtilDateTime.getYear(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:dayStart(now, timeZone, locale)}', { Timestamp
now ->
- UtilDateTime.getDayStart(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:dayEnd(now, timeZone, locale)}', { Timestamp now
->
- UtilDateTime.getDayEnd(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:weekStart(now, timeZone, locale)}', { Timestamp
now ->
- UtilDateTime.getWeekStart(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:weekEnd(now, timeZone, locale)}', { Timestamp
now ->
- UtilDateTime.getWeekEnd(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:monthStart(now, timeZone, locale)}', { Timestamp
now ->
- UtilDateTime.getMonthStart(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:monthEnd(now, timeZone, locale)}', { Timestamp
now ->
- UtilDateTime.getMonthEnd(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:yearStart(now, timeZone, locale)}', { Timestamp
now ->
- UtilDateTime.getYearStart(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:yearEnd(now, timeZone, locale)}', { Timestamp
now ->
- UtilDateTime.getYearEnd(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:dateStr(now, timeZone, locale)}', { Timestamp
now ->
- UelFunctions.dateString(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:localizedDateStr(now, timeZone, locale)}', {
Timestamp now ->
- UelFunctions.localizedDateString(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:localizedDateTimeStr(now, timeZone, locale)}', {
Timestamp now ->
- UelFunctions.localizedDateTimeString(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- doUelDateTest('${date:timeStr(now, timeZone, locale)}', { Timestamp
now ->
- UelFunctions.timeString(now, TimeZone.getDefault(),
Locale.getDefault())
- })
- }
-
- void testNowTimestampUel() {
- FlexibleStringExpander fse =
FlexibleStringExpander.getInstance('${date:nowTimestamp()}')
- assert (fse.expand([:]).time - UtilDateTime.nowTimestamp().time).abs()
< 500 // less than 500 ms apart
- }
-
- private void doUelDateTest(String uelInput, Closure uelFunction) {
- Timestamp now = UtilDateTime.nowTimestamp()
- Map context = [now: now,
- timeZone: TimeZone.getDefault(),
- locale: Locale.getDefault()]
- FlexibleStringExpander fse =
FlexibleStringExpander.getInstance(uelInput)
- assert fse.expand(context) == uelFunction(now)
- }
-
-}
diff --git
a/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/MathUelTest.groovy
b/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/MathUelTest.groovy
deleted file mode 100644
index 8cf9e7efd7..0000000000
---
a/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/MathUelTest.groovy
+++ /dev/null
@@ -1,90 +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.test.uel
-
-import org.apache.ofbiz.base.util.string.FlexibleStringExpander
-import org.apache.ofbiz.service.testtools.OFBizTestCase
-
-/**
- * ./gradlew 'ofbiz -t component=base -t suitename=basetests'
- */
-/* codenarc-disable GStringExpressionWithinString,ClosureAsLastMethodParameter
*/
-
-class MathUelTest extends OFBizTestCase {
-
- MathUelTest(String name) { super(name) }
-
- void testMathUel() { // codenarc-disable JUnitTestMethodWithoutAssert
- doMathTest('${math:absDouble(a)}', [a: -0.3, b: null], { a, b ->
Math.abs(a as double) })
- doMathTest('${math:absFloat(a)}', [a: -0.3, b: null], { a, b ->
Math.abs(a as float) })
- doMathTest('${math:absInt(a)}', [a: -2, b: null], { a, b -> Math.abs(a
as int) })
- doMathTest('${math:absLong(a)}', [a: -5, b: null], { a, b ->
Math.abs(a as long) })
- doMathTest('${math:acos(a)}', [a: 0.2, b: null], { a, b ->
Math.acos(a) })
- doMathTest('${math:asin(a)}', [a: 0.2, b: null], { a, b ->
Math.asin(a) })
- doMathTest('${math:atan(a)}', [a: 0.2, b: null], { a, b ->
Math.atan(a) })
- doMathTest('${math:atan2(a, b)}', [a: 0.2, b: 0.2], { a, b ->
Math.atan2(a, b) })
- doMathTest('${math:cbrt(a)}', [a: 10, b: null], { a, b -> Math.cbrt(a)
})
- doMathTest('${math:ceil(a)}', [a: 20, b: null], { a, b -> Math.ceil(a)
})
- doMathTest('${math:cos(a)}', [a: 0.2, b: null], { a, b -> Math.cos(a)
})
- doMathTest('${math:cosh(a)}', [a: 0.2, b: null], { a, b ->
Math.cosh(a) })
- doMathTest('${math:exp(a)}', [a: 29, b: null], { a, b -> Math.exp(a) })
- doMathTest('${math:expm1(a)}', [a: 20, b: null], { a, b ->
Math.expm1(a) })
- doMathTest('${math:floor(a)}', [a: 23.4, b: null], { a, b ->
Math.floor(a) })
- doMathTest('${math:hypot(a, b)}', [a: 29, b: 12], { a, b ->
Math.hypot(a, b) })
- doMathTest('${math:IEEEremainder(a, b)}', [a: 12, b: 1.3], { a, b ->
Math.IEEEremainder(a, b) })
- doMathTest('${math:log(a)}', [a: 20, b: null], { a, b -> Math.log(a) })
- doMathTest('${math:log10(a)}', [a: 29, b: null], { a, b ->
Math.log10(a) })
- doMathTest('${math:log1p(a)}', [a: 12, b: null], { a, b ->
Math.log1p(a) })
- doMathTest('${math:maxDouble(a, b)}', [a: 12, b: 13], { a, b ->
Math.max(a as double, b as double) })
- doMathTest('${math:maxFloat(a, b)}', [a: 2.4, b: 3.9], { a, b ->
Math.max(a as float, b as float) })
- doMathTest('${math:maxInt(a, b)}', [a: 2.6, b: 3.7], { a, b ->
Math.max(a as int, b as int) })
- doMathTest('${math:maxLong(a, b)}', [a: 23, b: 32], { a, b ->
Math.max(a as long, b as long) })
- doMathTest('${math:minDouble(a, b)}', [a: 10, b: 20], { a, b ->
Math.min(a as double, b as double) })
- doMathTest('${math:minFloat(a, b)}', [a: 1.2, b: 2.5], { a, b ->
Math.min(a as float, b as float) })
- doMathTest('${math:minInt(a, b)}', [a: 12, b: 13], { a, b ->
Math.min(a as int, b as int) })
- doMathTest('${math:minLong(a, b)}', [a: 24, b: 14], { a, b ->
Math.min(a as long, b as long) })
- doMathTest('${math:pow(a, b)}', [a: 12, b: 13], { a, b -> Math.pow(a,
b) })
- doMathTest('${math:rint(a)}', [a: 29, b: null], { a, b -> Math.rint(a)
})
- doMathTest('${math:roundDouble(a)}', [a: 23.4, b: null], { a, b ->
Math.round(a as double) })
- doMathTest('${math:roundFloat(a)}', [a: 12.4, b: null], { a, b ->
Math.round(a as float) })
- doMathTest('${math:signumDouble(a)}', [a: 23, b: null], { a, b ->
Math.signum(a as double) })
- doMathTest('${math:signumFloat(a)}', [a: 23, b: null], { a, b ->
Math.signum(a as float) })
- doMathTest('${math:sin(a)}', [a: 12, b: null], { a, b -> Math.sin(a) })
- doMathTest('${math:sinh(a)}', [a: 12, b: null], { a, b -> Math.sinh(a)
})
- doMathTest('${math:sqrt(a)}', [a: 34, b: null], { a, b -> Math.sqrt(a)
})
- doMathTest('${math:tan(a)}', [a: 13, b: null], { a, b -> Math.tan(a) })
- doMathTest('${math:tanh(a)}', [a: 30, b: null], { a, b -> Math.tanh(a)
})
- doMathTest('${math:toDegrees(a)}', [a: 30, b: null], { a, b ->
Math.toDegrees(a) })
- doMathTest('${math:toRadians(a)}', [a: 12, b: null], { a, b ->
Math.toRadians(a) })
- doMathTest('${math:ulpDouble(a)}', [a: 12, b: null], { a, b ->
Math.ulp(a as double) })
- doMathTest('${math:ulpFloat(a)}', [a: 30, b: null], { a, b ->
Math.ulp(a as float) })
- }
-
- void testMathRandom() {
- FlexibleStringExpander fse =
FlexibleStringExpander.getInstance('${math:random()}')
- assert fse.expand([:]) instanceof Double
- assert fse.expand([:]) != BigDecimal.ZERO
- }
-
- private void doMathTest(String uelInput, Map context, Closure uelFunction)
{
- FlexibleStringExpander fse =
FlexibleStringExpander.getInstance(uelInput)
- assert new BigDecimal(fse.expand(context)) == new
BigDecimal(uelFunction(context.a, context.b))
- }
-
-}
diff --git
a/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/StringUelTest.groovy
b/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/StringUelTest.groovy
deleted file mode 100644
index ad24acce02..0000000000
---
a/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/StringUelTest.groovy
+++ /dev/null
@@ -1,70 +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.test.uel
-
-import org.apache.ofbiz.base.util.string.FlexibleStringExpander
-import org.apache.ofbiz.base.util.string.UelFunctions
-import org.apache.ofbiz.service.testtools.OFBizTestCase
-
-/**
- * ./gradlew 'ofbiz -t component=base -t suitename=basetests'
- */
-/* codenarc-disable GStringExpressionWithinString,ClosureAsLastMethodParameter
*/
-
-class StringUelTest extends OFBizTestCase {
-
- StringUelTest(String name) { super(name) }
-
- void testUelString() { // codenarc-disable JUnitTestMethodWithoutAssert
- doStringTest('${str:endsWith(a, b)}', [a: 'dog', b: 'og', c: null],
- { a, b, c -> UelFunctions.endsWith(a, b) })
- doStringTest('${str:indexOf(a, b)}', [a: 'dog', b: 'og', c: null],
- { a, b, c -> UelFunctions.indexOf(a, b) })
- doStringTest('${str:lastIndexOf(a, b)}', [a: 'dog', b: 'og', c: null],
- { a, b, c -> UelFunctions.lastIndexOf(a, b) })
- doStringTest('${str:length(a)}', [a: 'dog', b: null, c: null],
- { a, b, c -> UelFunctions.length(a) })
- doStringTest('${str:replace(a, b, c)}', [a: 'the dog', b: 'dog', c:
'cat'],
- { a, b, c -> UelFunctions.replace(a, b, c) })
- doStringTest('${str:replaceAll(a, b, c)}', [a: 'the dog', b: 'dog', c:
'cat'],
- { a, b, c -> UelFunctions.replaceAll(a, b, c) })
- doStringTest('${str:replaceFirst(a, b, c)}', [a: 'the dog', b: 'dog',
c: 'cat'],
- { a, b, c -> UelFunctions.replaceFirst(a, b, c) })
- doStringTest('${str:startsWith(a, b)}', [a: 'the dog', b: 'the', c:
null],
- { a, b, c -> UelFunctions.startsWith(a, b) })
- doStringTest('${str:endstring(a, b)}', [a: 'the dog', b: 3, c: null],
- { a, b, c -> UelFunctions.endString(a, b) })
- doStringTest('${str:substring(a, b, c)}', [a: 'the dog', b: 3, c: 7],
- { a, b, c -> UelFunctions.subString(a, b, c) })
- doStringTest('${str:toString(a)}', [a: 'foo', b: null, c: null],
- { a, b, c -> UelFunctions.toString(a) })
- doStringTest('${str:toLowerCase(a)}', [a: 'FOO', b: null, c: null],
- { a, b, c -> UelFunctions.toLowerCase(a) })
- doStringTest('${str:toUpperCase(a)}', [a: 'foo', b: null, c: null],
- { a, b, c -> UelFunctions.toUpperCase(a) })
- doStringTest('${str:trim(a)}', [a: ' foo ', b: null, c: null],
- { a, b, c -> UelFunctions.trim(a) })
- }
-
- private void doStringTest(String uelInput, Map context, Closure
uelFunction) {
- FlexibleStringExpander fse =
FlexibleStringExpander.getInstance(uelInput)
- assert fse.expand(context) == uelFunction(context.a, context.b,
context.c)
- }
-
-}
diff --git
a/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/DateUelTest.groovy
b/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/DateUelTest.groovy
new file mode 100644
index 0000000000..99394f89e3
--- /dev/null
+++
b/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/DateUelTest.groovy
@@ -0,0 +1,131 @@
+/*******************************************************************************
+ * 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.test.uel
+
+import org.apache.ofbiz.base.util.UtilDateTime
+import org.apache.ofbiz.base.util.string.FlexibleStringExpander
+import org.apache.ofbiz.base.util.string.UelFunctions
+
+import java.sql.Timestamp
+import java.util.stream.Stream
+
+import org.junit.jupiter.api.BeforeAll
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.Arguments
+import org.junit.jupiter.params.provider.MethodSource
+
+/**
+ * ./gradlew test --tests "org.apache.ofbiz.base.test.uel.DateUelTest"
+ */
+/* codenarc-disable GStringExpressionWithinString,ClosureAsLastMethodParameter
*/
+class DateUelTest {
+
+ @BeforeAll
+ static void loadUelFunctions() {
+ UelTestSupport.ensureUelFunctionsLoaded()
+ }
+
+ @ParameterizedTest(name = '{0}')
+ @MethodSource('dateUelExpressions')
+ void dateUelExpressionMatchesExpectedValue(String uelInput, Closure<?>
expectedFunction) { // codenarc-disable JUnitTestMethodWithoutAssert
+ Timestamp now = UtilDateTime.nowTimestamp()
+ Map context = [now: now,
+ timeZone: TimeZone.getDefault(),
+ locale: Locale.getDefault()]
+ FlexibleStringExpander fse =
FlexibleStringExpander.getInstance(uelInput)
+ assert fse.expand(context) == expectedFunction(now)
+ }
+
+ @Test
+ void nowTimestampUelIsWithinToleranceOfActualNow() {
+ FlexibleStringExpander fse =
FlexibleStringExpander.getInstance('${date:nowTimestamp()}')
+ assert (fse.expand([:]).time - UtilDateTime.nowTimestamp().time).abs()
< 500 // less than 500 ms apart
+ }
+
+ @SuppressWarnings('UnusedPrivateMethod')
+ private static Stream<Arguments> dateUelExpressions() {
+ Stream.of(
+ Arguments.of('${date:second(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getSecond(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:minute(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getMinute(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:hour(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getHour(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:dayOfMonth(now, timeZone, locale)}', {
Timestamp now ->
+ UtilDateTime.getDayOfMonth(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:dayOfWeek(now, timeZone, locale)}', {
Timestamp now ->
+ UtilDateTime.getDayOfWeek(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:dayOfYear(now, timeZone, locale)}', {
Timestamp now ->
+ UtilDateTime.getDayOfYear(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:week(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getWeek(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:month(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getMonth(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:year(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getYear(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:dayStart(now, timeZone, locale)}', {
Timestamp now ->
+ UtilDateTime.getDayStart(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:dayEnd(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getDayEnd(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:weekStart(now, timeZone, locale)}', {
Timestamp now ->
+ UtilDateTime.getWeekStart(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:weekEnd(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getWeekEnd(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:monthStart(now, timeZone, locale)}', {
Timestamp now ->
+ UtilDateTime.getMonthStart(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:monthEnd(now, timeZone, locale)}', {
Timestamp now ->
+ UtilDateTime.getMonthEnd(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:yearStart(now, timeZone, locale)}', {
Timestamp now ->
+ UtilDateTime.getYearStart(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:yearEnd(now, timeZone, locale)}', { Timestamp
now ->
+ UtilDateTime.getYearEnd(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:dateStr(now, timeZone, locale)}', { Timestamp
now ->
+ UelFunctions.dateString(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:localizedDateStr(now, timeZone, locale)}', {
Timestamp now ->
+ UelFunctions.localizedDateString(now, TimeZone.getDefault(),
Locale.getDefault())
+ }),
+ Arguments.of('${date:localizedDateTimeStr(now, timeZone,
locale)}', { Timestamp now ->
+ UelFunctions.localizedDateTimeString(now,
TimeZone.getDefault(), Locale.getDefault())
+ }),
+ Arguments.of('${date:timeStr(now, timeZone, locale)}', { Timestamp
now ->
+ UelFunctions.timeString(now, TimeZone.getDefault(),
Locale.getDefault())
+ })
+ )
+ }
+
+}
diff --git
a/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/MathUelTest.groovy
b/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/MathUelTest.groovy
new file mode 100644
index 0000000000..54e1e75149
--- /dev/null
+++
b/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/MathUelTest.groovy
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * 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.test.uel
+
+import org.apache.ofbiz.base.util.string.FlexibleStringExpander
+
+import java.util.stream.Stream
+
+import org.junit.jupiter.api.BeforeAll
+import org.junit.jupiter.api.Test
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.Arguments
+import org.junit.jupiter.params.provider.MethodSource
+
+/**
+ * ./gradlew test --tests "org.apache.ofbiz.base.test.uel.MathUelTest"
+ */
+/* codenarc-disable GStringExpressionWithinString,ClosureAsLastMethodParameter
*/
+class MathUelTest {
+
+ @BeforeAll
+ static void loadUelFunctions() {
+ UelTestSupport.ensureUelFunctionsLoaded()
+ }
+
+ @ParameterizedTest(name = '{0}')
+ @MethodSource('mathUelExpressions')
+ void mathUelExpressionMatchesExpectedValue(String uelInput, Map context,
+ Closure<?> expectedFunction) { // codenarc-disable
JUnitTestMethodWithoutAssert
+ FlexibleStringExpander fse =
FlexibleStringExpander.getInstance(uelInput)
+ assert new BigDecimal(fse.expand(context)) == new
BigDecimal(expectedFunction(context.a, context.b))
+ }
+
+ @Test
+ void mathRandomUelReturnsNonZeroDouble() {
+ FlexibleStringExpander fse =
FlexibleStringExpander.getInstance('${math:random()}')
+ assert fse.expand([:]) instanceof Double
+ assert fse.expand([:]) != BigDecimal.ZERO
+ }
+
+ @SuppressWarnings('UnusedPrivateMethod')
+ private static Stream<Arguments> mathUelExpressions() {
+ Stream.of(
+ Arguments.of('${math:absDouble(a)}', [a: -0.3, b: null], { a, b ->
Math.abs(a as double) }),
+ Arguments.of('${math:absFloat(a)}', [a: -0.3, b: null], { a, b ->
Math.abs(a as float) }),
+ Arguments.of('${math:absInt(a)}', [a: -2, b: null], { a, b ->
Math.abs(a as int) }),
+ Arguments.of('${math:absLong(a)}', [a: -5, b: null], { a, b ->
Math.abs(a as long) }),
+ Arguments.of('${math:acos(a)}', [a: 0.2, b: null], { a, b ->
Math.acos(a) }),
+ Arguments.of('${math:asin(a)}', [a: 0.2, b: null], { a, b ->
Math.asin(a) }),
+ Arguments.of('${math:atan(a)}', [a: 0.2, b: null], { a, b ->
Math.atan(a) }),
+ Arguments.of('${math:atan2(a, b)}', [a: 0.2, b: 0.2], { a, b ->
Math.atan2(a, b) }),
+ Arguments.of('${math:cbrt(a)}', [a: 10, b: null], { a, b ->
Math.cbrt(a) }),
+ Arguments.of('${math:ceil(a)}', [a: 20, b: null], { a, b ->
Math.ceil(a) }),
+ Arguments.of('${math:cos(a)}', [a: 0.2, b: null], { a, b ->
Math.cos(a) }),
+ Arguments.of('${math:cosh(a)}', [a: 0.2, b: null], { a, b ->
Math.cosh(a) }),
+ Arguments.of('${math:exp(a)}', [a: 29, b: null], { a, b ->
Math.exp(a) }),
+ Arguments.of('${math:expm1(a)}', [a: 20, b: null], { a, b ->
Math.expm1(a) }),
+ Arguments.of('${math:floor(a)}', [a: 23.4, b: null], { a, b ->
Math.floor(a) }),
+ Arguments.of('${math:hypot(a, b)}', [a: 29, b: 12], { a, b ->
Math.hypot(a, b) }),
+ Arguments.of('${math:IEEEremainder(a, b)}', [a: 12, b: 1.3], { a,
b -> Math.IEEEremainder(a, b) }),
+ Arguments.of('${math:log(a)}', [a: 20, b: null], { a, b ->
Math.log(a) }),
+ Arguments.of('${math:log10(a)}', [a: 29, b: null], { a, b ->
Math.log10(a) }),
+ Arguments.of('${math:log1p(a)}', [a: 12, b: null], { a, b ->
Math.log1p(a) }),
+ Arguments.of('${math:maxDouble(a, b)}', [a: 12, b: 13], { a, b ->
Math.max(a as double, b as double) }),
+ Arguments.of('${math:maxFloat(a, b)}', [a: 2.4, b: 3.9], { a, b ->
Math.max(a as float, b as float) }),
+ Arguments.of('${math:maxInt(a, b)}', [a: 2.6, b: 3.7], { a, b ->
Math.max(a as int, b as int) }),
+ Arguments.of('${math:maxLong(a, b)}', [a: 23, b: 32], { a, b ->
Math.max(a as long, b as long) }),
+ Arguments.of('${math:minDouble(a, b)}', [a: 10, b: 20], { a, b ->
Math.min(a as double, b as double) }),
+ Arguments.of('${math:minFloat(a, b)}', [a: 1.2, b: 2.5], { a, b ->
Math.min(a as float, b as float) }),
+ Arguments.of('${math:minInt(a, b)}', [a: 12, b: 13], { a, b ->
Math.min(a as int, b as int) }),
+ Arguments.of('${math:minLong(a, b)}', [a: 24, b: 14], { a, b ->
Math.min(a as long, b as long) }),
+ Arguments.of('${math:pow(a, b)}', [a: 12, b: 13], { a, b ->
Math.pow(a, b) }),
+ Arguments.of('${math:rint(a)}', [a: 29, b: null], { a, b ->
Math.rint(a) }),
+ Arguments.of('${math:roundDouble(a)}', [a: 23.4, b: null], { a, b
-> Math.round(a as double) }),
+ Arguments.of('${math:roundFloat(a)}', [a: 12.4, b: null], { a, b
-> Math.round(a as float) }),
+ Arguments.of('${math:signumDouble(a)}', [a: 23, b: null], { a, b
-> Math.signum(a as double) }),
+ Arguments.of('${math:signumFloat(a)}', [a: 23, b: null], { a, b ->
Math.signum(a as float) }),
+ Arguments.of('${math:sin(a)}', [a: 12, b: null], { a, b ->
Math.sin(a) }),
+ Arguments.of('${math:sinh(a)}', [a: 12, b: null], { a, b ->
Math.sinh(a) }),
+ Arguments.of('${math:sqrt(a)}', [a: 34, b: null], { a, b ->
Math.sqrt(a) }),
+ Arguments.of('${math:tan(a)}', [a: 13, b: null], { a, b ->
Math.tan(a) }),
+ Arguments.of('${math:tanh(a)}', [a: 30, b: null], { a, b ->
Math.tanh(a) }),
+ Arguments.of('${math:toDegrees(a)}', [a: 30, b: null], { a, b ->
Math.toDegrees(a) }),
+ Arguments.of('${math:toRadians(a)}', [a: 12, b: null], { a, b ->
Math.toRadians(a) }),
+ Arguments.of('${math:ulpDouble(a)}', [a: 12, b: null], { a, b ->
Math.ulp(a as double) }),
+ Arguments.of('${math:ulpFloat(a)}', [a: 30, b: null], { a, b ->
Math.ulp(a as float) })
+ )
+ }
+
+}
diff --git
a/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/MiscUelTest.groovy
b/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/MiscUelTest.groovy
similarity index 85%
rename from
framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/MiscUelTest.groovy
rename to
framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/MiscUelTest.groovy
index cce82265c1..7b5659196c 100644
---
a/framework/base/src/main/groovy/org/apache/ofbiz/base/test/uel/MiscUelTest.groovy
+++
b/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/MiscUelTest.groovy
@@ -20,35 +20,44 @@ package org.apache.ofbiz.base.test.uel
import org.apache.ofbiz.base.util.string.FlexibleStringExpander
import org.apache.ofbiz.base.util.string.UelFunctions
-import org.apache.ofbiz.service.testtools.OFBizTestCase
+
+import org.junit.jupiter.api.BeforeAll
+import org.junit.jupiter.api.Test
/**
- * ./gradlew 'ofbiz -t component=base -t suitename=basetests'
+ * ./gradlew test --tests "org.apache.ofbiz.base.test.uel.MiscUelTest"
*/
/* codenarc-disable GStringExpressionWithinString,ClosureAsLastMethodParameter
*/
-class MiscUelTest extends OFBizTestCase {
+class MiscUelTest {
- MiscUelTest(String name) { super(name) }
+ @BeforeAll
+ static void loadUelFunctions() {
+ UelTestSupport.ensureUelFunctionsLoaded()
+ }
- void testSystemUel() { // codenarc-disable JUnitTestMethodWithoutAssert
+ @Test
+ void systemEnvAndPropertyUelFunctionsWork() { // codenarc-disable
JUnitTestMethodWithoutAssert
doUelSystemTest('${sys:getenv("foo")}', 'foo', { String prop ->
UelFunctions.sysGetEnv(prop) })
doUelSystemTest('${sys:getProperty("bar")}', 'bar', { String prop ->
UelFunctions.sysGetProp(prop) })
}
- void testUtilSizeUel() {
+ @Test
+ void utilSizeUelFunctionReturnsListSize() {
List foo = [1, 2, 3]
FlexibleStringExpander fse =
FlexibleStringExpander.getInstance('${util:size(foo)}')
assert fse.expand([foo: foo]) == UelFunctions.getSize(foo)
}
- void testDefaultLocaleAndTimzoneUel() {
+ @Test
+ void defaultLocaleAndTimeZoneUelFunctionsReturnSystemDefaults() {
FlexibleStringExpander fse =
FlexibleStringExpander.getInstance('${util:defaultLocale()}')
assert fse.expand([foo: 'bar']) == Locale.getDefault()
fse = FlexibleStringExpander.getInstance('${util:defaultTimeZone()}')
assert fse.expand([foo: 'bar']) == TimeZone.getDefault()
}
- void testLabelUel() {
+ @Test
+ void labelUelFunctionResolvesPropertyLabel() {
String labelFile = 'CommonEntityLabels', labelKey =
'VisualTheme.description.RAINBOWSTONE_AMBER'
FlexibleStringExpander fse = FlexibleStringExpander.getInstance(
'${util:label(\'CommonEntityLabels\',\'VisualTheme.description.RAINBOWSTONE_AMBER\',
locale)}')
diff --git
a/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/StringUelTest.groovy
b/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/StringUelTest.groovy
new file mode 100644
index 0000000000..b114027cad
--- /dev/null
+++
b/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/StringUelTest.groovy
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * 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.test.uel
+
+import org.apache.ofbiz.base.util.string.FlexibleStringExpander
+import org.apache.ofbiz.base.util.string.UelFunctions
+
+import java.util.stream.Stream
+
+import org.junit.jupiter.api.BeforeAll
+import org.junit.jupiter.params.ParameterizedTest
+import org.junit.jupiter.params.provider.Arguments
+import org.junit.jupiter.params.provider.MethodSource
+
+/**
+ * ./gradlew test --tests "org.apache.ofbiz.base.test.uel.StringUelTest"
+ */
+/* codenarc-disable GStringExpressionWithinString,ClosureAsLastMethodParameter
*/
+class StringUelTest {
+
+ @BeforeAll
+ static void loadUelFunctions() {
+ UelTestSupport.ensureUelFunctionsLoaded()
+ }
+
+ @ParameterizedTest(name = '{0}')
+ @MethodSource('stringUelExpressions')
+ void stringUelExpressionMatchesExpectedValue(String uelInput, Map context,
+ Closure<?> expectedFunction) { // codenarc-disable
JUnitTestMethodWithoutAssert
+ FlexibleStringExpander fse =
FlexibleStringExpander.getInstance(uelInput)
+ assert fse.expand(context) == expectedFunction(context.a, context.b,
context.c)
+ }
+
+ @SuppressWarnings('UnusedPrivateMethod')
+ private static Stream<Arguments> stringUelExpressions() {
+ Stream.of(
+ Arguments.of('${str:endsWith(a, b)}', [a: 'dog', b: 'og', c: null],
+ { a, b, c -> UelFunctions.endsWith(a, b) }),
+ Arguments.of('${str:indexOf(a, b)}', [a: 'dog', b: 'og', c: null],
+ { a, b, c -> UelFunctions.indexOf(a, b) }),
+ Arguments.of('${str:lastIndexOf(a, b)}', [a: 'dog', b: 'og', c:
null],
+ { a, b, c -> UelFunctions.lastIndexOf(a, b) }),
+ Arguments.of('${str:length(a)}', [a: 'dog', b: null, c: null],
+ { a, b, c -> UelFunctions.length(a) }),
+ Arguments.of('${str:replace(a, b, c)}', [a: 'the dog', b: 'dog',
c: 'cat'],
+ { a, b, c -> UelFunctions.replace(a, b, c) }),
+ Arguments.of('${str:replaceAll(a, b, c)}', [a: 'the dog', b:
'dog', c: 'cat'],
+ { a, b, c -> UelFunctions.replaceAll(a, b, c) }),
+ Arguments.of('${str:replaceFirst(a, b, c)}', [a: 'the dog', b:
'dog', c: 'cat'],
+ { a, b, c -> UelFunctions.replaceFirst(a, b, c) }),
+ Arguments.of('${str:startsWith(a, b)}', [a: 'the dog', b: 'the',
c: null],
+ { a, b, c -> UelFunctions.startsWith(a, b) }),
+ Arguments.of('${str:endstring(a, b)}', [a: 'the dog', b: 3, c:
null],
+ { a, b, c -> UelFunctions.endString(a, b) }),
+ Arguments.of('${str:substring(a, b, c)}', [a: 'the dog', b: 3, c:
7],
+ { a, b, c -> UelFunctions.subString(a, b, c) }),
+ Arguments.of('${str:toString(a)}', [a: 'foo', b: null, c: null],
+ { a, b, c -> UelFunctions.toString(a) }),
+ Arguments.of('${str:toLowerCase(a)}', [a: 'FOO', b: null, c: null],
+ { a, b, c -> UelFunctions.toLowerCase(a) }),
+ Arguments.of('${str:toUpperCase(a)}', [a: 'foo', b: null, c: null],
+ { a, b, c -> UelFunctions.toUpperCase(a) }),
+ Arguments.of('${str:trim(a)}', [a: ' foo ', b: null, c: null],
+ { a, b, c -> UelFunctions.trim(a) })
+ )
+ }
+
+}
diff --git
a/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/UelFunctionsBootstrapListener.groovy
b/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/UelFunctionsBootstrapListener.groovy
new file mode 100644
index 0000000000..33bfd6141b
--- /dev/null
+++
b/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/UelFunctionsBootstrapListener.groovy
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * 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.test.uel
+
+import org.apache.ofbiz.base.util.Debug
+import org.junit.platform.launcher.LauncherSession
+import org.junit.platform.launcher.LauncherSessionListener
+
+/**
+ * Registered via META-INF/services (see the resource file alongside this
class) so JUnit
+ * Platform's LauncherFactory discovers and invokes launcherSessionOpened()
exactly once, before
+ * any test in the JVM is discovered or executed - regardless of which test
class Gradle would
+ * otherwise run first. This is the structural fix for a class-execution-order
dependency that
+ * UelTestSupport.ensureUelFunctionsLoaded()'s per-class @BeforeAll wiring
alone can't guarantee
+ * once dozens of unrelated tests elsewhere in the repo can also touch
UelFunctions first in a
+ * full, unfiltered gradlew test run.
+ *
+ * <p>UelTestSupport.ensureUelFunctionsLoaded() is also called directly from
each of the 4 UEL
+ * test classes' own {@literal @}BeforeAll. Both call sites are intentionally
present: this
+ * listener is the fast/global path for a normal full-suite run, while the
per-class
+ * {@literal @}BeforeAll is what retries the bootstrap - and correctly
attributes a failure to the
+ * right test class - if this listener's own attempt failed.
+ */
+class UelFunctionsBootstrapListener implements LauncherSessionListener {
+
+ private static final String MODULE =
UelFunctionsBootstrapListener.getName()
+
+ @Override
+ void launcherSessionOpened(LauncherSession session) {
+ try {
+ UelTestSupport.ensureUelFunctionsLoaded()
+ } catch (Exception e) {
+ // Deliberately swallowed here: an exception from this
session-wide hook would abort
+ // every test in the JVM, not just the ones that need UEL
functions. Leaving
+ // COMPONENTS_LOADED unset means the affected UEL test classes'
own @BeforeAll will
+ // retry and surface this same failure, scoped correctly to just
those classes.
+ Debug.logError(e, 'UEL function bootstrap failed during session
startup; ' +
+ 'UEL test classes will retry and report the failure',
MODULE)
+ }
+ }
+
+}
diff --git
a/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/UelTestSupport.groovy
b/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/UelTestSupport.groovy
new file mode 100644
index 0000000000..1b01aa1ee4
--- /dev/null
+++
b/framework/base/src/test/groovy/org/apache/ofbiz/base/test/uel/UelTestSupport.groovy
@@ -0,0 +1,59 @@
+/*******************************************************************************
+ * 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.test.uel
+
+import org.apache.ofbiz.base.component.ComponentConfig
+import org.apache.ofbiz.base.container.ComponentContainerTestSupport
+
+import java.nio.file.Path
+import java.nio.file.Paths
+import java.util.concurrent.atomic.AtomicBoolean
+
+/**
+ * UelFunctions.FUNCTION_MAPPER
(framework/base/.../util/string/UelFunctions.java) is a static
+ * field built exactly once, the first time UelFunctions is touched by any
code in the JVM, by
+ * scanning ComponentConfig for every component's <uel-mapping>
declarations. ComponentConfig
+ * is normally populated by ComponentContainer during full OFBiz boot - never
triggered by plain
+ * gradlew test. ensureUelFunctionsLoaded() runs that one piece standalone
(metadata/XML scanning
+ * only, no database or web container involved) so UEL-function-based unit
tests in this package
+ * don't need the ofbiz --test container.
+ *
+ * <p>Idempotent and safe to call from every UEL test class's own {@literal
@}BeforeAll,
+ * regardless of which class Gradle happens to run first in this JVM - only
the first call
+ * actually does anything.
+ */
+class UelTestSupport {
+
+ private static final AtomicBoolean COMPONENTS_LOADED = new
AtomicBoolean(false)
+
+ static void ensureUelFunctionsLoaded() {
+ if (!COMPONENTS_LOADED.get()) {
+ if (!ComponentConfig.componentExists('base')) {
+ Path ofbizHome = Paths.get('').toAbsolutePath().normalize()
+
ComponentContainerTestSupport.bootstrapComponents('uel-test-bootstrap',
ofbizHome)
+ if (!ComponentConfig.componentExists('base')) {
+ throw new IllegalStateException("UEL bootstrap loaded no
components from ${ofbizHome} - " +
+ 'is the JVM working directory the OFBiz project
root?')
+ }
+ }
+ COMPONENTS_LOADED.set(true)
+ }
+ }
+
+}
diff --git
a/framework/base/src/test/java/org/apache/ofbiz/base/container/ComponentContainerTest.java
b/framework/base/src/test/java/org/apache/ofbiz/base/container/ComponentContainerTest.java
index cd9b6e40c2..17518c3985 100644
---
a/framework/base/src/test/java/org/apache/ofbiz/base/container/ComponentContainerTest.java
+++
b/framework/base/src/test/java/org/apache/ofbiz/base/container/ComponentContainerTest.java
@@ -36,8 +36,8 @@ import org.junit.jupiter.api.Test;
public final class ComponentContainerTest {
- private static final Path ORDER_CONFIG = Paths.get("applications",
"order", "config");
- private static final Path ACCOUNTING_CONFIG = Paths.get("applications",
"accounting", "config");
+ private static final Path ORDER_CONFIG = Paths.get("applications",
"test-order", "config");
+ private static final Path ACCOUNTING_CONFIG = Paths.get("applications",
"test-accounting", "config");
private static final Path[] CONFIGS = {ORDER_CONFIG, ACCOUNTING_CONFIG};
private Path ofbizHome =
Paths.get(ComponentContainerTest.class.getResource("testsdata").toURI())
@@ -65,9 +65,17 @@ public final class ComponentContainerTest {
ComponentContainer containerObj = new ComponentContainer();
containerObj.init("component-container", ofbizHome);
+ // ComponentConfig's cache is a single JVM-wide static shared with the
rest of the test
+ // suite (e.g. the UEL bootstrap session listener also loads the real,
~90-component
+ // project into it). Filter down to just this test's own fixture names
so the assertion
+ // stays a genuine, order-sensitive check of sortDependencies() -
accounting depends on
+ // order, so a correct topological sort must place test-order before
test-accounting even
+ // though alphabetical scan order would visit test-accounting first -
regardless of
+ // whatever else has been loaded into the shared cache by other tests
in this JVM.
List<String> loadedComponents = ComponentConfig.components()
.map(ComponentConfig::getGlobalName)
+ .filter(name -> name.equals("test-order") ||
name.equals("test-accounting"))
.collect(Collectors.toList());
- assertEquals(Arrays.asList("order", "accounting"), loadedComponents);
+ assertEquals(Arrays.asList("test-order", "test-accounting"),
loadedComponents);
}
}
diff --git
a/framework/base/src/test/java/org/apache/ofbiz/base/container/ComponentContainerTestSupport.java
b/framework/base/src/test/java/org/apache/ofbiz/base/container/ComponentContainerTestSupport.java
new file mode 100644
index 0000000000..a3c4dcf845
--- /dev/null
+++
b/framework/base/src/test/java/org/apache/ofbiz/base/container/ComponentContainerTestSupport.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * 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.container;
+
+import java.nio.file.Path;
+
+/**
+ * Test-only bridge exposing ComponentContainer's package-private init(String,
Path) to other
+ * test packages (e.g. org.apache.ofbiz.base.test.uel's UelTestSupport),
without widening its
+ * visibility in production code. This class lives in src/test, so it is never
present on the
+ * production classpath.
+ */
+public final class ComponentContainerTestSupport {
+
+ private ComponentContainerTestSupport() { }
+
+ public static void bootstrapComponents(String name, Path ofbizHome) throws
ContainerException {
+ new ComponentContainer().init(name, ofbizHome);
+ }
+
+}
diff --git
a/framework/base/src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener
b/framework/base/src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener
new file mode 100644
index 0000000000..99d083c25d
--- /dev/null
+++
b/framework/base/src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener
@@ -0,0 +1 @@
+org.apache.ofbiz.base.test.uel.UelFunctionsBootstrapListener
diff --git
a/framework/base/src/test/resources/org/apache/ofbiz/base/container/testsdata/applications/accounting/ofbiz-component.xml
b/framework/base/src/test/resources/org/apache/ofbiz/base/container/testsdata/applications/test-accounting/ofbiz-component.xml
similarity index 92%
rename from
framework/base/src/test/resources/org/apache/ofbiz/base/container/testsdata/applications/accounting/ofbiz-component.xml
rename to
framework/base/src/test/resources/org/apache/ofbiz/base/container/testsdata/applications/test-accounting/ofbiz-component.xml
index 83e2534f55..e87479b973 100644
---
a/framework/base/src/test/resources/org/apache/ofbiz/base/container/testsdata/applications/accounting/ofbiz-component.xml
+++
b/framework/base/src/test/resources/org/apache/ofbiz/base/container/testsdata/applications/test-accounting/ofbiz-component.xml
@@ -18,10 +18,10 @@ specific language governing permissions and limitations
under the License.
-->
-<ofbiz-component name="accounting"
+<ofbiz-component name="test-accounting"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://ofbiz.apache.org/dtds/ofbiz-component.xsd">
- <depends-on component-name="order" />
+ <depends-on component-name="test-order" />
<resource-loader name="main" type="component"/>
<classpath type="dir" location="config"/>
</ofbiz-component>
diff --git
a/framework/base/src/test/resources/org/apache/ofbiz/base/container/testsdata/applications/order/ofbiz-component.xml
b/framework/base/src/test/resources/org/apache/ofbiz/base/container/testsdata/applications/test-order/ofbiz-component.xml
similarity index 96%
rename from
framework/base/src/test/resources/org/apache/ofbiz/base/container/testsdata/applications/order/ofbiz-component.xml
rename to
framework/base/src/test/resources/org/apache/ofbiz/base/container/testsdata/applications/test-order/ofbiz-component.xml
index 1b70403e89..92f90063f8 100644
---
a/framework/base/src/test/resources/org/apache/ofbiz/base/container/testsdata/applications/order/ofbiz-component.xml
+++
b/framework/base/src/test/resources/org/apache/ofbiz/base/container/testsdata/applications/test-order/ofbiz-component.xml
@@ -17,7 +17,7 @@ KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
-<ofbiz-component name="order"
+<ofbiz-component name="test-order"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="https://ofbiz.apache.org/dtds/ofbiz-component.xsd">
<resource-loader name="main" type="component"/>
diff --git a/framework/base/testdef/basetests.xml
b/framework/base/testdef/basetests.xml
index 81b1638abd..b01f063cbb 100644
--- a/framework/base/testdef/basetests.xml
+++ b/framework/base/testdef/basetests.xml
@@ -24,17 +24,4 @@
<junit-test-suite class-name="org.apache.ofbiz.base.test.SimpleTests"/>
</test-case>
- <test-case case-name="uel-date-tests">
- <junit-test-suite
class-name="org.apache.ofbiz.base.test.uel.DateUelTest"/>
- </test-case>
- <test-case case-name="uel-math-tests">
- <junit-test-suite
class-name="org.apache.ofbiz.base.test.uel.MathUelTest"/>
- </test-case>
- <test-case case-name="uel-string-tests">
- <junit-test-suite
class-name="org.apache.ofbiz.base.test.uel.StringUelTest"/>
- </test-case>
- <test-case case-name="uel-misc-tests">
- <junit-test-suite
class-name="org.apache.ofbiz.base.test.uel.MiscUelTest"/>
- </test-case>
-
</test-suite>