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

Added ability to add custom parser (correct) #46

Open
wants to merge 1 commit 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
13 changes: 13 additions & 0 deletions README.md
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,19 @@ Utilize these tools to validate your JSON schema

## More Examples

### Add new response type parser
RestAssured can already parse JSON and XML response bodies, however you are able to overwrite
these with your own parsing functions or add new parsing functionality.
```C#
//Create a method to parse your input
public static dynamic CsvToJson(string input)
{
// Code to parse csv string to JObject
}
//Then inside main method you add this parser
RestAssured.AddParser("csv",CsvToJson);
```

### Breaking up a call chain
```C#
//Create a new test suite
Expand Down
Empty file modified src/RA.Tests/MockResponseContextWithJson.cs
100644 → 100755
Empty file.
67 changes: 67 additions & 0 deletions src/RA.Tests/MockResponseWithCustomParse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
using System;
using System.Collections.Generic;
using System.Net;
using Newtonsoft.Json.Linq;
using NUnit.Framework;

namespace RA.Tests
{
[TestFixture]
public class MockResponseWithCustomParse
{
private readonly ResponseContext _responseWithCsv;
private static readonly int _mockElapsedMs = 500;
private readonly TimeSpan _mockElapsedTimespan = new TimeSpan(0, 0, 0, 0, _mockElapsedMs);

public static dynamic CsvToJson(string input)
{
string[] lines = input.Split("\n");
string[] keys = lines[0].Split(",");
JArray jarr = new JArray();
for(int i=1;i<lines.Length;i++)
{
string[] values = lines[i].Split(",");
JObject jobj = new JObject();
for(int j=0;j<values.Length;j++)
jobj.Add(keys[j],values[j]);
jarr.Add(jobj);
}
return jarr;
}
public MockResponseWithCustomParse()
{
var responseObjectContent =
"key,value\n" +
"AL,Alabama\n" +
"AK,Alaska";

var header = new Dictionary<string, IEnumerable<string>>
{
{
"Content-Type",
new List<string> {"text/csv"}
}
};

var emptyHeader = new Dictionary<string, IEnumerable<string>>();

var loadResults = new List<LoadResponse> {new LoadResponse(200, 78978078)};

ResponseContext.AddParser("csv", CsvToJson);

_responseWithCsv = new ResponseContext(HttpStatusCode.OK, responseObjectContent, header,
_mockElapsedTimespan, loadResults);
}

[Test]
public void CustomParserShouldPass()
{
_responseWithCsv
.TestHeader("testHeader","Content-type", x => x.Contains("csv"))
.TestBody("first item has AL", x => x[0].key == "AL")
.TestBody("first item has Alabama", x => x[0].value == "Alabama")
.TestBody("second item has AK", x => x[1].key == "AK")
.AssertAll();
}
}
}
71 changes: 49 additions & 22 deletions src/RA/ResponseContext.cs
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -220,54 +220,81 @@ private void Initialize()
ParseLoad();
}

private void Parse()
/// <summary>
/// Holds response parser functions
/// </summary>
private static Dictionary<string, Func<string, dynamic>> parsers = new Dictionary<string, Func<string, dynamic>>()
{
var contentType = ContentType();

if (contentType.Contains("json"))
{
if (!string.IsNullOrEmpty(_content))
{ "json", delegate(string instr)
{
try
{
_parsedContent = JObject.Parse(_content);
return;
return JObject.Parse(instr);
}
catch
{
try
{
return JArray.Parse(instr);
}
catch(Exception e)
{
throw e;
Copy link

@wdolek wdolek Aug 19, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please note that this is breaking change. Original code silently swallows exception (which is not nice indeed), but your change throws. I would agree with your change, however it would be worth mentioning it in readme alongside feature you have added.

Also want to check, way you catch and throw - is that intentional? Do we even need try-catch block there if we want exception to be thrown anyway?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is a breaking change. While it originally swallowed the exception when parsing, if it got to the end without managing to parse it would throw an exception if the _content wasn't empty. Mine checks if it's an empty context at the beginning rather than the end, then throws the exception from that step instead of at the end.

}
}

}
},
{ "xml", delegate(string instr)
{
try
{
_parsedContent = JArray.Parse(_content);
return;
return XDocument.Parse(instr);
}
catch
catch(Exception e)
{
throw e;
}
}
else
{
return;
}
}
else if (contentType.Contains("xml"))
},
};

/// <summary>
/// Adds Parser to allow unsupporter response types to be parsed
/// </summary>
/// <param name="type">Content-Type to use provided function to parse</param>
/// <param name="func">Function to parse type</param>
public static void AddParser(string type, Func<string, dynamic> func)
{
if (parsers.ContainsKey(type))
parsers[type] = func;
else
parsers.Add(type, func);
}

private void Parse()
{
if (string.IsNullOrEmpty(_content))
return;

var contentType = ContentType();

foreach (var type in parsers.Keys)
{
if (!string.IsNullOrEmpty(_content))
if (contentType.Contains(type))
{
try
{
_parsedContent = XDocument.Parse(_content);
_parsedContent = parsers[type](_content);
return;
}
catch
{
throw new Exception(string.Format("{0} parser failed to build dynamic object from data", type));
}
}
}

if (!string.IsNullOrEmpty(_content))
throw new Exception(string.Format("({0}) not supported", contentType));
throw new Exception(string.Format("({0}) not supported. Consider adding a parser for this type using RestAssured.AddParser", contentType));
}

private void ParseLoad()
Expand Down
13 changes: 12 additions & 1 deletion src/RA/RestAssured.cs
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,7 +1,18 @@
namespace RA
using System;

namespace RA
{
public class RestAssured
{
/// <summary>
/// Adds Parser to allow unsupported response types to be parsed
/// </summary>
/// <param name="type">Content-Type to use provided function to parse</param>
/// <param name="func">Function to parse from body string to dynamic object</param>
public static void AddParser(string type, Func<String, dynamic> func)
=> ResponseContext.AddParser(type, func);


public SetupContext Given()
{
return new SetupContext();
Expand Down