| /* |
| * Copyright 2008 Niclas Hedhman. All rights Reserved. |
| * |
| * 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.qi4j.runtime.composite; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import org.junit.Assert; |
| import org.junit.Before; |
| import org.junit.Test; |
| import org.qi4j.bootstrap.BindingException; |
| |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertTrue; |
| |
| public class UsageGraphTest |
| { |
| |
| @Before |
| public void setUp() |
| { |
| Thing.counter = 1; |
| } |
| |
| @Test |
| public void verifyRandomDoesNotAffect() |
| throws Exception |
| { |
| for( int i = 0; i < 100; i++ ) |
| { |
| whenGraphIsOpenEndedGivenNotAllowCyclicDependenciesThenNoError(); |
| whenGraphIsCyclicGivenAllowCyclicDependencyThenNoError(); |
| } |
| } |
| |
| @Test |
| public void whenGraphIsOpenEndedGivenNotAllowCyclicDependenciesThenNoError() |
| throws Exception |
| { |
| Thing thing1 = new Thing(); |
| Thing thing2 = new Thing(); |
| Thing thing3 = new Thing(); |
| Thing thing4 = new Thing(); |
| Thing thing5 = new Thing(); |
| Thing thing6 = new Thing(); |
| Thing thing7 = new Thing(); |
| thing1.uses.add( thing3 ); |
| thing2.uses.add( thing3 ); |
| thing3.uses.add( thing4 ); |
| thing4.uses.add( thing5 ); |
| thing1.uses.add( thing6 ); |
| thing7.uses.add( thing1 ); |
| thing7.uses.add( thing2 ); |
| thing7.uses.add( thing4 ); |
| List<Thing> data = new ArrayList<Thing>(); |
| data.add( thing7 ); |
| data.add( thing4 ); |
| data.add( thing3 ); |
| data.add( thing1 ); |
| data.add( thing6 ); |
| data.add( thing5 ); |
| data.add( thing2 ); |
| randomize( data ); |
| UsageGraph<Thing> deps = new UsageGraph<Thing>( data, new Userator(), false ); |
| assertFalse( deps.transitiveUse( thing1, thing1 ) ); |
| assertFalse( deps.transitiveUse( thing1, thing2 ) ); |
| assertTrue( deps.transitiveUse( thing1, thing3 ) ); |
| assertTrue( deps.transitiveUse( thing1, thing4 ) ); |
| assertTrue( deps.transitiveUse( thing1, thing5 ) ); |
| assertTrue( deps.transitiveUse( thing1, thing6 ) ); |
| assertFalse( deps.transitiveUse( thing1, thing7 ) ); |
| assertFalse( deps.transitiveUse( thing2, thing1 ) ); |
| assertFalse( deps.transitiveUse( thing2, thing2 ) ); |
| assertTrue( deps.transitiveUse( thing2, thing3 ) ); |
| assertTrue( deps.transitiveUse( thing2, thing4 ) ); |
| assertTrue( deps.transitiveUse( thing2, thing5 ) ); |
| assertFalse( deps.transitiveUse( thing2, thing6 ) ); |
| assertFalse( deps.transitiveUse( thing2, thing7 ) ); |
| assertFalse( deps.transitiveUse( thing3, thing1 ) ); |
| assertFalse( deps.transitiveUse( thing3, thing2 ) ); |
| assertFalse( deps.transitiveUse( thing3, thing3 ) ); |
| assertTrue( deps.transitiveUse( thing3, thing4 ) ); |
| assertTrue( deps.transitiveUse( thing3, thing5 ) ); |
| assertFalse( deps.transitiveUse( thing3, thing6 ) ); |
| assertFalse( deps.transitiveUse( thing3, thing7 ) ); |
| assertFalse( deps.transitiveUse( thing4, thing1 ) ); |
| assertFalse( deps.transitiveUse( thing4, thing2 ) ); |
| assertFalse( deps.transitiveUse( thing4, thing3 ) ); |
| assertFalse( deps.transitiveUse( thing4, thing4 ) ); |
| assertTrue( deps.transitiveUse( thing4, thing5 ) ); |
| assertFalse( deps.transitiveUse( thing4, thing6 ) ); |
| assertFalse( deps.transitiveUse( thing4, thing7 ) ); |
| assertFalse( deps.transitiveUse( thing5, thing1 ) ); |
| assertFalse( deps.transitiveUse( thing5, thing2 ) ); |
| assertFalse( deps.transitiveUse( thing5, thing3 ) ); |
| assertFalse( deps.transitiveUse( thing5, thing4 ) ); |
| assertFalse( deps.transitiveUse( thing5, thing5 ) ); |
| assertFalse( deps.transitiveUse( thing5, thing6 ) ); |
| assertFalse( deps.transitiveUse( thing5, thing7 ) ); |
| assertFalse( deps.transitiveUse( thing6, thing1 ) ); |
| assertFalse( deps.transitiveUse( thing6, thing2 ) ); |
| assertFalse( deps.transitiveUse( thing6, thing3 ) ); |
| assertFalse( deps.transitiveUse( thing6, thing4 ) ); |
| assertFalse( deps.transitiveUse( thing6, thing5 ) ); |
| assertFalse( deps.transitiveUse( thing6, thing6 ) ); |
| assertFalse( deps.transitiveUse( thing6, thing7 ) ); |
| assertTrue( deps.transitiveUse( thing7, thing1 ) ); |
| assertTrue( deps.transitiveUse( thing7, thing2 ) ); |
| assertTrue( deps.transitiveUse( thing7, thing3 ) ); |
| assertTrue( deps.transitiveUse( thing7, thing4 ) ); |
| assertTrue( deps.transitiveUse( thing7, thing5 ) ); |
| assertTrue( deps.transitiveUse( thing7, thing6 ) ); |
| assertFalse( deps.transitiveUse( thing7, thing7 ) ); |
| List<Thing> resolved = deps.resolveOrder(); |
| System.out.println( resolved ); |
| assertTrue( resolved.indexOf( thing1 ) > resolved.indexOf( thing6 ) ); |
| assertTrue( resolved.indexOf( thing2 ) > resolved.indexOf( thing3 ) ); |
| assertTrue( resolved.indexOf( thing2 ) > resolved.indexOf( thing4 ) ); |
| assertTrue( resolved.indexOf( thing2 ) > resolved.indexOf( thing5 ) ); |
| assertTrue( resolved.indexOf( thing7 ) > resolved.indexOf( thing1 ) ); |
| assertTrue( resolved.indexOf( thing7 ) > resolved.indexOf( thing2 ) ); |
| assertTrue( resolved.indexOf( thing7 ) > resolved.indexOf( thing4 ) ); |
| assertTrue( resolved.indexOf( thing1 ) > resolved.indexOf( thing3 ) ); |
| assertTrue( resolved.indexOf( thing1 ) > resolved.indexOf( thing4 ) ); |
| assertTrue( resolved.indexOf( thing1 ) > resolved.indexOf( thing5 ) ); |
| assertTrue( resolved.indexOf( thing3 ) > resolved.indexOf( thing4 ) ); |
| assertTrue( resolved.indexOf( thing3 ) > resolved.indexOf( thing5 ) ); |
| assertTrue( resolved.indexOf( thing4 ) > resolved.indexOf( thing5 ) ); |
| assertTrue( resolved.indexOf( thing7 ) > resolved.indexOf( thing4 ) ); |
| assertTrue( resolved.indexOf( thing7 ) > resolved.indexOf( thing5 ) ); |
| assertTrue( resolved.indexOf( thing7 ) > resolved.indexOf( thing6 ) ); |
| } |
| |
| private void randomize( List<Thing> data ) |
| { |
| int n = (int) ( Math.random() * 100 ); |
| for( int i = 0; i < n; i++ ) |
| { |
| int pos1 = 0; |
| int pos2 = 0; |
| while( pos1 == pos2 ) |
| { |
| pos1 = (int) ( Math.floor( Math.random() * data.size() ) ); |
| pos2 = (int) ( Math.floor( Math.random() * data.size() ) ); |
| } |
| if( pos1 < pos2 ) |
| { |
| int temp = pos2; |
| pos2 = pos1; |
| pos1 = temp; |
| } |
| Thing thing1 = data.remove( pos1 ); |
| Thing thing2 = data.remove( pos2 ); |
| data.add( pos2, thing1 ); |
| data.add( pos1, thing2 ); |
| } |
| } |
| |
| @Test |
| public void whenAskingForDependencyGivenThatGraphContainsCyclicDepThenDetectTheError() |
| throws Exception |
| { |
| Thing thing1 = new Thing(); |
| Thing thing2 = new Thing(); |
| Thing thing3 = new Thing(); |
| Thing thing4 = new Thing(); |
| Thing thing5 = new Thing(); |
| Thing thing6 = new Thing(); |
| Thing thing7 = new Thing(); |
| thing1.uses.add( thing3 ); |
| thing2.uses.add( thing3 ); |
| thing3.uses.add( thing4 ); |
| thing4.uses.add( thing5 ); |
| thing5.uses.add( thing1 ); // <-- Cyclic |
| thing1.uses.add( thing6 ); |
| thing7.uses.add( thing1 ); |
| thing7.uses.add( thing2 ); |
| thing7.uses.add( thing4 ); |
| List<Thing> data = new ArrayList<Thing>(); |
| data.add( thing7 ); |
| data.add( thing4 ); |
| data.add( thing1 ); |
| data.add( thing3 ); |
| data.add( thing6 ); |
| data.add( thing5 ); |
| data.add( thing2 ); |
| randomize( data ); |
| UsageGraph<Thing> deps = new UsageGraph<Thing>( data, new Userator(), false ); |
| try |
| { |
| List<Thing> resolved = deps.resolveOrder(); |
| Assert.fail( "Cyclic Dependency Not Detected." ); |
| } |
| catch( BindingException e ) |
| { |
| // Expected! |
| } |
| } |
| |
| @Test |
| public void whenAskingForResolveOrderGivenThatGraphContainsCyclicDepThenDetectTheError() |
| throws Exception |
| { |
| Thing thing1 = new Thing(); |
| Thing thing2 = new Thing(); |
| Thing thing3 = new Thing(); |
| Thing thing4 = new Thing(); |
| Thing thing5 = new Thing(); |
| Thing thing6 = new Thing(); |
| Thing thing7 = new Thing(); |
| thing1.uses.add( thing3 ); |
| thing2.uses.add( thing3 ); |
| thing3.uses.add( thing4 ); |
| thing4.uses.add( thing5 ); |
| thing5.uses.add( thing1 ); // <-- Cyclic |
| thing1.uses.add( thing6 ); |
| thing7.uses.add( thing1 ); |
| thing7.uses.add( thing2 ); |
| thing7.uses.add( thing4 ); |
| List<Thing> data = new ArrayList<Thing>(); |
| data.add( thing7 ); |
| data.add( thing4 ); |
| data.add( thing1 ); |
| data.add( thing3 ); |
| data.add( thing6 ); |
| data.add( thing5 ); |
| data.add( thing2 ); |
| randomize( data ); |
| UsageGraph<Thing> deps = new UsageGraph<Thing>( data, new Userator(), false ); |
| try |
| { |
| assertTrue( deps.transitiveUse( thing1, thing3 ) ); |
| Assert.fail( "Cyclic Dependency Not Detected." ); |
| } |
| catch( BindingException e ) |
| { |
| // Expected! |
| } |
| } |
| |
| @Test |
| public void whenGraphIsCyclicGivenAllowCyclicDependencyThenNoError() |
| throws Exception |
| { |
| Thing thing1 = new Thing(); |
| Thing thing2 = new Thing(); |
| Thing thing3 = new Thing(); |
| Thing thing4 = new Thing(); |
| Thing thing5 = new Thing(); |
| Thing thing6 = new Thing(); |
| Thing thing7 = new Thing(); |
| thing1.uses.add( thing3 ); |
| thing2.uses.add( thing3 ); |
| thing3.uses.add( thing4 ); |
| thing4.uses.add( thing5 ); |
| thing1.uses.add( thing6 ); |
| thing5.uses.add( thing1 ); // <-- Cyclic |
| thing7.uses.add( thing1 ); |
| thing7.uses.add( thing2 ); |
| thing7.uses.add( thing4 ); |
| List<Thing> data = new ArrayList<Thing>(); |
| data.add( thing7 ); |
| data.add( thing4 ); |
| data.add( thing1 ); |
| data.add( thing3 ); |
| data.add( thing6 ); |
| data.add( thing5 ); |
| data.add( thing2 ); |
| randomize( data ); |
| UsageGraph<Thing> deps = new UsageGraph<Thing>( data, new Userator(), true ); |
| assertTrue( deps.transitiveUse( thing1, thing1 ) ); |
| assertFalse( deps.transitiveUse( thing1, thing2 ) ); |
| assertTrue( deps.transitiveUse( thing1, thing3 ) ); |
| assertTrue( deps.transitiveUse( thing1, thing4 ) ); |
| assertTrue( deps.transitiveUse( thing1, thing5 ) ); |
| assertTrue( deps.transitiveUse( thing1, thing6 ) ); |
| assertFalse( deps.transitiveUse( thing1, thing7 ) ); |
| assertTrue( deps.transitiveUse( thing2, thing1 ) ); |
| assertFalse( deps.transitiveUse( thing2, thing2 ) ); |
| assertTrue( deps.transitiveUse( thing2, thing3 ) ); |
| assertTrue( deps.transitiveUse( thing2, thing4 ) ); |
| assertTrue( deps.transitiveUse( thing2, thing5 ) ); |
| assertTrue( deps.transitiveUse( thing2, thing6 ) ); |
| assertFalse( deps.transitiveUse( thing2, thing7 ) ); |
| assertTrue( deps.transitiveUse( thing3, thing1 ) ); |
| assertFalse( deps.transitiveUse( thing3, thing2 ) ); |
| assertTrue( deps.transitiveUse( thing3, thing3 ) ); |
| assertTrue( deps.transitiveUse( thing3, thing4 ) ); |
| assertTrue( deps.transitiveUse( thing3, thing5 ) ); |
| assertTrue( deps.transitiveUse( thing3, thing6 ) ); |
| assertFalse( deps.transitiveUse( thing3, thing7 ) ); |
| assertTrue( deps.transitiveUse( thing4, thing1 ) ); |
| assertFalse( deps.transitiveUse( thing4, thing2 ) ); |
| assertTrue( deps.transitiveUse( thing4, thing3 ) ); |
| assertTrue( deps.transitiveUse( thing4, thing4 ) ); |
| assertTrue( deps.transitiveUse( thing4, thing5 ) ); |
| assertTrue( deps.transitiveUse( thing4, thing6 ) ); |
| assertFalse( deps.transitiveUse( thing4, thing7 ) ); |
| assertTrue( deps.transitiveUse( thing5, thing1 ) ); |
| assertFalse( deps.transitiveUse( thing5, thing2 ) ); |
| assertTrue( deps.transitiveUse( thing5, thing3 ) ); |
| assertTrue( deps.transitiveUse( thing5, thing4 ) ); |
| assertTrue( deps.transitiveUse( thing5, thing5 ) ); |
| assertTrue( deps.transitiveUse( thing5, thing6 ) ); |
| assertFalse( deps.transitiveUse( thing5, thing7 ) ); |
| assertFalse( deps.transitiveUse( thing6, thing1 ) ); |
| assertFalse( deps.transitiveUse( thing6, thing2 ) ); |
| assertFalse( deps.transitiveUse( thing6, thing3 ) ); |
| assertFalse( deps.transitiveUse( thing6, thing4 ) ); |
| assertFalse( deps.transitiveUse( thing6, thing5 ) ); |
| assertFalse( deps.transitiveUse( thing6, thing6 ) ); |
| assertFalse( deps.transitiveUse( thing6, thing7 ) ); |
| assertTrue( deps.transitiveUse( thing7, thing1 ) ); |
| assertTrue( deps.transitiveUse( thing7, thing2 ) ); |
| assertTrue( deps.transitiveUse( thing7, thing3 ) ); |
| assertTrue( deps.transitiveUse( thing7, thing4 ) ); |
| assertTrue( deps.transitiveUse( thing7, thing5 ) ); |
| assertTrue( deps.transitiveUse( thing7, thing6 ) ); |
| assertFalse( deps.transitiveUse( thing7, thing7 ) ); |
| List<Thing> resolved = deps.resolveOrder(); |
| System.out.println( resolved ); |
| assertTrue( resolved.indexOf( thing1 ) > resolved.indexOf( thing6 ) ); |
| assertTrue( resolved.indexOf( thing2 ) > resolved.indexOf( thing3 ) ); |
| assertTrue( resolved.indexOf( thing2 ) > resolved.indexOf( thing4 ) ); |
| assertTrue( resolved.indexOf( thing2 ) > resolved.indexOf( thing5 ) ); |
| assertTrue( resolved.indexOf( thing2 ) > resolved.indexOf( thing1 ) ); |
| assertTrue( resolved.indexOf( thing7 ) > resolved.indexOf( thing1 ) ); |
| assertTrue( resolved.indexOf( thing7 ) > resolved.indexOf( thing2 ) ); |
| assertTrue( resolved.indexOf( thing7 ) > resolved.indexOf( thing4 ) ); |
| |
| // The cyclic nodes can not be determine which one is before the other |
| } |
| |
| public class Userator |
| implements UsageGraph.Use<Thing> |
| { |
| |
| public List<Thing> uses( Thing source ) |
| { |
| return source.uses; |
| } |
| } |
| |
| public static class Thing |
| { |
| private static int counter = 1; |
| |
| private List<Thing> uses = new ArrayList<Thing>(); |
| private String name = "Thing" + counter++; |
| |
| public String toString() |
| { |
| return name; |
| } |
| } |
| } |