예제 #1
0
        public static void Equal(IReadOnlyList <ApiProperty> expectedCollection, JToken actualJToken)
        {
            // Handle when 'expected' is null.
            if (expectedCollection == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            Assert.Equal(JTokenType.Array, actualJTokenType);

            var actualJArray = (JArray)actualJToken;

            Assert.Equal(expectedCollection.Count, actualJArray.Count);
            var count = expectedCollection.Count;

            for (var index = 0; index < count; ++index)
            {
                var expectedObjectProperty     = expectedCollection[index];
                var actualObjectPropertyJToken = actualJArray[index];

                Assert.NotNull(actualObjectPropertyJToken);
                Assert.Equal(JTokenType.Object, actualObjectPropertyJToken.Type);

                var actualObjectPropertyJObject = (JObject)actualObjectPropertyJToken;
                ApiPropertyAssert.Equal(expectedObjectProperty, actualObjectPropertyJObject);
            }
        }
예제 #2
0
        public static void Equal(ResourceIdentifier expected, JToken actualJToken)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            Assert.Equal(JTokenType.Object, actualJTokenType);

            var actualJObject = (JObject)actualJToken;

            Assert.Equal(expected.Type, (string)actualJObject.SelectToken(Keywords.Type));
            Assert.Equal(expected.Id, (string)actualJObject.SelectToken(Keywords.Id));

            var actualMetaJToken = actualJObject.SelectToken(Keywords.Meta);

            ClrObjectAssert.Equal(expected.Meta, actualMetaJToken);
        }
예제 #3
0
        public static void Equal(JsonApiVersion expected, JToken actualJToken)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            Assert.Equal(JTokenType.Object, actualJTokenType);

            var actualJObject = (JObject)actualJToken;

            // Version
            Assert.Equal(expected.Version, (string)actualJObject.SelectToken(Keywords.Version));

            // Meta
            var actualMetaJToken = actualJObject.SelectToken(Keywords.Meta);

            MetaAssert.Equal(expected.Meta, actualMetaJToken);
        }
        public static void Equal(Relationships expected, JToken actualJToken)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            Assert.Equal(JTokenType.Object, actualJTokenType);

            var actualJObject = (JObject)actualJToken;

            var expectedRelationshipsCount = expected.Count;
            var actualRelationshipsCount   = actualJObject.Count;

            Assert.Equal(expectedRelationshipsCount, actualRelationshipsCount);

            foreach (var key in expected.Keys)
            {
                var expectedRelationship = expected[key];
                Assert.IsAssignableFrom <Relationship>(expectedRelationship);

                var actualRelationshipJToken = actualJObject[key];
                RelationshipAssert.Equal(expectedRelationship, actualRelationshipJToken);
            }
        }
        public static void Equal(ApiObject expected, JToken actualJToken)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            Assert.Equal(JTokenType.Object, actualJTokenType);

            var actualJObject = (JObject)actualJToken;

            var expectedCollection = expected.ToList();
            var actualCollection   = actualJObject.Properties().ToList();

            Assert.Equal(expectedCollection.Count, actualCollection.Count);

            var count = expectedCollection.Count;

            for (var index = 0; index < count; ++index)
            {
                var expectedObjectProperty = expectedCollection[index];
                var actualJProperty        = actualCollection[index];

                ApiPropertyAssert.Equal(expectedObjectProperty, actualJProperty);
            }
        }
예제 #6
0
        public static void Equal(IEnumerable <Error> expected, JToken actualJToken)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            Assert.Equal(JTokenType.Array, actualJTokenType);

            var actualJArray = (JArray)actualJToken;

            var expectedCollection = expected.SafeToReadOnlyList();

            Assert.Equal(expectedCollection.Count, actualJArray.Count);
            var count = expectedCollection.Count;

            for (var index = 0; index < count; ++index)
            {
                var expectedError     = expectedCollection[index];
                var actualErrorJToken = actualJArray[index];

                Assert.NotNull(actualErrorJToken);
                Assert.Equal(JTokenType.Object, actualErrorJToken.Type);

                var actualErrorJObject = (JObject)actualErrorJToken;
                ErrorAssert.Equal(expectedError, actualErrorJObject);
            }
        }
예제 #7
0
        public static void Equal(Links expected, JToken actualJToken)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            Assert.Equal(JTokenType.Object, actualJTokenType);

            var actualJObject = (JObject)actualJToken;

            var expectedLinksCount = expected.Count;
            var actualLinksCount   = actualJObject.Count;

            Assert.Equal(expectedLinksCount, actualLinksCount);

            foreach (var key in expected.Keys)
            {
                var expectedLink = expected[key];
                Assert.IsType <Link>(expectedLink);

                var actualLinkJToken = actualJObject[key];
                LinkAssert.Equal(expectedLink, actualLinkJToken);
            }
        }
        public static void Equal(object expected, JObject actualJObject)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJObject);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJObject);

            var expectedTypeInfo = expected.GetType().GetTypeInfo();

            // .. Handle special case when expected type is 'Resource'
            if (expectedTypeInfo == ResourceTypeInfo)
            {
                var expectedResource = (Resource)expected;
                ResourceAssert.Equal(expectedResource, actualJObject);
            }
            // .. Handle special case when expected type is 'ResourceIdentifier'
            else if (expectedTypeInfo == ResourceIdentifierTypeInfo)
            {
                var expectedResourceIdentifier = (ResourceIdentifier)expected;
                ResourceIdentifierAssert.Equal(expectedResourceIdentifier, actualJObject);
            }
            // .. Handle special case when expected type is 'JObject'
            else if (expectedTypeInfo == JObjectTypeInfo)
            {
                var expectedJObject = (JObject)expected;
                Assert.Equal(expectedJObject, actualJObject);
            }
            // .. Handle normal case when expected type is an object that is
            // .. not 'Resource' or 'ResourceIdentifier'.
            else
            {
                var expectedProperties = expectedTypeInfo.GetProperties();
                foreach (var expectedProperty in expectedProperties)
                {
                    // ReSharper disable once UnusedVariable
                    var expectedPropertyName  = GetDotNetPropertyName(expectedProperty);
                    var expectedPropertyValue = expectedProperty.GetValue(expected, null);

                    var actualPropertyName = GetJsonApiPropertyName(expectedProperty);
                    var actualJToken       = actualJObject.SelectToken(actualPropertyName);

                    ClrObjectAssert.Equal(expectedPropertyValue, actualJToken);
                }
            }
        }
예제 #9
0
        public static void Equal(Error expected, JToken actualJToken)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            Assert.Equal(JTokenType.Object, actualJTokenType);

            var actualJObject = (JObject)actualJToken;

            // Id
            Assert.Equal(expected.Id, (string)actualJObject.SelectToken(Keywords.Id));

            // Status
            Assert.Equal(expected.Status, (string)actualJObject.SelectToken(Keywords.Status));

            // Code
            Assert.Equal(expected.Code, (string)actualJObject.SelectToken(Keywords.Code));

            // Title
            Assert.Equal(expected.Title, (string)actualJObject.SelectToken(Keywords.Title));

            // Detail
            Assert.Equal(expected.Detail, (string)actualJObject.SelectToken(Keywords.Detail));

            // Source
            var actualSourceJToken = actualJObject.SelectToken(Keywords.Source);

            ClrObjectAssert.Equal(expected.Source, actualSourceJToken);

            // Links
            var actualLinksJToken = actualJObject.SelectToken(Keywords.Links);

            LinksAssert.Equal(expected.Links, actualLinksJToken);

            // Meta
            var actualMetaJToken = actualJObject.SelectToken(Keywords.Meta);

            MetaAssert.Equal(expected.Meta, actualMetaJToken);
        }
예제 #10
0
        public static void Equal(Resource expected, JToken actualJToken)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            Assert.Equal(JTokenType.Object, actualJTokenType);

            var actualJObject = (JObject)actualJToken;

            // Type
            Assert.Equal(expected.Type, (string)actualJObject.SelectToken(Keywords.Type));

            // Id
            Assert.Equal(expected.Id, (string)actualJObject.SelectToken(Keywords.Id));

            // Attributes
            var actualAttributesJToken = actualJObject.SelectToken(Keywords.Attributes);

            ApiObjectAssert.Equal(expected.Attributes, actualAttributesJToken);

            // Relationships
            var actualRelationshipsJToken = actualJObject.SelectToken(Keywords.Relationships);

            RelationshipsAssert.Equal(expected.Relationships, actualRelationshipsJToken);

            // Links
            var actualLinksJToken = actualJObject.SelectToken(Keywords.Links);

            LinksAssert.Equal(expected.Links, actualLinksJToken);

            // Meta
            var actualMetaJToken = actualJObject.SelectToken(Keywords.Meta);

            MetaAssert.Equal(expected.Meta, actualMetaJToken);
        }
예제 #11
0
        // PUBLIC METHODS ///////////////////////////////////////////////////
        #region Assert Methods
        public static void Equal(Meta expected, JToken actualJToken)
        {
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            Assert.Equal(JTokenType.Object, actualJTokenType);

            var actualJObject = (JObject)actualJToken;
            var actualMeta    = (Meta)actualJObject;

            MetaAssert.Equal(expected, actualMeta);
        }
예제 #12
0
        // PUBLIC METHODS ///////////////////////////////////////////////////
        #region Assert Methods
        public static void Equal(ApiProperty expected, JToken actualJToken)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            Assert.Equal(JTokenType.Property, actualJTokenType);

            var actualJProperty = (JProperty)actualJToken;

            Assert.Equal(expected.Name, actualJProperty.Name);
            ClrObjectAssert.Equal(expected.ValueAsObject(), actualJProperty.Value);
        }
        public static void Equal(object expected, object actual)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                if (actual == null)
                {
                    return;
                }

                var actualType1 = actual.GetType();
                if (actualType1.IsSubclassOf(typeof(JToken)))
                {
                    var actualJToken = (JToken)actual;
                    ClrObjectAssert.IsNull(actualJToken);
                    return;
                }
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actual);

            var actualType2 = actual.GetType();

            if (actualType2.IsSubclassOf(typeof(JToken)))
            {
                var actualJToken = (JToken)actual;
                ClrObjectAssert.Equal(expected, actualJToken);
            }
            else
            {
                // Use FluentAssertions to compare for attribute equality
                // instead of reference equality in Assert.Equal(expectetd, actual)
                actual.ShouldBeEquivalentTo(expected);
            }
        }
예제 #14
0
        public static void Equal(Link expected, JToken actualJToken)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            var expectedHRef = expected.HRef;
            var expectedMeta = expected.Meta;

            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            switch (actualJTokenType)
            {
            case JTokenType.String:
            {
                var actualHRef = (string)actualJToken;
                Assert.Equal(expectedHRef, actualHRef);

                Assert.Null(expectedMeta);
            }
            break;

            case JTokenType.Object:
            {
                var actualJObject = (JObject)actualJToken;

                // HRef String
                var actualHRefJToken = actualJObject.SelectToken(Keywords.HRef);
                if (expectedHRef == null)
                {
                    if (actualHRefJToken == null)
                    {
                        return;
                    }

                    var actualHRefJTokenType = actualHRefJToken.Type;
                    Assert.Equal(JTokenType.Null, actualHRefJTokenType);
                }
                else
                {
                    Assert.Equal(JTokenType.String, actualHRefJToken.Type);

                    var actualHRef = (string)actualHRefJToken;
                    Assert.Equal(expectedHRef, actualHRef);
                }

                // Meta Object
                var actualMetaJToken = actualJObject.SelectToken(Keywords.Meta);
                ClrObjectAssert.Equal(expectedMeta, actualMetaJToken);
            }
            break;

            case JTokenType.None:
            case JTokenType.Null:
            {
                Assert.Null(expectedHRef);
                Assert.Null(expectedMeta);
            }
            break;

            default:
                Assert.True(false, String.Format("Invalid JToken [type={0}] for link.", actualJTokenType));
                return;
            }
        }
        // PUBLIC METHODS ///////////////////////////////////////////////////
        #region Assert Methods
        public static void Equal(object expected, JToken actualJToken)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            switch (actualJTokenType)
            {
            case JTokenType.Array:
            {
                var expectedArray = ((IEnumerable <object>)expected).ToList();
                var actualJArray  = (JArray)actualJToken;

                Assert.Equal(expectedArray.Count, actualJArray.Count);
                var count = expectedArray.Count;
                for (var i = 0; i < count; ++i)
                {
                    var expectedItem     = expectedArray[i];
                    var actualJTokenItem = actualJArray[i];
                    ClrObjectAssert.Equal(expectedItem, actualJTokenItem);
                }
            }
            break;

            case JTokenType.Object:
            {
                var actualJObject = (JObject)actualJToken;
                ClrObjectAssert.Equal(expected, actualJObject);
            }
            break;

            case JTokenType.Integer:
            {
                var expectedInteger = Convert.ToInt64(expected);
                var actualInteger   = (long)actualJToken;
                Assert.Equal(expectedInteger, actualInteger);
            }
            break;

            case JTokenType.Float:
            {
                var expectedFloat = Convert.ToDecimal(expected);
                var actualFloat   = (decimal)actualJToken;
                Assert.Equal(expectedFloat, actualFloat);
            }
            break;

            case JTokenType.String:
            {
                // Special case if expected is or derives from JToken.
                var expectedType = expected.GetType();
                if (typeof(JToken).IsAssignableFrom(expectedType))
                {
                    Assert.Equal(expected, actualJToken);
                    return;
                }

                var actualString = (string)actualJToken;
                var actual       = TypeConverter.Convert(actualString, expectedType);
                Assert.Equal(expected, actual);
            }
            break;

            case JTokenType.Boolean:
            {
                var expectedBool = Convert.ToBoolean(expected);
                var actualBool   = (bool)actualJToken;
                Assert.Equal(expectedBool, actualBool);
            }
            break;

            case JTokenType.Date:
            {
                var expectedType = expected.GetType();
                if (expectedType == typeof(DateTime))
                {
                    var expectedDateTime       = (DateTime)expected;
                    var jsonSerializerSettings = new JsonSerializerSettings
                    {
                        DateParseHandling = DateParseHandling.DateTime
                    };
                    var jsonSerializer = JsonSerializer.Create(jsonSerializerSettings);
                    var actualDateTime = actualJToken.ToObject <DateTime>(jsonSerializer);
                    Assert.Equal(expectedDateTime, actualDateTime);
                }
                else if (expectedType == typeof(DateTimeOffset))
                {
                    var expectedDateTimeOffset = (DateTimeOffset)expected;
                    var jsonSerializerSettings = new JsonSerializerSettings
                    {
                        DateParseHandling = DateParseHandling.DateTimeOffset
                    };
                    var jsonSerializer       = JsonSerializer.Create(jsonSerializerSettings);
                    var actualDateTimeOffset = actualJToken.ToObject <DateTimeOffset>(jsonSerializer);
                    Assert.Equal(expectedDateTimeOffset, actualDateTimeOffset);
                }
                else
                {
                    Assert.True(false, "Expected date type is not DateTime or DateTimeOffset.");
                }
            }
            break;

            default:
                Assert.True(false, String.Format("Unknown actual JTokenType [value={0}] in expected object to actual JToken assert method.", actualJTokenType));
                break;
            }
        }
예제 #16
0
        public static void Equal(Document expected, JToken actualJToken)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            Assert.Equal(JTokenType.Object, actualJTokenType);

            var actualJObject = (JObject)actualJToken;

            // Meta
            var actualMetaJToken = actualJObject.SelectToken(Keywords.Meta);

            MetaAssert.Equal(expected.Meta, actualMetaJToken);

            // Links
            var actualLinksJToken = actualJObject.SelectToken(Keywords.Links);

            LinksAssert.Equal(expected.Links, actualLinksJToken);

            // Data

            // Document types can be the following:
            // 1. Document
            // 2. EmptyDocument
            // 3. ErrorsDocument
            // 4. NullDocument
            // 5. ResourceDocument
            // 6. ResourceIdentifierDocument
            // 7. ResourceCollectionDocument
            // 8. ResourceIdentifierCollectionDocument
            var expectedType       = expected.GetType();
            var actualDataJToken   = actualJObject.SelectToken(Keywords.Data);
            var actualErrorsJToken = actualJObject.SelectToken(Keywords.Errors);

            if (actualDataJToken != null && actualErrorsJToken != null)
            {
                var message = "Document can not contain both \"{0}\" and \"{1}\" members.".FormatWith(Keywords.Data, Keywords.Errors);
                Assert.True(false, message);
                return;
            }

            if (actualDataJToken != null)
            {
                var actualDataJTokenType = actualDataJToken.Type;
                switch (actualDataJTokenType)
                {
                // NullDocument, ResourceDocument, or ResourceIdentifierDocument (data is null)
                case JTokenType.None:
                case JTokenType.Null:
                {
                    // For this scenario, the expected type is either a NullDocument, ResourceDocument, or a ResourceIdentifierDocument.
                    Assert.True(expected.IsDataNullOrEmpty());
                }
                break;

                // ResourceDocument or ResourceIdentifierDocument (one resource or resource identifier)
                case JTokenType.Object:
                {
                    var actualDataJObject = (JObject)actualDataJToken;
                    var dataType          = actualDataJObject.GetDataType();
                    switch (dataType)
                    {
                    case DataType.Resource:
                    {
                        Assert.Equal(ResourceDocumentTypeInfo, expectedType);

                        var expectedResourceDocument = (ResourceDocument)expected;
                        var expectedResource         = expectedResourceDocument.Data;

                        ResourceAssert.Equal(expectedResource, actualDataJToken);

                        // Included
                        var expectedIncluded     = expected.GetIncludedResources();
                        var actualIncludedJToken = actualJObject.SelectToken(Keywords.Included);
                        ResourceAssert.Equal(expectedIncluded, actualIncludedJToken);
                    }
                    break;

                    case DataType.ResourceIdentifier:
                    {
                        Assert.Equal(ResourceIdentifierDocumentTypeInfo, expectedType);

                        var expectedResourceIdentifierDocument = (ResourceIdentifierDocument)expected;
                        var expectedResourceIdentifier         = expectedResourceIdentifierDocument.Data;

                        ResourceIdentifierAssert.Equal(expectedResourceIdentifier, actualDataJToken);
                    }
                    break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }
                }
                break;

                // ResourceCollectionDocument or ResourceIdentifierCollectionDocument (many resources or resource identifiers)
                case JTokenType.Array:
                {
                    var actualDataJArray = (JArray)actualDataJToken;
                    var count            = actualDataJArray.Count;
                    if (count == 0)
                    {
                        // For this scenario, the expected type is either an EmptyDocument, ResourceCollectionDocument, or a ResourceIdentifierCollectionDocument.
                        Assert.True(expected.IsDataNullOrEmpty());
                    }
                    else
                    {
                        var dataType = ((JObject)actualDataJArray[0]).GetDataType();
                        switch (dataType)
                        {
                        case DataType.Resource:
                        {
                            Assert.Equal(ResourceCollectionDocumentTypeInfo, expectedType);

                            var expectedResourceCollectionDocument = (ResourceCollectionDocument)expected;
                            var expectedResourceCollection         = expectedResourceCollectionDocument.Data;

                            ResourceAssert.Equal(expectedResourceCollection, actualDataJToken);

                            // Included
                            var expectedIncluded     = expected.GetIncludedResources();
                            var actualIncludedJToken = actualJObject.SelectToken(Keywords.Included);
                            ResourceAssert.Equal(expectedIncluded, actualIncludedJToken);
                        }
                        break;

                        case DataType.ResourceIdentifier:
                        {
                            Assert.Equal(ResourceIdentifierCollectionDocumentTypeInfo, expectedType);

                            var expectedResourceIdentifierCollectionDocument = (ResourceIdentifierCollectionDocument)expected;
                            var expectedResourceIdentifierCollection         = expectedResourceIdentifierCollectionDocument.Data;

                            ResourceIdentifierAssert.Equal(expectedResourceIdentifierCollection, actualDataJToken);
                        }
                        break;

                        default:
                            throw new ArgumentOutOfRangeException();
                        }
                    }
                }
                break;

                default:
                    Assert.True(false, String.Format("Invalid JToken [type={0}] for document.", actualJTokenType));
                    break;
                }
            }
            else if (actualErrorsJToken != null)
            {
                // Errors
                var expectedErrors = expected.GetErrors();
                ErrorAssert.Equal(expectedErrors, actualErrorsJToken);
            }
            else
            {
                Assert.Equal(DocumentTypeInfo, expectedType);
            }
        }
예제 #17
0
        public static void Equal(Relationship expected, JToken actualJToken)
        {
            // Handle when 'expected' is null.
            if (expected == null)
            {
                ClrObjectAssert.IsNull(actualJToken);
                return;
            }

            // Handle when 'expected' is not null.
            Assert.NotNull(actualJToken);

            var actualJTokenType = actualJToken.Type;

            Assert.Equal(JTokenType.Object, actualJTokenType);

            var actualJObject = (JObject)actualJToken;

            // Links
            var actualLinksJToken = actualJObject.SelectToken(Keywords.Links);

            LinksAssert.Equal(expected.Links, actualLinksJToken);

            // Data

            // Relationship types can be the following:
            // 1. Relationship (Base with no Data)
            // 2. ToOneRelationship (Derived from Relationship with one resource identifier (0 or 1))
            // 3. ToManyRelationship (Derived from Relationship with many resource identifiers (N))
            var expectedType     = expected.GetType();
            var actualDataJToken = actualJObject.SelectToken(Keywords.Data);

            if (actualDataJToken == null)
            {
                Assert.Equal(RelationshipTypeInfo, expectedType);
            }
            else
            {
                var actualDataJTokenType = actualDataJToken.Type;
                switch (actualDataJTokenType)
                {
                // ToOneRelationship (empty to-one relationship)
                case JTokenType.None:
                case JTokenType.Null:
                {
                    Assert.Equal(ToOneRelationshipTypeInfo, expectedType);
                    var expectedToOneRelationship  = (ToOneRelationship)expected;
                    var expectedResourceIdentifier = expectedToOneRelationship.Data;
                    Assert.Null(expectedResourceIdentifier);
                }
                break;

                // ToOneRelationship (non-empty to-one relationship)
                case JTokenType.Object:
                {
                    Assert.Equal(ToOneRelationshipTypeInfo, expectedType);

                    var expectedToOneRelationship  = (ToOneRelationship)expected;
                    var expectedResourceIdentifier = expectedToOneRelationship.Data;

                    var actualResourceIdentifierJToken = actualDataJToken;
                    ResourceIdentifierAssert.Equal(expectedResourceIdentifier, actualResourceIdentifierJToken);
                }
                break;

                // ToManyRelationship
                case JTokenType.Array:
                {
                    Assert.Equal(ToManyRelationshipTypeInfo, expectedType);

                    var expectedToManyRelationship           = (ToManyRelationship)expected;
                    var expectedResourceIdentifierCollection = expectedToManyRelationship.Data;

                    if (expectedResourceIdentifierCollection.Any())
                    {
                        // ToManyRelationship (non-empty to-many relationship)
                        Assert.True(actualDataJToken.Any());

                        var actualResourceIdentifierJToken = actualDataJToken;
                        ResourceIdentifierAssert.Equal(expectedResourceIdentifierCollection, actualResourceIdentifierJToken);
                    }
                    else
                    {
                        // ToManyRelationship (empty to-many relationship)
                        Assert.False(actualDataJToken.Any());
                    }
                }
                break;

                default:
                    Assert.True(false, String.Format("Invalid JToken [type={0}] for relationship.", actualJTokenType));
                    break;
                }
            }

            // Meta
            var actualMetaJToken = actualJObject.SelectToken(Keywords.Meta);

            MetaAssert.Equal(expected.Meta, actualMetaJToken);
        }