Skip to content

Commit

Permalink
#23: Added first version of BDD framework
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcinCelej committed Feb 27, 2023
1 parent 9a6627f commit 0b1d0ab
Show file tree
Hide file tree
Showing 11 changed files with 371 additions and 0 deletions.
13 changes: 13 additions & 0 deletions Behaviours/Synergy.Behaviours.Testing/Feature.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Synergy.Behaviours.Testing;

public class Feature<TFeature> : IFeature
where TFeature : new()
{
public static TFeature Given() => new();
public TFeature When() => Self;
public TFeature Then() => Self;
public TFeature And() => Self;
public TFeature But() => Self;
public TFeature Moreover() => Self;
protected TFeature Self => (TFeature)(object)this;
}
118 changes: 118 additions & 0 deletions Behaviours/Synergy.Behaviours.Testing/FeatureGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;

namespace Synergy.Behaviours.Testing;

public static class FeatureGenerator
{
public static void Generate<TBehaviour>(
this TBehaviour feature,
string from,
string to,
bool withMoreover = false,
[CallerFilePath] string callerFilePath = ""
)
where TBehaviour : IFeature
{
StringBuilder code = new StringBuilder();
string className = feature.GetType().Name;
var gherkinPath = Path.Combine(Path.GetDirectoryName(callerFilePath), from);
var gherkins = File.ReadAllLines(gherkinPath);

code.AppendLine("using System.CodeDom.Compiler;");
code.AppendLine();
code.AppendLine($"namespace {feature.GetType().Namespace};");
code.AppendLine();
code.AppendLine(
$"[GeneratedCode(\"{typeof(FeatureGenerator).Assembly.FullName}\", \"{typeof(FeatureGenerator).Assembly.GetName().Version.ToString()}\")]");
code.AppendLine($"public partial class {className}");
code.AppendLine("{");
// code.AppendLine(" [Fact]");
// code.AppendLine(" public void Generate()");
// code.AppendLine($" => Behaviours<{featureClass}>.Generate({nameof(from)}: \"{from}\", this);");

string? scenarioMethod = null;
foreach (var line in gherkins)
{
if (line.Contains("#"))
{
//scenarioMethod = Moreover();
code.AppendLine(line.Replace("#", "//"));
continue;
}

if (string.IsNullOrEmpty(line.Trim()))
{
scenarioMethod = CloseScenario();
code.AppendLine();
continue;
}

var scenario = Regex.Match(line, "\\s*Scenario\\: (.*)");
if (scenario.Success)
{
scenarioMethod = FeatureGenerator.ToMethod(scenario.Groups[1]
.Value);
code.AppendLine(" [Xunit.Fact]");
code.AppendLine($" public void {scenarioMethod}() // {line.Trim()}");
code.AppendLine($" => ");
}

var given = Regex.Match(line, "\\s*Given (.*)");
if (given.Success)
code.AppendLine($" Given().{FeatureGenerator.ToMethod(given.Groups[1].Value)}() // {line.Trim()}");

var and = Regex.Match(line, "\\s*And (.*)");
if (and.Success)
code.AppendLine($" .And().{FeatureGenerator.ToMethod(and.Groups[1].Value)}() // {line.Trim()}");

var but = Regex.Match(line, "\\s*But (.*)");
if (but.Success)
code.AppendLine($" .But().{FeatureGenerator.ToMethod(but.Groups[1].Value)}() // {line.Trim()}");

var when = Regex.Match(line, "\\s*When (.*)");
if (when.Success)
code.AppendLine($" .When().{FeatureGenerator.ToMethod(when.Groups[1].Value)}() // {line.Trim()}");

var then = Regex.Match(line, "\\s*Then (.*)");
if (then.Success)
code.AppendLine($" .Then().{FeatureGenerator.ToMethod(then.Groups[1].Value)}() // {line.Trim()}");
}

CloseScenario();

// code.AppendLine();
// code.AppendLine($" partial class {featureClass}");
// code.AppendLine(" {");
// code.AppendLine(" }");
code.AppendLine("}");

var destinationFilePath = Path.Combine(Path.GetDirectoryName(callerFilePath), to);
File.WriteAllText(destinationFilePath, code.ToString());

string? CloseScenario()
{
if (scenarioMethod != null)
{
if (withMoreover)
code.AppendLine($" .Moreover().Verify{scenarioMethod}();");
else
code.AppendLine($" ;");
}

scenarioMethod = null;
return scenarioMethod;
}
}

private static string ToMethod(string sentence)
{
var parts = sentence.Split(" ");
var m = string.Concat(parts.Where(p => !string.IsNullOrEmpty(p))
.Select(p => p.Substring(0, 1)
.ToUpperInvariant() + p.Substring(1)));
m = Regex.Replace(m, "[^A-Za-z0-9_]", "");
return m;
}
}
5 changes: 5 additions & 0 deletions Behaviours/Synergy.Behaviours.Testing/IFeature.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Synergy.Behaviours.Testing;

public interface IFeature
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<Title>Synergy Behaviour Driven Development</Title>
<Authors>Synergy Marcin Celej</Authors>
<Description>Behaviour Driven Development support</Description>
<Copyright>Copyright © Synergy Marcin Celej 2023</Copyright>
<PackageProjectUrl>https://github.com/synergy-software/synergy.framework</PackageProjectUrl>
<PackageIcon>synergy.png</PackageIcon>
<PackageTags>BDD Behaviour Driven Development</PackageTags>
</PropertyGroup>

<ItemGroup>
<None Update="synergy.png">
<Pack>true</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>

</Project>
Binary file added Behaviours/Synergy.Behaviours.Testing/synergy.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
49 changes: 49 additions & 0 deletions Behaviours/Synergy.Behaviours.Tests/Calculator.Behaviours.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
using Synergy.Behaviours.Testing;
using Xunit;

namespace Synergy.Behaviours.Tests;

public partial class CalculatorFeature : Feature<CalculatorFeature>
{
[Fact]
public void GenerateFeature()
=> this.Generate(
from: "Calculator.feature",
to: "Calculator.Feature.cs"
);

private int _firstNumber;

private CalculatorFeature TheFirstNumberIs50()
{
this._firstNumber = 50;
return this;
}

private int _secondNumber;
private int _result;

private CalculatorFeature TheSecondNumberIs70()
{
this._secondNumber = 70;
return this;
}

private CalculatorFeature TheTwoNumbersAreAdded()
{
var calculator = new Calculator { FirstNumber = this._firstNumber, SecondNumber = this._secondNumber };
_result = calculator.Add();
return this;
}

private CalculatorFeature TheResultShouldBe120()
{
Assert.Equal(120, this._result);
return this;
}

private CalculatorFeature VerifyAddTwoNumbers()
{
return this;
}
}
45 changes: 45 additions & 0 deletions Behaviours/Synergy.Behaviours.Tests/Calculator.Feature.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 35 additions & 0 deletions Behaviours/Synergy.Behaviours.Tests/Calculator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
namespace Synergy.Behaviours.Tests;

public class Calculator
{
public int FirstNumber { get; set; }

public int SecondNumber { get; set; }

public int Add()
{
return FirstNumber + SecondNumber;
}

public int Subtract()
{
return FirstNumber - SecondNumber;
}

public int Divide()
{
if (FirstNumber == 0 || SecondNumber == 0)
{
return 0;
}
else
{
return FirstNumber / SecondNumber;
}
}

public int Multiply()
{
return FirstNumber * SecondNumber;
}
}
41 changes: 41 additions & 0 deletions Behaviours/Synergy.Behaviours.Tests/Calculator.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
Feature: Calculator
![Calculator](https://specflow.org/wp-content/uploads/2020/09/calculator.png)
Simple calculator for performing calculations on **two** numbers

Link to a feature: [Calculator](SpecFlowCalculator.Specs/Features/Calculator.feature)
***Further read***: **[Learn more about how to generate Living Documentation](https://docs.specflow.org/projects/specflow-livingdoc/en/latest/LivingDocGenerator/Generating-Documentation.html)**

@Add
Scenario: Add two numbers
Given the first number is 50
And the second number is 70
When the two numbers are added
Then the result should be 120

# @Subtract
# Scenario: Subtract two numbers
# Given the first number is 50
# And the second number is 25
# When the two numbers are subtracted
# Then the result should be 25
#
# @Divide
# Scenario: Divide two numbers
# Given the first number is 100
# And the second number is 2
# When the two numbers are divided
# Then the result should be 50
#
# @Divide
# Scenario: Divide by 0 returns 0
# Given the first number is 0
# And the second number is 70
# When the two numbers are divided
# Then the result should be 0
#
# @Multiply
# Scenario: Multiply two numbers
# Given the first number is 5
# And the second number is 50
# When the two numbers are multiplied
# Then the result should be 250
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<OutputType>Library</OutputType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="xunit" Version="2.4.2" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Synergy.Behaviours.Testing\Synergy.Behaviours.Testing.csproj" />
</ItemGroup>

<ItemGroup>
<Compile Update="Calculator.Behaviours.cs">
<DependentUpon>Calculator.Feature.cs</DependentUpon>
</Compile>
</ItemGroup>

</Project>
Loading

0 comments on commit 0b1d0ab

Please sign in to comment.