diff --git a/app/carnival-graph/src/main/groovy/carnival/graph/Base.groovy b/app/carnival-graph/src/main/groovy/carnival/graph/Base.groovy index e35cdfe..9ee3ebf 100644 --- a/app/carnival-graph/src/main/groovy/carnival/graph/Base.groovy +++ b/app/carnival-graph/src/main/groovy/carnival/graph/Base.groovy @@ -70,8 +70,8 @@ class Base { NAME_SPACE, /** - * If the name space if global, the class that defined the model is - * stored in the vertex definition class property, which is requried by + * If the name space is global, the class that defines the model is + * stored in the vertex definition class property, which is required by * parts of the Carnival machinery. */ VERTEX_DEFINITION_CLASS diff --git a/app/carnival-graph/src/main/groovy/carnival/graph/VertexDefinition.groovy b/app/carnival-graph/src/main/groovy/carnival/graph/VertexDefinition.groovy index d57d8fa..0c00ba4 100644 --- a/app/carnival-graph/src/main/groovy/carnival/graph/VertexDefinition.groovy +++ b/app/carnival-graph/src/main/groovy/carnival/graph/VertexDefinition.groovy @@ -70,6 +70,9 @@ trait VertexDefinition extends ElementDefinition { */ Boolean isClass = null + // NOTE: propertyDefs come from WithPropertyDefsTrait, via + // ElementDefinition extends WithPropertyDefsTrait + /////////////////////////////////////////////////////////////////////////// // GETTERS / SETTERS diff --git a/app/carnival-graph/src/test/groovy/carnival/graph/EdgeDefTraitSpec.groovy b/app/carnival-graph/src/test/groovy/carnival/graph/EdgeDefinitionSpec.groovy similarity index 100% rename from app/carnival-graph/src/test/groovy/carnival/graph/EdgeDefTraitSpec.groovy rename to app/carnival-graph/src/test/groovy/carnival/graph/EdgeDefinitionSpec.groovy diff --git a/app/carnival-graph/src/test/groovy/carnival/graph/PropertyDefTraitSpec.groovy b/app/carnival-graph/src/test/groovy/carnival/graph/PropertyDefinitionSpec.groovy similarity index 100% rename from app/carnival-graph/src/test/groovy/carnival/graph/PropertyDefTraitSpec.groovy rename to app/carnival-graph/src/test/groovy/carnival/graph/PropertyDefinitionSpec.groovy diff --git a/app/carnival-graph/src/test/groovy/carnival/graph/VertexDefSpec.groovy b/app/carnival-graph/src/test/groovy/carnival/graph/VertexDefSpec.groovy deleted file mode 100644 index 46c10f1..0000000 --- a/app/carnival-graph/src/test/groovy/carnival/graph/VertexDefSpec.groovy +++ /dev/null @@ -1,91 +0,0 @@ -package carnival.graph - - - -import spock.lang.Specification -import spock.lang.Unroll -import spock.lang.Shared - -import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph -import org.apache.tinkerpop.gremlin.structure.T -import org.apache.tinkerpop.gremlin.process.traversal.Traversal -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource -import org.apache.tinkerpop.gremlin.structure.Vertex - - - -/** - * gradle test --tests "carnival.graph.VertexDefSpec" - * - */ -class VertexDefSpec extends Specification { - - static enum VX implements VertexDefinition { - THING, - - THING_1( - vertexProperties:[ - PX.PROP_A.withConstraints(required:true), - PX.PROP_B - ] - ), - - private VX() {} - private VX(Map m) {m.each { k,v -> this."$k" = v }} - } - - - static enum PX implements PropertyDefinition { - PROP_A, - PROP_B - } - - - - /////////////////////////////////////////////////////////////////////////// - // FIELDS - /////////////////////////////////////////////////////////////////////////// - - @Shared graph - @Shared g - - - - /////////////////////////////////////////////////////////////////////////// - // SET UP - /////////////////////////////////////////////////////////////////////////// - - - def setupSpec() { - } - - def setup() { - graph = TinkerGraph.open() - g = graph.traversal() - } - - def cleanup() { - if (g) g.close() - if (graph) graph.close() - } - - def cleanupSpec() { - } - - - - /////////////////////////////////////////////////////////////////////////// - // TESTS - /////////////////////////////////////////////////////////////////////////// - - def "lookup"() { - when: - Vertex v1 = VX.THING.instance().create(graph) - VertexDefinition d1 = Definition.lookup(v1) - - then: - d1 == VX.THING - } - -} - diff --git a/app/carnival-graph/src/test/groovy/carnival/graph/VertexDefTraitSpec.groovy b/app/carnival-graph/src/test/groovy/carnival/graph/VertexDefTraitSpec.groovy deleted file mode 100644 index 72d6edf..0000000 --- a/app/carnival-graph/src/test/groovy/carnival/graph/VertexDefTraitSpec.groovy +++ /dev/null @@ -1,351 +0,0 @@ -package carnival.graph - - - -import spock.lang.Specification -import spock.lang.Unroll -import spock.lang.Shared - -import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph -import org.apache.tinkerpop.gremlin.structure.T -import org.apache.tinkerpop.gremlin.process.traversal.Traversal -import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource -import org.apache.tinkerpop.gremlin.structure.VertexProperty -//import static org.apache.tinkerpop.gremlin.neo4j.process.traversal.LabelP.of - - - -/** - * gradle test --tests "carnival.graph.VertexDefinitionSpec" - * - */ -class VertexDefinitionSpec extends Specification { - - static enum VX implements VertexDefinition { - THING, - - THING_1( - vertexProperties:[ - PX.PROP_A.withConstraints(required:true) - ] - ), - - THING_2( - vertexProperties:[ - PX.PROP_A - ] - ), - - THING_3( - vertexProperties:[ - PX.PROP_A.defaultValue(1).withConstraints(required:true) - ] - ), - - THING_4( - vertexProperties:[ - PX.PROP_A.withConstraints(required:true), - PX.PROP_B - ] - ), - - THING_5(propertiesMustBeDefined:false), - - A_CLASS, - B_CLASS ( - superClass: VX.A_CLASS - ), - B ( - instanceOf: VX.B_CLASS - ), - - CLASS_OF_SOMETHING ( - isClass: true - ), - - NOT_A_CLASS ( - isClass: false - ) - - private VX() {} - private VX(Map m) {m.each { k,v -> this."$k" = v }} - } - - - static enum PX implements PropertyDefinition { - PROP_A, - PROP_B - } - - - - /////////////////////////////////////////////////////////////////////////// - // FIELDS - /////////////////////////////////////////////////////////////////////////// - - @Shared graph - @Shared g - - - - /////////////////////////////////////////////////////////////////////////// - // SET UP - /////////////////////////////////////////////////////////////////////////// - - - def setupSpec() { - } - - def setup() { - graph = TinkerGraph.open() - g = graph.traversal() - } - - def cleanup() { - if (g) g.close() - if (graph) graph.close() - } - - def cleanupSpec() { - } - - - - /////////////////////////////////////////////////////////////////////////// - // TESTS - /////////////////////////////////////////////////////////////////////////// - - def "instanceOf edge is automatically created"() { - setup: - // these have to be explicitly set as we are not using Carnival, just - // creating a TinkerGraph and testing VertexDefinition in isolation - if (!VX.A_CLASS.vertex) VX.A_CLASS.vertex = VX.A_CLASS.instance().create(graph) - if (!VX.B_CLASS.vertex) VX.B_CLASS.vertex = VX.B_CLASS.instance().create(graph) - - when: - def b = VX.B.instance().create(graph) - - then: - b != null - g.V(b) - .out(Base.EX.IS_INSTANCE_OF) - .is(VX.B_CLASS.vertex) - .tryNext().isPresent() - } - - - class Something implements VertexDefinition { - String name - String name() { - this.name - } - } - - def "cannot set superclass unless is a class"() { - when: - def s = new Something(name:"a") - - then: - !s.isClass() - - when: - s.superClass = VX.THING - - then: - Exception e = thrown() - } - - - def "cannot set instanceof of class"() { - when: - def s = new Something(name:"a_class") - - then: - s.isClass() - - when: - s.instanceOf = VX.THING - - then: - Exception e = thrown() - - } - - - def "explicit isClass"() { - expect: - VX.CLASS_OF_SOMETHING.isClass() - !VX.NOT_A_CLASS.isClass() - VX.A_CLASS.isClass - VX.A_CLASS.isClass() - } - - - def "can add undefined props on switch"() { - when: - def v1 = VX.THING_5.instance().withProperty(PX.PROP_A, 'a').create(graph) - - then: - noExceptionThrown() - } - - - def "properties must be defined by default"() { - when: - def v1 = VX.THING.instance().withProperty(PX.PROP_A, 'a').create(graph) - - then: - Exception e = thrown() - e instanceof IllegalArgumentException - //e.printStackTrace() - } - - - def "two defined properties"() { - when: - def v1 = VX.THING_4.instance().withProperties( - PX.PROP_A, 'a', - PX.PROP_B, 'b' - ).create(graph) - v1.property('someOtherProp', 'qq') - def dps1 = VX.THING_4.definedPropertiesOf(v1) - println "dps1: $dps1" - - then: - dps1 != null - dps1.size() == 2 - dps1.find { it.label == PX.PROP_A.label } - dps1.find { it.label == PX.PROP_B.label } - - when: - def dp1 = dps1.find { it.label == PX.PROP_A.label } - - then: - dp1.label() == PX.PROP_A.label - dp1.value() == 'a' - - when: - def dp2 = dps1.find { it.label == PX.PROP_B.label } - - then: - dp2.label() == PX.PROP_B.label - dp2.value() == 'b' - } - - - def "one defined property"() { - when: - def v1 = VX.THING_4.instance().withProperty(PX.PROP_A, 'a').create(graph) - v1.property('someOtherProp', 'qq') - def dps1 = VX.THING_4.definedPropertiesOf(v1) - println "dps1: $dps1" - - then: - dps1 != null - dps1.size() == 1 - - when: - def dp1 = dps1.first() - - then: - dp1 instanceof VertexProperty - dp1.label() == PX.PROP_A.label - dp1.value() == 'a' - } - - - def "controlled instance vertex enum"() { - given: - def v - - when: - v = VX.THING.instance().vertex(graph, g) - - then: - v - !v.property(Base.PX.IS_CLASS.label).isPresent() - v.property(Base.PX.NAME_SPACE.label).isPresent() - v.value(Base.PX.NAME_SPACE.label) == 'carnival.graph.VertexDefinitionSpec$VX' - } - - - def "controlled instance vertex object"() { - given: - def v - def vDef - - when: - vDef = new DynamicVertexDef('THING_2') - - then: - vDef instanceof DynamicVertexDef - vDef.getNameSpace() == 'carnival.graph.DynamicVertexDef' - - when: - vDef.nameSpace = 'some.custom.NameSpace' - - then: - vDef.nameSpace == 'some.custom.NameSpace' - - when: - v = vDef.instance().vertex(graph, g) - - then: - v - !v.property(Base.PX.IS_CLASS.label).isPresent() - v.property(Base.PX.NAME_SPACE.label).isPresent() - v.value(Base.PX.NAME_SPACE.label) == 'some.custom.NameSpace' - } - - - def "createVertex enum"() { - given: - def v - - expect: - VX.THING.getNameSpace() == 'carnival.graph.VertexDefinitionSpec$VX' - - when: - v = VX.THING.instance().vertex(graph, g) - - then: - v - !v.property(Base.PX.IS_CLASS.label).isPresent() - v.property(Base.PX.NAME_SPACE.label).isPresent() - v.value(Base.PX.NAME_SPACE.label) == 'carnival.graph.VertexDefinitionSpec$VX' - } - - - - def "createVertex object"() { - given: - def v - def vDef - - when: - vDef = new DynamicVertexDef('THING_2') - - then: - vDef instanceof DynamicVertexDef - vDef.getNameSpace() == 'carnival.graph.DynamicVertexDef' - - when: - vDef.nameSpace = 'some.custom.NameSpace' - - then: - vDef.nameSpace == 'some.custom.NameSpace' - - when: - v = vDef.instance().vertex(graph, g) - - then: - v - !v.property(Base.PX.IS_CLASS.label).isPresent() - v.property(Base.PX.NAME_SPACE.label).isPresent() - v.value(Base.PX.NAME_SPACE.label) == 'some.custom.NameSpace' - } - - - -} - diff --git a/app/carnival-graph/src/test/groovy/carnival/graph/VertexDefinitionSpec.groovy b/app/carnival-graph/src/test/groovy/carnival/graph/VertexDefinitionSpec.groovy index db0eda7..ff87fd3 100644 --- a/app/carnival-graph/src/test/groovy/carnival/graph/VertexDefinitionSpec.groovy +++ b/app/carnival-graph/src/test/groovy/carnival/graph/VertexDefinitionSpec.groovy @@ -10,63 +10,72 @@ import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph import org.apache.tinkerpop.gremlin.structure.T import org.apache.tinkerpop.gremlin.process.traversal.Traversal import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource +import org.apache.tinkerpop.gremlin.structure.VertexProperty import org.apache.tinkerpop.gremlin.structure.Vertex -import org.apache.tinkerpop.gremlin.structure.Edge +//import static org.apache.tinkerpop.gremlin.neo4j.process.traversal.LabelP.of /** - * gradle test --tests "carnival.graph.VertexModelSpec" + * gradle test --tests "carnival.graph.VertexDefinitionSpec" * */ -class VertexModelSpec extends Specification { - - @VertexModel - static enum VX { - THING_1(PX) - - /*VX(Class aClass) { - println "aClass: ${aClass}" - if (aClass.isEnum()) { - aClass.values().each { - this.propertyDefs.add(it) - } - } - }*/ - - /*VX(Enum propertyDefEnum) { - println "aString: ${aString}" - println "anInteger: ${anInteger}" - propertyDefEnum.values().each { - this.propertyDefs.add(it) - } - }*/ - - /*VX(Class enumClass) { - if (enumClass.isEnum()) { - def vals = enumClass.values() - for (int i=0; i this."$k" = v }} + } - @PropertyModel - static enum PX { + static enum PX implements PropertyDefinition { PROP_A, - PROP_B, - PROP_C + PROP_B } @@ -107,13 +116,247 @@ class VertexModelSpec extends Specification { // TESTS /////////////////////////////////////////////////////////////////////////// + def "instanceOf edge is automatically created"() { + setup: + // these have to be explicitly set as we are not using Carnival, just + // creating a TinkerGraph and testing VertexDefinition in isolation + if (!VX.A_CLASS.vertex) VX.A_CLASS.vertex = VX.A_CLASS.instance().create(graph) + if (!VX.B_CLASS.vertex) VX.B_CLASS.vertex = VX.B_CLASS.instance().create(graph) + + when: + def b = VX.B.instance().create(graph) + + then: + b != null + g.V(b) + .out(Base.EX.IS_INSTANCE_OF) + .is(VX.B_CLASS.vertex) + .tryNext().isPresent() + } + + + class Something implements VertexDefinition { + String name + String name() { + this.name + } + } + + def "cannot set superclass unless is a class"() { + when: + def s = new Something(name:"a") + + then: + !s.isClass() + + when: + s.superClass = VX.THING + + then: + Exception e = thrown() + } + + + def "cannot set instanceof of class"() { + when: + def s = new Something(name:"a_class") + + then: + s.isClass() + + when: + s.instanceOf = VX.THING + + then: + Exception e = thrown() + + } - def "vertex props"() { + def "explicit isClass"() { expect: - VX.THING_1.propertyDefs != null - VX.THING_1.propertyDefs.size() == 3 + VX.CLASS_OF_SOMETHING.isClass() + !VX.NOT_A_CLASS.isClass() + VX.A_CLASS.isClass + VX.A_CLASS.isClass() } + + def "can add undefined props on switch"() { + when: + def v1 = VX.THING_5.instance().withProperty(PX.PROP_A, 'a').create(graph) + + then: + noExceptionThrown() + } + + + def "properties must be defined by default"() { + when: + def v1 = VX.THING.instance().withProperty(PX.PROP_A, 'a').create(graph) + + then: + Exception e = thrown() + e instanceof IllegalArgumentException + //e.printStackTrace() + } + + + def "two defined properties"() { + when: + def v1 = VX.THING_4.instance().withProperties( + PX.PROP_A, 'a', + PX.PROP_B, 'b' + ).create(graph) + v1.property('someOtherProp', 'qq') + def dps1 = VX.THING_4.definedPropertiesOf(v1) + println "dps1: $dps1" + + then: + dps1 != null + dps1.size() == 2 + dps1.find { it.label == PX.PROP_A.label } + dps1.find { it.label == PX.PROP_B.label } + + when: + def dp1 = dps1.find { it.label == PX.PROP_A.label } + + then: + dp1.label() == PX.PROP_A.label + dp1.value() == 'a' + + when: + def dp2 = dps1.find { it.label == PX.PROP_B.label } + + then: + dp2.label() == PX.PROP_B.label + dp2.value() == 'b' + } + + + def "one defined property"() { + when: + def v1 = VX.THING_4.instance().withProperty(PX.PROP_A, 'a').create(graph) + v1.property('someOtherProp', 'qq') + def dps1 = VX.THING_4.definedPropertiesOf(v1) + println "dps1: $dps1" + + then: + dps1 != null + dps1.size() == 1 + + when: + def dp1 = dps1.first() + + then: + dp1 instanceof VertexProperty + dp1.label() == PX.PROP_A.label + dp1.value() == 'a' + } + + + def "controlled instance vertex enum"() { + given: + def v + + when: + v = VX.THING.instance().vertex(graph, g) + + then: + v + !v.property(Base.PX.IS_CLASS.label).isPresent() + v.property(Base.PX.NAME_SPACE.label).isPresent() + v.value(Base.PX.NAME_SPACE.label) == 'carnival.graph.VertexDefinitionSpec$VX' + } + + + def "controlled instance vertex object"() { + given: + def v + def vDef + + when: + vDef = new DynamicVertexDef('THING_2') + + then: + vDef instanceof DynamicVertexDef + vDef.getNameSpace() == 'carnival.graph.DynamicVertexDef' + + when: + vDef.nameSpace = 'some.custom.NameSpace' + + then: + vDef.nameSpace == 'some.custom.NameSpace' + + when: + v = vDef.instance().vertex(graph, g) + + then: + v + !v.property(Base.PX.IS_CLASS.label).isPresent() + v.property(Base.PX.NAME_SPACE.label).isPresent() + v.value(Base.PX.NAME_SPACE.label) == 'some.custom.NameSpace' + } + + + def "createVertex enum"() { + given: + def v + + expect: + VX.THING.getNameSpace() == 'carnival.graph.VertexDefinitionSpec$VX' + + when: + v = VX.THING.instance().vertex(graph, g) + + then: + v + !v.property(Base.PX.IS_CLASS.label).isPresent() + v.property(Base.PX.NAME_SPACE.label).isPresent() + v.value(Base.PX.NAME_SPACE.label) == 'carnival.graph.VertexDefinitionSpec$VX' + } + + + + def "createVertex object"() { + given: + def v + def vDef + + when: + vDef = new DynamicVertexDef('THING_2') + + then: + vDef instanceof DynamicVertexDef + vDef.getNameSpace() == 'carnival.graph.DynamicVertexDef' + + when: + vDef.nameSpace = 'some.custom.NameSpace' + + then: + vDef.nameSpace == 'some.custom.NameSpace' + + when: + v = vDef.instance().vertex(graph, g) + + then: + v + !v.property(Base.PX.IS_CLASS.label).isPresent() + v.property(Base.PX.NAME_SPACE.label).isPresent() + v.value(Base.PX.NAME_SPACE.label) == 'some.custom.NameSpace' + } + + + def "lookup"() { + when: + Vertex v1 = VX.THING.instance().create(graph) + VertexDefinition d1 = Definition.lookup(v1) + + then: + d1 == VX.THING + } + + + } diff --git a/app/carnival-graph/src/test/groovy/carnival/graph/VertexModelSpec.groovy b/app/carnival-graph/src/test/groovy/carnival/graph/VertexModelSpec.groovy new file mode 100644 index 0000000..db0eda7 --- /dev/null +++ b/app/carnival-graph/src/test/groovy/carnival/graph/VertexModelSpec.groovy @@ -0,0 +1,119 @@ +package carnival.graph + + + +import spock.lang.Specification +import spock.lang.Unroll +import spock.lang.Shared + +import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerGraph +import org.apache.tinkerpop.gremlin.structure.T +import org.apache.tinkerpop.gremlin.process.traversal.Traversal +import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource +import org.apache.tinkerpop.gremlin.structure.Vertex +import org.apache.tinkerpop.gremlin.structure.Edge + + + +/** + * gradle test --tests "carnival.graph.VertexModelSpec" + * + */ +class VertexModelSpec extends Specification { + + @VertexModel + static enum VX { + THING_1(PX) + + /*VX(Class aClass) { + println "aClass: ${aClass}" + if (aClass.isEnum()) { + aClass.values().each { + this.propertyDefs.add(it) + } + } + }*/ + + /*VX(Enum propertyDefEnum) { + println "aString: ${aString}" + println "anInteger: ${anInteger}" + propertyDefEnum.values().each { + this.propertyDefs.add(it) + } + }*/ + + /*VX(Class enumClass) { + if (enumClass.isEnum()) { + def vals = enumClass.values() + for (int i=0; i 1) throw new RuntimeException("multiple matches for $methodName: ${matches}") - if (matches.size() < 1) return null - def match = matches.first() + // if no matches, we need to return null + if (matches.size() == 0) return null + + // if there is only one match, we want to return it whether + // it was defined in the 'this' class or not + if (matches.size() == 1) return matches[0] + + // there are multiple matches, try to find the one defined in + // this class. this needs to be refined to look up the inheritance + // tree and pick the first that matches. + matches = matches.findAll({ + it.enclosingClass == this.class + }) + + // if matches does not equal 1 exactly, it means that there were + // multiple matches that could not be resolved + if (matches.size() != 1) throw new RuntimeException("multiple matches for $methodName: ${matches}") + + def match = matches[0] return match } diff --git a/app/carnival-util/src/test/groovy/carnival/util/MethodsHolderSpec.groovy b/app/carnival-util/src/test/groovy/carnival/util/MethodsHolderSpec.groovy index 0a7c887..f012d02 100644 --- a/app/carnival-util/src/test/groovy/carnival/util/MethodsHolderSpec.groovy +++ b/app/carnival-util/src/test/groovy/carnival/util/MethodsHolderSpec.groovy @@ -12,19 +12,19 @@ interface MhsSomeInterface { } class MhsParentHolder implements MethodsHolder { - class Method1 implements MhsSomeInterface { } - } class MhsChildHolder extends MhsParentHolder { - class Method2 implements MhsSomeInterface { } - } +class MhsChildHolderOverride extends MhsParentHolder { + class Method1 implements MhsSomeInterface { } +} + public class MethodsHolderSpec extends Specification { @@ -35,6 +35,42 @@ public class MethodsHolderSpec extends Specification { // TESTS /////////////////////////////////////////////////////////////////////////// + void "can override a method"() { + when: + def mh1 = new MhsParentHolder() + def mh1classes = mh1.allMethodClasses(MhsSomeInterface) + + then: + mh1classes.size() == 1 + mh1classes[0] == MhsParentHolder.Method1 + + when: + def mh2 = new MhsChildHolderOverride() + def mh2classes = mh2.allMethodClasses(MhsSomeInterface) + + then: + mh2classes.size() == 2 + mh2classes.contains(MhsParentHolder.Method1) + mh2classes.contains(MhsChildHolderOverride.Method1) + + when: + def mh2MatchingClasses = mh2.findAllMethodClasses(MhsSomeInterface, 'Method1') + + then: + mh2MatchingClasses.size() == 2 + + when: + def mh2SpecificMatch = mh2.findMethodClass(MhsSomeInterface, 'Method1') + println "mh2SpecificMatch: ${mh2SpecificMatch} ${mh2SpecificMatch.enclosingClass}" + println "mh2SpecificMatch: ${mh2SpecificMatch.declaredClasses} ${mh2SpecificMatch.declaringClass} ${mh2SpecificMatch.superclass}" + + then: + mh2SpecificMatch != null + mh2SpecificMatch.enclosingClass == MhsChildHolderOverride + mh2SpecificMatch.name.contains('Method1') + } + + void "allMethodClasses finds methods up inheritance chain"() { when: def mh1 = new MhsParentHolder()