You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tinkerpop.apache.org by jo...@apache.org on 2017/11/30 09:19:59 UTC
[15/33] tinkerpop git commit: Gherkin-based test runner
Gherkin-based test runner
Project: http://git-wip-us.apache.org/repos/asf/tinkerpop/repo
Commit: http://git-wip-us.apache.org/repos/asf/tinkerpop/commit/cee68591
Tree: http://git-wip-us.apache.org/repos/asf/tinkerpop/tree/cee68591
Diff: http://git-wip-us.apache.org/repos/asf/tinkerpop/diff/cee68591
Branch: refs/heads/TINKERPOP-1827
Commit: cee68591c944fb23f1439b471db531f2823a8f9f
Parents: fe7b175
Author: Jorge Bay Gondra <jo...@gmail.com>
Authored: Mon Sep 25 17:27:13 2017 +0200
Committer: Jorge Bay Gondra <jo...@gmail.com>
Committed: Thu Nov 30 10:00:07 2017 +0100
----------------------------------------------------------------------
.../Gherkin/Attributes/BddAttribute.cs | 37 ++
.../Gherkin/Attributes/GivenAttribute.cs | 33 ++
.../Gherkin/Attributes/ThenAttribute.cs | 33 ++
.../Gherkin/Attributes/WhenAttribute.cs | 33 ++
.../Gherkin/CommonSteps.cs | 156 +++++++++
.../Gherkin/GherkinTestRunner.cs | 335 +++++++++++++++++++
.../Gherkin/StepDefinition.cs | 39 +++
.../Gherkin/TraversalTranslations.cs | 102 ++++++
.../Gremlin.Net.IntegrationTest.csproj | 13 +-
.../RemoteConnectionFactory.cs | 18 +-
10 files changed, 790 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/cee68591/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/BddAttribute.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/BddAttribute.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/BddAttribute.cs
new file mode 100644
index 0000000..1e9a242
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/BddAttribute.cs
@@ -0,0 +1,37 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using System;
+
+namespace Gremlin.Net.IntegrationTest.Gherkin.Attributes
+{
+ internal class BddAttribute : Attribute
+ {
+ public string Message { get; }
+
+ internal BddAttribute(string message)
+ {
+ Message = message;
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/cee68591/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/GivenAttribute.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/GivenAttribute.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/GivenAttribute.cs
new file mode 100644
index 0000000..7266145
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/GivenAttribute.cs
@@ -0,0 +1,33 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+namespace Gremlin.Net.IntegrationTest.Gherkin.Attributes
+{
+ internal class GivenAttribute : BddAttribute
+ {
+ public GivenAttribute(string message) : base(message)
+ {
+
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/cee68591/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/ThenAttribute.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/ThenAttribute.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/ThenAttribute.cs
new file mode 100644
index 0000000..25e1932
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/ThenAttribute.cs
@@ -0,0 +1,33 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+namespace Gremlin.Net.IntegrationTest.Gherkin.Attributes
+{
+ internal class ThenAttribute : BddAttribute
+ {
+ public ThenAttribute(string message) : base(message)
+ {
+
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/cee68591/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/WhenAttribute.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/WhenAttribute.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/WhenAttribute.cs
new file mode 100644
index 0000000..26286c6
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/Attributes/WhenAttribute.cs
@@ -0,0 +1,33 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+namespace Gremlin.Net.IntegrationTest.Gherkin.Attributes
+{
+ internal class WhenAttribute : BddAttribute
+ {
+ public WhenAttribute(string message) : base(message)
+ {
+
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/cee68591/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
new file mode 100644
index 0000000..50ea9b8
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/CommonSteps.cs
@@ -0,0 +1,156 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http.Headers;
+using System.Runtime.CompilerServices;
+using Gherkin.Ast;
+using Gremlin.Net.IntegrationTest.Gherkin.Attributes;
+using Gremlin.Net.Process.Traversal;
+using Gremlin.Net.Structure;
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Xunit;
+
+namespace Gremlin.Net.IntegrationTest.Gherkin
+{
+ internal class GeneralDefinitions : StepDefinition
+ {
+ private GraphTraversalSource _g;
+ private dynamic _traversal;
+ private object[] _result;
+
+ private static readonly IDictionary<string, Func<GraphTraversalSource, ITraversal>> FixedTranslations =
+ new Dictionary<string, Func<GraphTraversalSource, ITraversal>>
+ {
+ { "g.V().has(\"no\").count()", g => g.V().Has("no").Count() }
+ };
+
+ [Given("the modern graph")]
+ public void ChooseModernGraph()
+ {
+ var connection = ConnectionFactory.CreateRemoteConnection();
+ _g = new Graph().Traversal().WithRemote(connection);
+ }
+
+ [When("iterated to list")]
+ public void IterateToList()
+ {
+ if (!(_traversal is ITraversal))
+ {
+ throw new InvalidOperationException("Traversal should be set before iterating");
+ }
+ IEnumerable enumerable = _traversal.ToList();
+ _result = enumerable.Cast<object>().ToArray();
+ }
+
+ [Given("the traversal of")]
+ public void TranslateTraversal(string traversalText)
+ {
+ if (_g == null)
+ {
+ throw new InvalidOperationException("g should be a traversal source");
+ }
+ _traversal = TraversalTranslations.GetTraversal(traversalText, _g);
+ }
+
+ [Then("the result should be (\\w+)")]
+ public void AssertResult(string characterizedAs, DataTable table)
+ {
+ TableRow[] rows;
+ switch (characterizedAs)
+ {
+ case "empty":
+ Assert.Equal(0, _result.Length);
+ return;
+ case "ordered":
+ rows = table.Rows.ToArray();
+ Assert.Equal(rows.Length, _result.Length);
+ for (var i = 0; i < rows.Length; i++)
+ {
+ var row = rows[i];
+ var cells = row.Cells.ToArray();
+ var typeName = cells[0].Value;
+ var expectedValue = ConvertExpectedToType(typeName, cells[1].Value);
+ var resultItem = ConvertResultItem(typeName, _result[i]);
+ Assert.Equal(expectedValue, resultItem);
+ }
+ break;
+ case "unordered":
+ rows = table.Rows.ToArray();
+ Assert.Equal(rows.Length, _result.Length);
+ foreach (var row in rows)
+ {
+ var cells = row.Cells.ToArray();
+ var typeName = cells[0].Value;
+ var expectedValue = ConvertExpectedToType(typeName, cells[1].Value);
+ // Convert all the values in the result to the type
+ var convertedResult = _result.Select(item => ConvertResultItem(typeName, item));
+ Assert.Contains(expectedValue, convertedResult);
+ }
+ break;
+ default:
+ throw new NotSupportedException($"Result as '{characterizedAs}' not supported");
+ }
+ }
+
+ private object ConvertResultItem(string typeName, object value)
+ {
+ if (typeName == "map")
+ {
+ // We need to convert the original typed value into IDictionary<string, string>
+ return StringMap(
+ Assert.IsAssignableFrom<IDictionary>(value));
+ }
+ return value;
+ }
+
+ private IDictionary<string, string> StringMap(IDictionary originalMap)
+ {
+ var result = new Dictionary<string, string>(originalMap.Count);
+ foreach (var key in originalMap.Keys)
+ {
+ result.Add(key.ToString(), originalMap[key]?.ToString());
+ }
+ return result;
+ }
+
+ private object ConvertExpectedToType(string typeName, string stringValue)
+ {
+ switch (typeName)
+ {
+ case "numeric":
+ return Convert.ToInt64(stringValue);
+ case "string":
+ return stringValue;
+ case "map":
+ IDictionary<string, JToken> jsonObject = JObject.Parse(stringValue);
+ return jsonObject.ToDictionary(item => item.Key, item => item.Value.ToString());
+ }
+ throw new NotSupportedException($"Data table result with subtype of {typeName} not supported");
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/cee68591/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs
new file mode 100644
index 0000000..e1df3a8
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/GherkinTestRunner.cs
@@ -0,0 +1,335 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text.RegularExpressions;
+using Xunit;
+using Gherkin;
+using Gherkin.Ast;
+using Gremlin.Net.IntegrationTest.Gherkin.Attributes;
+using Microsoft.VisualStudio.TestPlatform.Utilities;
+using Newtonsoft.Json.Serialization;
+using Xunit.Abstractions;
+using Xunit.Sdk;
+
+namespace Gremlin.Net.IntegrationTest.Gherkin
+{
+ public class GherkinTestRunner
+ {
+ private readonly ITestOutputHelper _output;
+
+ private static class Keywords
+ {
+ public const string Given = "GIVEN";
+ public const string And = "AND";
+ public const string But = "BUT";
+ public const string When = "WHEN";
+ public const string Then = "THEN";
+ }
+
+ public enum StepBlock
+ {
+ Given,
+ When,
+ Then
+ }
+
+ private static readonly IDictionary<StepBlock, Type> Attributes = new Dictionary<StepBlock, Type>
+ {
+ { StepBlock.Given, typeof(GivenAttribute) },
+ { StepBlock.When, typeof(WhenAttribute) },
+ { StepBlock.Then, typeof(ThenAttribute) }
+ };
+
+ public GherkinTestRunner(ITestOutputHelper output)
+ {
+ _output = output;
+ }
+
+ [Fact]
+ public void RunGherkinBasedTests()
+ {
+ Console.WriteLine("Starting Gherkin-based tests");
+ var stepDefinitionTypes = GetStepDefinitionTypes();
+ var results = new List<ResultFeature>();
+ foreach (var feature in GetFeatures())
+ {
+ var resultFeature = new ResultFeature(feature);
+ results.Add(resultFeature);
+ foreach (var scenario in feature.Children)
+ {
+ var failedSteps = new Dictionary<Step, Exception>();
+ resultFeature.Scenarios[scenario] = failedSteps;
+ StepBlock? currentStep = null;
+ StepDefinition stepDefinition = null;
+ foreach (var step in scenario.Steps)
+ {
+ var previousStep = currentStep;
+ currentStep = GetStepBlock(currentStep, step.Keyword);
+ if (currentStep == StepBlock.Given && previousStep != StepBlock.Given)
+ {
+ stepDefinition?.Dispose();
+ stepDefinition = GetStepDefinitionInstance(stepDefinitionTypes, step.Text);
+ }
+ if (stepDefinition == null)
+ {
+ throw new NotSupportedException(
+ $"Step '{step.Text} not supported without a 'Given' step first");
+ }
+ var result = ExecuteStep(stepDefinition, currentStep.Value, step);
+ if (result != null)
+ {
+ failedSteps.Add(step, result);
+ }
+ }
+ }
+ }
+ OutputResults(results);
+ Console.WriteLine("Finished Gherkin-based tests");
+ }
+
+ private void WriteOutput(string line)
+ {
+ _output.WriteLine(line);
+ }
+
+ private void OutputResults(List<ResultFeature> results)
+ {
+ var totalScenarios = results.Sum(f => f.Scenarios.Count);
+ var totalFailedScenarios = results.Sum(f => f.Scenarios.Count(s => s.Value.Count > 0));
+ WriteOutput("Gherkin tests summary");
+ WriteOutput($"Total scenarios: {totalScenarios}. " +
+ $"Passed: {totalScenarios-totalFailedScenarios}. Failed: {totalFailedScenarios}.");
+ if (totalFailedScenarios == 0)
+ {
+ return;
+ }
+ var identifier = 0;
+ var failures = new List<Exception>();
+ foreach (var resultFeature in results)
+ {
+ var failedScenarios = resultFeature.Scenarios.Where(s => s.Value.Count > 0).ToArray();
+ if (failedScenarios.Length > 0)
+ {
+ WriteOutput($"Feature: {resultFeature.Feature.Name}");
+ }
+ else
+ {
+ continue;
+ }
+ foreach (var resultScenario in failedScenarios)
+ {
+ WriteOutput($" Scenario: {resultScenario.Key.Name}");
+ foreach (var step in resultScenario.Key.Steps)
+ {
+ Exception failure;
+ resultScenario.Value.TryGetValue(step, out failure);
+ if (failure == null)
+ {
+ WriteOutput($" {step.Keyword} {step.Text}");
+ }
+ else
+ {
+ WriteOutput($" {++identifier}) {step.Keyword} {step.Text} (failed)");
+ failures.Add(failure);
+ }
+ }
+ }
+ }
+ WriteOutput("Failures:");
+ for (var index = 0; index < failures.Count; index++)
+ {
+ WriteOutput($"{index+1}) {failures[index]}");
+ }
+ throw new Exception($"Gherkin test failed, see summary above for more detail");
+ }
+
+ public class ResultFeature
+ {
+ public Feature Feature { get;}
+
+ public IDictionary<ScenarioDefinition, IDictionary<Step, Exception>> Scenarios { get; }
+
+ public ResultFeature(Feature feature)
+ {
+ Feature = feature;
+ Scenarios = new Dictionary<ScenarioDefinition, IDictionary<Step, Exception>>();
+ }
+ }
+
+ private Exception ExecuteStep(StepDefinition instance, StepBlock stepBlock, Step step)
+ {
+ var attribute = Attributes[stepBlock];
+ var methodAndParameters = instance.GetType().GetMethods()
+ .Select(m =>
+ {
+ var attr = (BddAttribute) m.GetCustomAttribute(attribute);
+ if (attr == null)
+ {
+ return null;
+ }
+ var match = Regex.Match(step.Text, attr.Message);
+ if (!match.Success)
+ {
+ return null;
+ }
+ var parameters = new List<object>();
+ for (var i = 1; i < match.Groups.Count; i++)
+ {
+ parameters.Add(match.Groups[i].Value);
+ }
+ if (step.Argument is DocString)
+ {
+ parameters.Add(((DocString) step.Argument).Content);
+ }
+ else if (step.Argument != null)
+ {
+ parameters.Add(step.Argument);
+ }
+ if (m.GetParameters().Length != parameters.Count)
+ {
+ return null;
+ }
+ return Tuple.Create(m, parameters.ToArray());
+ })
+ .FirstOrDefault(t => t != null);
+ if (methodAndParameters == null)
+ {
+ throw new InvalidOperationException(
+ $"There is no step definition method for {stepBlock} '{step.Text}'");
+ }
+ try
+ {
+ methodAndParameters.Item1.Invoke(instance, methodAndParameters.Item2);
+ }
+ catch (TargetInvocationException ex)
+ {
+ // Exceptions should not be thrown
+ // Should be captured for result
+ return ex.InnerException;
+ }
+ catch (Exception ex)
+ {
+ return ex;
+ }
+ // Success
+ return null;
+ }
+
+ private static StepBlock GetStepBlock(StepBlock? currentStep, string stepKeyword)
+ {
+ switch (stepKeyword.Trim().ToUpper())
+ {
+ case Keywords.Given:
+ return StepBlock.Given;
+ case Keywords.When:
+ return StepBlock.When;
+ case Keywords.Then:
+ return StepBlock.Then;
+ case Keywords.And:
+ case Keywords.But:
+ if (currentStep == null)
+ {
+ throw new InvalidOperationException("'And' or 'But' is not supported outside a step");
+ }
+ return currentStep.Value;
+ }
+ throw new NotSupportedException($"Step with keyword {stepKeyword} not supported");
+ }
+
+ private static StepDefinition GetStepDefinitionInstance(IEnumerable<Type> stepDefinitionTypes, string stepText)
+ {
+ var type = stepDefinitionTypes
+ .FirstOrDefault(t => t.GetMethods().Any(m =>
+ {
+ var attr = m.GetCustomAttribute<GivenAttribute>();
+ if (attr == null)
+ {
+ return false;
+ }
+ return Regex.IsMatch(stepText, attr.Message);
+ }));
+ if (type == null)
+ {
+ throw new InvalidOperationException($"No step definition class matches Given '{stepText}'");
+ }
+ return (StepDefinition) Activator.CreateInstance(type);
+ }
+
+ private ICollection<Type> GetStepDefinitionTypes()
+ {
+ var assembly = GetType().GetTypeInfo().Assembly;
+ var types = assembly.GetTypes()
+ .Where(t => typeof(StepDefinition).IsAssignableFrom(t) && !t.GetTypeInfo().IsAbstract)
+ .ToArray();
+ if (types.Length == 0)
+ {
+ throw new InvalidOperationException($"No step definitions in {assembly.FullName}");
+ }
+ return types;
+ }
+
+ private IEnumerable<Feature> GetFeatures()
+ {
+ // TODO: go through all the .feature files
+ const string gherkinFile = "/Users/jorge/workspace/temp/count.feature";
+ var parser = new Parser();
+ var doc = parser.Parse(gherkinFile);
+ yield return doc.Feature;
+ }
+
+ private void PrintGherkin()
+ {
+ var gherkinFile = "/Users/jorge/workspace/temp/count.feature";
+ var parser = new Parser();
+ GherkinDocument doc = parser.Parse(gherkinFile);
+ foreach (var scenario in doc.Feature.Children)
+ {
+ WriteOutput("--------");
+ WriteOutput("Scenario: " + scenario.Name);
+ foreach (var step in scenario.Steps)
+ {
+ WriteOutput(" Step");
+ WriteOutput(" Keyword: " + step.Keyword);
+ WriteOutput(" Text: " + step.Text);
+ WriteOutput(" Argument: " + step.Argument);
+ if (step.Argument is DocString)
+ {
+ WriteOutput(" " + ((DocString)step.Argument).Content);
+ }
+ if (step.Argument is DataTable)
+ {
+ foreach (var row in ((DataTable)step.Argument).Rows)
+ {
+ WriteOutput(" Row: " + string.Join(", ", row.Cells.Select(x => x.Value)));
+ }
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/cee68591/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/StepDefinition.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/StepDefinition.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/StepDefinition.cs
new file mode 100644
index 0000000..3412fbd
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/StepDefinition.cs
@@ -0,0 +1,39 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using System;
+using System.Dynamic;
+using Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection;
+
+namespace Gremlin.Net.IntegrationTest.Gherkin
+{
+ public abstract class StepDefinition : IDisposable
+ {
+ internal RemoteConnectionFactory ConnectionFactory = new RemoteConnectionFactory();
+
+ public virtual void Dispose()
+ {
+ ConnectionFactory.Dispose();
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/cee68591/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalTranslations.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalTranslations.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalTranslations.cs
new file mode 100644
index 0000000..af02b8c
--- /dev/null
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gherkin/TraversalTranslations.cs
@@ -0,0 +1,102 @@
+#region License
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#endregion
+
+using System;
+using System.Collections.Generic;
+using System.Reflection;
+using Gremlin.Net.Process.Traversal;
+
+namespace Gremlin.Net.IntegrationTest.Gherkin
+{
+ internal class TraversalTranslations
+ {
+ private static readonly IDictionary<string, Func<GraphTraversalSource, ITraversal>> FixedTranslations =
+ new Dictionary<string, Func<GraphTraversalSource, ITraversal>>
+ {
+ { "g.V().has(\"no\").count()", g => g.V().Has("no").Count() },
+ { "g.V().fold().count(Scope.local)", g => g.V().Fold<object>().Count(Scope.Local)}
+ };
+
+ internal static ITraversal GetTraversal(string traversalText, GraphTraversalSource g)
+ {
+ Func<GraphTraversalSource, ITraversal> traversalBuilder;
+ if (!FixedTranslations.TryGetValue(traversalText, out traversalBuilder))
+ {
+ return BuildFromMethods(traversalText, g);
+ }
+ return traversalBuilder(g);
+ }
+
+ private static ITraversal BuildFromMethods(string traversalText, GraphTraversalSource g)
+ {
+ var parts = traversalText.Split('.');
+ if (parts[0] != "g")
+ {
+ throw BuildException(traversalText);
+ }
+ ITraversal traversal;
+ switch (parts[1])
+ {
+ case "V()":
+ traversal = g.V();
+ break;
+ case "E()":
+ traversal = g.E();
+ break;
+ default:
+ throw BuildException(traversalText);
+ }
+ for (var i = 2; i < parts.Length; i++)
+ {
+ var name = GetCsharpName(parts[i], traversalText);
+ var method = traversal.GetType().GetMethod(name);
+ if (method == null)
+ {
+ throw new InvalidOperationException($"Traversal method '{parts[i]}' not found for testing");
+ }
+ if (method.IsGenericMethod)
+ {
+ throw new InvalidOperationException(
+ $"Can not build traversal to test as '{name}()' method is generic");
+ }
+ traversal = (ITraversal) method.Invoke(traversal, new object[] { new object[0]});
+ }
+ return traversal;
+ }
+
+ private static string GetCsharpName(string part, string traversalText)
+ {
+ if (!part.EndsWith("()"))
+ {
+ throw BuildException(traversalText);
+ }
+ // Transform to PascalCasing and remove the parenthesis
+ return char.ToUpper(part[0]) + part.Substring(1, part.Length - 3);
+ }
+
+ private static Exception BuildException(string traversalText)
+ {
+ return new InvalidOperationException($"Can not build a traversal to test from '{traversalText}'");
+ }
+ }
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/cee68591/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj
index c5e923d..40552ad 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Gremlin.Net.IntegrationTest.csproj
@@ -1,5 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
-
<PropertyGroup>
<TargetFramework>netcoreapp1.0</TargetFramework>
<DebugType>portable</DebugType>
@@ -10,17 +9,14 @@
<SignAssembly>true</SignAssembly>
<PublicSign Condition="'$(OS)' != 'Windows_NT'">true</PublicSign>
</PropertyGroup>
-
<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
-
<ItemGroup>
<ProjectReference Include="..\..\src\Gremlin.Net\Gremlin.Net.csproj" />
</ItemGroup>
-
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0" />
@@ -31,9 +27,12 @@
<PackageReference Include="OpenCover" Version="4.6.519" />
<PackageReference Include="coveralls.io" Version="1.3.4" />
</ItemGroup>
-
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
-
-</Project>
+ <ItemGroup>
+ <Reference Include="Gherkin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
+ <HintPath>..\..\..\..\temp\Gherkin.dll</HintPath>
+ </Reference>
+ </ItemGroup>
+</Project>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/tinkerpop/blob/cee68591/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/RemoteConnectionFactory.cs
----------------------------------------------------------------------
diff --git a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/RemoteConnectionFactory.cs b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/RemoteConnectionFactory.cs
index 47d4f06..249db60 100644
--- a/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/RemoteConnectionFactory.cs
+++ b/gremlin-dotnet/test/Gremlin.Net.IntegrationTest/Process/Traversal/DriverRemoteConnection/RemoteConnectionFactory.cs
@@ -22,16 +22,20 @@
#endregion
using System;
+using System.Collections.Generic;
using Gremlin.Net.Driver;
using Gremlin.Net.Process.Remote;
+using DriverRemoteConnectionImpl = Gremlin.Net.Driver.Remote.DriverRemoteConnection;
namespace Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
{
- internal class RemoteConnectionFactory
+ internal class RemoteConnectionFactory : IDisposable
{
private static readonly string TestHost = ConfigProvider.Configuration["TestServerIpAddress"];
private static readonly int TestPort = Convert.ToInt32(ConfigProvider.Configuration["TestServerPort"]);
+ private readonly IList<DriverRemoteConnectionImpl> _connections = new List<DriverRemoteConnectionImpl>();
+
public IRemoteConnection CreateRemoteConnection()
{
// gmodern is the standard test traversalsource that the main body of test uses
@@ -40,8 +44,18 @@ namespace Gremlin.Net.IntegrationTest.Process.Traversal.DriverRemoteConnection
public IRemoteConnection CreateRemoteConnection(string traversalSource)
{
- return new Net.Driver.Remote.DriverRemoteConnection(
+ var c = new DriverRemoteConnectionImpl(
new GremlinClient(new GremlinServer(TestHost, TestPort)), traversalSource);
+ _connections.Add(c);
+ return c;
+ }
+
+ public void Dispose()
+ {
+ foreach (var connection in _connections)
+ {
+ connection.Dispose();
+ }
}
}
}
\ No newline at end of file