diff --git a/common/src/test/java/org/eclipse/daanse/olap/calc/base/type/tuplebase/TupleListTest.java b/common/src/test/java/org/eclipse/daanse/olap/calc/base/type/tuplebase/TupleListTest.java
new file mode 100644
index 00000000..c97db3ea
--- /dev/null
+++ b/common/src/test/java/org/eclipse/daanse/olap/calc/base/type/tuplebase/TupleListTest.java
@@ -0,0 +1,44 @@
+/*
+ * This software is subject to the terms of the Eclipse Public License v1.0
+ * Agreement, available at the following URL:
+ * http://www.eclipse.org/legal/epl-v10.html.
+ * You must accept the terms of that agreement to use this software.
+ *
+ * Copyright (C) 2002-2017 Hitachi Vantara and others
+ * All Rights Reserved.
+ *
+ * ---- All changes after Fork in 2023 ------------------------
+ *
+ * Project: Eclipse daanse
+ *
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors after Fork in 2023:
+ * SmartCity Jena - initial
+ */
+package org.eclipse.daanse.olap.calc.base.type.tuplebase;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.eclipse.daanse.olap.api.calc.todo.TupleList;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit test for {@link TupleList} and common implementations.
+ *
+ * @author jhyde
+ */
+class TupleListTest {
+
+ @Test
+ void testTupleList() {
+ assertTrue(TupleCollections.createList(1) instanceof UnaryTupleList);
+ assertTrue(TupleCollections.createList(2) instanceof ArrayTupleList);
+ }
+}
diff --git a/common/src/test/java/org/eclipse/daanse/olap/fun/SortTest.java b/common/src/test/java/org/eclipse/daanse/olap/fun/SortTest.java
new file mode 100644
index 00000000..0e7e2ea1
--- /dev/null
+++ b/common/src/test/java/org/eclipse/daanse/olap/fun/SortTest.java
@@ -0,0 +1,81 @@
+/*
+ * This software is subject to the terms of the Eclipse Public License v1.0
+ * Agreement, available at the following URL:
+ * http://www.eclipse.org/legal/epl-v10.html.
+ * You must accept the terms of that agreement to use this software.
+ *
+ * Copyright (c) 2002-2020 Hitachi Vantara.. All rights reserved.
+ *
+ * ---- All changes after Fork in 2023 ------------------------
+ *
+ * Project: Eclipse daanse
+ *
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors after Fork in 2023:
+ * SmartCity Jena - initial
+ */
+package org.eclipse.daanse.olap.fun;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.eclipse.daanse.olap.common.SystemWideProperties;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Test;
+
+
+/**
+ * SortTest tests the collation order of positive and negative
+ * infinity, and {@link Double#NaN}.
+ *
+ * @author jhyde
+ * @since Sep 21, 2006
+ */
+class SortTest {
+
+ /**
+ * Access properties via this object and their values will be reset.
+ */
+
+ @AfterEach
+ public void afterEach() {
+ SystemWideProperties.instance().populateInitial();
+ }
+
+ @Test
+ void testFoo() {
+ // Check that each value compares according to its position in the total
+ // order. For example, NaN compares greater than
+ // Double.NEGATIVE_INFINITY, -34.5, -0.001, 0, 0.00000567, 1, 3.14;
+ // equal to NaN; and less than Double.POSITIVE_INFINITY.
+ double[] values = {
+ Double.NEGATIVE_INFINITY,
+ FunUtil.DOUBLE_NULL,
+ -34.5,
+ -0.001,
+ 0,
+ 0.00000567,
+ 1,
+ 3.14,
+ Double.NaN,
+ Double.POSITIVE_INFINITY,
+ };
+ for ( int i = 0; i < values.length; i++ ) {
+ for ( int j = 0; j < values.length; j++ ) {
+ int expected = Integer.compare( i, j );
+ assertEquals(
+ expected,
+ FunUtil.compareValues( values[ i ], values[ j ] ),
+ "values[" + i + "]=" + values[ i ] + ", values[" + j
+ + "]=" + values[ j ]);
+ }
+ }
+ }
+
+}
diff --git a/common/src/test/java/org/eclipse/daanse/olap/function/def/crossjoin/CrossJoinTest.java b/common/src/test/java/org/eclipse/daanse/olap/function/def/crossjoin/CrossJoinTest.java
new file mode 100644
index 00000000..8009c23a
--- /dev/null
+++ b/common/src/test/java/org/eclipse/daanse/olap/function/def/crossjoin/CrossJoinTest.java
@@ -0,0 +1,501 @@
+/*
+ * This software is subject to the terms of the Eclipse Public License v1.0
+ * Agreement, available at the following URL:
+ * http://www.eclipse.org/legal/epl-v10.html.
+ * You must accept the terms of that agreement to use this software.
+ *
+ * Copyright (c) 2002-2020 Hitachi Vantara.. All rights reserved.
+ * ---- All changes after Fork in 2023 ------------------------
+ *
+ * Project: Eclipse daanse
+ *
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors after Fork in 2023:
+ * SmartCity Jena - initial
+ */
+
+package org.eclipse.daanse.olap.function.def.crossjoin;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.io.PrintWriter;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import org.eclipse.daanse.mdx.model.api.expression.operation.FunctionOperationAtom;
+import org.eclipse.daanse.mdx.model.api.expression.operation.OperationAtom;
+import org.eclipse.daanse.olap.api.ConfigConstants;
+import org.eclipse.daanse.olap.api.Context;
+import org.eclipse.daanse.olap.api.DataType;
+import org.eclipse.daanse.olap.api.Statement;
+import org.eclipse.daanse.olap.api.Validator;
+import org.eclipse.daanse.olap.api.calc.Calc;
+import org.eclipse.daanse.olap.api.calc.compiler.ExpressionCompiler;
+import org.eclipse.daanse.olap.api.calc.todo.TupleCursor;
+import org.eclipse.daanse.olap.api.calc.todo.TupleIterable;
+import org.eclipse.daanse.olap.api.calc.todo.TupleList;
+import org.eclipse.daanse.olap.api.connection.Connection;
+import org.eclipse.daanse.olap.api.element.Member;
+import org.eclipse.daanse.olap.api.function.FunctionDefinition;
+import org.eclipse.daanse.olap.api.function.FunctionMetaData;
+import org.eclipse.daanse.olap.api.function.FunctionParameter;
+import org.eclipse.daanse.olap.api.query.component.Expression;
+import org.eclipse.daanse.olap.api.query.component.ResolvedFunCall;
+import org.eclipse.daanse.olap.api.result.Position;
+import org.eclipse.daanse.olap.api.result.Result;
+import org.eclipse.daanse.olap.api.type.MemberType;
+import org.eclipse.daanse.olap.api.type.SetType;
+import org.eclipse.daanse.olap.api.type.TupleType;
+import org.eclipse.daanse.olap.api.type.Type;
+import org.eclipse.daanse.olap.calc.base.type.tuplebase.ArrayTupleList;
+import org.eclipse.daanse.olap.calc.base.type.tuplebase.UnaryTupleList;
+import org.eclipse.daanse.olap.common.SystemWideProperties;
+import org.eclipse.daanse.olap.function.core.FunctionParameterR;
+import org.eclipse.daanse.olap.query.component.ResolvedFunCallImpl;
+import org.eclipse.daanse.olap.server.ExecutionImpl;
+import org.eclipse.daanse.olap.server.LocusImpl;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+
+/**
+ * CrossJoint tests the collation order of positive and negative
+ * infinity, and {@link Double#NaN}.
+ *
+ * @author Richard M. Emberson
+ * @since Jan 14, 2007
+ */
+
+public class CrossJoinTest {
+
+ private static final String SELECT_GENDER_MEMBERS =
+ "select Gender.members on 0 from sales";
+
+ private static final String SALES_CUBE = "Sales";
+
+ private ExecutionImpl excMock = mock( ExecutionImpl.class );
+
+ static List> m3 = Arrays.asList(
+ Arrays.asList( new TestMember( "k" ), new TestMember( "l" ) ),
+ Arrays.asList( new TestMember( "m" ), new TestMember( "n" ) ) );
+
+ static List> m4 = Arrays.asList(
+ Arrays.asList( new TestMember( "U" ), new TestMember( "V" ) ),
+ Arrays.asList( new TestMember( "W" ), new TestMember( "X" ) ),
+ Arrays.asList( new TestMember( "Y" ), new TestMember( "Z" ) ) );
+
+ static final Comparator> memberComparator =
+ new Comparator<>() {
+ @Override
+ public int compare( List ma1, List ma2 ) {
+ for ( int i = 0; i < ma1.size(); i++ ) {
+ int c = ma1.get( i ).compareTo( ma2.get( i ) );
+ if ( c < 0 ) {
+ return c;
+ } else if ( c > 0 ) {
+ return c;
+ }
+ }
+ return 0;
+ }
+ };
+
+ private CrossJoinFunDef crossJoinFunDef;
+
+ @BeforeEach
+ protected void beforeEach() throws Exception {
+ crossJoinFunDef = new CrossJoinFunDef( new NullFunDef().getFunctionMetaData() );
+ }
+
+ @AfterEach
+ protected void afterEach() throws Exception {
+ SystemWideProperties.instance().populateInitial();
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // Iterable
+ ////////////////////////////////////////////////////////////////////////
+
+ @Test
+ void testListTupleListTupleIterCalc() {
+ Statement statement = mock(Statement.class);
+ Connection rolapConnection = mock(Connection.class);
+ Context context = mock(Context.class);
+ when(context.getConfigValue(ConfigConstants.CHECK_CANCEL_OR_TIMEOUT_INTERVAL, ConfigConstants.CHECK_CANCEL_OR_TIMEOUT_INTERVAL_DEFAULT_VALUE, Integer.class)).thenReturn(0);
+ when(rolapConnection.getContext()).thenReturn(context);
+ when(statement.getMondrianConnection()).thenReturn(rolapConnection);
+ when(excMock.getMondrianStatement()).thenReturn(statement);
+ CrossJoinIterCalc calc =
+ new CrossJoinIterCalc( getResolvedFunCall(), null, crossJoinFunDef.getCtag() );
+
+ doTupleTupleIterTest( calc, excMock );
+ }
+
+ private void doTupleTupleIterTest(
+ CrossJoinIterCalc calc, ExecutionImpl execution ) {
+ TupleList l4 = makeListTuple( m4 );
+ String s4 = toString( l4 );
+ String e4 = "{[U, V], [W, X], [Y, Z]}";
+ assertEquals( e4, s4 );
+
+ TupleList l3 = makeListTuple( m3 );
+ String s3 = toString( l3 );
+ String e3 = "{[k, l], [m, n]}";
+ assertEquals( e3, s3 );
+
+ String s = LocusImpl.execute(
+ execution, "CrossJoinTest", new LocusImpl.Action() {
+ @Override
+ public String execute() {
+ TupleIterable iterable = calc.makeIterable( l4, l3 );
+ return CrossJoinTest.this.toString( iterable );
+ }
+ } );
+ String e =
+ "{[U, V, k, l], [U, V, m, n], [W, X, k, l], "
+ + "[W, X, m, n], [Y, Z, k, l], [Y, Z, m, n]}";
+ assertEquals( e, s );
+ }
+
+
+ private static TupleList getGenderMembers( Result genders ) {
+ TupleList genderMembers = new UnaryTupleList();
+ for ( Position pos : genders.getAxes()[ 0 ].getPositions() ) {
+ genderMembers.add( pos );
+ }
+ return genderMembers;
+ }
+
+ private Integer crossJoinIterCalcIterate(
+ final TupleList list1, final TupleList list2,
+ final ExecutionImpl execution ) {
+ return LocusImpl.execute(
+ execution, "CrossJoinTest", new LocusImpl.Action() {
+ @Override
+ public Integer execute() {
+ TupleIterable iterable =
+ new CrossJoinIterCalc(
+ getResolvedFunCall(), null, crossJoinFunDef.getCtag() ).makeIterable( list1, list2 );
+ TupleCursor tupleCursor = iterable.tupleCursor();
+ // total count of all iterations
+ int counter = 0;
+ while ( tupleCursor.forward() ) {
+ counter++;
+ }
+ return Integer.valueOf( counter );
+ }
+ } );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // Immutable List
+ ////////////////////////////////////////////////////////////////////////
+
+ @Test
+ void testImmutableListTupleListTupleListCalc() {
+ ImmutableListCalc calc =
+ new ImmutableListCalc(
+ getResolvedFunCall(), null, crossJoinFunDef.getCtag() );
+
+ doTupleTupleListTest( calc );
+ }
+
+ protected void doTupleTupleListTest(
+ BaseListCalc calc ) {
+ TupleList l4 = makeListTuple( m4 );
+ String s4 = toString( l4 );
+ String e4 = "{[U, V], [W, X], [Y, Z]}";
+ assertEquals( e4, s4 );
+
+ TupleList l3 = makeListTuple( m3 );
+ String s3 = toString( l3 );
+ String e3 = "{[k, l], [m, n]}";
+ assertEquals( e3, s3 );
+
+ TupleList list = calc.makeList( l4, l3 );
+ String s = toString( list );
+ String e =
+ "{[U, V, k, l], [U, V, m, n], [W, X, k, l], "
+ + "[W, X, m, n], [Y, Z, k, l], [Y, Z, m, n]}";
+ assertEquals( e, s );
+
+ TupleList subList = list.subList( 0, 6 );
+ s = toString( subList );
+ assertEquals( 6, subList.size() );
+ assertEquals( e, s );
+
+ subList = subList.subList( 0, 6 );
+ s = toString( subList );
+ assertEquals( 6, subList.size() );
+ assertEquals( e, s );
+
+ subList = subList.subList( 1, 5 );
+ s = toString( subList );
+ e = "{[U, V, m, n], [W, X, k, l], [W, X, m, n], [Y, Z, k, l]}";
+ assertEquals( 4, subList.size() );
+ assertEquals( e, s );
+
+ subList = subList.subList( 2, 4 );
+ s = toString( subList );
+ e = "{[W, X, m, n], [Y, Z, k, l]}";
+ assertEquals( 2, subList.size() );
+ assertEquals( e, s );
+
+ subList = subList.subList( 1, 2 );
+ s = toString( subList );
+ e = "{[Y, Z, k, l]}";
+ assertEquals( 1, subList.size() );
+ assertEquals( e, s );
+
+ subList = list.subList( 1, 4 );
+ s = toString( subList );
+ e = "{[U, V, m, n], [W, X, k, l], [W, X, m, n]}";
+ assertEquals( 3, subList.size() );
+ assertEquals( e, s );
+
+ subList = list.subList( 2, 4 );
+ s = toString( subList );
+ e = "{[W, X, k, l], [W, X, m, n]}";
+ assertEquals( 2, subList.size() );
+ assertEquals( e, s );
+
+ subList = list.subList( 2, 3 );
+ s = toString( subList );
+ e = "{[W, X, k, l]}";
+ assertEquals( 1, subList.size() );
+ assertEquals( e, s );
+
+ subList = list.subList( 4, 4 );
+ s = toString( subList );
+ e = "{}";
+ assertEquals( 0, subList.size() );
+ assertEquals( e, s );
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ // Mutable List
+ ////////////////////////////////////////////////////////////////////////
+ @Test
+ void testMutableListTupleListTupleListCalc() {
+ MutableListCalc calc =
+ new MutableListCalc(
+ getResolvedFunCall(), null, crossJoinFunDef.getCtag() );
+
+ doMTupleTupleListTest( calc );
+ }
+
+ protected void doMTupleTupleListTest(
+ BaseListCalc calc ) {
+ TupleList l1 = makeListTuple( m3 );
+ String s1 = toString( l1 );
+ String e1 = "{[k, l], [m, n]}";
+ assertEquals( e1, s1 );
+
+ TupleList l2 = makeListTuple( m4 );
+ String s2 = toString( l2 );
+ String e2 = "{[U, V], [W, X], [Y, Z]}";
+ assertEquals( e2, s2 );
+
+ TupleList list = calc.makeList( l1, l2 );
+ String s = toString( list );
+ String e = "{[k, l, U, V], [k, l, W, X], [k, l, Y, Z], "
+ + "[m, n, U, V], [m, n, W, X], [m, n, Y, Z]}";
+ assertEquals( e, s );
+
+ if ( false ) {
+ // Cannot apply Collections.reverse to TupleList
+ // because TupleList.set always returns null.
+ // (This is a violation of the List contract, but it is inefficient
+ // to construct a list to return.)
+ Collections.reverse( list );
+ s = toString( list );
+ e = "{[m, n, Y, Z], [m, n, W, X], [m, n, U, V], "
+ + "[k, l, Y, Z], [k, l, W, X], [k, l, U, V]}";
+ assertEquals( e, s );
+ }
+
+ // sort
+ Collections.sort( list, memberComparator );
+ s = toString( list );
+ e = "{[k, l, U, V], [k, l, W, X], [k, l, Y, Z], "
+ + "[m, n, U, V], [m, n, W, X], [m, n, Y, Z]}";
+ assertEquals( e, s );
+
+ List members = list.remove( 1 );
+ s = toString( list );
+ e = "{[k, l, U, V], [k, l, Y, Z], [m, n, U, V], "
+ + "[m, n, W, X], [m, n, Y, Z]}";
+ assertEquals( e, s );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // Helper methods
+ ////////////////////////////////////////////////////////////////////////
+ protected String toString( TupleIterable l ) {
+ StringBuffer buf = new StringBuffer( 100 );
+ buf.append( '{' );
+ int j = 0;
+ for ( List o : l ) {
+ if ( j++ > 0 ) {
+ buf.append( ", " );
+ }
+ buf.append( o );
+ }
+ buf.append( '}' );
+ return buf.toString();
+ }
+
+ protected TupleList makeListTuple( List> ms ) {
+ final TupleList list = new ArrayTupleList( ms.get( 0 ).size() );
+ for ( List m : ms ) {
+ list.add( m );
+ }
+ return list;
+ }
+
+ protected ResolvedFunCallImpl getResolvedFunCall() {
+ FunctionDefinition funDef = new TestFunDef();
+ Expression[] args = new Expression[ 0 ];
+ Type returnType =
+ new SetType(
+ new TupleType(
+ new Type[] {
+ new MemberType( null, null, null, null ),
+ new MemberType( null, null, null, null ) } ) );
+ return new ResolvedFunCallImpl( funDef, args, returnType );
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ // Helper classes
+ ////////////////////////////////////////////////////////////////////////
+ public static class TestFunDef implements FunctionDefinition {
+ TestFunDef() {
+ }
+
+
+ @Override
+ public Expression createCall( Validator validator, Expression[] args ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getSignature() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void unparse( Expression[] args, PrintWriter pw ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Calc compileCall( ResolvedFunCall call, ExpressionCompiler compiler ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public FunctionMetaData getFunctionMetaData() {
+ return new FunctionMetaData() {
+
+ @Override
+ public OperationAtom operationAtom() {
+
+ return new FunctionOperationAtom("SomeName");
+ }
+
+ @Override
+ public String description() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DataType returnCategory() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DataType[] parameterDataTypes() {
+ throw new UnsupportedOperationException();
+ }
+
+
+ @Override
+ public FunctionParameterR[] parameters() {
+ throw new UnsupportedOperationException();
+ }
+
+ };
+ }
+ }
+
+ public static class NullFunDef implements FunctionDefinition {
+ public NullFunDef() {
+ }
+
+
+
+ @Override
+ public Expression createCall( Validator validator, Expression[] args ) {
+ return null;
+ }
+
+ @Override
+ public String getSignature() {
+ return "";
+ }
+
+ @Override
+ public void unparse( Expression[] args, PrintWriter pw ) {
+ //
+ }
+
+ @Override
+ public Calc> compileCall( ResolvedFunCall call, ExpressionCompiler compiler ) {
+ return null;
+ }
+
+ @Override
+ public FunctionMetaData getFunctionMetaData() {
+ return new FunctionMetaData() {
+
+ @Override
+ public OperationAtom operationAtom() {
+ return new FunctionOperationAtom("");
+ }
+
+ @Override
+ public String description() {
+ return "";
+ }
+
+ @Override
+ public DataType returnCategory() {
+ return DataType.UNKNOWN;
+ }
+
+ @Override
+ public DataType[] parameterDataTypes() {
+ return new DataType[ 0 ];
+ }
+
+ @Override
+ public FunctionParameter[] parameters() {
+ return new FunctionParameter[0];
+ }
+ };
+ }
+ }
+}
diff --git a/common/src/test/java/org/eclipse/daanse/olap/function/def/crossjoin/TestMember.java b/common/src/test/java/org/eclipse/daanse/olap/function/def/crossjoin/TestMember.java
new file mode 100644
index 00000000..9fff7269
--- /dev/null
+++ b/common/src/test/java/org/eclipse/daanse/olap/function/def/crossjoin/TestMember.java
@@ -0,0 +1,349 @@
+/*
+ * This software is subject to the terms of the Eclipse Public License v1.0
+ * Agreement, available at the following URL:
+ * http://www.eclipse.org/legal/epl-v10.html.
+ * You must accept the terms of that agreement to use this software.
+ *
+ * Copyright (c) 2002-2020 Hitachi Vantara.. All rights reserved.
+ *
+ * ---- All changes after Fork in 2023 ------------------------
+ *
+ * Project: Eclipse daanse
+ *
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors after Fork in 2023:
+ * SmartCity Jena - initial
+ */
+package org.eclipse.daanse.olap.function.def.crossjoin;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.eclipse.daanse.olap.api.MatchType;
+import org.eclipse.daanse.olap.api.CatalogReader;
+import org.eclipse.daanse.olap.api.Segment;
+import org.eclipse.daanse.olap.api.element.Dimension;
+import org.eclipse.daanse.olap.api.element.DimensionType;
+import org.eclipse.daanse.olap.api.element.Hierarchy;
+import org.eclipse.daanse.olap.api.element.Level;
+import org.eclipse.daanse.olap.api.element.Member;
+import org.eclipse.daanse.olap.api.element.MetaData;
+import org.eclipse.daanse.olap.api.element.OlapElement;
+import org.eclipse.daanse.olap.api.element.Catalog;
+import org.eclipse.daanse.olap.api.element.Cube;
+import org.eclipse.daanse.olap.api.query.component.Expression;
+import org.eclipse.daanse.olap.element.AbstractProperty;
+
+/**
+ * Mock implementation of {@link Member} for testing.
+ *
+ * @author Richard M. Emberson
+ */
+public class TestMember implements Member {
+ private final String identifer;
+
+ public TestMember( String identifer ) {
+ this.identifer = identifer;
+ }
+
+ @Override
+public String toString() {
+ return identifer;
+ }
+
+ @Override
+public int compareTo( Object o ) {
+ TestMember other = (TestMember) o;
+ return this.identifer.compareTo( other.identifer );
+ }
+
+ @Override
+public Member getParentMember() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public Level getLevel() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public Hierarchy getHierarchy() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public String getParentUniqueName() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public MemberType getMemberType() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public boolean isParentChildLeaf() {
+ return false;
+ }
+
+ @Override
+public boolean isParentChildPhysicalMember() {
+ return false;
+ }
+
+ @Override
+public void setName( String name ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public boolean isAll() {
+ return false;
+ }
+
+ @Override
+public boolean isMeasure() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public boolean isNull() {
+ return true;
+ }
+
+ @Override
+public boolean isChildOrEqualTo( Member member ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public boolean isCalculated() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public boolean isEvaluated() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public int getSolveOrder() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public Expression getExpression() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public List getAncestorMembers() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public boolean isCalculatedInQuery() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public Object getPropertyValue( String propertyName ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public Object getPropertyValue( String propertyName, boolean matchCase ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public String getPropertyFormattedValue( String propertyName ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public void setProperty( String name, Object value ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public AbstractProperty[] getProperties() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public int getOrdinal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public Comparable getOrderKey() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public boolean isHidden() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public int getDepth() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public Member getDataMember() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public boolean isOnSameHierarchyChain( Member otherMember ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public String getUniqueName() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public String getName() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public String getDescription() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public OlapElement lookupChild(
+ CatalogReader schemaReader, Segment s, MatchType matchType ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public String getQualifiedName() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public String getCaption() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public String getLocalized( LocalizedProperty prop, Locale locale ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public boolean isVisible() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+public Dimension getDimension() {
+ return new MockDimension();
+ }
+
+
+ @Override
+ public MetaData getMetaData() {
+ throw new UnsupportedOperationException();
+
+ }
+
+ private static class MockDimension implements Dimension {
+ @Override
+ public List extends Hierarchy> getHierarchies() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isMeasures() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public DimensionType getDimensionType() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Catalog getCatalog() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getUniqueName() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getName() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getDescription() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isVisible() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public OlapElement lookupChild(
+ CatalogReader schemaReader,
+ Segment s, MatchType matchType ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getQualifiedName() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getCaption() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getLocalized( LocalizedProperty prop, Locale locale ) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Hierarchy getHierarchy() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Dimension getDimension() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public MetaData getMetaData() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Cube getCube() {
+ return null;
+ }
+
+ }
+
+}
diff --git a/common/src/test/java/org/eclipse/daanse/olap/function/def/union/UnionFunDefTest.java b/common/src/test/java/org/eclipse/daanse/olap/function/def/union/UnionFunDefTest.java
new file mode 100644
index 00000000..881f02d4
--- /dev/null
+++ b/common/src/test/java/org/eclipse/daanse/olap/function/def/union/UnionFunDefTest.java
@@ -0,0 +1,220 @@
+/*
+ * This software is subject to the terms of the Eclipse Public License v1.0
+ * Agreement, available at the following URL:
+ * http://www.eclipse.org/legal/epl-v10.html.
+ * You must accept the terms of that agreement to use this software.
+ *
+ * Copyright (c) 2002-2017 Hitachi Vantara. All rights reserved.
+ *
+ * ---- All changes after Fork in 2023 ------------------------
+ *
+ * Project: Eclipse daanse
+ *
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors after Fork in 2023:
+ * SmartCity Jena - initial
+ */
+
+package org.eclipse.daanse.olap.function.def.union;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mock;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.daanse.olap.api.calc.Calc;
+import org.eclipse.daanse.olap.api.calc.todo.TupleList;
+import org.eclipse.daanse.olap.api.element.Member;
+import org.eclipse.daanse.olap.api.element.MetaData;
+import org.eclipse.daanse.olap.api.element.Property;
+import org.eclipse.daanse.olap.api.function.FunctionDefinition;
+import org.eclipse.daanse.olap.api.query.component.Expression;
+import org.eclipse.daanse.olap.api.type.SetType;
+import org.eclipse.daanse.olap.calc.base.type.tuplebase.ArrayTupleList;
+import org.eclipse.daanse.olap.calc.base.type.tuplebase.UnaryTupleList;
+import org.eclipse.daanse.olap.element.MemberBase;
+import org.eclipse.daanse.olap.function.def.crossjoin.CrossJoinFunDef;
+import org.eclipse.daanse.olap.function.def.crossjoin.CrossJoinTest;
+import org.eclipse.daanse.olap.function.def.crossjoin.ImmutableListCalc;
+import org.eclipse.daanse.olap.query.component.ResolvedFunCallImpl;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+import org.slf4j.Logger;
+
+/**
+ * Tests for UnionFunDef
+ *
+ * @author Yury Bakhmutski
+ */
+class UnionFunDefTest {
+
+ /**
+ * Test for MONDRIAN-2250 issue.
+ * Tests that the result is independent on the hashCode.
+ * For this purpose MemberForTest with rewritten hashCode is used.
+ *
+ * Tuples are gotten from customer attachments.
+ */
+ @Test
+ void testMondrian2250() {
+ Member[] dates = new Member[4];
+ for (int i = 25; i < 29; i++) {
+ dates[i - 25] =
+ new MemberForTest("[Consumption Date.Calendar].[2014-07-" + i + "]");
+ }
+ List list = Arrays.asList(dates);
+ UnaryTupleList unaryTupleList = new UnaryTupleList(list);
+
+ Member consumptionMethod =
+ new MemberForTest("[Consumption Method].[PVR]");
+ Member measuresAverageTimeshift =
+ new MemberForTest("[Measures].[Average Timeshift]");
+ String[] hours = { "00", "14", "15", "16", "23" };
+ Member[] times = new Member[5];
+ for (int i = 0; i < hours.length; i++) {
+ times[i] =
+ new MemberForTest("[Consumption Time.Time].[" + hours[i] + ":00]");
+ }
+
+ int arity = 3;
+ ArrayTupleList arrayTupleList = new ArrayTupleList(arity);
+ for (Member time : times) {
+ List currentList = new ArrayList(3);
+ currentList.add(consumptionMethod);
+ currentList.add(measuresAverageTimeshift);
+ currentList.add(time);
+ arrayTupleList.add(currentList);
+ }
+
+ CrossJoinFunDef crossJoinFunDef =
+ new CrossJoinFunDef(new CrossJoinTest.NullFunDef().getFunctionMetaData());
+ Expression[] expMock = new Expression[1];
+ expMock[0] = mock(Expression.class);
+ ResolvedFunCallImpl resolvedFunCall =
+ new ResolvedFunCallImpl(mock(FunctionDefinition.class), expMock, mock(SetType.class));
+ Calc[] calcs = new Calc[1];
+ calcs[0] = Mockito.mock(Calc.class);
+ ImmutableListCalc immutableListCalc =
+ new ImmutableListCalc(
+ resolvedFunCall, calcs, crossJoinFunDef.getCtag());
+
+ TupleList listForUnion1 =
+ immutableListCalc.makeList(unaryTupleList, arrayTupleList);
+
+ List list2 = Arrays.asList(dates);
+ UnaryTupleList unaryTupleList2 = new UnaryTupleList(list2);
+
+ Member measuresTotalViewingTime =
+ new MemberForTest("[Measures].[Total Viewing Time]");
+ ArrayTupleList arrayTupleList2 = new ArrayTupleList(arity);
+ for (Member time : times) {
+ List currentList = new ArrayList(3);
+ currentList.add(consumptionMethod);
+ currentList.add(measuresTotalViewingTime);
+ currentList.add(time);
+ arrayTupleList2.add(currentList);
+ }
+
+ TupleList listForUnion2 =
+ immutableListCalc.makeList(unaryTupleList2, arrayTupleList2);
+
+ UnionCalc unionFunDefMock = mock(UnionCalc.class);
+ doCallRealMethod().when(unionFunDefMock).union(
+ any(), any(), anyBoolean());
+
+ TupleList tupleList =
+ unionFunDefMock.union(listForUnion1, listForUnion2, false);
+ System.out.println(tupleList);
+ assertEquals(40, tupleList.size());
+ }
+
+
+ private class MemberForTest extends MemberBase {
+ private String identifer;
+
+ public MemberForTest(String identifer) {
+ this.identifer = identifer;
+ }
+
+ @Override
+ public String getUniqueName() {
+ return identifer;
+ }
+
+ @Override
+ public int hashCode() {
+ return 31;
+ }
+
+ @Override
+ public void setName(String name) {
+ }
+
+ @Override
+ public boolean isCalculatedInQuery() {
+ return false;
+ }
+
+ @Override
+ public Object getPropertyValue(String propertyName) {
+ return null;
+ }
+
+ @Override
+ public Object getPropertyValue(String propertyName, boolean matchCase) {
+ return null;
+ }
+
+ @Override
+ public void setProperty(String name, Object value) {
+
+ }
+
+ @Override
+ public Property[] getProperties() {
+ return null;
+ }
+
+ @Override
+ public int getDepth() {
+ return 0;
+ }
+
+ @Override
+ public int compareTo(Object arg0) {
+ return 0;
+ }
+
+ @Override
+ public MetaData getMetaData() {
+ return null;
+ }
+
+ @Override
+ public String getName() {
+ return null;
+ }
+
+ @Override
+ public Object getCaptionValue() {
+ return null;
+ }
+
+ @Override
+ protected Logger getLogger() {
+ return null;
+ }
+ }
+}
diff --git a/common/src/test/java/org/eclipse/daanse/olap/util/I18nTest.java b/common/src/test/java/org/eclipse/daanse/olap/util/I18nTest.java
new file mode 100644
index 00000000..2379d4ee
--- /dev/null
+++ b/common/src/test/java/org/eclipse/daanse/olap/util/I18nTest.java
@@ -0,0 +1,81 @@
+/*
+ * This software is subject to the terms of the Eclipse Public License v1.0
+ * Agreement, available at the following URL:
+ * http://www.eclipse.org/legal/epl-v10.html.
+ * You must accept the terms of that agreement to use this software.
+ *
+ * Copyright (c) 2002-2017 Hitachi Vantara.. All rights reserved.
+ *
+ * ---- All changes after Fork in 2023 ------------------------
+ *
+ * Project: Eclipse daanse
+ *
+ * Copyright (c) 2023 Contributors to the Eclipse Foundation.
+ *
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors after Fork in 2023:
+ * SmartCity Jena - initial
+ */
+package org.eclipse.daanse.olap.util;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import java.util.Calendar;
+import java.util.Locale;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test suite for internalization and localization.
+ *
+ * @see mondrian.util.FormatTest
+ *
+ * @author jhyde
+ * @since September 22, 2005
+ */
+class I18nTest {
+ public static final char Euro = '\u20AC';
+ public static final char Nbsp = ' ';
+ public static final char EA = '\u00e9'; // e acute
+ public static final char UC = '\u00FB'; // u circumflex
+
+ @Test
+ void testFormat() {
+ // Make sure Util is loaded, so that the LocaleFormatFactory gets
+ // registered.
+// discard(Util.NL);
+
+ Locale spanish = new Locale("es", "ES");
+ Locale german = new Locale("de", "DE");
+
+ // Thousands and decimal separators are different in Spain
+ Format numFormat = new Format("#,000.00", spanish);
+ assertEquals(numFormat.format(new Double(123456.789)), "123.456,79");
+
+ // Currency too
+ Format currencyFormat = new Format("Currency", spanish);
+ assertEquals(
+ "1.234.567,79 €",
+ currencyFormat.format(new Double(1234567.789)));
+
+ // Dates
+ Format dateFormat = new Format("Medium Date", spanish);
+ Calendar calendar = Calendar.getInstance();
+ calendar.set(Calendar.YEAR, 2005);
+ calendar.set(Calendar.MONTH, 0); // January, 0-based
+ calendar.set(Calendar.DATE, 22);
+ java.util.Date date = calendar.getTime();
+ assertEquals("22-ene-05", dateFormat.format(date));
+
+ // Dates in German
+ dateFormat = new Format("Long Date", german);
+ assertEquals("Samstag, Januar 22, 2005", dateFormat.format(date));
+ }
+
+
+}
\ No newline at end of file