package com.tinkerpop.gremlin.structure;

import com.tinkerpop.gremlin.process.computer.GraphComputer;
import org.junit.Test;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static org.junit.Assert.assertTrue;

/**
 * A set of tests that ensure that the {@link ExceptionConsistencyTest} covers all defined Blueprints exceptions.
 *
 * @author Stephen Mallette (http://stephen.genoprime.com)
 */
public class ExceptionCoverageTest {

    @Test
    public void shouldCoverAllExceptionsInTests() {

        // these are the classes that have Exceptions that need to be checked.
        final Class[] blueprintsExceptions = {
                Edge.Exceptions.class,
                Element.Exceptions.class,
                Graph.Exceptions.class,
                GraphComputer.Exceptions.class,
                Graph.Variables.Exceptions.class,
                Property.Exceptions.class,
                Transaction.Exceptions.class,
                Vertex.Exceptions.class
        };

        // this is a list of exceptions that are "excused" from the coverage tests.  in most cases there should only
        // be exceptions ignored if they are "base" exception methods that are used to compose other exceptions,
        // like the first set listed (and labelled as such) below in the list assignments.
        final Set<String> ignore = new HashSet<String>() {{
            // these exceptions is not used directly...they are called by other exception methods.
            add("com.tinkerpop.gremlin.structure.Property$Exceptions#propertyKeyIsReserved");
            add("com.tinkerpop.gremlin.structure.Graph$Variables$Exceptions#memoryKeyIsReserved");

            // this is a general exception to be used as needed.  it is not explicitly tested:
            add("com.tinkerpop.gremlin.structure.Graph$Exceptions#argumentCanNotBeNull");

            //add("com.tinkerpop.gremlin.structure.Graph$Exceptions#onlyOneOrNoGraphComputerClass");
            //add("com.tinkerpop.gremlin.structure.Graph$Exceptions#graphDoesNotSupportProvidedGraphComputer");

            // todo: need to write consistency tests for the following items still...........
            add("com.tinkerpop.gremlin.process.computer.GraphComputer$Exceptions#adjacentElementPropertiesCanNotBeRead");
            add("com.tinkerpop.gremlin.process.computer.GraphComputer$Exceptions#adjacentElementPropertiesCanNotBeWritten");
            add("com.tinkerpop.gremlin.process.computer.GraphComputer$Exceptions#constantComputeKeyHasAlreadyBeenSet");
            add("com.tinkerpop.gremlin.process.computer.GraphComputer$Exceptions#adjacentVerticesCanNotBeQueried");
            add("com.tinkerpop.gremlin.process.computer.GraphComputer$Exceptions#isolationNotSupported");
            //add("com.tinkerpop.gremlin.process.computer.GraphComputer$Exceptions#computerHasAlreadyBeenSubmittedAVertexProgram");
            add("com.tinkerpop.gremlin.process.computer.GraphComputer$Exceptions#providedKeyIsNotASideEffectKey");

            add("com.tinkerpop.gremlin.structure.Graph$Exceptions#vertexAdditionsNotSupported");
            add("com.tinkerpop.gremlin.structure.Element$Exceptions#propertyAdditionNotSupported");
            add("com.tinkerpop.gremlin.structure.Vertex$Exceptions#edgeAdditionsNotSupported");

            add("com.tinkerpop.gremlin.structure.Graph$Exceptions#vertexLookupsNotSupported");
            add("com.tinkerpop.gremlin.structure.Graph$Exceptions#edgeLookupsNotSupported");

            add("com.tinkerpop.gremlin.structure.Element$Exceptions#propertyRemovalNotSupported");
            add("com.tinkerpop.gremlin.structure.Vertex$Exceptions#vertexRemovalNotSupported");
            add("com.tinkerpop.gremlin.structure.Edge$Exceptions#edgeRemovalNotSupported");

        }};

        // implemented exceptions are the classes that potentially contains exception consistency checks.
        final Set<String> implementedExceptions = Stream.concat(Stream.of(ExceptionConsistencyTest.class.getDeclaredClasses()),
                Stream.of(FeatureSupportTest.class.getDeclaredClasses()))
                .<ExceptionCoverage>flatMap(c -> Stream.of(c.getAnnotationsByType(ExceptionCoverage.class)))
                .flatMap(ec -> Stream.of(ec.methods()).map(m -> String.format("%s#%s", ec.exceptionClass().getName(), m)))
                .collect(Collectors.<String>toSet());

        // evaluate each of the blueprints exceptions and find the list of exception methods...assert them against
        // the list of implementedExceptions to make sure they are covered.
        Stream.of(blueprintsExceptions).flatMap(c -> Stream.of(c.getDeclaredMethods()).map((Method m) -> String.format("%s#%s", c.getName(), m.getName())))
                .filter(s -> !ignore.contains(s))
                .forEach(s -> {
                    System.out.println(s);
                    assertTrue(implementedExceptions.contains(s));
                });
    }
}

@@ -96,16 +96,81 @@
 mputer;%0A
+import com.tinkerpop.gremlin.process.computer.GraphComputerTest;%0A
 import o
@@ -239,37 +239,154 @@
 til.
-HashSet;%0Aimport java.util.Set
+ArrayList;%0Aimport java.util.Arrays;%0Aimport java.util.HashSet;%0Aimport java.util.List;%0Aimport java.util.Set;%0Aimport java.util.function.UnaryOperator
 ;%0Aim
@@ -595,18 +595,17 @@
 ned 
-Blueprints
+TinkerPop
  exc
@@ -881,35 +881,41 @@
 Class%5B%5D 
-blueprintsException
+exceptionDefinitionClasse
 s = %7B%0A  
@@ -3164,123 +3164,8 @@
 m%22);
-%0A            add(%22com.tinkerpop.gremlin.process.computer.GraphComputer$Exceptions#providedKeyIsNotASideEffectKey%22);
 %0A%0A  
@@ -3961,84 +3961,131 @@
  // 
-implemented exceptions are the classes that potentially contains exception c
+register test classes here that contain @ExceptionCoverage annotations%0A        final List%3CClass%3C?%3E%3E testClassesThatContainC
 onsi
@@ -4094,90 +4094,182 @@
 ency
- c
+C
 hecks
-.%0A        final Set%3CString%3E implementedExceptions = Stream.concat(Stream.of
+ = new ArrayList%3C%3E();%0A        testClassesThatContainConsistencyChecks.add(GraphComputerTest.class);%0A        testClassesThatContainConsistencyChecks.addAll(Arrays.asList
 (Exc
@@ -4317,31 +4317,27 @@
 asses())
-,%0A     
+);%0A
         
    Strea
@@ -4332,67 +4332,322 @@
     
-   Stream.of(FeatureSupportTest.class.getDeclaredClasses())
+testClassesThatContainConsistencyChecks.addAll(Arrays.asList(FeatureSupportTest.class.getDeclaredClasses()));%0A%0A        // implemented exceptions are the classes that potentially contains exception consistency checks.%0A        final Set%3CString%3E implementedExceptions = testClassesThatContainConsistencyChecks.stream(
 )%0A  
@@ -5144,27 +5144,33 @@
 .of(
-blueprintsException
+exceptionDefinitionClasse
 s).f

Make exception coverage test more clear as to what is expected.