From d2b6106e75c9edcac210b17a39eff7c33723f7bb Mon Sep 17 00:00:00 2001 From: Michael Pollmeier Date: Tue, 30 Apr 2024 13:17:46 +0200 Subject: [PATCH 1/3] port (most of) TraversalTests to generated schema --- .../generic/neighboraccessors/NodeA.scala | 8 +- .../testdomains/generic/Schema.scala | 2 +- .../flatgraph/traversal/TraversalTests.scala | 91 ++++++++++--------- 3 files changed, 54 insertions(+), 47 deletions(-) rename {core => tests}/src/test/scala/flatgraph/traversal/TraversalTests.scala (60%) diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/generic/neighboraccessors/NodeA.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/generic/neighboraccessors/NodeA.scala index 42be492a..c8cede30 100644 --- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/generic/neighboraccessors/NodeA.scala +++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/generic/neighboraccessors/NodeA.scala @@ -9,12 +9,12 @@ final class AccessNeighborsForNodeA(val node: nodes.NodeA) extends AnyVal { */ def nodeAViaConnectedToIn: Iterator[nodes.NodeA] = connectedToIn.collectAll[nodes.NodeA] - /** Traverse to node_a via connected_to OUT edge. + /** connected node Traverse to node_a via connected_to OUT edge. */ @deprecated("please use connectedTo instead") def nodeAViaConnectedToOut: Iterator[nodes.NodeA] = connectedTo - /** Traverse to node_a via connected_to OUT edge. + /** connected node Traverse to node_a via connected_to OUT edge. */ def connectedTo: Iterator[nodes.NodeA] = connectedToOut.collectAll[nodes.NodeA] @@ -29,11 +29,11 @@ final class AccessNeighborsForNodeATraversal(val traversal: Iterator[nodes.NodeA */ def nodeAViaConnectedToIn: Iterator[nodes.NodeA] = traversal.flatMap(_.nodeAViaConnectedToIn) - /** Traverse to node_a via connected_to OUT edge. + /** connected node Traverse to node_a via connected_to OUT edge. */ def connectedTo: Iterator[nodes.NodeA] = traversal.flatMap(_.connectedTo) - /** Traverse to node_a via connected_to OUT edge. + /** connected node Traverse to node_a via connected_to OUT edge. */ @deprecated("please use connectedTo instead") def nodeAViaConnectedToOut: Iterator[nodes.NodeA] = traversal.flatMap(_.nodeAViaConnectedToOut) diff --git a/test-schemas/src/main/scala/flatgraph/testdomains/generic/Schema.scala b/test-schemas/src/main/scala/flatgraph/testdomains/generic/Schema.scala index 605444bc..8b3e4110 100644 --- a/test-schemas/src/main/scala/flatgraph/testdomains/generic/Schema.scala +++ b/test-schemas/src/main/scala/flatgraph/testdomains/generic/Schema.scala @@ -33,7 +33,7 @@ object Schema { // TODO add support for edge properties with cardinality ONE and LIST val connectedTo = builder.addEdgeType("connected_to").addProperty(stringMandatory) - nodeA.addOutEdge(connectedTo, nodeA, stepNameOut = "connectedTo") + nodeA.addOutEdge(connectedTo, nodeA, stepNameOut = "connectedTo", stepNameOutDoc = "Connected neighbor node") builder.build } diff --git a/core/src/test/scala/flatgraph/traversal/TraversalTests.scala b/tests/src/test/scala/flatgraph/traversal/TraversalTests.scala similarity index 60% rename from core/src/test/scala/flatgraph/traversal/TraversalTests.scala rename to tests/src/test/scala/flatgraph/traversal/TraversalTests.scala index c46a3421..1ecf3d3b 100644 --- a/core/src/test/scala/flatgraph/traversal/TraversalTests.scala +++ b/tests/src/test/scala/flatgraph/traversal/TraversalTests.scala @@ -1,29 +1,36 @@ package flatgraph.traversal -import flatgraph.Implicits.start -import flatgraph.GNode -import flatgraph.help.{DocSearchPackages, Table} import flatgraph.help.Table.AvailableWidthProvider -import flatgraph.traversal.Language.* -import flatgraph.traversal.testdomains.simple.SimpleDomain.{Connection, Thing} -import flatgraph.traversal.testdomains.simple.{ExampleGraphSetup, SimpleDomain} +import flatgraph.help.{DocSearchPackages, Table} +import flatgraph.testdomains.generic.GenericDomain +import flatgraph.testdomains.generic.Language.* +import flatgraph.testdomains.generic.edges.ConnectedTo +import flatgraph.testdomains.generic.nodes.NodeA +import flatgraph.{GNode, TestGraphs} import org.scalatest.matchers.should.Matchers.* import org.scalatest.wordspec.AnyWordSpec import scala.collection.mutable -class TraversalTests extends AnyWordSpec with ExampleGraphSetup { - /* most tests work with this simple graph: +class TraversalTests extends AnyWordSpec { + + /* sample graph: * L3 <- L2 <- L1 <- Center -> R1 -> R2 -> R3 -> R4 -> R5 */ - def centerTrav = Iterator.single(center) + val flatlineGraph = TestGraphs.createFlatlineGraph() + def centerTrav = flatlineGraph.nodeA.stringMandatory("Center") - "GNode traversals" in { - centerTrav.label.l shouldBe Seq(Thing.Label) + "domain specific traversals" in { + centerTrav.connectedTo.size shouldBe 2 + centerTrav.connectedToIn.size shouldBe 0 + } + + "generic GNode traversals" in { + centerTrav.label.l shouldBe Seq(NodeA.Label) centerTrav.outE.size shouldBe 2 centerTrav.inE.size shouldBe 0 - centerTrav.outE(Connection.Label).size shouldBe 2 - centerTrav.inE(Connection.Label).size shouldBe 0 + centerTrav.outE(ConnectedTo.Label).size shouldBe 2 + centerTrav.inE(ConnectedTo.Label).size shouldBe 0 } "can only be iterated once" in { @@ -37,9 +44,9 @@ class TraversalTests extends AnyWordSpec with ExampleGraphSetup { } ".sideEffect step should apply provided function and do nothing else" in { - val sack = mutable.ListBuffer.empty[GNode] - center.start.out.sideEffect(sack.addOne).out.toSetMutable shouldBe Set(l2, r2) - sack.toSet shouldBe Set(l1, r1) + val sack = mutable.ListBuffer.empty[NodeA] + centerTrav.connectedTo.sideEffect(sack.addOne).connectedTo.stringMandatory.toSetMutable shouldBe Set("L2", "R2") + sack.map(_.stringMandatory).toSet shouldBe Set("L1", "R1") } ".dedup step" should { @@ -122,35 +129,35 @@ class TraversalTests extends AnyWordSpec with ExampleGraphSetup { } "give a domain overview" in { - import flatgraph.traversal.testdomains.simple.SimpleDomain - - val helpText = SimpleDomain.help + given DocSearchPackages = GenericDomain.defaultDocSearchPackage + val helpText = GenericDomain.help // should list starter steps etc. - helpText should include(".things") - helpText should include("all things") + helpText should include(".nodeA") + helpText should include(".nodeB") + helpText should include("all nodes") } - "provide node-specific overview" when { - "using simple domain" in { - val thingTraversal = SimpleDomain.traversal(SimpleDomain.newGraph).things - val thingTraversalHelp = thingTraversal.help - - thingTraversalHelp should include(".name") // step from `flatgraph.traversal.testdomains.simple.SimpleDomainTraversal` - thingTraversalHelp should include(".sideEffect") // step from Traversal - thingTraversalHelp should include(".label") // step from ElementTraversal - thingTraversalHelp should include(".out") // step from NodeTraversal - - // scala generates additional `fooBar$extension` methods, but those don't matter in the context of .help/@Doc - thingTraversalHelp shouldNot include("$extension") - - val thingTraversalHelpVerbose = thingTraversal.helpVerbose - thingTraversalHelpVerbose should include("name of the Thing") - thingTraversalHelpVerbose should include("simple.SimpleDomainTravers") - thingTraversalHelpVerbose should include("node label") - thingTraversalHelpVerbose should include("flatgraph.traversal.NodeSteps") - thingTraversalHelpVerbose should include("result to a list") - thingTraversalHelpVerbose should include("flatgraph.traversal.GenericSt") - } + "provide node-specific overview" in { + val nodeATraversal = flatlineGraph.nodeA + val nodeATraversalHelp = nodeATraversal.help + + // TODO bring these back, by generating the @Doc annotations +// nodeATraversalHelp should include(".connectedTo") // step from `flatgraph.traversal.testdomains.simple.SimpleDomainTraversal` + nodeATraversalHelp should include(".sideEffect") // step from Traversal + nodeATraversalHelp should include(".label") // step from ElementTraversal + nodeATraversalHelp should include(".out") // step from NodeTraversal + + // scala generates additional `fooBar$extension` methods, but those don't matter in the context of .help/@Doc + nodeATraversalHelp shouldNot include("$extension") + + val thingTraversalHelpVerbose = nodeATraversal.helpVerbose + // TODO bring these back, by generating the @Doc annotations +// thingTraversalHelpVerbose should include("name of the Thing") +// thingTraversalHelpVerbose should include("simple.SimpleDomainTravers") + thingTraversalHelpVerbose should include("node label") + thingTraversalHelpVerbose should include("flatgraph.traversal.NodeSteps") + thingTraversalHelpVerbose should include("result to a list") + thingTraversalHelpVerbose should include("flatgraph.traversal.GenericSt") } } From 0512347de4fc790b71f8d98abaa13b5cccb22568 Mon Sep 17 00:00:00 2001 From: Michael Pollmeier Date: Thu, 2 May 2024 09:17:06 +0200 Subject: [PATCH 2/3] port RepeatTraversalTests --- .../generic/neighboraccessors/NodeA.scala | 8 +- .../src/test/scala/flatgraph/TestGraphs.scala | 21 ++- .../flatgraph/algorithm/PathFinderTests.scala | 24 +-- .../traversal/RepeatTraversalTests.scala | 140 ++++++++++-------- .../flatgraph/traversal/TraversalTests.scala | 6 +- 5 files changed, 113 insertions(+), 86 deletions(-) rename {core => tests}/src/test/scala/flatgraph/traversal/RepeatTraversalTests.scala (71%) diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/generic/neighboraccessors/NodeA.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/generic/neighboraccessors/NodeA.scala index c8cede30..bba53b74 100644 --- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/generic/neighboraccessors/NodeA.scala +++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/generic/neighboraccessors/NodeA.scala @@ -9,12 +9,12 @@ final class AccessNeighborsForNodeA(val node: nodes.NodeA) extends AnyVal { */ def nodeAViaConnectedToIn: Iterator[nodes.NodeA] = connectedToIn.collectAll[nodes.NodeA] - /** connected node Traverse to node_a via connected_to OUT edge. + /** Connected neighbor node Traverse to node_a via connected_to OUT edge. */ @deprecated("please use connectedTo instead") def nodeAViaConnectedToOut: Iterator[nodes.NodeA] = connectedTo - /** connected node Traverse to node_a via connected_to OUT edge. + /** Connected neighbor node Traverse to node_a via connected_to OUT edge. */ def connectedTo: Iterator[nodes.NodeA] = connectedToOut.collectAll[nodes.NodeA] @@ -29,11 +29,11 @@ final class AccessNeighborsForNodeATraversal(val traversal: Iterator[nodes.NodeA */ def nodeAViaConnectedToIn: Iterator[nodes.NodeA] = traversal.flatMap(_.nodeAViaConnectedToIn) - /** connected node Traverse to node_a via connected_to OUT edge. + /** Connected neighbor node Traverse to node_a via connected_to OUT edge. */ def connectedTo: Iterator[nodes.NodeA] = traversal.flatMap(_.connectedTo) - /** connected node Traverse to node_a via connected_to OUT edge. + /** Connected neighbor node Traverse to node_a via connected_to OUT edge. */ @deprecated("please use connectedTo instead") def nodeAViaConnectedToOut: Iterator[nodes.NodeA] = traversal.flatMap(_.nodeAViaConnectedToOut) diff --git a/tests/src/test/scala/flatgraph/TestGraphs.scala b/tests/src/test/scala/flatgraph/TestGraphs.scala index 28bf9f6c..a278a3df 100644 --- a/tests/src/test/scala/flatgraph/TestGraphs.scala +++ b/tests/src/test/scala/flatgraph/TestGraphs.scala @@ -3,6 +3,7 @@ package flatgraph import flatgraph.testdomains.generic.GenericDomain import flatgraph.testdomains.generic.edges.ConnectedTo import flatgraph.testdomains.generic.nodes.NewNodeA +import flatgraph.testdomains.generic.Language.* import java.nio.file.Path @@ -32,8 +33,7 @@ object TestGraphs { genericDomain } - /** L3 <- L2 <- L1 <- Center -> R1 -> R2 -> R3 -> R4 -> R5 - */ + /** L3 <- L2 <- L1 <- Center -> R1 -> R2 -> R3 -> R4 -> R5 */ def createFlatlineGraph(): GenericDomain = { val genericDomain = GenericDomain.empty val diffGraph = GenericDomain.newDiffGraphBuilder @@ -74,4 +74,21 @@ object TestGraphs { genericDomain } + /** L3 <- L2 <- L1 <- Center -> R1 -> R2 -> R3 -> R4 -> R5 */ + trait FlatlineGraphFixture { + val genericDomain = TestGraphs.createFlatlineGraph() + val Seq(center, l1, l2, l3, r1, r2, r3, r4, r5) = genericDomain.nodeA.sortBy(_.stringMandatory).l + + // verify graph setup + assert(center.stringMandatory == "Center") + assert(l1.stringMandatory == "L1") + assert(l2.stringMandatory == "L2") + assert(l3.stringMandatory == "L3") + assert(r1.stringMandatory == "R1") + assert(r2.stringMandatory == "R2") + assert(r3.stringMandatory == "R3") + assert(r4.stringMandatory == "R4") + assert(r5.stringMandatory == "R5") + } + } diff --git a/tests/src/test/scala/flatgraph/algorithm/PathFinderTests.scala b/tests/src/test/scala/flatgraph/algorithm/PathFinderTests.scala index 4588e5b4..c82cc436 100644 --- a/tests/src/test/scala/flatgraph/algorithm/PathFinderTests.scala +++ b/tests/src/test/scala/flatgraph/algorithm/PathFinderTests.scala @@ -2,31 +2,17 @@ package flatgraph.algorithm import flatgraph.Edge.Direction import flatgraph.TestGraphs +import flatgraph.TestGraphs.FlatlineGraphFixture import flatgraph.algorithm.PathFinder.* import flatgraph.testdomains.generic.Language.* import flatgraph.testdomains.generic.edges.ConnectedTo import org.scalatest.matchers.should.Matchers.* import org.scalatest.wordspec.AnyWordSpec -class PathFinderTests extends AnyWordSpec { - - /* sample graph: - * L3 <- L2 <- L1 <- Center -> R1 -> R2 -> R3 -> R4 -> R5 - */ - val flatlineGraph = TestGraphs.createFlatlineGraph() - val Seq(center, l1, l2, l3, r1, r2, r3, r4, r5) = flatlineGraph.nodeA.sortBy(_.stringMandatory).l - - "verify graph setup" in { - center.stringMandatory shouldBe "Center" - l1.stringMandatory shouldBe "L1" - l2.stringMandatory shouldBe "L2" - l3.stringMandatory shouldBe "L3" - r1.stringMandatory shouldBe "R1" - r2.stringMandatory shouldBe "R2" - r3.stringMandatory shouldBe "R3" - r4.stringMandatory shouldBe "R4" - r5.stringMandatory shouldBe "R5" - } +/* uses 'flat line' sample graph: + * L3 <- L2 <- L1 <- Center -> R1 -> R2 -> R3 -> R4 -> R5 + */ +class PathFinderTests extends AnyWordSpec with FlatlineGraphFixture { "identity" in { val path = PathFinder(center, center) diff --git a/core/src/test/scala/flatgraph/traversal/RepeatTraversalTests.scala b/tests/src/test/scala/flatgraph/traversal/RepeatTraversalTests.scala similarity index 71% rename from core/src/test/scala/flatgraph/traversal/RepeatTraversalTests.scala rename to tests/src/test/scala/flatgraph/traversal/RepeatTraversalTests.scala index 55fc2614..9d8ae5ec 100644 --- a/core/src/test/scala/flatgraph/traversal/RepeatTraversalTests.scala +++ b/tests/src/test/scala/flatgraph/traversal/RepeatTraversalTests.scala @@ -1,17 +1,22 @@ package flatgraph.traversal -import flatgraph.{DiffGraphApplier, DiffGraphBuilder, GNode, GenericDNode, TestHelpers} +import flatgraph.TestGraphs.FlatlineGraphFixture +import flatgraph.traversal.Language.* +import flatgraph.testdomains.generic.Language.* +import flatgraph.testdomains.generic.PropertyKeys.StringMandatory +import flatgraph.* +import flatgraph.testdomains.generic.GenericDomain +import flatgraph.testdomains.generic.edges.ConnectedTo +import flatgraph.testdomains.generic.nodes.{NewNodeA, NodeA} import org.scalatest.matchers.should.Matchers.* import org.scalatest.wordspec.AnyWordSpec -import flatgraph.Implicits.* -import flatgraph.traversal.testdomains.simple.{ExampleGraphSetup, SimpleDomain} -import flatgraph.traversal.testdomains.simple.ExampleGraphSetup.Properties.Name -import flatgraph.traversal.Language.* -import flatgraph.traversal.testdomains.simple.SimpleDomain.{Connection, Thing} import scala.collection.mutable -class RepeatTraversalTests extends AnyWordSpec with ExampleGraphSetup { +/* uses 'flat line' sample graph: + * L3 <- L2 <- L1 <- Center -> R1 -> R2 -> R3 -> R4 -> R5 + */ +class RepeatTraversalTests extends AnyWordSpec with FlatlineGraphFixture { /* most tests work with this simple graph: * L3 <- L2 <- L1 <- Center -> R1 -> R2 -> R3 -> R4 -> R5 */ @@ -56,8 +61,14 @@ class RepeatTraversalTests extends AnyWordSpec with ExampleGraphSetup { "emit nodes that meet given condition" in { val expectedResults = Set("L1", "L2", "L3") centerTrav - .repeat(_.out)(_.emit(_.where(_.property(Name).filter(_.startsWith("L")))).breadthFirstSearch) - .property(Name) + .repeat(_.out)(_.emit(_.where(_.property(StringMandatory).filter(_.startsWith("L")))).breadthFirstSearch) + .property(StringMandatory) + .toSetMutable shouldBe expectedResults + + // with domain specific language + centerTrav + .repeat(_.connectedTo)(_.emit(_.where(_.stringMandatory("L.*"))).breadthFirstSearch) + .stringMandatory .toSetMutable shouldBe expectedResults } @@ -71,54 +82,56 @@ class RepeatTraversalTests extends AnyWordSpec with ExampleGraphSetup { val expectedResults = Set("L2", "R2") centerTrav - .repeat(_.out)(_.until(_.property(Name).filter(_.matches(".*2")))) - .property(Name) + .repeat(_.out)(_.until(_.property(StringMandatory).filter(_.matches(".*2")))) + .property(StringMandatory) .toSetMutable shouldBe expectedResults centerTrav - .repeat(_.out)(_.until(_.property(Name).filter(_.matches(".*2"))).breadthFirstSearch) - .property(Name) + .repeat(_.out)(_.until(_.property(StringMandatory).filter(_.matches(".*2"))).breadthFirstSearch) + .property(StringMandatory) .toSetMutable shouldBe expectedResults } "work in combination with emit" in { val expectedResults = Set("Center", "L1", "L2", "R1", "R2") centerTrav - .repeat(_.out)(_.until(_.property(Name).filter(_.matches(".*2"))).emit) - .property(Name) + .repeat(_.out)(_.until(_.property(StringMandatory).filter(_.matches(".*2"))).emit) + .property(StringMandatory) .toSetMutable shouldBe expectedResults centerTrav - .repeat(_.out)(_.until(_.property(Name).filter(_.matches(".*2"))).emit.breadthFirstSearch) - .property(Name) + .repeat(_.out)(_.until(_.property(StringMandatory).filter(_.matches(".*2"))).emit.breadthFirstSearch) + .property(StringMandatory) .toSetMutable shouldBe expectedResults } "result in 'repeat/until' behaviour, i.e. `until` condition is only evaluated after one iteration" in { val expectedResults = Set("L1", "R1") - centerTrav.repeat(_.out)(_.until(_.hasLabel(Thing.Label))).property(Name).toSetMutable shouldBe expectedResults + centerTrav.repeat(_.out)(_.until(_.hasLabel(NodeA.Label))).property(StringMandatory).toSetMutable shouldBe expectedResults centerTrav - .repeat(_.out)(_.until(_.hasLabel(Thing.Label)).breadthFirstSearch) - .property(Name) + .repeat(_.out)(_.until(_.hasLabel(NodeA.Label)).breadthFirstSearch) + .property(StringMandatory) .toSetMutable shouldBe expectedResults } "be combinable with `.maxDepth`" in { centerTrav - .repeat(_.out)(_.until(_.property(Name).filter(_ == "R2")).maxDepth(3)) - .property(Name) + .repeat(_.out)(_.until(_.property(StringMandatory).filter(_ == "R2")).maxDepth(3)) + .property(StringMandatory) .toSetMutable shouldBe Set("L3", "R2") } } "until and maxDepth" should { "work in combination" in { - centerTrav.repeat(_.out)(_.until(_.property(Name).filter(_ == "R2")).maxDepth(2)).toSetMutable shouldBe Set(l2, r2) - centerTrav.repeat(_.out)(_.breadthFirstSearch.until(_.property(Name).filter(_ == "R2")).maxDepth(2)).toSetMutable shouldBe Set(l2, r2) + centerTrav.repeat(_.out)(_.until(_.property(StringMandatory).filter(_ == "R2")).maxDepth(2)).toSetMutable shouldBe Set(l2, r2) + centerTrav + .repeat(_.out)(_.breadthFirstSearch.until(_.property(StringMandatory).filter(_ == "R2")).maxDepth(2)) + .toSetMutable shouldBe Set(l2, r2) } "work in combination with path" in { centerTrav.enablePathTracking - .repeat(_.out)(_.until(_.property(Name).filter(_ == "R2")).maxDepth(2)) + .repeat(_.out)(_.until(_.property(StringMandatory).filter(_ == "R2")).maxDepth(2)) .path .filter(_.last == r2) .l shouldBe Seq(Vector(center, r1, r2)) @@ -127,36 +140,41 @@ class RepeatTraversalTests extends AnyWordSpec with ExampleGraphSetup { "support repeat/while behaviour" should { "base case: given `whilst` condition is also evaluated for first iteration" in { - centerTrav.repeat(_.out)(_.whilst(_.property(Name).filter(_ == "does not exist"))).toSetMutable shouldBe Set(center) + centerTrav.repeat(_.out)(_.whilst(_.property(StringMandatory).filter(_ == "does not exist"))).toSetMutable shouldBe Set(center) } "walk one iteration" in { - centerTrav.repeat(_.out)(_.whilst(_.property(Name).filter(_ == "Center"))).toSetMutable shouldBe Set(l1, r1) + centerTrav.repeat(_.out)(_.whilst(_.property(StringMandatory).filter(_ == "Center"))).toSetMutable shouldBe Set(l1, r1) } "walk two iterations" in { centerTrav - .repeat(_.out)(_.whilst(_.or(_.property(Name).filter(_.endsWith("1")), _.property(Name).filter(_ == "Center")))) + .repeat(_.out)( + _.whilst(_.or(_.property(StringMandatory).filter(_.endsWith("1")), _.property(StringMandatory).filter(_ == "Center"))) + ) .toSetMutable shouldBe Set(l2, r2) } "emitting nodes along the way" in { - centerTrav.repeat(_.out)(_.emit.whilst(_.property(Name).filter(_ == "Center"))).toSetMutable shouldBe Set(center, l1, r1) - centerTrav.repeat(_.out)(_.emitAllButFirst.whilst(_.property(Name).filter(_ == "Center"))).toSetMutable shouldBe Set(l1, r1) + centerTrav.repeat(_.out)(_.emit.whilst(_.property(StringMandatory).filter(_ == "Center"))).toSetMutable shouldBe Set(center, l1, r1) + centerTrav.repeat(_.out)(_.emitAllButFirst.whilst(_.property(StringMandatory).filter(_ == "Center"))).toSetMutable shouldBe Set( + l1, + r1 + ) } "with path tracking enabled" in { - centerTrav.enablePathTracking.repeat(_.out)(_.whilst(_.property(Name).filter(_ == "Center"))).path.toSetMutable shouldBe Set( - Seq(center, r1), - Seq(center, l1) - ) + centerTrav.enablePathTracking + .repeat(_.out)(_.whilst(_.property(StringMandatory).filter(_ == "Center"))) + .path + .toSetMutable shouldBe Set(Seq(center, r1), Seq(center, l1)) } "be combinable with `.maxDepth`" in { - centerTrav.repeat(_.out)(_.whilst(_.property(Name).filter(_ != "R2")).maxDepth(3)).property(Name).toSetMutable shouldBe Set( - "L3", - "R2" - ) + centerTrav + .repeat(_.out)(_.whilst(_.property(StringMandatory).filter(_ != "R2")).maxDepth(3)) + .property(StringMandatory) + .toSetMutable shouldBe Set("L3", "R2") } } @@ -262,14 +280,14 @@ class RepeatTraversalTests extends AnyWordSpec with ExampleGraphSetup { val traversedNodes = mutable.ListBuffer.empty[GNode] centerTrav.repeat(_.sideEffect(traversedNodes.addOne).out).iterate() - traversedNodes.property(Name).l shouldBe List("Center", "L1", "L2", "L3", "R1", "R2", "R3", "R4", "R5") + traversedNodes.property(StringMandatory).l shouldBe List("Center", "L1", "L2", "L3", "R1", "R2", "R3", "R4", "R5") } "uses BFS (breadth first search) if configured" in { val traversedNodes = mutable.ListBuffer.empty[GNode] centerTrav.repeat(_.sideEffect(traversedNodes.addOne).out)(_.breadthFirstSearch).iterate() - traversedNodes.property(Name).l shouldBe List("Center", "L1", "R1", "L2", "R2", "L3", "R3", "R4", "R5") + traversedNodes.property(StringMandatory).l shouldBe List("Center", "L1", "R1", "L2", "R2", "L3", "R3", "R4", "R5") } "hasNext is idempotent: DFS" in { @@ -279,7 +297,7 @@ class RepeatTraversalTests extends AnyWordSpec with ExampleGraphSetup { // hasNext will run the provided repeat traversal exactly 3 times (as configured) traversal.hasNext shouldBe true traversedNodes.size shouldBe 3 - traversedNodes.property(Name).l shouldBe List("Center", "L1", "L2") + traversedNodes.property(StringMandatory).l shouldBe List("Center", "L1", "L2") // hasNext is idempotent - calling it again doesn't result in any further traversing traversal.hasNext shouldBe true traversedNodes.size shouldBe 3 @@ -292,37 +310,43 @@ class RepeatTraversalTests extends AnyWordSpec with ExampleGraphSetup { // hasNext will run the provided repeat traversal exactly 3 times (as configured) traversal.hasNext shouldBe true traversedNodes.size shouldBe 2 - traversedNodes.property(Name).l shouldBe List("Center", "L1") + traversedNodes.property(StringMandatory).l shouldBe List("Center", "L1") // hasNext is idempotent - calling it again doesn't result in any further traversing traversal.hasNext shouldBe true traversedNodes.size shouldBe 2 } "supports large amount of iterations" in { - // using circular graph so that we can repeat any number of times - val graph = SimpleDomain.newGraph + // create circular graph so that we can repeat any number of times + val genericDomain = GenericDomain.empty + val graph = genericDomain.graph + val diffGraph = GenericDomain.newDiffGraphBuilder - val Seq(a, b, c) = TestHelpers.addNodes(graph, 0.to(2).map(_ => new GenericDNode(0))) + val newA = NewNodeA().stringMandatory("a") + val newB = NewNodeA().stringMandatory("b") + val newC = NewNodeA().stringMandatory("c") val diff = DiffGraphBuilder(graph.schema) - .setNodeProperty(a, Name.name, "a") - .setNodeProperty(b, Name.name, "b") - .setNodeProperty(c, Name.name, "c") - .addEdge(a, b, Connection.Label) - .addEdge(b, c, Connection.Label) - .addEdge(c, a, Connection.Label) + .addEdge(newA, newB, ConnectedTo.Label) + .addEdge(newB, newC, ConnectedTo.Label) + .addEdge(newC, newA, ConnectedTo.Label) DiffGraphApplier.applyDiff(graph, diff) val repeatCount = 100000 - a.start.repeat(_.out)(_.maxDepth(repeatCount)).property(Name).l shouldBe List("b") - a.start.repeat(_.out)(_.maxDepth(repeatCount).breadthFirstSearch).property(Name).l shouldBe List("b") + + genericDomain.nodeA.stringMandatory("a").repeat(_.out)(_.maxDepth(repeatCount)).property(StringMandatory).l shouldBe List("b") + genericDomain.nodeA + .stringMandatory("a") + .repeat(_.out)(_.maxDepth(repeatCount).breadthFirstSearch) + .property(StringMandatory) + .l shouldBe List("b") // for reference: tinkerpop becomes very slow with large iteration counts: // on my machine this didn't terminate within 5mins, hence commenting out // import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.__.__ // __(a).repeat( // __().out().asInstanceOf[org.apache.tinkerpop.gremlin.process.traversal.Traversal[_, Node]] - // ).times(repeatCount).values[String](Name.name).next() shouldBe "b" + // ).times(repeatCount).values[String](StringMandatory.name).next() shouldBe "b" } "support .path step" when { @@ -345,10 +369,10 @@ class RepeatTraversalTests extends AnyWordSpec with ExampleGraphSetup { } "using `until` modulator" in { - centerTrav.enablePathTracking.repeat(_.out)(_.until(_.property(Name).filter(_.endsWith("2")))).path.toSetMutable shouldBe Set( - Seq(center, l1, l2), - Seq(center, r1, r2) - ) + centerTrav.enablePathTracking + .repeat(_.out)(_.until(_.property(StringMandatory).filter(_.endsWith("2")))) + .path + .toSetMutable shouldBe Set(Seq(center, l1, l2), Seq(center, r1, r2)) } "using breadth first search" in { diff --git a/tests/src/test/scala/flatgraph/traversal/TraversalTests.scala b/tests/src/test/scala/flatgraph/traversal/TraversalTests.scala index 1ecf3d3b..3a189d68 100644 --- a/tests/src/test/scala/flatgraph/traversal/TraversalTests.scala +++ b/tests/src/test/scala/flatgraph/traversal/TraversalTests.scala @@ -143,9 +143,9 @@ class TraversalTests extends AnyWordSpec { // TODO bring these back, by generating the @Doc annotations // nodeATraversalHelp should include(".connectedTo") // step from `flatgraph.traversal.testdomains.simple.SimpleDomainTraversal` - nodeATraversalHelp should include(".sideEffect") // step from Traversal - nodeATraversalHelp should include(".label") // step from ElementTraversal - nodeATraversalHelp should include(".out") // step from NodeTraversal + nodeATraversalHelp should include(".sideEffect") // step from Traversal + nodeATraversalHelp should include(".label") // step from ElementTraversal + nodeATraversalHelp should include(".out") // step from NodeTraversal // scala generates additional `fooBar$extension` methods, but those don't matter in the context of .help/@Doc nodeATraversalHelp shouldNot include("$extension") From 3fc58860613eda96cd6b5915bdad38697cc51292 Mon Sep 17 00:00:00 2001 From: Michael Pollmeier Date: Thu, 2 May 2024 09:18:04 +0200 Subject: [PATCH 3/3] remove ExampleGraphSetup --- .../simple/ExampleGraphSetup.scala | 123 ------------------ 1 file changed, 123 deletions(-) delete mode 100644 core/src/test/scala/flatgraph/traversal/testdomains/simple/ExampleGraphSetup.scala diff --git a/core/src/test/scala/flatgraph/traversal/testdomains/simple/ExampleGraphSetup.scala b/core/src/test/scala/flatgraph/traversal/testdomains/simple/ExampleGraphSetup.scala deleted file mode 100644 index 56229215..00000000 --- a/core/src/test/scala/flatgraph/traversal/testdomains/simple/ExampleGraphSetup.scala +++ /dev/null @@ -1,123 +0,0 @@ -package flatgraph.traversal.testdomains.simple - -import flatgraph.help.Table.AvailableWidthProvider -import flatgraph.{DiffGraphApplier, DiffGraphBuilder, FreeSchema, GNode, GenericDNode, Graph, SinglePropertyKey, TestSchema} -import flatgraph.help.{Doc, DocSearchPackages, Traversal, TraversalHelp, TraversalSource} -import flatgraph.traversal.testdomains.simple.SimpleDomain.Thing -import flatgraph.traversal.Language.* - -/* simple example graph: - * L3 <- L2 <- L1 <- Center -> R1 -> R2 -> R3 -> R4 -> R5 - * */ -trait ExampleGraphSetup { - import ExampleGraphSetup.Properties.* - val nonExistingLabel = "this label does not exist" - - val graph = SimpleDomain.newGraph - val l3 = addNode() - val l2 = addNode() - val l1 = addNode() - val center = addNode() - val r1 = addNode() - val r2 = addNode() - val r3 = addNode() - val r4 = addNode() - val r5 = addNode() - - val diff = new DiffGraphBuilder(graph.schema) - // TODO reimplement arrow synax from odb - // center --- Connection.Label --> l1 - // l1 --- Connection.Label --> l2 - // l2 --- Connection.Label --> l3 - // center --- Connection.Label --> r1 - // r1 --- (Connection.Label, Connection.Properties.Distance.of(10)) --> r2 - // r2 --- (Connection.Label, Connection.Properties.Distance.of(10)) --> r3 - // r3 --- (Connection.Label, Connection.Properties.Distance.of(13)) --> r4 - // r4 --- (Connection.Label, Connection.Properties.Distance.of(14)) --> r5 - diff - ._addEdge(center, l1, 0) - ._addEdge(l1, l2, 0) - ._addEdge(l2, l3, 0) - ._addEdge(center, r1, 0) - ._addEdge(r1, r2, 0) - ._addEdge(r2, r3, 0) - ._addEdge(r3, r4, 0) - ._addEdge(r4, r5, 0) - .setNodeProperty(l3, Name.name, "L3") - .setNodeProperty(l2, Name.name, "L2") - .setNodeProperty(l1, Name.name, "L1") - .setNodeProperty(center, Name.name, "Center") - .setNodeProperty(r1, Name.name, "R1") - .setNodeProperty(r2, Name.name, "R2") - .setNodeProperty(r3, Name.name, "R3") - .setNodeProperty(r4, Name.name, "R4") - .setNodeProperty(r5, Name.name, "R5") - DiffGraphApplier.applyDiff(graph, diff) - - def addNode(): GNode = { - val newNode = new GenericDNode(0) - DiffGraphApplier.applyDiff(graph, DiffGraphBuilder(graph.schema).addNode(newNode)) - newNode.storedRef.get // that reference is set by DiffGraphApplier - } -} -object ExampleGraphSetup { - // property keys etc are normally generated by DomainClassesGenerator for a given schema - object Properties { - val Name = SinglePropertyKey(kind = 0, name = "name", default = "") - val NonExisting = SinglePropertyKey(kind = 10, name = "this property key does not exist", default = "default value 0") - } -} - -object SimpleDomain { - class Thing(graph: Graph, nodeKind: Short, seqId: Int) extends GNode(graph, nodeKind, seqId) { - def name: String = ??? - } - object Thing { - val Label = "Thing" - } - - object Connection { - val Label = "Connection" - } - - val defaultDocSearchPackage: DocSearchPackages = DocSearchPackages(getClass.getPackage.getName) - def help(using AvailableWidthProvider) = - TraversalHelp(defaultDocSearchPackage).forTraversalSources(verbose = false) - def helpVerbose(using AvailableWidthProvider) = - TraversalHelp(defaultDocSearchPackage).forTraversalSources(verbose = true) - - def newGraph: Graph = { - val edgeLabels = Array(Connection.Label) - val schema = new FreeSchema( - nodeLabels = Array(Thing.Label), - edgeLabels = edgeLabels, - propertyLabels = Array(ExampleGraphSetup.Properties.Name.name), - propertyNamesByNodeLabel = Map.empty, - edgePropertyPrototypes = new Array(edgeLabels.length), - nodePropertyPrototypes = Array(Array.empty[String]) - ) - Graph(schema) - } - - def traversal(graph: Graph) = new SimpleDomainTraversalSource(graph) -} - -@TraversalSource -class SimpleDomainTraversalSource(graph: Graph) { - - @Doc(info = "all things") - def things: Iterator[Thing] = - graph.nodes("V0").cast[Thing] -} - -/** Example for domain specific extension steps that are defined in a different package. TraversalTests verifies that the .help step finds - * the documentation as specified in @Doc - * - * @param traversal - */ -@Traversal(elementType = classOf[SimpleDomain.Thing]) -class SimpleDomainTraversal(val traversal: Iterator[SimpleDomain.Thing]) extends AnyVal { - - @Doc(info = "name of the Thing") - def name: Iterator[String] = traversal.map(_.name) -}