This is an automated email from the ASF dual-hosted git repository.
spmallette pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/tinkerpop.git
The following commit(s) were added to refs/heads/master by this push:
new 26881ebdc5 Added support for property assertion
26881ebdc5 is described below
commit 26881ebdc562d0c9872b6a094e32750d9e9c6ae0
Author: Stephen Mallette <[email protected]>
AuthorDate: Wed Feb 18 14:26:18 2026 -0500
Added support for property assertion
Property assertion isn't perfect but it's a best effort that at least lets
the test suite exercise this data type a bit. Removed handlers for syntax no
longer supported and fixed up some tests that were impacted. CTR
---
docs/src/dev/developer/for-committers.asciidoc | 9 ++-
gremlin-go/driver/cucumber/cucumberSteps_test.go | 9 +++
gremlin-go/driver/cucumber/gremlin.go | 11 +++-
.../gremlin-javascript/test/cucumber/gremlin.js | 11 +++-
.../src/main/python/tests/feature/feature_steps.py | 9 +++
.../src/main/python/tests/feature/gremlin.py | 11 +++-
.../tinkerpop/gremlin/features/StepDefinition.java | 25 +++----
.../gremlin/test/features/map/Edge.feature | 24 ++-----
.../gremlin/test/features/map/Properties.feature | 77 ++++++++++++++++++----
.../test/features/semantics/Orderability.feature | 64 ++++++++++++++++++
10 files changed, 192 insertions(+), 58 deletions(-)
diff --git a/docs/src/dev/developer/for-committers.asciidoc
b/docs/src/dev/developer/for-committers.asciidoc
index 822909a0c2..09840a706b 100644
--- a/docs/src/dev/developer/for-committers.asciidoc
+++ b/docs/src/dev/developer/for-committers.asciidoc
@@ -412,8 +412,10 @@ included to further qualify the type of numeric. The
following options are avail
* Path - *p[_xxx_,_yyy_,_zzz_,...]* - A comma separated collection of values
that make up the `Path` should be added to
between the square brackets. These values respect the type system thus
allowing for creation of `Path` of vertices,
edges, maps, and any other available type.
+* Property - *prop[_key_,_value_]* - The key is simply a string, and the value
is expected to be a typed value using the
+syntax presented here.
* Set - *s[_xxx_,_yyy_,_zzz_,...]* - A comma separated collection of values
that make up the set should be added to
-between the square brackets. These values respect the type system thus
allowing for creation of sets of vertices,
+between the square brackets. These values respect the type system thus
allowing to create sets of vertices,
edges, maps, and any other available type.
* String - Any value not using the system notation will be interpreted as
a string by default.
@@ -423,6 +425,11 @@ such as null and spaces.
* Vertex - *v[_xxx_]* - The "xxx" should be replaced with the "name" property
of a vertex in the graph. This syntax may
include the `.id` suffix which would indicate getting the vertex identifier or
the `.sid` suffix which gets a string
representation of the edge identifier.
+* VertexProperty - *vp[_xxx_]* - The "xxx" should be replaced with a
representation of a vertex property in the form of
+the `vertex_name-key->value`. Note that the key is just a string and the value
is a typed value using the syntax
+presented here.
+
+vp[marko-name->marko]
In addition, parameter names should adhere to a common form as they hold some
meaning to certain language variant
implementations:
diff --git a/gremlin-go/driver/cucumber/cucumberSteps_test.go
b/gremlin-go/driver/cucumber/cucumberSteps_test.go
index c5b0e2d9ee..6ac7aa5487 100644
--- a/gremlin-go/driver/cucumber/cucumberSteps_test.go
+++ b/gremlin-go/driver/cucumber/cucumberSteps_test.go
@@ -56,6 +56,7 @@ func init() {
regexp.MustCompile(`^d\[(.*)]\.[n]$`): toBigInt,
regexp.MustCompile(`^d\[(.*)]\.[i]$`): toInt32,
regexp.MustCompile(`^vp\[(.+)]$`): toVertexProperty,
+ regexp.MustCompile(`^prop\[(.+)]$`): toProperty,
regexp.MustCompile(`^v\[(.+)]$`): toVertex,
regexp.MustCompile(`^v\[(.+)]\.id$`): toVertexId,
regexp.MustCompile(`^e\[(.+)]$`): toEdge,
@@ -174,6 +175,14 @@ func toInt32(stringVal, graphName string) interface{} {
return int32(val)
}
+// Parse property as key/value pair.
+func toProperty(stringVal, graphName string) interface{} {
+ commaIdx := strings.Index(stringVal, ",")
+ key := stringVal[:commaIdx]
+ value := parseValue(stringVal[commaIdx+1:], graphName)
+ return &gremlingo.Property{Key: key, Value: value}
+}
+
// Parse vertex property.
func toVertexProperty(name, graphName string) interface{} {
if vp, ok := tg.getDataGraphFromMap(graphName).vertexProperties[name];
ok {
diff --git a/gremlin-go/driver/cucumber/gremlin.go
b/gremlin-go/driver/cucumber/gremlin.go
index af2643c77b..cbc8080890 100644
--- a/gremlin-go/driver/cucumber/gremlin.go
+++ b/gremlin-go/driver/cucumber/gremlin.go
@@ -1114,9 +1114,8 @@ var translationMap = map[string][]func(g
*gremlingo.GraphTraversalSource, p map[
"g_E": {func(g *gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return g.E()}},
"g_EX11X": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["eid11"])}},
"g_EX11AsStringX": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["eid11"])}},
- "g_EXe11X": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["e11"])}},
- "g_EXe7_e11X": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["e7"],
p["e11"])}},
- "g_EXlistXe7_e11XX": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["xx1"])}},
+ "g_EXeid7_eid11X": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["eid7"],
p["eid11"])}},
+ "g_EXlistXeid7_eid11XX": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["xx1"])}},
"g_EXnullX": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.E(nil)}},
"g_EXlistXnullXX": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["xx1"])}},
"g_EX11_nullX": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.E(p["eid11"],
nil)}},
@@ -1525,6 +1524,10 @@ var translationMap = map[string][]func(g
*gremlingo.GraphTraversalSource, p map[
"g_V_hasXageX_propertiesXage_nameX_value": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return g.V().Has("age").Properties("age",
"name").Value()}},
"g_V_propertiesXname_age_nullX_value": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return g.V().Properties("name", "age",
nil).Value()}},
"g_V_valuesXname_age_nullX": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.V().Values("name",
"age", nil)}},
+ "g_E_propertiesXweightX": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.E().Properties("weight")}},
+ "g_E_properties": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.AddV("person").Property("name",
"alice").As("a").AddV("person").Property("name",
"bob").As("b").AddE("knows").From("a").To("b").Property("weight",
0.5).Property("since", int32(2020))}, func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.E().Properties()}},
+ "g_E_propertiesXsinceX": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.AddV("person").Property("name",
"alice").As("a").AddV("person").Property("name",
"bob").As("b").AddE("knows").From("a").To("b").Property("weight",
0.5).Property("since", int32(2020))}, func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.E().Properties("since")}},
+ "g_E_properties_multi_edges": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.AddV("person").Property("name",
"alice").As("a").AddV("person").Property("name",
"bob").As("b").AddE("knows").From("a").To("b").Property("weight",
0.5).Property("since",
int32(2020)).AddE("likes").From("a").To("b").Property("weight",
1.0).Property("tag", "friend")}, func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraver [...]
"g_injectX__feature___test__nullX_rTrim": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return g.Inject("feature ", "one test ", nil, "", "
", " abc", "abc ", " abc ", " ").RTrim()}},
"g_injectX__feature___test__nullX_rTrimXlocalX": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return g.Inject([]interface{}{" feature ", " one
test ", nil, "", " ", " abc", "abc ", " abc ", "
"}).RTrim(gremlingo.Scope.Local)}},
"g_injectX__feature__X_rTrim": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject(" feature
").RTrim()}},
@@ -1895,6 +1898,8 @@ var translationMap = map[string][]func(g
*gremlingo.GraphTraversalSource, p map[
"g_V_properties_order_id": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.V().Properties().Order().Id()}},
"g_E_properties_order_value": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.AddV("person").Property("name",
"alice").As("a").AddE("self").From("a").To("a").Property("weight",
0.5).Property("a", int32(10)).AddE("self").From("a").To("a").Property("weight",
1.0).Property("a", int32(11)).AddE("self").From("a").To("a").Property("weight",
0.4).Property("a", int32(12)).AddE("self").From("a").To("a").Property("weight",
1.0).Property("a [...]
"g_E_properties_order_byXdescX_value": {func(g
*gremlingo.GraphTraversalSource, p map[string]interface{})
*gremlingo.GraphTraversal {return g.AddV("person").Property("name",
"alice").As("a").AddE("self").From("a").To("a").Property("weight",
0.5).Property("a", int32(10)).AddE("self").From("a").To("a").Property("weight",
1.0).Property("a", int32(11)).AddE("self").From("a").To("a").Property("weight",
0.4).Property("a", int32(12)).AddE("self").From("a").To("a").Property("weight",
1.0).Pr [...]
+ "g_E_properties_order": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.AddV("person").Property("name",
"alice").As("a").AddE("self").From("a").To("a").Property("weight",
0.5).Property("a", int32(10)).AddE("self").From("a").To("a").Property("weight",
1.0).Property("a", int32(11)).AddE("self").From("a").To("a").Property("weight",
0.4).Property("a", int32(12)).AddE("self").From("a").To("a").Property("weight",
1.0).Property("a", int [...]
+ "g_E_properties_order_byXdescX": {func(g *gremlingo.GraphTraversalSource,
p map[string]interface{}) *gremlingo.GraphTraversal {return
g.AddV("person").Property("name",
"alice").As("a").AddE("self").From("a").To("a").Property("weight",
0.5).Property("a", int32(10)).AddE("self").From("a").To("a").Property("weight",
1.0).Property("a", int32(11)).AddE("self").From("a").To("a").Property("weight",
0.4).Property("a", int32(12)).AddE("self").From("a").To("a").Property("weight",
1.0).Property [...]
"g_inject_order": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("zzz",
"foo", uuid.MustParse("6100808b-62f9-42b7-957e-ed66c30f40d1"),
[]interface{}{"a", "b", "c", "d"}, 1, time.Date(2023, 8, 1, 0, 0, 0, 0,
time.FixedZone("UTC+00:00", 0)), []interface{}{"a", "b", "c"},
map[interface{}]interface{}{"a": "a", "b": "b" }, nil, 2.0, time.Date(2023, 1,
1, 0, 0, 0, 0, time.FixedZone("UTC+00:00", 0)), gremlingo.NewSimpleSet("x",
[...]
"g_inject_order_byXdescX": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return g.Inject("zzz",
"foo", uuid.MustParse("6100808b-62f9-42b7-957e-ed66c30f40d1"),
[]interface{}{"a", "b", "c", "d"}, 1, time.Date(2023, 8, 1, 0, 0, 0, 0,
time.FixedZone("UTC+00:00", 0)), []interface{}{"a", "b", "c"},
map[interface{}]interface{}{"a": "a", "b": "b" }, nil, 2.0, time.Date(2023, 1,
1, 0, 0, 0, 0, time.FixedZone("UTC+00:00", 0)), gremlingo.NewSimple [...]
"g_V_out_out_order_byXascX": {func(g *gremlingo.GraphTraversalSource, p
map[string]interface{}) *gremlingo.GraphTraversal {return
g.V().Out().Out().Order().By(gremlingo.Order.Asc)}},
diff --git
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
index 4af404f05a..d7d5e2e56d 100644
---
a/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
+++
b/gremlin-javascript/src/main/javascript/gremlin-javascript/test/cucumber/gremlin.js
@@ -1145,9 +1145,8 @@ const gremlins = {
g_E: [function({g}) { return g.E() }],
g_EX11X: [function({g, eid11}) { return g.E(eid11) }],
g_EX11AsStringX: [function({g, eid11}) { return g.E(eid11) }],
- g_EXe11X: [function({g, e11}) { return g.E(e11) }],
- g_EXe7_e11X: [function({g, e7, e11}) { return g.E(e7, e11) }],
- g_EXlistXe7_e11XX: [function({g, xx1}) { return g.E(xx1) }],
+ g_EXeid7_eid11X: [function({g, eid11, eid7}) { return g.E(eid7, eid11) }],
+ g_EXlistXeid7_eid11XX: [function({g, xx1}) { return g.E(xx1) }],
g_EXnullX: [function({g}) { return g.E(null) }],
g_EXlistXnullXX: [function({g, xx1}) { return g.E(xx1) }],
g_EX11_nullX: [function({g, eid11}) { return g.E(eid11, null) }],
@@ -1556,6 +1555,10 @@ const gremlins = {
g_V_hasXageX_propertiesXage_nameX_value: [function({g}) { return
g.V().has("age").properties("age", "name").value() }],
g_V_propertiesXname_age_nullX_value: [function({g}) { return
g.V().properties("name", "age", null).value() }],
g_V_valuesXname_age_nullX: [function({g}) { return g.V().values("name",
"age", null) }],
+ g_E_propertiesXweightX: [function({g}) { return g.E().properties("weight")
}],
+ g_E_properties: [function({g}) { return g.addV("person").property("name",
"alice").as("a").addV("person").property("name",
"bob").as("b").addE("knows").from_("a").to("b").property("weight",
0.5).property("since", 2020) }, function({g}) { return g.E().properties() }],
+ g_E_propertiesXsinceX: [function({g}) { return
g.addV("person").property("name",
"alice").as("a").addV("person").property("name",
"bob").as("b").addE("knows").from_("a").to("b").property("weight",
0.5).property("since", 2020) }, function({g}) { return
g.E().properties("since") }],
+ g_E_properties_multi_edges: [function({g}) { return
g.addV("person").property("name",
"alice").as("a").addV("person").property("name",
"bob").as("b").addE("knows").from_("a").to("b").property("weight",
0.5).property("since",
2020).addE("likes").from_("a").to("b").property("weight", 1.0).property("tag",
"friend") }, function({g}) { return g.E().properties() }],
g_injectX__feature___test__nullX_rTrim: [function({g}) { return
g.inject("feature ", "one test ", null, "", " ", " abc", "abc ", " abc ", "
").rTrim() }],
g_injectX__feature___test__nullX_rTrimXlocalX: [function({g}) { return
g.inject([" feature ", " one test ", null, "", " ", " abc", "abc ", " abc ",
" "]).rTrim(Scope.local) }],
g_injectX__feature__X_rTrim: [function({g}) { return g.inject(" feature
").rTrim() }],
@@ -1926,6 +1929,8 @@ const gremlins = {
g_V_properties_order_id: [function({g}) { return
g.V().properties().order().id() }],
g_E_properties_order_value: [function({g}) { return
g.addV("person").property("name",
"alice").as("a").addE("self").from_("a").to("a").property("weight",
0.5).property("a", 10).addE("self").from_("a").to("a").property("weight",
1.0).property("a", 11).addE("self").from_("a").to("a").property("weight",
0.4).property("a", 12).addE("self").from_("a").to("a").property("weight",
1.0).property("a", 13).addE("self").from_("a").to("a").property("weight",
0.4).property("a", 14).addE("self").fr [...]
g_E_properties_order_byXdescX_value: [function({g}) { return
g.addV("person").property("name",
"alice").as("a").addE("self").from_("a").to("a").property("weight",
0.5).property("a", 10).addE("self").from_("a").to("a").property("weight",
1.0).property("a", 11).addE("self").from_("a").to("a").property("weight",
0.4).property("a", 12).addE("self").from_("a").to("a").property("weight",
1.0).property("a", 13).addE("self").from_("a").to("a").property("weight",
0.4).property("a", 14).addE(" [...]
+ g_E_properties_order: [function({g}) { return
g.addV("person").property("name",
"alice").as("a").addE("self").from_("a").to("a").property("weight",
0.5).property("a", 10).addE("self").from_("a").to("a").property("weight",
1.0).property("a", 11).addE("self").from_("a").to("a").property("weight",
0.4).property("a", 12).addE("self").from_("a").to("a").property("weight",
1.0).property("a", 13).addE("self").from_("a").to("a").property("weight",
0.4).property("a", 14).addE("self").from_("a [...]
+ g_E_properties_order_byXdescX: [function({g}) { return
g.addV("person").property("name",
"alice").as("a").addE("self").from_("a").to("a").property("weight",
0.5).property("a", 10).addE("self").from_("a").to("a").property("weight",
1.0).property("a", 11).addE("self").from_("a").to("a").property("weight",
0.4).property("a", 12).addE("self").from_("a").to("a").property("weight",
1.0).property("a", 13).addE("self").from_("a").to("a").property("weight",
0.4).property("a", 14).addE("self") [...]
g_inject_order: [function({g}) { return g.inject("zzz", "foo",
uuid.parse("6100808b-62f9-42b7-957e-ed66c30f40d1"), ["a", "b", "c", "d"], 1,
new Date('2023-08-01T00:00Z'), ["a", "b", "c"], new Map([["a", "a"], ["b",
"b"]]), null, 2.0, new Date('2023-01-01T00:00Z'), new Set(["x", "y", "z"]), new
Map([["a", "a"], ["b", false], ["c", "c"]]), "bar",
uuid.parse("5100808b-62f9-42b7-957e-ed66c30f40d1"), true, false,
Number.POSITIVE_INFINITY, Number.NaN, Number.NEGATIVE_INFINITY).order() }],
g_inject_order_byXdescX: [function({g}) { return g.inject("zzz", "foo",
uuid.parse("6100808b-62f9-42b7-957e-ed66c30f40d1"), ["a", "b", "c", "d"], 1,
new Date('2023-08-01T00:00Z'), ["a", "b", "c"], new Map([["a", "a"], ["b",
"b"]]), null, 2.0, new Date('2023-01-01T00:00Z'), new Set(["x", "y", "z"]), new
Map([["a", "a"], ["b", false], ["c", "c"]]), "bar",
uuid.parse("5100808b-62f9-42b7-957e-ed66c30f40d1"), true, false,
Number.POSITIVE_INFINITY, Number.NaN, Number.NEGATIVE_INFINITY).ord [...]
g_V_out_out_order_byXascX: [function({g}) { return
g.V().out().out().order().by(Order.asc) }],
diff --git a/gremlin-python/src/main/python/tests/feature/feature_steps.py
b/gremlin-python/src/main/python/tests/feature/feature_steps.py
index f586e47918..d669923b12 100644
--- a/gremlin-python/src/main/python/tests/feature/feature_steps.py
+++ b/gremlin-python/src/main/python/tests/feature/feature_steps.py
@@ -369,6 +369,12 @@ def _convert(val, ctx):
return __find_cached_element(ctx, graph_name, val[2:-1], "e")
elif isinstance(val, str) and re.match(r"^vp\[.*\]$", val): # parse
vertexproperty
return __find_cached_element(ctx, graph_name, val[3:-1], "vp")
+ elif isinstance(val, str) and re.match(r"^prop\[.+\]$", val): # parse
property as key/value pair
+ inner = val[5:-1]
+ comma_idx = inner.index(",")
+ key = inner[:comma_idx]
+ value = _convert(inner[comma_idx + 1:], ctx)
+ return Property(key, value, None)
elif isinstance(val, str) and re.match(r"^m\[.*\]$", val): # parse json
as a map
return _convert(json.loads(val[2:-1]), ctx)
elif isinstance(val, str) and re.match(r"^p\[.*\]$", val): # parse path
@@ -438,6 +444,9 @@ def _convert_results(val):
if isinstance(val, Path):
# kill out labels as they aren't in the assertion logic
return Path([set([])], val.objects)
+ elif isinstance(val, Property) and not isinstance(val, VertexProperty):
+ # strip element for key/value only comparison with prop[...] syntax
+ return Property(val.key, val.value, None)
elif _is_nan(val):
# we need to use the string form for NaN to test the results since
float.nan != float.nan
return "d[NaN]"
diff --git a/gremlin-python/src/main/python/tests/feature/gremlin.py
b/gremlin-python/src/main/python/tests/feature/gremlin.py
index aad2a75ca9..cf19d6d85c 100644
--- a/gremlin-python/src/main/python/tests/feature/gremlin.py
+++ b/gremlin-python/src/main/python/tests/feature/gremlin.py
@@ -1117,9 +1117,8 @@ world.gremlins = {
'g_E': [(lambda g:g.E())],
'g_EX11X': [(lambda g, eid11=None:g.E(eid11))],
'g_EX11AsStringX': [(lambda g, eid11=None:g.E(eid11))],
- 'g_EXe11X': [(lambda g, e11=None:g.E(e11))],
- 'g_EXe7_e11X': [(lambda g, e7=None,e11=None:g.E(e7, e11))],
- 'g_EXlistXe7_e11XX': [(lambda g, xx1=None:g.E(xx1))],
+ 'g_EXeid7_eid11X': [(lambda g, eid11=None,eid7=None:g.E(eid7, eid11))],
+ 'g_EXlistXeid7_eid11XX': [(lambda g, xx1=None:g.E(xx1))],
'g_EXnullX': [(lambda g:g.E(None))],
'g_EXlistXnullXX': [(lambda g, xx1=None:g.E(xx1))],
'g_EX11_nullX': [(lambda g, eid11=None:g.E(eid11, None))],
@@ -1528,6 +1527,10 @@ world.gremlins = {
'g_V_hasXageX_propertiesXage_nameX_value': [(lambda
g:g.V().has('age').properties('age', 'name').value())],
'g_V_propertiesXname_age_nullX_value': [(lambda g:g.V().properties('name',
'age', None).value())],
'g_V_valuesXname_age_nullX': [(lambda g:g.V().values('name', 'age',
None))],
+ 'g_E_propertiesXweightX': [(lambda g:g.E().properties('weight'))],
+ 'g_E_properties': [(lambda g:g.add_v('person').property('name',
'alice').as_('a').add_v('person').property('name',
'bob').as_('b').add_e('knows').from_('a').to('b').property('weight',
0.5).property('since', 2020)), (lambda g:g.E().properties())],
+ 'g_E_propertiesXsinceX': [(lambda g:g.add_v('person').property('name',
'alice').as_('a').add_v('person').property('name',
'bob').as_('b').add_e('knows').from_('a').to('b').property('weight',
0.5).property('since', 2020)), (lambda g:g.E().properties('since'))],
+ 'g_E_properties_multi_edges': [(lambda
g:g.add_v('person').property('name',
'alice').as_('a').add_v('person').property('name',
'bob').as_('b').add_e('knows').from_('a').to('b').property('weight',
0.5).property('since',
2020).add_e('likes').from_('a').to('b').property('weight', 1.0).property('tag',
'friend')), (lambda g:g.E().properties())],
'g_injectX__feature___test__nullX_rTrim': [(lambda g:g.inject('feature ',
'one test ', None, '', ' ', ' abc', 'abc ', ' abc ', ' ').r_trim())],
'g_injectX__feature___test__nullX_rTrimXlocalX': [(lambda g:g.inject(['
feature ', ' one test ', None, '', ' ', ' abc', 'abc ', ' abc ', '
']).r_trim(Scope.local))],
'g_injectX__feature__X_rTrim': [(lambda g:g.inject(' feature
').r_trim())],
@@ -1898,6 +1901,8 @@ world.gremlins = {
'g_V_properties_order_id': [(lambda g:g.V().properties().order().id_())],
'g_E_properties_order_value': [(lambda
g:g.add_v('person').property('name',
'alice').as_('a').add_e('self').from_('a').to('a').property('weight',
0.5).property('a', 10).add_e('self').from_('a').to('a').property('weight',
1.0).property('a', 11).add_e('self').from_('a').to('a').property('weight',
0.4).property('a', 12).add_e('self').from_('a').to('a').property('weight',
1.0).property('a', 13).add_e('self').from_('a').to('a').property('weight',
0.4).property('a', 14).add_e('self').from_ [...]
'g_E_properties_order_byXdescX_value': [(lambda
g:g.add_v('person').property('name',
'alice').as_('a').add_e('self').from_('a').to('a').property('weight',
0.5).property('a', 10).add_e('self').from_('a').to('a').property('weight',
1.0).property('a', 11).add_e('self').from_('a').to('a').property('weight',
0.4).property('a', 12).add_e('self').from_('a').to('a').property('weight',
1.0).property('a', 13).add_e('self').from_('a').to('a').property('weight',
0.4).property('a', 14).add_e('sel [...]
+ 'g_E_properties_order': [(lambda g:g.add_v('person').property('name',
'alice').as_('a').add_e('self').from_('a').to('a').property('weight',
0.5).property('a', 10).add_e('self').from_('a').to('a').property('weight',
1.0).property('a', 11).add_e('self').from_('a').to('a').property('weight',
0.4).property('a', 12).add_e('self').from_('a').to('a').property('weight',
1.0).property('a', 13).add_e('self').from_('a').to('a').property('weight',
0.4).property('a', 14).add_e('self').from_('a'). [...]
+ 'g_E_properties_order_byXdescX': [(lambda
g:g.add_v('person').property('name',
'alice').as_('a').add_e('self').from_('a').to('a').property('weight',
0.5).property('a', 10).add_e('self').from_('a').to('a').property('weight',
1.0).property('a', 11).add_e('self').from_('a').to('a').property('weight',
0.4).property('a', 12).add_e('self').from_('a').to('a').property('weight',
1.0).property('a', 13).add_e('self').from_('a').to('a').property('weight',
0.4).property('a', 14).add_e('self').fr [...]
'g_inject_order': [(lambda g:g.inject('zzz', 'foo',
uuid.UUID('6100808b-62f9-42b7-957e-ed66c30f40d1'), ['a', 'b', 'c', 'd'], 1,
datetime.datetime.fromisoformat('2023-08-01T00:00+00:00'), ['a', 'b', 'c'], {
'a': 'a', 'b': 'b' }, None, 2.0,
datetime.datetime.fromisoformat('2023-01-01T00:00+00:00'), {'x', 'y', 'z'}, {
'a': 'a', 'b': False, 'c': 'c' }, 'bar',
uuid.UUID('5100808b-62f9-42b7-957e-ed66c30f40d1'), True, False, float('inf'),
float('nan'), float('-inf')).order())],
'g_inject_order_byXdescX': [(lambda g:g.inject('zzz', 'foo',
uuid.UUID('6100808b-62f9-42b7-957e-ed66c30f40d1'), ['a', 'b', 'c', 'd'], 1,
datetime.datetime.fromisoformat('2023-08-01T00:00+00:00'), ['a', 'b', 'c'], {
'a': 'a', 'b': 'b' }, None, 2.0,
datetime.datetime.fromisoformat('2023-01-01T00:00+00:00'), {'x', 'y', 'z'}, {
'a': 'a', 'b': False, 'c': 'c' }, 'bar',
uuid.UUID('5100808b-62f9-42b7-957e-ed66c30f40d1'), True, False, float('inf'),
float('nan'), float('-inf')).order().by(Ord [...]
'g_V_out_out_order_byXascX': [(lambda
g:g.V().out().out().order().by(Order.asc))],
diff --git
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java
index a8dfa900da..3b1912556b 100644
---
a/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java
+++
b/gremlin-test/src/main/java/org/apache/tinkerpop/gremlin/features/StepDefinition.java
@@ -167,11 +167,6 @@ public final class StepDefinition {
add(Pair.with(Pattern.compile("v\\[(.+)\\]\\.id"), s ->
world.convertIdToScript(g.V().has("name", s).id().next(), Vertex.class)));
add(Pair.with(Pattern.compile("v\\[(.+)\\]\\.sid"), s ->
world.convertIdToScript(g.V().has("name", s).id().next(), Vertex.class)));
- add(Pair.with(Pattern.compile("v\\[(.+)\\]"), s -> {
- final Iterator<Object> itty = g.V().has("name", s).id();
- return String.format("new Vertex(%s,\"%s\")", itty.hasNext() ?
- world.convertIdToScript(itty.next(), Vertex.class) : s,
Vertex.DEFAULT_LABEL);
- }));
add(Pair.with(Pattern.compile("e\\[(.+)\\]\\.id"), s ->
world.convertIdToScript(getEdgeId(g, s), Edge.class)));
add(Pair.with(Pattern.compile("e\\[(.+)\\]\\.sid"), s ->
world.convertIdToScript(getEdgeId(g, s), Edge.class)));
add(Pair.with(Pattern.compile("t\\[(.*)\\]"), s ->
String.format("T.%s", s)));
@@ -180,15 +175,6 @@ public final class StepDefinition {
add(Pair.with(Pattern.compile("(null)"), s -> "null"));
add(Pair.with(Pattern.compile("(true)"), s -> "true"));
add(Pair.with(Pattern.compile("(false)"), s -> "false"));
-
- // the following force ignore conditions as they cannot be parsed by
the grammar at this time. the grammar will
- // need to be modified to handle them or perhaps these tests stay
relegated to the JVM in some way
- add(Pair.with(Pattern.compile("e\\[(.+)\\]"), s -> {
- throw new AssumptionViolatedException("This test uses a Edge as a
parameter which is not supported by gremlin-language");
- }));
- add(Pair.with(Pattern.compile("p\\[(.*)\\]"), s -> {
- throw new AssumptionViolatedException("This test uses a Path as a
parameter which is not supported by gremlin-language");
- }));
}};
private List<Pair<Pattern, Function<String,Object>>>
objectMatcherConverters = new ArrayList<Pair<Pattern,
Function<String,Object>>>() {{
@@ -218,10 +204,13 @@ public final class StepDefinition {
// return the string values as is, used to wrap results that may
contain other regex patterns
add(Pair.with(Pattern.compile("str\\[(.*)\\]"), String::valueOf));
- /*
- * TODO FIXME Add same support for other languages (js, python, .net)
- */
add(Pair.with(Pattern.compile("vp\\[(.+)\\]"), s ->
getVertexProperty(g, s)));
+ add(Pair.with(Pattern.compile("prop\\[(.+)\\]"), s -> {
+ final int commaIdx = s.indexOf(",");
+ final String key = s.substring(0, commaIdx);
+ final Object value = convertToObject(s.substring(commaIdx + 1));
+ return Pair.with(key, value);
+ }));
add(Pair.with(Pattern.compile("p\\[(.*)\\]"), s -> {
final String[] items = s.split(",");
@@ -652,6 +641,8 @@ public final class StepDefinition {
return new LinkedHashMap() {{
put(((Map.Entry<?, ?>) o).getKey(), ((Map.Entry<?, ?>)
o).getValue());
}};
+ } else if (o instanceof Property && !(o instanceof
VertexProperty)) {
+ return Pair.with(((Property) o).key(), ((Property) o).value());
} else {
return o;
}
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Edge.feature
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Edge.feature
index 3bab88cc1e..0736def307 100644
---
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Edge.feature
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Edge.feature
@@ -58,25 +58,13 @@ Feature: Step - E(), inV(), outV(), bothV(), otherV()
| result |
| e[josh-created->lop] |
- Scenario: g_EXe11X
+ Scenario: g_EXeid7_eid11X
Given the modern graph
- And using the parameter e11 defined as "e[josh-created->lop]"
- And the traversal of
- """
- g.E(e11)
- """
- When iterated to list
- Then the result should be unordered
- | result |
- | e[josh-created->lop] |
-
- Scenario: g_EXe7_e11X
- Given the modern graph
- And using the parameter e7 defined as "e[marko-knows->vadas]"
- And using the parameter e11 defined as "e[josh-created->lop]"
+ And using the parameter eid7 defined as "e[marko-knows->vadas].id"
+ And using the parameter eid11 defined as "e[josh-created->lop].id"
And the traversal of
"""
- g.E(e7,e11)
+ g.E(eid7,eid11)
"""
When iterated to list
Then the result should be unordered
@@ -84,9 +72,9 @@ Feature: Step - E(), inV(), outV(), bothV(), otherV()
| e[marko-knows->vadas] |
| e[josh-created->lop] |
- Scenario: g_EXlistXe7_e11XX
+ Scenario: g_EXlistXeid7_eid11XX
Given the modern graph
- And using the parameter xx1 defined as
"l[e[marko-knows->vadas],e[josh-created->lop]]"
+ And using the parameter xx1 defined as
"l[e[marko-knows->vadas].id,e[josh-created->lop].id]"
And the traversal of
"""
g.E(xx1)
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Properties.feature
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Properties.feature
index cf672397e2..c87ac1654d 100644
---
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Properties.feature
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/map/Properties.feature
@@ -108,23 +108,74 @@ Feature: Step - properties()
| lop |
| ripple |
- Scenario: g_injectXg_VX1X_propertiesXnameX_nextX_value
- Given an unsupported test
- Then nothing should happen because
+ Scenario: g_E_propertiesXweightX
+ Given the modern graph
+ And the traversal of
"""
- The test suite doesn't do well with vertex property values.
+ g.E().properties("weight")
"""
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | prop[weight,d[0.2].d] |
+ | prop[weight,d[0.4].d] |
+ | prop[weight,d[0.4].d] |
+ | prop[weight,d[0.5].d] |
+ | prop[weight,d[1.0].d] |
+ | prop[weight,d[1.0].d] |
- Scenario: g_V_hasXageX_properties_hasXid_nameIdX_value
- Given an unsupported test
- Then nothing should happen because
+ Scenario: g_E_properties
+ Given the empty graph
+ And the graph initializer of
+ """
+ g.addV("person").property("name","alice").as("a").
+ addV("person").property("name","bob").as("b").
+ addE("knows").from("a").to("b").property("weight",
0.5d).property("since", 2020i)
+ """
+ And the traversal of
"""
- GLV suite doesn't support property identifiers and related assertions
+ g.E().properties()
"""
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | prop[weight,d[0.5].d] |
+ | prop[since,d[2020].i] |
- Scenario: g_V_hasXageX_properties_hasXid_nameIdAsStringX_value
- Given an unsupported test
- Then nothing should happen because
+ Scenario: g_E_propertiesXsinceX
+ Given the empty graph
+ And the graph initializer of
+ """
+ g.addV("person").property("name","alice").as("a").
+ addV("person").property("name","bob").as("b").
+ addE("knows").from("a").to("b").property("weight",
0.5d).property("since", 2020i)
+ """
+ And the traversal of
"""
- GLV suite doesn't support property identifiers and related assertions
- """
\ No newline at end of file
+ g.E().properties("since")
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | prop[since,d[2020].i] |
+
+ Scenario: g_E_properties_multi_edges
+ Given the empty graph
+ And the graph initializer of
+ """
+ g.addV("person").property("name","alice").as("a").
+ addV("person").property("name","bob").as("b").
+ addE("knows").from("a").to("b").property("weight",
0.5d).property("since", 2020i).
+ addE("likes").from("a").to("b").property("weight",
1.0d).property("tag", "friend")
+ """
+ And the traversal of
+ """
+ g.E().properties()
+ """
+ When iterated to list
+ Then the result should be unordered
+ | result |
+ | prop[weight,d[0.5].d] |
+ | prop[since,d[2020].i] |
+ | prop[weight,d[1.0].d] |
+ | prop[tag,friend] |
\ No newline at end of file
diff --git
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/semantics/Orderability.feature
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/semantics/Orderability.feature
index 0079aac13f..5f99974a06 100644
---
a/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/semantics/Orderability.feature
+++
b/gremlin-test/src/main/resources/org/apache/tinkerpop/gremlin/test/features/semantics/Orderability.feature
@@ -150,6 +150,70 @@ Feature: Orderability
| d[11].i |
| d[10].i |
+ Scenario: g_E_properties_order
+ Given the empty graph
+ And the graph initializer of
+ """
+ g.addV("person").property("name", "alice").as("a").
+ addE("self").from("a").to("a").property("weight", 0.5d).property("a",
10i).
+ addE("self").from("a").to("a").property("weight", 1.0d).property("a",
11i).
+ addE("self").from("a").to("a").property("weight", 0.4d).property("a",
12i).
+ addE("self").from("a").to("a").property("weight", 1.0d).property("a",
13i).
+ addE("self").from("a").to("a").property("weight", 0.4d).property("a",
14i).
+ addE("self").from("a").to("a").property("weight", 0.2d).property("a",
15i)
+ """
+ And the traversal of
+ """
+ g.E().properties().order()
+ """
+ When iterated to list
+ Then the result should be ordered
+ | result |
+ | prop[a,d[10].i] |
+ | prop[a,d[11].i] |
+ | prop[a,d[12].i] |
+ | prop[a,d[13].i] |
+ | prop[a,d[14].i] |
+ | prop[a,d[15].i] |
+ | prop[weight,d[0.2].d] |
+ | prop[weight,d[0.4].d] |
+ | prop[weight,d[0.4].d] |
+ | prop[weight,d[0.5].d] |
+ | prop[weight,d[1.0].d] |
+ | prop[weight,d[1.0].d] |
+
+ Scenario: g_E_properties_order_byXdescX
+ Given the empty graph
+ And the graph initializer of
+ """
+ g.addV("person").property("name", "alice").as("a").
+ addE("self").from("a").to("a").property("weight", 0.5d).property("a",
10i).
+ addE("self").from("a").to("a").property("weight", 1.0d).property("a",
11i).
+ addE("self").from("a").to("a").property("weight", 0.4d).property("a",
12i).
+ addE("self").from("a").to("a").property("weight", 1.0d).property("a",
13i).
+ addE("self").from("a").to("a").property("weight", 0.4d).property("a",
14i).
+ addE("self").from("a").to("a").property("weight", 0.2d).property("a",
15i)
+ """
+ And the traversal of
+ """
+ g.E().properties().order().by(desc)
+ """
+ When iterated to list
+ Then the result should be ordered
+ | result |
+ | prop[weight,d[1.0].d] |
+ | prop[weight,d[1.0].d] |
+ | prop[weight,d[0.5].d] |
+ | prop[weight,d[0.4].d] |
+ | prop[weight,d[0.4].d] |
+ | prop[weight,d[0.2].d] |
+ | prop[a,d[15].i] |
+ | prop[a,d[14].i] |
+ | prop[a,d[13].i] |
+ | prop[a,d[12].i] |
+ | prop[a,d[11].i] |
+ | prop[a,d[10].i] |
+
@GraphComputerVerificationInjectionNotSupported
Scenario: g_inject_order
Given the empty graph