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
9 changes: 3 additions & 6 deletions JSONAPI.EntityFramework.Tests/EntityConverterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,7 @@ public void SetupEntities()
public void SerializeTest()
{
// Arrange
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter();
formatter.PluralizationService = new JSONAPI.Core.PluralizationService();
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter(new JSONAPI.Core.PluralizationService());
MemoryStream stream = new MemoryStream();

// Act
Expand All @@ -124,8 +123,7 @@ public void SerializeTest()
public void DeserializePostIntegrationTest()
{
// Arrange
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter();
formatter.PluralizationService = new JSONAPI.Core.PluralizationService();
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter(new JSONAPI.Core.PluralizationService());
MemoryStream stream = new MemoryStream();

EntityFrameworkMaterializer materializer = new EntityFrameworkMaterializer(context);
Expand Down Expand Up @@ -159,8 +157,7 @@ public void DeserializePostIntegrationTest()
public void UnderpostingTest()
{
// Arrange
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter();
formatter.PluralizationService = new JSONAPI.Core.PluralizationService();
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter(new JSONAPI.Core.PluralizationService());
MemoryStream stream = new MemoryStream();

EntityFrameworkMaterializer materializer = new EntityFrameworkMaterializer(context);
Expand Down
3 changes: 1 addition & 2 deletions JSONAPI.Tests/Core/MetadataManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,7 @@ public void PropertyWasPresentTest()
{
// Arrange

JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter();
formatter.PluralizationService = new JSONAPI.Core.PluralizationService();
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter(new JSONAPI.Core.PluralizationService());
MemoryStream stream = new MemoryStream();

stream = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(@"{""posts"":{""id"":42,""links"":{""author"":""18""}}}"));
Expand Down
114 changes: 111 additions & 3 deletions JSONAPI.Tests/Core/ModelManagerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
using JSONAPI.Core;
using JSONAPI.Tests.Models;
using System.Reflection;
using System.Collections.Generic;
using System.Collections;

namespace JSONAPI.Tests.Core
{
[TestClass]
public class ModelManagerTests
{
private class InvalidModel
private class InvalidModel // No Id discernable!
{
public string Data { get; set; }
}
Expand All @@ -18,7 +20,7 @@ private class InvalidModel
public void FindsIdNamedId()
{
// Arrange
var mm = new ModelManager();
var mm = new ModelManager(new PluralizationService());

// Act
PropertyInfo idprop = mm.GetIdProperty(typeof(Author));
Expand All @@ -32,13 +34,119 @@ public void FindsIdNamedId()
public void DoesntFindMissingId()
{
// Arrange
var mm = new ModelManager();
var mm = new ModelManager(new PluralizationService());

// Act
PropertyInfo idprop = mm.GetIdProperty(typeof(InvalidModel));

// Assert
Assert.Fail("An InvalidOperationException should be thrown and we shouldn't get here!");
}

[TestMethod]
public void GetJsonKeyForTypeTest()
{
// Arrange
var pluralizationService = new PluralizationService();
var mm = new ModelManager(pluralizationService);

// Act
var postKey = mm.GetJsonKeyForType(typeof(Post));
var authorKey = mm.GetJsonKeyForType(typeof(Author));
var commentKey = mm.GetJsonKeyForType(typeof(Comment));

// Assert
Assert.AreEqual("posts", postKey);
Assert.AreEqual("authors", authorKey);
Assert.AreEqual("comments", commentKey);
}

[TestMethod]
public void GetJsonKeyForPropertyTest()
{
// Arrange
var pluralizationService = new PluralizationService();
var mm = new ModelManager(pluralizationService);

// Act
var idKey = mm.GetJsonKeyForProperty(typeof(Author).GetProperty("Id"));
var nameKey = mm.GetJsonKeyForProperty(typeof(Author).GetProperty("Name"));
var postsKey = mm.GetJsonKeyForProperty(typeof(Author).GetProperty("Posts"));

// Assert
Assert.AreEqual("id", idKey);
Assert.AreEqual("name", nameKey);
Assert.AreEqual("posts", postsKey);

}

[TestMethod]
public void GetPropertyForJsonKeyTest()
{
// Arrange
var pluralizationService = new PluralizationService();
var mm = new ModelManager(pluralizationService);
Type authorType = typeof(Author).GetType();

// Act
var idProp = mm.GetPropertyForJsonKey(authorType, "id");
var nameProp = mm.GetPropertyForJsonKey(authorType, "name");
var postsProp = mm.GetPropertyForJsonKey(authorType, "posts");

// Assert
Assert.AreSame(authorType.GetProperty("Id"), idProp);
Assert.AreSame(authorType.GetProperty("Name"), nameProp);
Assert.AreSame(authorType.GetProperty("Posts"), postsProp);

}

[TestMethod]
public void IsSerializedAsManyTest()
{
// Arrange
var mm = new ModelManager(new PluralizationService());

// Act
bool isArray = mm.IsSerializedAsMany(typeof(Post[]));
bool isGenericEnumerable = mm.IsSerializedAsMany(typeof(IEnumerable<Post>));
bool isString = mm.IsSerializedAsMany(typeof(string));
bool isAuthor = mm.IsSerializedAsMany(typeof(Author));
bool isNonGenericEnumerable = mm.IsSerializedAsMany(typeof(IEnumerable));

// Assert
Assert.IsTrue(isArray);
Assert.IsTrue(isGenericEnumerable);
Assert.IsFalse(isString);
Assert.IsFalse(isAuthor);
Assert.IsFalse(isNonGenericEnumerable);
}

[TestMethod]
public void GetElementTypeTest()
{
// Arrange
var mm = new ModelManager(new PluralizationService());

// Act
Type postTypeFromArray = mm.GetElementType(typeof(Post[]));
Type postTypeFromEnumerable = mm.GetElementType(typeof(IEnumerable<Post>));

// Assert
Assert.AreSame(typeof(Post), postTypeFromArray);
Assert.AreSame(typeof(Post), postTypeFromEnumerable);
}

[TestMethod]
public void GetElementTypeInvalidArgumentTest()
{
// Arrange
var mm = new ModelManager(new PluralizationService());

// Act
Type x = mm.GetElementType(typeof(Author));

// Assert
Assert.IsNull(x, "Return value of GetElementType should be null for a non-Many type argument!");
}
}
}
21 changes: 7 additions & 14 deletions JSONAPI.Tests/Json/JsonApiMediaFormaterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ private enum TestEnum
public void CanWritePrimitiveTest()
{
// Arrange
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter();
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter(new PluralizationService());
// Act
// Assert
Assert.IsTrue(formatter.CanWriteTypeAsPrimitive(typeof(Int32)), "CanWriteTypeAsPrimitive returned wrong answer for Integer!");
Expand All @@ -133,8 +133,7 @@ public void SerializerIntegrationTest()
//ModelConverter mc = new ModelConverter();
//ContractResolver.PluralizationService = new PluralizationService();

JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter();
formatter.PluralizationService = new JSONAPI.Core.PluralizationService();
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter(new JSONAPI.Core.PluralizationService());
MemoryStream stream = new MemoryStream();

// Act
Expand All @@ -158,8 +157,7 @@ public void SerializeArrayIntegrationTest()
//ModelConverter mc = new ModelConverter();
//ContractResolver.PluralizationService = new PluralizationService();

JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter();
formatter.PluralizationService = new JSONAPI.Core.PluralizationService();
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter(new JSONAPI.Core.PluralizationService());
MemoryStream stream = new MemoryStream();

// Act
Expand All @@ -180,7 +178,6 @@ 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
Expand All @@ -199,8 +196,7 @@ public void Should_serialize_error()
public void SerializeErrorIntegrationTest()
{
// Arrange
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter();
formatter.PluralizationService = new JSONAPI.Core.PluralizationService();
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter(new JSONAPI.Core.PluralizationService());
MemoryStream stream = new MemoryStream();

// Act
Expand All @@ -224,8 +220,7 @@ public void SerializeErrorIntegrationTest()
public void DeserializeCollectionIntegrationTest()
{
// Arrange
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter();
formatter.PluralizationService = new JSONAPI.Core.PluralizationService();
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter(new JSONAPI.Core.PluralizationService());
MemoryStream stream = new MemoryStream();

formatter.WriteToStreamAsync(typeof(Post), new List<Post> {p, p2}, stream, (System.Net.Http.HttpContent)null, (System.Net.TransportContext)null);
Expand All @@ -246,8 +241,7 @@ public void DeserializeCollectionIntegrationTest()
[TestMethod(), Timeout(1000)]
public void DeserializeExtraPropertyTest()
{
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter();
formatter.PluralizationService = new JSONAPI.Core.PluralizationService();
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter(new JSONAPI.Core.PluralizationService());
MemoryStream stream = new MemoryStream();

stream = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(@"{""authors"":{""id"":13,""name"":""Jason Hater"",""bogus"":""PANIC!"",""links"":{""posts"":[]}}}"));
Expand All @@ -264,8 +258,7 @@ public void DeserializeExtraPropertyTest()
[TestMethod(), Timeout(1000)]
public void DeserializeExtraRelationshipTest()
{
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter();
formatter.PluralizationService = new JSONAPI.Core.PluralizationService();
JsonApiFormatter formatter = new JSONAPI.Json.JsonApiFormatter(new JSONAPI.Core.PluralizationService());
MemoryStream stream = new MemoryStream();

stream = new MemoryStream(System.Text.Encoding.ASCII.GetBytes(@"{""authors"":{""id"":13,""name"":""Jason Hater"",""links"":{""posts"":[],""bogus"":[""PANIC!""]}}}"));
Expand Down
6 changes: 3 additions & 3 deletions JSONAPI.Tests/Json/LinkTemplateTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ public void SetupModels()
public void GetResourceWithLinkTemplateRelationship()
{
var formatter = new JsonApiFormatter
{
PluralizationService = new JSONAPI.Core.PluralizationService()
};
(
new JSONAPI.Core.PluralizationService()
);
var stream = new MemoryStream();

formatter.WriteToStreamAsync(typeof(Post), ThePost, stream, null, null);
Expand Down
64 changes: 64 additions & 0 deletions JSONAPI/Core/IModelManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,70 @@ namespace JSONAPI.Core
{
public interface IModelManager
{
IPluralizationService PluralizationService { get; }

/// <summary>
/// Returns the property that is treated as the unique identifier in a given class.
/// This is used most importantly by JsonApiFormatter to determine what value to
/// write when serializing a "Many" relationship as an array of Ids. It is also
/// used to make dummy related objects (with only the Id property set) when
/// deserializing a JSON payload that specifies a related object only by Id.
///
/// Rules for determining this may vary by implementation.
/// </summary>
/// <param name="type"></param>
/// <returns>The property determined to represent the Id.</returns>
PropertyInfo GetIdProperty(Type type);

/// <summary>
/// Returns the key that will be used to represent a collection of objects of a
/// given type, for example in the top-level of a JSON API document or within
/// the "linked" objects section of a payload.
/// </summary>
/// <param name="type">The serializable Type</param>
/// <returns>The string denoting the given type in JSON documents.</returns>
string GetJsonKeyForType(Type type);

/// <summary>
/// Returns the key that will be used to represent the given property in serialized
/// JSON. Inverse of GetPropertyForJsonKey.
/// </summary>
/// <param name="propInfo">The serializable property</param>
/// <returns>The string denoting the given property within a JSON document.</returns>
string GetJsonKeyForProperty(PropertyInfo propInfo); //TODO: Do we need to have a type parameter here, in case the property is inherited?

/// <summary>
/// Returns the property corresponding to a given JSON Key. Inverse of GetJsonKeyForProperty.
/// </summary>
/// <param name="type">The Type to find the property on</param>
/// <param name="jsonKey">The JSON key representing a property</param>
/// <returns></returns>
PropertyInfo GetPropertyForJsonKey(Type type, string jsonKey);

/// <summary>
/// Analogue to System.Type.GetProperties(), but made available so that any caching done
/// by an IModelManager can be leveraged to return the results faster.
/// </summary>
/// <param name="type">The type to get properties from</param>
/// <returns>All properties recognized by the IModelManager.</returns>
//TODO: This needs to include JsonIgnore'd properties, so that they can be found and explicitly included at runtime...confusing? Add another method that excludes these?
PropertyInfo[] GetProperties(Type type);

/// <summary>
/// Determines whether or not the given type will be treated as a "Many" relationship.
/// </summary>
/// <param name="type">The serializable Type</param>
/// <returns>True for Array and IEnumerable&lt;T&gt; types, false otherwise.</returns>
bool IsSerializedAsMany(Type type);

/// <summary>
/// Analogue for System.Type.GetElementType, but works for arrays or IEnumerable&lt;T&gt;,
/// and provides a capture point to cache potentially expensive reflection operations that
/// have to occur repeatedly in JsonApiFormatter.
/// </summary>
/// <param name="manyType">A type which must be either an Array type or implement IEnumerable&lt;T&gt;.</param>
/// <returns>The element type of an Array, or the first generic parameter of an IEnumerable&lt;T&gt;.</returns>
Type GetElementType(Type manyType);

}
}
Loading