Skip to content

Commit

Permalink
CollectionInverseVariable: tests + docs
Browse files Browse the repository at this point in the history
  • Loading branch information
ge0ffrey committed Mar 31, 2015
1 parent d1996cf commit 05fcab9
Show file tree
Hide file tree
Showing 11 changed files with 717 additions and 130 deletions.
Expand Up @@ -109,16 +109,26 @@ public void linkShadowSources(DescriptorPolicy descriptorPolicy) {
+ sourceEntityDescriptor.getEntityClass() + ").\n"
+ entityDescriptor.buildInvalidVariableNameExceptionMessage(sourceVariableName));
}
boolean chained = (sourceVariableDescriptor instanceof GenuineVariableDescriptor) &&
((GenuineVariableDescriptor) sourceVariableDescriptor).isChained();
if (singleton) {
if (!(sourceVariableDescriptor instanceof GenuineVariableDescriptor) ||
!((GenuineVariableDescriptor) sourceVariableDescriptor).isChained()) {
if (!chained) {
throw new IllegalArgumentException("The entityClass (" + entityDescriptor.getEntityClass()
+ ") has a " + InverseRelationShadowVariable.class.getSimpleName()
+ " annotated property (" + variablePropertyAccessor.getName()
+ ") which does not return a " + Collection.class.getSimpleName()
+ " with sourceVariableName (" + sourceVariableName
+ ") which is not chained. Only a chained variable supports a singleton inverse.");
}
} else {
if (chained) {
throw new IllegalArgumentException("The entityClass (" + entityDescriptor.getEntityClass()
+ ") has a " + InverseRelationShadowVariable.class.getSimpleName()
+ " annotated property (" + variablePropertyAccessor.getName()
+ ") which does returns a " + Collection.class.getSimpleName()
+ " with sourceVariableName (" + sourceVariableName
+ ") which is chained. A chained variable supports only a singleton inverse.");
}
}
sourceVariableDescriptor.registerShadowVariableDescriptor(this);
}
Expand Down
@@ -0,0 +1,78 @@
/*
* Copyright 2015 JBoss Inc
*
* Licensed 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.optaplanner.core.impl.domain.variable.inverserelation;

import java.util.Arrays;
import java.util.Collection;

import org.junit.Test;
import org.mockito.InOrder;
import org.optaplanner.core.impl.domain.entity.descriptor.EntityDescriptor;
import org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor;
import org.optaplanner.core.impl.domain.variable.descriptor.GenuineVariableDescriptor;
import org.optaplanner.core.impl.domain.variable.descriptor.ShadowVariableDescriptor;
import org.optaplanner.core.impl.score.director.ScoreDirector;
import org.optaplanner.core.impl.testdata.domain.chained.rich.TestdataRichChainedAnchor;
import org.optaplanner.core.impl.testdata.domain.chained.rich.TestdataRichChainedEntity;
import org.optaplanner.core.impl.testdata.domain.chained.rich.TestdataRichChainedSolution;
import org.optaplanner.core.impl.testdata.domain.shadow.inverserelation.TestdataInverseRelationEntity;
import org.optaplanner.core.impl.testdata.domain.shadow.inverserelation.TestdataInverseRelationSolution;
import org.optaplanner.core.impl.testdata.domain.shadow.inverserelation.TestdataInverseRelationValue;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.optaplanner.core.impl.testdata.util.PlannerAssert.assertCollectionContainsExactly;

public class CollectionInverseVariableListenerTest {

@Test
public void normal() {
ScoreDirector scoreDirector = mock(ScoreDirector.class);
SolutionDescriptor solutionDescriptor = TestdataInverseRelationSolution.buildSolutionDescriptor();
EntityDescriptor entityDescriptor = solutionDescriptor.findEntityDescriptorOrFail(TestdataInverseRelationEntity.class);
EntityDescriptor shadowEntityDescriptor = solutionDescriptor.findEntityDescriptorOrFail(TestdataInverseRelationValue.class);
ShadowVariableDescriptor entitiesVariableDescriptor = shadowEntityDescriptor.getShadowVariableDescriptor("entities");
CollectionInverseVariableListener variableListener = new CollectionInverseVariableListener(
(InverseRelationShadowVariableDescriptor) entitiesVariableDescriptor,
entityDescriptor.getGenuineVariableDescriptor("value"));

TestdataInverseRelationValue val1 = new TestdataInverseRelationValue("1");
TestdataInverseRelationValue val2 = new TestdataInverseRelationValue("2");
TestdataInverseRelationValue val3 = new TestdataInverseRelationValue("3");
TestdataInverseRelationEntity a = new TestdataInverseRelationEntity("a", val1);
TestdataInverseRelationEntity b = new TestdataInverseRelationEntity("b", val1);
TestdataInverseRelationEntity c = new TestdataInverseRelationEntity("c", val3);
TestdataInverseRelationEntity d = new TestdataInverseRelationEntity("d", val3);

TestdataInverseRelationSolution solution = new TestdataInverseRelationSolution("solution");
solution.setEntityList(Arrays.asList(a, b, c, d));
solution.setValueList(Arrays.asList(val1, val2, val3));

assertCollectionContainsExactly(val1.getEntities(), a, b);
assertCollectionContainsExactly(val2.getEntities());
assertCollectionContainsExactly(val3.getEntities(), c, d);

variableListener.beforeVariableChanged(scoreDirector, c);
c.setValue(val2);
variableListener.afterVariableChanged(scoreDirector, c);

assertCollectionContainsExactly(val1.getEntities(), a, b);
assertCollectionContainsExactly(val2.getEntities(), c);
assertCollectionContainsExactly(val3.getEntities(), d);
}

}
@@ -0,0 +1,74 @@
/*
* Copyright 2015 JBoss Inc
*
* Licensed 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.optaplanner.core.impl.domain.variable.inverserelation;

import java.util.Arrays;
import java.util.Collection;

import org.junit.Test;
import org.optaplanner.core.impl.domain.variable.descriptor.GenuineVariableDescriptor;
import org.optaplanner.core.impl.score.director.ScoreDirector;
import org.optaplanner.core.impl.testdata.domain.TestdataEntity;
import org.optaplanner.core.impl.testdata.domain.TestdataSolution;
import org.optaplanner.core.impl.testdata.domain.TestdataValue;
import org.optaplanner.core.impl.testdata.domain.shadow.inverserelation.TestdataInverseRelationEntity;
import org.optaplanner.core.impl.testdata.domain.shadow.inverserelation.TestdataInverseRelationSolution;
import org.optaplanner.core.impl.testdata.domain.shadow.inverserelation.TestdataInverseRelationValue;

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.optaplanner.core.impl.testdata.util.PlannerAssert.assertCollectionContainsExactly;

public class ExternalizedCollectionInverseVariableSupplyTest {

@Test
public void normal() {
GenuineVariableDescriptor variableDescriptor = TestdataEntity.buildVariableDescriptorForValue();
ScoreDirector scoreDirector = mock(ScoreDirector.class);
ExternalizedCollectionInverseVariableSupply supply = new ExternalizedCollectionInverseVariableSupply(variableDescriptor);

TestdataValue val1 = new TestdataValue("1");
TestdataValue val2 = new TestdataValue("2");
TestdataValue val3 = new TestdataValue("3");
TestdataEntity a = new TestdataEntity("a", val1);
TestdataEntity b = new TestdataEntity("b", val1);
TestdataEntity c = new TestdataEntity("c", val3);
TestdataEntity d = new TestdataEntity("d", val3);

TestdataSolution solution = new TestdataSolution("solution");
solution.setEntityList(Arrays.asList(a, b, c, d));
solution.setValueList(Arrays.asList(val1, val2, val3));

when(scoreDirector.getWorkingSolution()).thenReturn(solution);
supply.resetWorkingSolution(scoreDirector);

assertCollectionContainsExactly((Collection<Object>) supply.getInverseCollection(val1), a, b);
assertCollectionContainsExactly((Collection<Object>) supply.getInverseCollection(val2));
assertCollectionContainsExactly((Collection<Object>) supply.getInverseCollection(val3), c, d);

supply.beforeVariableChanged(scoreDirector, c);
c.setValue(val2);
supply.afterVariableChanged(scoreDirector, c);

assertCollectionContainsExactly((Collection<Object>) supply.getInverseCollection(val1), a, b);
assertCollectionContainsExactly((Collection<Object>) supply.getInverseCollection(val2), c);
assertCollectionContainsExactly((Collection<Object>) supply.getInverseCollection(val3), d);

supply.clearWorkingSolution(scoreDirector);
}

}
Expand Up @@ -36,7 +36,7 @@
public class SingletonInverseVariableListenerTest {

@Test
public void chained() {
public void chainedEntity() {
SolutionDescriptor solutionDescriptor = TestdataRichChainedSolution.buildSolutionDescriptor();
EntityDescriptor entityDescriptor = solutionDescriptor.findEntityDescriptorOrFail(TestdataRichChainedEntity.class);
ShadowVariableDescriptor nextEntityVariableDescriptor = entityDescriptor.getShadowVariableDescriptor("nextEntity");
Expand Down
@@ -0,0 +1,71 @@
/*
* Copyright 2015 JBoss Inc
*
* Licensed 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.optaplanner.core.impl.testdata.domain.shadow.inverserelation;

import org.optaplanner.core.api.domain.entity.PlanningEntity;
import org.optaplanner.core.api.domain.variable.PlanningVariable;
import org.optaplanner.core.impl.domain.entity.descriptor.EntityDescriptor;
import org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor;
import org.optaplanner.core.impl.domain.variable.descriptor.GenuineVariableDescriptor;
import org.optaplanner.core.impl.testdata.domain.TestdataObject;
import org.optaplanner.core.impl.testdata.domain.TestdataValue;

@PlanningEntity
public class TestdataInverseRelationEntity extends TestdataObject {

public static EntityDescriptor buildEntityDescriptor() {
SolutionDescriptor solutionDescriptor = TestdataInverseRelationSolution.buildSolutionDescriptor();
return solutionDescriptor.findEntityDescriptorOrFail(TestdataInverseRelationEntity.class);
}

public static GenuineVariableDescriptor buildVariableDescriptorForValue() {
SolutionDescriptor solutionDescriptor = TestdataInverseRelationSolution.buildSolutionDescriptor();
EntityDescriptor entityDescriptor = solutionDescriptor.findEntityDescriptorOrFail(TestdataInverseRelationEntity.class);
return entityDescriptor.getGenuineVariableDescriptor("value");
}

private TestdataInverseRelationValue value;

public TestdataInverseRelationEntity() {
}

public TestdataInverseRelationEntity(String code) {
super(code);
}

public TestdataInverseRelationEntity(String code, TestdataInverseRelationValue value) {
this(code);
this.value = value;
if (value != null) {
value.getEntities().add(this);
}
}

@PlanningVariable(valueRangeProviderRefs = "valueRange", nullable = true)
public TestdataInverseRelationValue getValue() {
return value;
}

public void setValue(TestdataInverseRelationValue value) {
this.value = value;
}

// ************************************************************************
// Complex methods
// ************************************************************************

}
@@ -0,0 +1,85 @@
/*
* Copyright 2015 JBoss Inc
*
* Licensed 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.optaplanner.core.impl.testdata.domain.shadow.inverserelation;

import java.util.Collection;
import java.util.List;

import org.optaplanner.core.api.domain.solution.PlanningEntityCollectionProperty;
import org.optaplanner.core.api.domain.solution.PlanningSolution;
import org.optaplanner.core.api.domain.solution.Solution;
import org.optaplanner.core.api.domain.valuerange.ValueRangeProvider;
import org.optaplanner.core.api.score.buildin.simple.SimpleScore;
import org.optaplanner.core.impl.domain.solution.descriptor.SolutionDescriptor;
import org.optaplanner.core.impl.testdata.domain.TestdataObject;
import org.optaplanner.core.impl.testdata.domain.TestdataUtils;

@PlanningSolution
public class TestdataInverseRelationSolution extends TestdataObject implements Solution<SimpleScore> {

public static SolutionDescriptor buildSolutionDescriptor() {
return TestdataUtils.buildSolutionDescriptor(TestdataInverseRelationSolution.class,
TestdataInverseRelationEntity.class, TestdataInverseRelationValue.class);
}

private List<TestdataInverseRelationValue> valueList;
private List<TestdataInverseRelationEntity> entityList;

private SimpleScore score;

public TestdataInverseRelationSolution() {
}

public TestdataInverseRelationSolution(String code) {
super(code);
}

@ValueRangeProvider(id = "valueRange")
public List<TestdataInverseRelationValue> getValueList() {
return valueList;
}

public void setValueList(List<TestdataInverseRelationValue> valueList) {
this.valueList = valueList;
}

@PlanningEntityCollectionProperty
public List<TestdataInverseRelationEntity> getEntityList() {
return entityList;
}

public void setEntityList(List<TestdataInverseRelationEntity> entityList) {
this.entityList = entityList;
}

public SimpleScore getScore() {
return score;
}

public void setScore(SimpleScore score) {
this.score = score;
}

// ************************************************************************
// Complex methods
// ************************************************************************

public Collection<? extends Object> getProblemFacts() {
return valueList;
}

}
@@ -0,0 +1,47 @@
/*
* Copyright 2015 JBoss Inc
*
* Licensed 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.optaplanner.core.impl.testdata.domain.shadow.inverserelation;

import java.util.ArrayList;
import java.util.Collection;

import org.optaplanner.core.api.domain.entity.PlanningEntity;
import org.optaplanner.core.api.domain.variable.InverseRelationShadowVariable;
import org.optaplanner.core.impl.testdata.domain.TestdataObject;

@PlanningEntity
public class TestdataInverseRelationValue extends TestdataObject {

private Collection<TestdataInverseRelationEntity> entities = new ArrayList<TestdataInverseRelationEntity>();

public TestdataInverseRelationValue() {
}

public TestdataInverseRelationValue(String code) {
super(code);
}

@InverseRelationShadowVariable(sourceVariableName = "value")
public Collection<TestdataInverseRelationEntity> getEntities() {
return entities;
}

public void setEntities(Collection<TestdataInverseRelationEntity> entities) {
this.entities = entities;
}

}

0 comments on commit 05fcab9

Please sign in to comment.