Skip to content

Commit

Permalink
Merge pull request pentaho#657 from YuryBY/MONDRIAN-2250-2
Browse files Browse the repository at this point in the history
Mondrian [2250] - additional fix
  • Loading branch information
mkambol committed Feb 24, 2016
2 parents 93f8ccc + b9f4c0d commit 671c9df
Show file tree
Hide file tree
Showing 2 changed files with 231 additions and 83 deletions.
2 changes: 1 addition & 1 deletion src/main/mondrian/olap/fun/CrossJoinFunDef.java
Original file line number Diff line number Diff line change
Expand Up @@ -405,7 +405,7 @@ protected TupleList makeList(final TupleList l1, final TupleList l2) {
@Override
public List<Member> get(int index) {
cartesianProductList.getIntoArray(index, members);
return Util.flatList(members);
return Util.flatListCopy(members);
}

@Override
Expand Down
312 changes: 230 additions & 82 deletions testsrc/main/mondrian/olap/fun/UnionFunDefTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,110 +4,258 @@
// http://www.eclipse.org/legal/epl-v10.html.
// You must accept the terms of that agreement to use this software.
//
// Copyright (c) 2002-2015 Pentaho Corporation. All rights reserved.
// Copyright (c) 2002-2016 Pentaho Corporation. All rights reserved.
*/
package mondrian.olap.fun;

import mondrian.calc.Calc;
import mondrian.calc.TupleList;
import mondrian.calc.impl.DelegatingTupleList;
import mondrian.calc.impl.ArrayTupleList;
import mondrian.calc.impl.UnaryTupleList;
import mondrian.mdx.ResolvedFunCall;
import mondrian.olap.Exp;
import mondrian.olap.FunDef;
import mondrian.olap.Member;
import mondrian.olap.type.SetType;
import mondrian.rolap.RolapMemberBase;

import junit.framework.TestCase;
import mondrian.test.FoodMartTestCase;

import org.mockito.Mockito;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;


import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.mock;

/**
* Tests for UnionFunDef
*
* @author Yury Bakhmutski
*/
public class UnionFunDefTest extends TestCase {

/**
* Test for MONDRIAN-2250 issue.
* Tuples are gotten from customer attachments.
*/
public void testUnion() {
DelegatingTupleList delegatingTupleList1 = new DelegatingTupleList(
4, new ArrayList<List<Member>>());
String totalViewingTime = "[Measures].[Total Viewing Time]";
fillDelegatingTupleLists(delegatingTupleList1, totalViewingTime);

DelegatingTupleList delegatingTupleList2 = new DelegatingTupleList(
4, new ArrayList<List<Member>>());
String averageTimeshift = "[Measures].[Average Timeshift]";
fillDelegatingTupleLists(delegatingTupleList2, averageTimeshift);

UnionFunDef unionFunDefMock = Mockito.mock(UnionFunDef.class);
doCallRealMethod().when(unionFunDefMock).union(
any(TupleList.class), any(TupleList.class), anyBoolean());

TupleList tupleList = unionFunDefMock.union(
delegatingTupleList1, delegatingTupleList2, false);
assertEquals(40, tupleList.size());
}

private void fillDelegatingTupleLists(
DelegatingTupleList delegatingTupleList, String measure)
{
String consumptionMethod = "[Consumption Method].[PVR]";
String[] dates = {"[2014-07-25]", "[2014-07-26]", "[2014-07-27]",
"[2014-07-28]"};
String consumptionDateCalendar = "[Consumption Date.Calendar]";
String[] time = {"[00:00]", "[14:00]", "[15:00]", "[16:00]",
"[23:00]"};
String consumptionTimeTime = "[Consumption Time.Time]";
for (int i = 0; i < dates.length; i++) {
List<Member> tuple = new ArrayList<Member>();
tuple.add(new MemberForTest(
consumptionDateCalendar + "." + dates[i]));
for (int j = 0; j < time.length; j++) {
tuple.add(new MemberForTest(consumptionMethod));
tuple.add(new MemberForTest(measure));
tuple.add(new MemberForTest(
consumptionTimeTime + "." + time[j]));
Member[] array = tuple.toArray(new Member[tuple.size()]);
delegatingTupleList.addTuple(array);
tuple.remove(3);
tuple.remove(2);
tuple.remove(1);
}
}
}

private class MemberForTest extends RolapMemberBase {
private String identifer;

public MemberForTest(String identifer) {
this.identifer = identifer;
}

@Override
public String getUniqueName() {
return identifer;
}

@Override
public int hashCode() {
return super.hashCode();
}

@Override
public boolean equals(Object o) {
throw new AssertionError(
"HashCode realization supposes equals() should not be called"
+ " with such tuples!");
}
};
public class UnionFunDefTest extends FoodMartTestCase {

/**
* 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.
*/
public 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<Member> 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<Member> currentList = new ArrayList(3);
currentList.add(consumptionMethod);
currentList.add(measuresAverageTimeshift);
currentList.add(time);
arrayTupleList.add(currentList);
}

CrossJoinFunDef crossJoinFunDef =
new CrossJoinFunDef(new CrossJoinTest.NullFunDef());
Exp[] expMock = new Exp[1];
expMock[0] = mock(Exp.class);
ResolvedFunCall resolvedFunCall =
new ResolvedFunCall(mock(FunDef.class), expMock, mock(SetType.class));
Calc[] calcs = new Calc[1];
calcs[0] = Mockito.mock(Calc.class);
CrossJoinFunDef.ImmutableListCalc immutableListCalc =
crossJoinFunDef.new ImmutableListCalc(
resolvedFunCall, calcs);

TupleList listForUnion1 =
immutableListCalc.makeList(unaryTupleList, arrayTupleList);

List<Member> 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<Member> currentList = new ArrayList(3);
currentList.add(consumptionMethod);
currentList.add(measuresTotalViewingTime);
currentList.add(time);
arrayTupleList2.add(currentList);
}

TupleList listForUnion2 =
immutableListCalc.makeList(unaryTupleList2, arrayTupleList2);

UnionFunDef unionFunDefMock = Mockito.mock(UnionFunDef.class);
doCallRealMethod().when(unionFunDefMock).union(
any(TupleList.class), any(TupleList.class), anyBoolean());

TupleList tupleList =
unionFunDefMock.union(listForUnion1, listForUnion2, false);
System.out.println(tupleList);
assertEquals(40, tupleList.size());
}

public void testArity4TupleUnion() {
String tupleSet =
"CrossJoin( [Customers].[USA].Children,"
+ " CrossJoin( Time.[1997].children, { (Gender.F, [Marital Status].M ) }) ) ";
String expected =
"{[Customers].[USA].[CA], [Time].[1997].[Q1], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[USA].[CA], [Time].[1997].[Q2], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[USA].[CA], [Time].[1997].[Q3], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[USA].[CA], [Time].[1997].[Q4], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[USA].[OR], [Time].[1997].[Q1], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[USA].[OR], [Time].[1997].[Q2], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[USA].[OR], [Time].[1997].[Q3], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[USA].[OR], [Time].[1997].[Q4], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[USA].[WA], [Time].[1997].[Q1], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[USA].[WA], [Time].[1997].[Q2], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[USA].[WA], [Time].[1997].[Q3], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[USA].[WA], [Time].[1997].[Q4], [Gender].[F], [Marital Status].[M]}";

assertAxisReturns("Union( " + tupleSet + ", " + tupleSet + ")", expected);
}

public void testArity5TupleUnion() {
String tupleSet = "CrossJoin( [Customers].[Canada].Children, "
+ "CrossJoin( [Time].[1997].lastChild, "
+ "CrossJoin ([Education Level].children,{ (Gender.F, [Marital Status].M ) })) )";
String expected =
"{[Customers].[Canada].[BC], [Time].[1997].[Q4], [Education Level].[Bachelors Degree], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q4], [Education Level].[Graduate Degree], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q4], [Education Level].[High School Degree], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q4], [Education Level].[Partial College], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q4], [Education Level].[Partial High School], [Gender].[F], [Marital Status].[M]}";

assertAxisReturns(tupleSet, expected);

assertAxisReturns("Union( " + tupleSet + ", " + tupleSet + ")", expected);
}

public void testArity5TupleUnionAll() {
String tupleSet = "CrossJoin( [Customers].[Canada].Children, "
+ "CrossJoin( [Time].[1998].firstChild, "
+ "CrossJoin ([Education Level].members,{ (Gender.F, [Marital Status].M ) })) )";
String expected =
"{[Customers].[Canada].[BC], [Time].[1998].[Q1], [Education Level].[All Education Levels], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1998].[Q1], [Education Level].[Bachelors Degree], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1998].[Q1], [Education Level].[Graduate Degree], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1998].[Q1], [Education Level].[High School Degree], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1998].[Q1], [Education Level].[Partial College], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1998].[Q1], [Education Level].[Partial High School], [Gender].[F], [Marital Status].[M]}";

assertAxisReturns(tupleSet, expected);

assertAxisReturns(
"Union( " + tupleSet + ", " + tupleSet + ", " + "ALL" + ")",
expected + "\n" + expected);
}

public void testArity6TupleUnion() {
String tupleSet1 = "CrossJoin( [Customers].[Canada].Children, "
+ "CrossJoin( [Time].[1997].firstChild, "
+ "CrossJoin ([Education Level].lastChild,"
+ "CrossJoin ([Yearly Income].lastChild,"
+ "{ (Gender.F, [Marital Status].M ) })) ) )";
String tupleSet2 = "CrossJoin( [Customers].[Canada].Children, "
+ "CrossJoin( [Time].[1997].firstChild, "
+ "CrossJoin ([Education Level].lastChild,"
+ "CrossJoin ([Yearly Income].children,"
+ "{ (Gender.F, [Marital Status].M ) })) ) )";

String tupleSet1Expected =
"{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$90K - $110K], [Gender].[F], [Marital Status].[M]}";
assertAxisReturns(tupleSet1, tupleSet1Expected);

String tupleSet2Expected =
"{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$10K - $30K], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$110K - $130K], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$130K - $150K], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$150K +], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$30K - $50K], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$50K - $70K], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$70K - $90K], [Gender].[F], [Marital Status].[M]}\n"
+ tupleSet1Expected;

assertAxisReturns(tupleSet2, tupleSet2Expected);

assertAxisReturns(
"Union( " + tupleSet2 + ", " + tupleSet1 + ")",
tupleSet2Expected);
}

public void testArity6TupleUnionAll() {
String tupleSet1 = "CrossJoin( [Customers].[Canada].Children, "
+ "CrossJoin( [Time].[1997].firstChild, "
+ "CrossJoin ([Education Level].lastChild,"
+ "CrossJoin ([Yearly Income].lastChild,"
+ "{ (Gender.F, [Marital Status].M ) })) ) )";
String tupleSet2 = "CrossJoin( [Customers].[Canada].Children, "
+ "CrossJoin( [Time].[1997].firstChild, "
+ "CrossJoin ([Education Level].lastChild,"
+ "CrossJoin ([Yearly Income].children,"
+ "{ (Gender.F, [Marital Status].M ) })) ) )";

String tupleSet1Expected =
"{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$90K - $110K], [Gender].[F], [Marital Status].[M]}";
assertAxisReturns(tupleSet1, tupleSet1Expected);

String tupleSet2Expected =
"{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$10K - $30K], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$110K - $130K], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$130K - $150K], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$150K +], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$30K - $50K], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$50K - $70K], [Gender].[F], [Marital Status].[M]}\n"
+ "{[Customers].[Canada].[BC], [Time].[1997].[Q1], [Education Level].[Partial High School], [Yearly Income].[$70K - $90K], [Gender].[F], [Marital Status].[M]}\n"
+ tupleSet1Expected;
assertAxisReturns(tupleSet2, tupleSet2Expected);

assertAxisReturns(
"Union( " + tupleSet1 + ", " + tupleSet2 + ", " + "ALL" + ")",
tupleSet1Expected + "\n" + tupleSet2Expected);
}

private class MemberForTest extends RolapMemberBase {
private String identifer;

public MemberForTest(String identifer) {
this.identifer = identifer;
}

@Override
public String getUniqueName() {
return identifer;
}

@Override
public int hashCode() {
return 31;
}
}
}

// End UnionFunDefTest.java

0 comments on commit 671c9df

Please sign in to comment.