Skip to content
Merged
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
12 changes: 12 additions & 0 deletions JSONAPI.Tests/Data/ErrorSerializerTest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"errors": [
{
"id": "TEST-ERROR-ID",
"status": "500",
"title": "System.Exception",
"detail": "This is the exception message!",
"inner": null,
"stackTrace": "Stack trace would go here"
}
]
}
1 change: 1 addition & 0 deletions JSONAPI.Tests/Data/FormatterErrorSerializationTest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"test":"foo"}
16 changes: 16 additions & 0 deletions JSONAPI.Tests/JSONAPI.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@
<Prefer32Bit>false</Prefer32Bit>
</PropertyGroup>
<ItemGroup>
<Reference Include="FluentAssertions">
<HintPath>..\packages\FluentAssertions.3.2.2\lib\net45\FluentAssertions.dll</HintPath>
</Reference>
<Reference Include="FluentAssertions.Core">
<HintPath>..\packages\FluentAssertions.3.2.2\lib\net45\FluentAssertions.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
Expand All @@ -60,6 +66,8 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Microsoft.AspNet.WebApi.WebHost.5.2.2\lib\net45\System.Web.Http.WebHost.dll</HintPath>
</Reference>
<Reference Include="System.XML" />
<Reference Include="System.Xml.Linq" />
</ItemGroup>
<ItemGroup>
<CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
Expand All @@ -68,7 +76,9 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Core\MetadataManagerTests.cs" />
<Compile Include="Json\ErrorSerializerTests.cs" />
<Compile Include="Json\JsonApiMediaFormaterTests.cs" />
<Compile Include="Json\JsonHelpers.cs" />
<Compile Include="Models\Author.cs" />
<Compile Include="Models\Comment.cs" />
<Compile Include="Models\Post.cs" />
Expand All @@ -82,6 +92,12 @@
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="Data\FormatterErrorSerializationTest.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Data\ErrorSerializerTest.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="Data\SerializerIntegrationTest.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
Expand Down
64 changes: 64 additions & 0 deletions JSONAPI.Tests/Json/ErrorSerializerTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System;
using System.IO;
using System.Web.Http;
using FluentAssertions;
using JSONAPI.Json;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;

namespace JSONAPI.Tests.Json
{
[TestClass]
public class ErrorSerializerTests
{
private class TestErrorIdProvider : IErrorIdProvider
{
public string GenerateId(HttpError error)
{
return "TEST-ERROR-ID";
}
}

[TestMethod]
public void CanSerialize_returns_true_for_HttpError()
{
var serializer = new ErrorSerializer();
var result = serializer.CanSerialize(typeof (HttpError));
result.Should().BeTrue();
}

[TestMethod]
public void CanSerialize_returns_false_for_Exception()
{
var serializer = new ErrorSerializer();
var result = serializer.CanSerialize(typeof(Exception));
result.Should().BeFalse();
}

[TestMethod]
[DeploymentItem(@"Data\ErrorSerializerTest.json")]
public void SerializeError_serializes_httperror()
{
using (var stream = new MemoryStream())
{
var textWriter = new StreamWriter(stream);
var writer = new JsonTextWriter(textWriter);
var error = new HttpError(new Exception("This is the exception message!"), true)
{
StackTrace = "Stack trace would go here"
};
var jsonSerializer = new JsonSerializer();

var serializer = new ErrorSerializer(new TestErrorIdProvider());
serializer.SerializeError(error, stream, writer, jsonSerializer);

writer.Flush();

var expectedJson = File.ReadAllText("ErrorSerializerTest.json");
var minifiedExpectedJson = JsonHelpers.MinifyJson(expectedJson);
var output = System.Text.Encoding.ASCII.GetString(stream.ToArray());
output.Should().Be(minifiedExpectedJson);
}
}
}
}
65 changes: 65 additions & 0 deletions JSONAPI.Tests/Json/JsonApiMediaFormaterTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web.Http;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using JSONAPI.Tests.Models;
using Newtonsoft.Json;
Expand All @@ -17,6 +20,22 @@ public class JsonApiMediaFormaterTests
Author a;
Post p, p2, p3, p4;

private class MockErrorSerializer : IErrorSerializer
{
public bool CanSerialize(Type type)
{
return true;
}

public void SerializeError(object error, Stream writeStream, JsonWriter writer, JsonSerializer serializer)
{
writer.WriteStartObject();
writer.WritePropertyName("test");
serializer.Serialize(writer, "foo");
writer.WriteEndObject();
}
}

[TestInitialize]
public void SetupModels()
{
Expand Down Expand Up @@ -155,6 +174,52 @@ public void SerializeArrayIntegrationTest()
//Assert.AreEqual("[2,3,4]", sw.ToString());
}

[TestMethod]
[DeploymentItem(@"Data\FormatterErrorSerializationTest.json")]
public void Should_serialize_error()
{
// Arrange
var formatter = new JSONAPI.Json.JsonApiFormatter(new MockErrorSerializer());
formatter.PluralizationService = new JSONAPI.Core.PluralizationService();
var stream = new MemoryStream();

// Act
var payload = new HttpError(new Exception(), true);
formatter.WriteToStreamAsync(typeof(HttpError), payload, stream, (System.Net.Http.HttpContent)null, (System.Net.TransportContext)null);

// Assert
var expectedJson = File.ReadAllText("FormatterErrorSerializationTest.json");
var minifiedExpectedJson = JsonHelpers.MinifyJson(expectedJson);
var output = System.Text.Encoding.ASCII.GetString(stream.ToArray());
output.Should().Be(minifiedExpectedJson);
}

[TestMethod]
[DeploymentItem(@"Data\ErrorSerializerTest.json")]
public void SerializeErrorIntegrationTest()
{
// Arrange
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter();
formatter.PluralizationService = new JSONAPI.Core.PluralizationService();
MemoryStream stream = new MemoryStream();

// Act
var payload = new HttpError(new Exception("This is the exception message!"), true)
{
StackTrace = "Stack trace would go here"
};
formatter.WriteToStreamAsync(typeof(HttpError), payload, stream, (System.Net.Http.HttpContent)null, (System.Net.TransportContext)null);

// Assert
var expectedJson = File.ReadAllText("ErrorSerializerTest.json");
var minifiedExpectedJson = JsonHelpers.MinifyJson(expectedJson);
var output = System.Text.Encoding.ASCII.GetString(stream.ToArray());
output = Regex.Replace(output,
@"[a-f0-9]{8}(?:-[a-f0-9]{4}){3}-[a-f0-9]{12}",
"TEST-ERROR-ID"); // We don't know what the GUID will be, so replace it
output.Should().Be(minifiedExpectedJson);
}

[TestMethod]
public void DeserializeCollectionIntegrationTest()
{
Expand Down
13 changes: 13 additions & 0 deletions JSONAPI.Tests/Json/JsonHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System.Text.RegularExpressions;

namespace JSONAPI.Tests.Json
{
static class JsonHelpers
{
// http://stackoverflow.com/questions/8913138/minify-indented-json-string-in-net
public static string MinifyJson(string input)
{
return Regex.Replace(input, "(\"(?:[^\"\\\\]|\\\\.)*\")|\\s+", "$1");
}
}
}
1 change: 1 addition & 0 deletions JSONAPI.Tests/packages.config
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="FluentAssertions" version="3.2.2" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Client" version="5.2.2" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.Core" version="5.2.2" targetFramework="net45" />
<package id="Microsoft.AspNet.WebApi.WebHost" version="5.2.2" targetFramework="net45" />
Expand Down
4 changes: 4 additions & 0 deletions JSONAPI/JSONAPI.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@
<Compile Include="Core\IMaterializer.cs" />
<Compile Include="Core\MetadataManager.cs" />
<Compile Include="Http\ApiController.cs" />
<Compile Include="Json\ErrorSerializer.cs" />
<Compile Include="Json\GuidErrorIdProvider.cs" />
<Compile Include="Json\IErrorIdProvider.cs" />
<Compile Include="Json\IErrorSerializer.cs" />
<Compile Include="Json\JsonApiFormatter.cs" />
<Compile Include="Json\RelationAggregator.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
Expand Down
77 changes: 77 additions & 0 deletions JSONAPI/Json/ErrorSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.IO;
using System.Web.Http;
using Newtonsoft.Json;

namespace JSONAPI.Json
{
internal class ErrorSerializer : IErrorSerializer
{
private class JsonApiError
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }

[JsonProperty(PropertyName = "status")]
public string Status { get; set; }

[JsonProperty(PropertyName = "title")]
public string Title { get; set; }

[JsonProperty(PropertyName = "detail")]
public string Detail { get; set; }

[JsonProperty(PropertyName = "inner")]
public JsonApiError Inner { get; set; }

[JsonProperty(PropertyName = "stackTrace")]
public string StackTrace { get; set; }

public JsonApiError(HttpError error)
{
Title = error.ExceptionType ?? error.Message;
Status = "500";
Detail = error.ExceptionMessage ?? error.MessageDetail;
StackTrace = error.StackTrace;

if (error.InnerException != null)
Inner = new JsonApiError(error.InnerException);
}
}

private readonly IErrorIdProvider _errorIdProvider;

public ErrorSerializer()
: this(new GuidErrorIdProvider())
{

}

public ErrorSerializer(IErrorIdProvider errorIdProvider)
{
_errorIdProvider = errorIdProvider;
}

public bool CanSerialize(Type type)
{
return type == typeof (HttpError);
}

public void SerializeError(object error, Stream writeStream, JsonWriter writer, JsonSerializer serializer)
{
var httpError = error as HttpError;
if (httpError == null) throw new Exception("Unsupported error type.");

writer.WriteStartObject();
writer.WritePropertyName("errors");

var jsonApiError = new JsonApiError(httpError)
{
Id = _errorIdProvider.GenerateId(httpError)
};
serializer.Serialize(writer, new[] { jsonApiError });

writer.WriteEndObject();
}
}
}
13 changes: 13 additions & 0 deletions JSONAPI/Json/GuidErrorIdProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using System;
using System.Web.Http;

namespace JSONAPI.Json
{
internal class GuidErrorIdProvider : IErrorIdProvider
{
public string GenerateId(HttpError error)
{
return Guid.NewGuid().ToString();
}
}
}
9 changes: 9 additions & 0 deletions JSONAPI/Json/IErrorIdProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Web.Http;

namespace JSONAPI.Json
{
internal interface IErrorIdProvider
{
string GenerateId(HttpError error);
}
}
12 changes: 12 additions & 0 deletions JSONAPI/Json/IErrorSerializer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Newtonsoft.Json;
using System;
using System.IO;

namespace JSONAPI.Json
{
internal interface IErrorSerializer
{
bool CanSerialize(Type type);
void SerializeError(object error, Stream writeStream, JsonWriter writer, JsonSerializer serializer);
}
}
Loading