Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Enable Generator type ProviderState #380

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/PactNet.Abstractions/Generators/Generate.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace PactNet.Generators;

public static class Generate
{
/// <summary>
/// Generates a value that is looked up from the provider state context using the given expression
/// </summary>
/// <param name="example">Example value</param>
/// <param name="expression">String expression</param>
/// <returns>Generator</returns>
public static IGenerator ProviderState(string example, string expression)
{
return new ProviderStateGenerator(example, expression);
}
}
13 changes: 13 additions & 0 deletions src/PactNet.Abstractions/Generators/IGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Newtonsoft.Json;
using PactNet.Matchers;

namespace PactNet.Generators;

public interface IGenerator : IMatcher
{
/// <summary>
/// Type of the generator
/// </summary>
[JsonProperty("pact:generator:type")]
string GeneratorType { get; }
}
24 changes: 24 additions & 0 deletions src/PactNet.Abstractions/Generators/ProviderStateGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Newtonsoft.Json;

namespace PactNet.Generators;

public class ProviderStateGenerator : IGenerator
{
public string Type => "type";

public dynamic Value { get; }

public string GeneratorType => "ProviderState";

/// <summary>
/// Expression to lookup in provider state context
/// </summary>
[JsonProperty("expression")]
public string Expression { get; }

public ProviderStateGenerator(dynamic example, string expression)
{
this.Value = example;
this.Expression = expression;
}
}
26 changes: 26 additions & 0 deletions src/PactNet.Abstractions/IRequestBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Net.Http;
using Newtonsoft.Json;
using PactNet.Generators;
using PactNet.Matchers;

namespace PactNet
Expand Down Expand Up @@ -116,6 +117,22 @@ public interface IRequestBuilderV3
/// <returns>Fluent builder</returns>
IRequestBuilderV3 WithRequest(string method, string path);

/// <summary>
/// Set the request
/// </summary>
/// <param name="method">Request method</param>
/// <param name="generator">Path value generator</param>
/// <returns>Fluent builder</returns>
IRequestBuilderV3 WithRequest(HttpMethod method, IGenerator generator);

/// <summary>
/// Set the request
/// </summary>
/// <param name="method">Request method</param>
/// <param name="generator">Path value generator</param>
/// <returns>Fluent builder</returns>
IRequestBuilderV3 WithRequest(string method, IGenerator generator);

/// <summary>
/// Add a query string parameter
/// </summary>
Expand All @@ -125,6 +142,15 @@ public interface IRequestBuilderV3
/// <remarks>You can add a query parameter with the same key multiple times</remarks>
IRequestBuilderV3 WithQuery(string key, string value);

/// <summary>
/// Add a query string parameter
/// </summary>
/// <param name="key">Query parameter key</param>
/// <param name="generator">Query parameter value generator</param>
/// <returns>Fluent builder</returns>
/// <remarks>You can add a query parameter with the same key multiple times</remarks>
IRequestBuilderV3 WithQuery(string key, IGenerator generator);

/// <summary>
/// Add a request header
/// </summary>
Expand Down
64 changes: 64 additions & 0 deletions src/PactNet/RequestBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Net.Http;
using Newtonsoft.Json;
using PactNet.Generators;
using PactNet.Interop;
using PactNet.Matchers;

Expand Down Expand Up @@ -145,6 +146,15 @@ IRequestBuilderV3 IRequestBuilderV3.Given(string providerState, IDictionary<stri
IRequestBuilderV3 IRequestBuilderV3.WithRequest(HttpMethod method, string path)
=> this.WithRequest(method, path);

/// <summary>
/// Set the request
/// </summary>
/// <param name="method">Request method</param>
/// <param name="generator">Path value generator</param>
/// <returns>Fluent builder</returns>
IRequestBuilderV3 IRequestBuilderV3.WithRequest(HttpMethod method, IGenerator generator)
=> this.WithRequest(method, generator);

/// <summary>
/// Set the request
/// </summary>
Expand All @@ -154,6 +164,15 @@ IRequestBuilderV3 IRequestBuilderV3.WithRequest(HttpMethod method, string path)
IRequestBuilderV3 IRequestBuilderV3.WithRequest(string method, string path)
=> this.WithRequest(method, path);

/// <summary>
/// Set the request
/// </summary>
/// <param name="method">Request method</param>
/// <param name="generator">Path value generator</param>
/// <returns>Fluent builder</returns>
IRequestBuilderV3 IRequestBuilderV3.WithRequest(string method, IGenerator generator)
=> this.WithRequest(method, generator);

/// <summary>
/// Add a query string parameter
/// </summary>
Expand All @@ -164,6 +183,16 @@ IRequestBuilderV3 IRequestBuilderV3.WithRequest(string method, string path)
IRequestBuilderV3 IRequestBuilderV3.WithQuery(string key, string value)
=> this.WithQuery(key, value);

/// <summary>
/// Add a query string parameter
/// </summary>
/// <param name="key">Query parameter key</param>
/// <param name="generator">Query parameter value generator</param>
/// <returns>Fluent builder</returns>
/// <remarks>You can add a query parameter with the same key multiple times</remarks>
IRequestBuilderV3 IRequestBuilderV3.WithQuery(string key, IGenerator generator)
=> this.WithQuery(key, generator);

/// <summary>
/// Add a request header
/// </summary>
Expand Down Expand Up @@ -244,6 +273,15 @@ internal RequestBuilder Given(string providerState, IDictionary<string, string>
internal RequestBuilder WithRequest(HttpMethod method, string path)
=> this.WithRequest(method.Method, path);

/// <summary>
/// Set the request
/// </summary>
/// <param name="method">Request method</param>
/// <param name="generator">Path value generator</param>
/// <returns>Fluent builder</returns>
internal RequestBuilder WithRequest(HttpMethod method, IGenerator generator)
=> this.WithRequest(method.Method, generator);

/// <summary>
/// Set the request
/// </summary>
Expand All @@ -258,6 +296,18 @@ internal RequestBuilder WithRequest(string method, string path)
return this;
}

/// <summary>
/// Set the request
/// </summary>
/// <param name="method">Request method</param>
/// <param name="generator">Path value generator</param>
/// <returns>Fluent builder</returns>
internal RequestBuilder WithRequest(string method, IGenerator generator)
{
var serialised = JsonConvert.SerializeObject(generator, this.defaultSettings);
return this.WithRequest(method, serialised);
}

/// <summary>
/// Add a query string parameter
/// </summary>
Expand All @@ -274,6 +324,20 @@ internal RequestBuilder WithQuery(string key, string value)
return this;
}

/// <summary>
/// Add a query string parameter
/// </summary>
/// <param name="key">Query parameter key</param>
/// <param name="generator">Query parameter value generator</param>
/// <returns>Fluent builder</returns>
/// <remarks>You can add a query parameter with the same key multiple times</remarks>
internal RequestBuilder WithQuery(string key, IGenerator generator)
{
var serialised = JsonConvert.SerializeObject(generator, this.defaultSettings);
return this.WithQuery(key, serialised);
}


/// <summary>
/// Add a request header
/// </summary>
Expand Down
20 changes: 20 additions & 0 deletions tests/PactNet.Abstractions.Tests/Generators/GenerateTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using FluentAssertions;
using PactNet.Generators;
using Xunit;

namespace PactNet.Abstractions.Tests.Generators
{
public class GenerateTests
{
[Fact]
public void ProviderState_WhenCalled_ReturnsGenerator()
{
const string example = "/ticket/WO1FN";
const string expression = @"/ticket/${pnr}";

var matcher = Generate.ProviderState(example, expression);

matcher.Should().BeEquivalentTo(new ProviderStateGenerator(example, expression));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using FluentAssertions;
using Newtonsoft.Json;
using PactNet.Generators;
using PactNet.Matchers;
using Xunit;

namespace PactNet.Abstractions.Tests.Generators
{
public class ProviderStateGeneratorTests
{
[Fact]
public void Ctor_WhenCalled_SerialisesCorrectly()
{
const string example = "[email protected]";
const string expression = "${email}";

var generator = new ProviderStateGenerator(example, expression);

string actual = JsonConvert.SerializeObject(generator);
string expected = $@"{{""pact:matcher:type"":""type"",""value"":""{example}"",""pact:generator:type"":""ProviderState"",""expression"":""{expression}""}}";

actual.Should().BeEquivalentTo(expected);
}
}
}
58 changes: 58 additions & 0 deletions tests/PactNet.Tests/RequestBuilderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Moq;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using PactNet.Generators;
using PactNet.Interop;
using Xunit;
using Match = PactNet.Matchers.Match;
Expand Down Expand Up @@ -66,6 +67,18 @@ public void WithRequest_HttpMethod_AddsRequest()
this.mockServer.Verify(s => s.WithRequest(this.handle, "POST", "/some/path"));
}

[Fact]
public void WithRequest_HttpMethod_ProviderStateGenerator_AddsRequest()
{
const string example = "/some/example-path";
const string expression = "/some/${path}";
const string expectedValue = $@"{{""pact:matcher:type"":""type"",""value"":""{example}"",""pact:generator:type"":""ProviderState"",""expression"":""{expression}""}}";

this.builder.WithRequest(HttpMethod.Post, Generate.ProviderState(example, expression));

this.mockServer.Verify(s => s.WithRequest(this.handle, "POST", expectedValue));
}

[Fact]
public void WithRequest_String_AddsRequest()
{
Expand All @@ -74,6 +87,18 @@ public void WithRequest_String_AddsRequest()
this.mockServer.Verify(s => s.WithRequest(this.handle, "POST", "/some/path"));
}

[Fact]
public void WithRequest_String_ProviderStateGenerator_AddsRequest()
{
const string example = "/some/example-path";
const string expression = "/some/${path}";
const string expectedValue = $@"{{""pact:matcher:type"":""type"",""value"":""{example}"",""pact:generator:type"":""ProviderState"",""expression"":""{expression}""}}";

this.builder.WithRequest("POST", Generate.ProviderState(example, expression));

this.mockServer.Verify(s => s.WithRequest(this.handle, "POST", expectedValue));
}

[Fact]
public void WithQuery_WhenCalled_AddsQueryParam()
{
Expand All @@ -82,6 +107,15 @@ public void WithQuery_WhenCalled_AddsQueryParam()
this.mockServer.Verify(s => s.WithQueryParameter(this.handle, "name", "value", 0));
}

[Fact]
public void WithQuery_Generator_WhenCalled_AddsQueryParam()
{
const string expectedValue = $@"{{""pact:matcher:type"":""type"",""value"":""example"",""pact:generator:type"":""ProviderState"",""expression"":""${{value}}""}}";

this.builder.WithQuery("name", Generate.ProviderState("example", "${value}"));
this.mockServer.Verify(s => s.WithQueryParameter(this.handle, "name", expectedValue, 0));
}

[Fact]
public void WithQuery_RepeatedQuery_SetsIndex()
{
Expand All @@ -94,6 +128,20 @@ public void WithQuery_RepeatedQuery_SetsIndex()
this.mockServer.Verify(s => s.WithQueryParameter(this.handle, "other", "value", 0));
}

[Fact]
public void WithQuery_Generator_RepeatedQuery_SetsIndex()
{
const string expectedValue2 = $@"{{""pact:matcher:type"":""type"",""value"":""value2"",""pact:generator:type"":""ProviderState"",""expression"":""${{value}}""}}";

this.builder.WithQuery("name", "value1");
this.builder.WithQuery("name", Generate.ProviderState("value2", "${value}"));
this.builder.WithQuery("other", "value");

this.mockServer.Verify(s => s.WithQueryParameter(this.handle, "name", "value1", 0));
this.mockServer.Verify(s => s.WithQueryParameter(this.handle, "name", expectedValue2, 1));
this.mockServer.Verify(s => s.WithQueryParameter(this.handle, "other", "value", 0));
}

[Fact]
public void WithHeader_Matcher_WhenCalled_AddsSerialisedHeaderParam()
{
Expand All @@ -104,6 +152,16 @@ public void WithHeader_Matcher_WhenCalled_AddsSerialisedHeaderParam()
this.mockServer.Verify(s => s.WithRequestHeader(this.handle, "name", expectedValue, 0));
}

[Fact]
public void WithHeader_Generator_WhenCalled_AddsSerialisedHeaderParam()
{
var expectedValue = "{\"pact:matcher:type\":\"type\",\"value\":\"header\",\"pact:generator:type\":\"ProviderState\",\"expression\":\"${header}\"}";

this.builder.WithHeader("name", Generate.ProviderState("header", "${header}"));

this.mockServer.Verify(s => s.WithRequestHeader(this.handle, "name", expectedValue, 0));
}

[Fact]
public void WithHeader_RepeatedMatcherHeader_SetsIndex()
{
Expand Down