/* * Copyright 2017 Red Hat, Inc. and/or its affiliates. * * 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.kie.workbench.common.stunner.core.validation.impl; import java.util.Collection; import java.util.List; import java.util.Optional; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.kie.workbench.common.stunner.core.TestingGraphInstanceBuilder; import org.kie.workbench.common.stunner.core.TestingGraphMockHandler; import org.kie.workbench.common.stunner.core.graph.Edge; import org.kie.workbench.common.stunner.core.graph.Graph; import org.kie.workbench.common.stunner.core.graph.Node; import org.kie.workbench.common.stunner.core.graph.content.definition.DefinitionSet; import org.kie.workbench.common.stunner.core.graph.processing.traverse.tree.TreeWalkTraverseProcessorImpl; import org.kie.workbench.common.stunner.core.rule.RuleEvaluationContext; import org.kie.workbench.common.stunner.core.rule.RuleManager; import org.kie.workbench.common.stunner.core.rule.RuleSet; import org.kie.workbench.common.stunner.core.rule.RuleViolation; import org.kie.workbench.common.stunner.core.rule.context.ConnectorCardinalityContext; import org.kie.workbench.common.stunner.core.rule.context.EdgeCardinalityContext; import org.kie.workbench.common.stunner.core.rule.context.ElementCardinalityContext; import org.kie.workbench.common.stunner.core.rule.context.GraphConnectionContext; import org.kie.workbench.common.stunner.core.rule.context.NodeContainmentContext; import org.kie.workbench.common.stunner.core.rule.violations.EmptyConnectionViolation; import org.kie.workbench.common.stunner.core.validation.Violation; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import static org.junit.Assert.*; import static org.kie.workbench.common.stunner.core.TestingGraphUtils.verifyCardinality; import static org.kie.workbench.common.stunner.core.TestingGraphUtils.verifyConnection; import static org.kie.workbench.common.stunner.core.TestingGraphUtils.verifyConnectorCardinality; import static org.kie.workbench.common.stunner.core.TestingGraphUtils.verifyContainment; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.*; @RunWith(MockitoJUnitRunner.class) public class GraphValidatorImplTest { private final static String DEF_SET_ID = "ds1"; @Mock private Object defSetBean; private GraphValidatorImpl tested; private TestingGraphMockHandler graphTestHandler; @Before @SuppressWarnings("unchecked") public void setup() throws Exception { this.graphTestHandler = new TestingGraphMockHandler(); when(graphTestHandler.definitionSetRegistry.getDefinitionSetById(eq(DEF_SET_ID))).thenReturn(defSetBean); when(graphTestHandler.ruleAdapter.getRuleSet(eq(defSetBean))).thenReturn(graphTestHandler.ruleSet); this.tested = new GraphValidatorImpl(graphTestHandler.definitionManager, graphTestHandler.ruleManager, new TreeWalkTraverseProcessorImpl()); } @Test @SuppressWarnings("unchecked") public void testValidateGraph1() { final RuleManager ruleManager = graphTestHandler.ruleManager; final RuleSet ruleSet = graphTestHandler.ruleSet; final Graph<DefinitionSet, Node> graph = graphTestHandler.graph; final TestingGraphInstanceBuilder.TestGraph1 testGraph1 = TestingGraphInstanceBuilder.newGraph1(graphTestHandler); tested.validate(graph, ruleSet, this::assertNoError); final int evalCount = testGraph1.evaluationsCount + 10; final ArgumentCaptor<RuleEvaluationContext> contextCaptor = ArgumentCaptor.forClass(RuleEvaluationContext.class); verify(ruleManager, times(evalCount)).evaluate(eq(ruleSet), contextCaptor.capture()); final List<RuleEvaluationContext> contexts = contextCaptor.getAllValues(); assertEquals(evalCount, contexts.size()); int cindex = testGraph1.evaluationsCount; verifyCardinality((ElementCardinalityContext) contexts.get(cindex++), graph); verifyContainment((NodeContainmentContext) contexts.get(cindex++), graph, testGraph1.startNode); verifyConnection((GraphConnectionContext) contexts.get(cindex++), testGraph1.edge1, testGraph1.startNode, testGraph1.intermNode); verifyConnectorCardinality((ConnectorCardinalityContext) contexts.get(cindex++), graph, testGraph1.intermNode, testGraph1.edge1, EdgeCardinalityContext.Direction.INCOMING, Optional.empty()); verifyConnectorCardinality((ConnectorCardinalityContext) contexts.get(cindex++), graph, testGraph1.startNode, testGraph1.edge1, EdgeCardinalityContext.Direction.OUTGOING, Optional.empty()); verifyContainment((NodeContainmentContext) contexts.get(cindex++), graph, testGraph1.intermNode); verifyConnection((GraphConnectionContext) contexts.get(cindex++), testGraph1.edge2, testGraph1.intermNode, testGraph1.endNode); verifyConnectorCardinality((ConnectorCardinalityContext) contexts.get(cindex++), graph, testGraph1.endNode, testGraph1.edge2, EdgeCardinalityContext.Direction.INCOMING, Optional.empty()); verifyConnectorCardinality((ConnectorCardinalityContext) contexts.get(cindex++), graph, testGraph1.intermNode, testGraph1.edge2, EdgeCardinalityContext.Direction.OUTGOING, Optional.empty()); verifyContainment((NodeContainmentContext) contexts.get(cindex++), graph, testGraph1.endNode); } @Test @SuppressWarnings("unchecked") public void testValidateGraph2() { final RuleManager ruleManager = graphTestHandler.ruleManager; final RuleSet ruleSet = graphTestHandler.ruleSet; final Graph<DefinitionSet, Node> graph = graphTestHandler.graph; final TestingGraphInstanceBuilder.TestGraph2 testGraph2 = TestingGraphInstanceBuilder.newGraph2(graphTestHandler); tested.validate(getGraph(), graphTestHandler.ruleSet, this::assertNoError); final int evalCount = testGraph2.evaluationsCount + 11; final ArgumentCaptor<RuleEvaluationContext> contextCaptor = ArgumentCaptor.forClass(RuleEvaluationContext.class); verify(ruleManager, times(evalCount)).evaluate(eq(ruleSet), contextCaptor.capture()); final List<RuleEvaluationContext> contexts = contextCaptor.getAllValues(); assertEquals(evalCount, contexts.size()); int cindex = testGraph2.evaluationsCount; verifyCardinality((ElementCardinalityContext) contexts.get(cindex++), graph); verifyContainment((NodeContainmentContext) contexts.get(cindex++), graph, testGraph2.parentNode); verifyContainment((NodeContainmentContext) contexts.get(cindex++), testGraph2.parentNode, testGraph2.startNode); verifyConnection((GraphConnectionContext) contexts.get(cindex++), testGraph2.edge1, testGraph2.startNode, testGraph2.intermNode); verifyConnectorCardinality((ConnectorCardinalityContext) contexts.get(cindex++), graph, testGraph2.intermNode, testGraph2.edge1, EdgeCardinalityContext.Direction.INCOMING, Optional.empty()); verifyConnectorCardinality((ConnectorCardinalityContext) contexts.get(cindex++), graph, testGraph2.startNode, testGraph2.edge1, EdgeCardinalityContext.Direction.OUTGOING, Optional.empty()); verifyContainment((NodeContainmentContext) contexts.get(cindex++), testGraph2.parentNode, testGraph2.intermNode); verifyConnection((GraphConnectionContext) contexts.get(cindex++), testGraph2.edge2, testGraph2.intermNode, testGraph2.endNode); verifyConnectorCardinality((ConnectorCardinalityContext) contexts.get(cindex++), graph, testGraph2.endNode, testGraph2.edge2, EdgeCardinalityContext.Direction.INCOMING, Optional.empty()); verifyConnectorCardinality((ConnectorCardinalityContext) contexts.get(cindex++), graph, testGraph2.intermNode, testGraph2.edge2, EdgeCardinalityContext.Direction.OUTGOING, Optional.empty()); verifyContainment((NodeContainmentContext) contexts.get(cindex++), testGraph2.parentNode, testGraph2.endNode); } @Test @SuppressWarnings("unchecked") public void testValidateEmptyViewConnectorNodes() { final RuleSet ruleSet = graphTestHandler.ruleSet; final Graph<DefinitionSet, Node> graph = graphTestHandler.graph; final TestingGraphInstanceBuilder.TestGraph1 testGraph1 = TestingGraphInstanceBuilder.newGraph1(graphTestHandler); // Update the edge2 and remove the connection's target node. // From this point, a validation error is expected. graphTestHandler.removeTargetConnection(testGraph1.edge2); tested.validate(graph, ruleSet, ruleViolations -> { assertEquals(1, ruleViolations.size()); final RuleViolation violation = ruleViolations.iterator().next(); assertNotNull(violation); assertTrue(violation instanceof EmptyConnectionViolation); EmptyConnectionViolation v = (EmptyConnectionViolation) violation; final Optional<Object[]> arguments = v.getArguments(); assertTrue(arguments.isPresent()); assertEquals(testGraph1.edge2.getUUID(), arguments.get()[0]); assertEquals(testGraph1.intermNode.getUUID(), arguments.get()[1]); assertNull(arguments.get()[2]); }); } private void assertNoError(final Collection<RuleViolation> violations) { assertFalse(violations.stream() .filter(v -> Violation.Type.ERROR.equals(v.getViolationType())) .findAny() .isPresent()); } @SuppressWarnings("unchecked") private Graph<?, Node<?, Edge>> getGraph() { return (Graph) graphTestHandler.graph; } }