public void JsonLightTaupoSerializerServiceDocumentTest()
        {
            var testCases = new JsonLightSerializerTestCase[]
            {
                // Service document
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.ServiceDocument().Workspace(
                        PayloadBuilder.Workspace()
                        .ResourceCollection("Coll1Title", "Coll1Href")
                        .ResourceCollection("Coll2Title", "Coll2Href")
                        .WithTitle("WorkspaceTitle"))
                                     .WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataValuePropertyName + @""":[
                            { ""name"":""Coll1Title"", ""url"":""Coll1Href"" },
                            { ""name"":""Coll2Title"", ""url"":""Coll2Href"" }
                          ]
                        }"
                },
            };

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                JsonValue actualValue   = this.JsonLightSerializer.ConvertToJsonLightValue(testCase.PayloadElement);
                JsonValue expectedValue = JsonTextPreservingParser.ParseValue(new StringReader(testCase.ExpectedJson));

                this.JsonValueComparer.Compare(expectedValue, actualValue);
            });
        }
        public void JsonLightTaupoSerializerErrorTest()
        {
            var testCases = new JsonLightSerializerTestCase[]
            {
                // Top-level error
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.Error("error-code").Message("error-message"),
                    ExpectedJson   = @"
                        {
                          """ + JsonLightConstants.ODataErrorPropertyName + @""":{""code"":""error-code"",""message"": ""error-message""}}
                        }"
                },
                // Top-level error with inner error
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.Error("error-code").Message("error-message").InnerError(
                        new ODataInternalExceptionPayload {
                        Message           = "inner-message",
                        TypeName          = "inner-typename",
                        StackTrace        = "inner-stack",
                        InternalException = new ODataInternalExceptionPayload {
                            Message    = "inner-inner-message",
                            TypeName   = "inner-inner-typename",
                            StackTrace = "inner-inner-stack",
                        }
                    }),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataErrorPropertyName + @""":{
                            ""code"":""error-code"",
                            ""message"":""error-message"", 
                            ""innererror"":{
                              ""message"":""inner-message"",
                              ""type"":""inner-typename"",
                              ""stacktrace"":""inner-stack"",
                              ""internalexception"":{
                                ""message"":""inner-inner-message"",
                                ""type"":""inner-inner-typename"",
                                ""stacktrace"":""inner-inner-stack""
                              }
                            }
                          }
                        }"
                },
            };

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                JsonValue actualValue   = this.JsonLightSerializer.ConvertToJsonLightValue(testCase.PayloadElement);
                JsonValue expectedValue = JsonTextPreservingParser.ParseValue(new StringReader(testCase.ExpectedJson));

                this.JsonValueComparer.Compare(expectedValue, actualValue);
            });
        }
        public void JsonLightTaupoSerializerFeedTest()
        {
            var testCases = new JsonLightSerializerTestCase[]
            {
                // Empty feed
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.EntitySet().WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson   = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataValuePropertyName + @""":[]
                        }"
                },
                // Empty feed with count and next link
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.EntitySet()
                                     .InlineCount(42)
                                     .NextLink("http://odata.org/next")
                                     .WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataCountAnnotationName + @""":42,
                          """ + JsonLightConstants.ODataValuePropertyName + @""":[],
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataNextLinkAnnotationName + @""":""http://odata.org/next""
                        }"
                },
                // Feed with single entry
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.EntitySet()
                                     .Append(PayloadBuilder.Entity().PrimitiveProperty("ID", (long)42))
                                     .WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataValuePropertyName + @""":[
                            { ""ID"":42 }
                          ]
                        }"
                },
            };

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                JsonValue actualValue   = this.JsonLightSerializer.ConvertToJsonLightValue(testCase.PayloadElement);
                JsonValue expectedValue = JsonTextPreservingParser.ParseValue(new StringReader(testCase.ExpectedJson));

                this.JsonValueComparer.Compare(expectedValue, actualValue);
            });
        }
Beispiel #4
0
        /// <summary>
        /// Adds a JSON specific representaion annotation to the specified ODataPayloadElement.
        /// </summary>
        /// <typeparam name="T">The type of the payload element to work on.</typeparam>
        /// <param name="payloadElement">The payload element to annotate.</param>
        /// <param name="json">The JSON text to annotate with.</param>
        /// <returns>The annotated payload element, for composability.</returns>
        public static T JsonRepresentation <T>(this T payloadElement, string json) where T : ODataPayloadElement
        {
            JsonValue jsonValue = null;

            if (json != null)
            {
                jsonValue = JsonTextPreservingParser.ParseValue(new StringReader(json));
            }

            return(payloadElement.JsonRepresentation(jsonValue));
        }
        public void JsonLightTaupoSerializerPropertyTest()
        {
            var testCases = new JsonLightSerializerTestCase[]
            {
                // Null property
                // TODO: Change the payload of null top-level properties #645
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.PrimitiveProperty("Prop", null).WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson   = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          ""value"":null
                        }"
                },
                // Primitive property
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.PrimitiveProperty("Prop", "" + JsonLightConstants.ODataValuePropertyName + @"").WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson   = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataValuePropertyName + @""":""" + JsonLightConstants.ODataValuePropertyName + @"""
                        }"
                },
                // Complex property
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.Property("Prop",
                                                             PayloadBuilder.ComplexValue("TestModel.City")
                                                             .PrimitiveProperty("City", "Vienna"))
                                     .WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + @""":""TestModel.City"", ""City"":""Vienna""
                        }"
                },
            };

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                JsonValue actualValue   = this.JsonLightSerializer.ConvertToJsonLightValue(testCase.PayloadElement);
                JsonValue expectedValue = JsonTextPreservingParser.ParseValue(new StringReader(testCase.ExpectedJson));

                this.JsonValueComparer.Compare(expectedValue, actualValue);
            });
        }
        public void JsonLightTaupoSerializerCollectionPropertyTest()
        {
            var testCases = new JsonLightSerializerTestCase[]
            {
                // Primitive collection property
                new JsonLightSerializerTestCase
                {
                    PayloadElement = new PrimitiveMultiValueProperty("Prop", PayloadBuilder.PrimitiveMultiValue().Item((long)1).Item((long)2)).WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson   = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataValuePropertyName + @""":[1,2]
                        }"
                },
                // Complex collection property
                new JsonLightSerializerTestCase
                {
                    PayloadElement = new ComplexMultiValueProperty("Prop",
                                                                   PayloadBuilder.ComplexMultiValue()
                                                                   .Item(PayloadBuilder.ComplexValue("TestModel.City")
                                                                         .PrimitiveProperty("City", "Vienna")))
                                     .WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataValuePropertyName + @""":[{ """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + @""":""TestModel.City"", ""City"":""Vienna"" }]
                        }"
                },
            };

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                JsonValue actualValue   = this.JsonLightSerializer.ConvertToJsonLightValue(testCase.PayloadElement);
                JsonValue expectedValue = JsonTextPreservingParser.ParseValue(new StringReader(testCase.ExpectedJson));

                this.JsonValueComparer.Compare(expectedValue, actualValue);
            });
        }
        public void JsonLightTaupoSerializerParameterTest()
        {
            var testCases = new JsonLightSerializerTestCase[]
            {
                // Parameter payload with null, primitive, complex and collection parameters
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.ComplexValue()
                                     .PrimitiveProperty("NullProp", null)
                                     .PrimitiveProperty("LongProp", (long)42)
                                     .Property("ComplexProp", PayloadBuilder.ComplexValue("TestModel.CityType").PrimitiveProperty("Name", "Vienna"))
                                     .Property("PrimitiveColl", PayloadBuilder.PrimitiveMultiValue().Item((long)1).Item((long)2))
                                     .Property("ComplexColl", PayloadBuilder.ComplexMultiValue()
                                               .Item(PayloadBuilder.ComplexValue().PrimitiveProperty("Name", "Vienna"))
                                               .Item(PayloadBuilder.ComplexValue().PrimitiveProperty("Name", "Prague"))),
                    ExpectedJson = @"
                        {
                          ""NullProp"":null,
                          ""LongProp"":42,
                          ""ComplexProp"":{""" + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + @""":""TestModel.CityType"", ""Name"":""Vienna""},
                          ""PrimitiveColl"":[1,2],
                          ""ComplexColl"":[{""Name"":""Vienna""}, {""Name"":""Prague""}]
                        }"
                },
            };

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                JsonValue actualValue   = this.JsonLightSerializer.ConvertToJsonLightValue(testCase.PayloadElement);
                JsonValue expectedValue = JsonTextPreservingParser.ParseValue(new StringReader(testCase.ExpectedJson));

                this.JsonValueComparer.Compare(expectedValue, actualValue);
            });
        }
Beispiel #8
0
        /// <summary>
        /// Converts a <see cref="PayloadReaderTestDescriptor"/> to an in-stream error <see cref="PayloadReaderTestDescriptor"/>.
        /// </summary>
        /// <param name="descriptor">The <see cref="PayloadReaderTestDescriptor"/> to convert.</param>
        /// <param name="format">The <see cref="ODataFormat"/> the test descriptor is created for.</param>
        /// <returns>An in-stream error <see cref="PayloadReaderTestDescriptor"/> based on the <paramref name="descriptor"/>.</returns>
        /// <remarks>The <paramref name="descriptor"/> is expected to represent a top-level error payload test descriptor.</remarks>
        internal static PayloadReaderTestDescriptor ToInStreamErrorTestDescriptor(this PayloadReaderTestDescriptor descriptor, ODataFormat format)
        {
            ExceptionUtilities.CheckArgumentNotNull(descriptor, "descriptor");
            ExceptionUtilities.CheckArgumentNotNull(format, "format");
            ExceptionUtilities.Assert(descriptor.PayloadElement.ElementType == ODataPayloadElementType.ODataErrorPayload, "Only error payloads expected.");
            ExceptionUtilities.Assert(descriptor.ExpectedResultCallback == null, "No expected results callback expected.");
            ExceptionUtilities.Assert(descriptor.PayloadEdmModel == null, "No model expected.");

            // Model that defines the CityType to be used for wrapping the error payload to convert it into an in-stream error.
            IEdmModel testModel = Test.OData.Utils.Metadata.TestModels.BuildTestModel();

            bool isValidTopLevelError = descriptor.ExpectedException == null;

            ODataPayloadElement wrappedPayloadElement = null;
            ExpectedException   expectedException     = null;

            if (format == ODataFormat.Atom)
            {
                var atomRepresentation = (XmlPayloadElementRepresentationAnnotation)descriptor.PayloadElement.GetAnnotation(typeof(XmlPayloadElementRepresentationAnnotation));
                ExceptionUtilities.Assert(atomRepresentation != null, "Expected a format-specific annotation.");
                XNode xmlRepresentation = atomRepresentation.XmlNodes.Single();

                XElement wrapperObject = new XElement(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomEntryElementName,
                                                      new XElement(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomCategoryElementName,
                                                                   new XAttribute(TestAtomConstants.AtomCategoryTermAttributeName, "TestModel.CityType"),
                                                                   new XAttribute(TestAtomConstants.AtomCategorySchemeAttributeName, TestAtomConstants.ODataSchemeNamespace),
                                                                   new XElement(TestAtomConstants.AtomXNamespace + TestAtomConstants.AtomContentElementName,
                                                                                new XAttribute(TestAtomConstants.AtomTypeAttributeName, "application/xml"),
                                                                                new XElement(TestAtomConstants.ODataMetadataXNamespace + TestAtomConstants.AtomPropertiesElementName,
                                                                                             new XElement(TestAtomConstants.ODataXNamespace + "PoliceStation", xmlRepresentation)))));

                // replace the payload and ATOM representation of the test descriptor and set the expected error message
                wrappedPayloadElement = PayloadBuilder.Entity("TestModel.CityType").XmlRepresentation(wrapperObject);

                if (isValidTopLevelError)
                {
                    // if we have a valid top-level error we expect an ODataErrorException to be thrown.
                    ODataError error = ConvertErrorPayload((ODataErrorPayload)descriptor.PayloadElement, /*forAtom*/ true);
                    expectedException = ODataExpectedExceptions.ODataErrorException(error, "ODataErrorException_GeneralError");
                }
                else
                {
                    expectedException = descriptor.ExpectedException;
                }
            }
            else if (format == ODataFormat.Json)
            {
                IEdmEntitySet  citiesSet = testModel.EntityContainer.FindEntitySet("Cities");
                IEdmEntityType cityType  = testModel.FindType("TestModel.CityType") as IEdmEntityType;

                var jsonRepresentation = (JsonPayloadElementRepresentationAnnotation)descriptor.PayloadElement.GetAnnotation(typeof(JsonPayloadElementRepresentationAnnotation));
                ExceptionUtilities.Assert(jsonRepresentation != null, "Expected a format-specific annotation.");
                JsonObject jsonObject = (JsonObject)jsonRepresentation.Json;

                // wrap the existing payload in an entity of type 'CityType'; the existing payload is used as value of the 'PoliceStation' property
                JsonObject wrapperObject = (JsonObject)JsonTextPreservingParser.ParseValue(new StringReader("{ \"" + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + "\":\"http://odata.org/test/$metadata#TestModel.DefaultContainer.Cities/$entity\" }"));
                wrapperObject.Add(new JsonProperty("PoliceStation", jsonObject));

                // replace the payload and Json representation of the test descriptor and set the expected error message
                wrappedPayloadElement = PayloadBuilder.Entity("TestModel.CityType")
                                        .ExpectedEntityType(cityType, citiesSet)
                                        .JsonRepresentation(wrapperObject);

                if (isValidTopLevelError)
                {
                    // if we have a valid top-level error we expect an ODataErrorException to be thrown.
                    ODataError error = ConvertErrorPayload((ODataErrorPayload)descriptor.PayloadElement, /*forAtom*/ false);
                    expectedException = ODataExpectedExceptions.ODataErrorException(error, "ODataErrorException_GeneralError");
                }
                else
                {
                    // if the top-level error is too deeply recursive, we expect to fail in the same way for the in-stream error.
                    if (descriptor.ExpectedException.ExpectedMessage.ResourceIdentifier == "ValidationUtils_RecursionDepthLimitReached")
                    {
                        expectedException = descriptor.ExpectedException;
                    }
                    else
                    {
                        // otherwise, if the top-level error is not valid, we expect an error message that the first
                        // property of the invalid top-level error object is not defined on type OfficeType.
                        string firstPropertyName = jsonObject.Properties.First().Name;
                        expectedException = ODataExpectedExceptions.ODataException("ValidationUtils_PropertyDoesNotExistOnType", firstPropertyName, "TestModel.OfficeType");
                    }
                }
            }
            else
            {
                throw new TaupoInvalidOperationException("Unsupported format for error test descriptor found: " + format.GetType().Name);
            }

            return(new PayloadReaderTestDescriptor(descriptor)
            {
                PayloadElement = wrappedPayloadElement,
                PayloadEdmModel = testModel,
                ExpectedResultPayloadElement = tc => descriptor.PayloadElement,
                ExpectedException = expectedException,
            });
        }
        public void JsonLightTaupoSerializerEntityReferenceLinkTest()
        {
            var testCases = new JsonLightSerializerTestCase[]
            {
                // Single entity reference link
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.DeferredLink("http://odata.org/erl")
                                     .WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataIdAnnotationName + @""":""http://odata.org/erl""
                        }"
                },
                // Collection of entity reference links
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.LinkCollection()
                                     .Item(PayloadBuilder.DeferredLink("http://odata.org/erl1"))
                                     .Item(PayloadBuilder.DeferredLink("http://odata.org/erl2"))
                                     .WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataValuePropertyName + @""":[
                            { """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataIdAnnotationName + @""":""http://odata.org/erl1"" },
                            { """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataIdAnnotationName + @""":""http://odata.org/erl2"" }
                          ]
                        }"
                },
                // Collection of entity reference links with inline count and next link
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.LinkCollection()
                                     .Item(PayloadBuilder.DeferredLink("http://odata.org/erl1"))
                                     .Item(PayloadBuilder.DeferredLink("http://odata.org/erl2"))
                                     .InlineCount(42)
                                     .NextLink("http://odata.org/nextlink")
                                     .WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataCountAnnotationName + @""": 42,
                          """ + JsonLightConstants.ODataValuePropertyName + @""":[
                            { """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataIdAnnotationName + @""":""http://odata.org/erl1"" },
                            { """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataIdAnnotationName + @""":""http://odata.org/erl2"" }
                          ],
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataNextLinkAnnotationName + @""":""http://odata.org/nextlink""
                        }"
                },
            };

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                PayloadFormatVersionAnnotatingVisitor.AnnotateJsonLight(testCase.PayloadElement, DataServiceProtocolVersion.Unspecified, false);
                JsonValue actualValue   = this.JsonLightSerializer.ConvertToJsonLightValue(testCase.PayloadElement);
                JsonValue expectedValue = JsonTextPreservingParser.ParseValue(new StringReader(testCase.ExpectedJson));

                this.JsonValueComparer.Compare(expectedValue, actualValue);
            });
        }
        public void JsonLightTaupoSerializerEntryTest()
        {
            var testCases = new JsonLightSerializerTestCase[]
            {
                // Entry with only ID
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.Entity()
                                     .PrimitiveProperty("ID", (long)42)
                                     .WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          ""ID"":42
                        }"
                },
                // Entry with ID and typename
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.Entity("TestModel.Customer")
                                     .PrimitiveProperty("ID", (long)42)
                                     .WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + @""":""TestModel.Customer"",
                          ""ID"":42
                        }"
                },
                // Entry with all metadata expanded
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.Entity("TestModel.CustomerWithImage")
                                     .Id("CustomerId")
                                     .ETag("etag")
                                     .WithEditLink("http://odata.org/editlink")
                                     .WithSelfLink("http://odata.org/readlink")
                                     .WithStreamContentType("image/jpg")
                                     .WithStreamEditLink("http://odata.org/streameditlink")
                                     .WithStreamSourceLink("http://odata.org/streamreadlink")
                                     .WithStreamETag("stream-etag")
                                     .PrimitiveProperty("ID", (long)42)
                                     .Operation(new ServiceOperationDescriptor {
                        IsAction = true, Metadata = "./metadata", Target = "http://odata.org/target", Title = "ActionTitle"
                    })
                                     .Operation(new ServiceOperationDescriptor {
                        IsAction = true, Metadata = "./metadata2", Target = "http://odata.org/target2", Title = "ActionTitle2"
                    })
                                     .Operation(new ServiceOperationDescriptor {
                        IsAction = false, Metadata = "./metadata", Target = "http://odata.org/target", Title = "ActionTitle"
                    })
                                     .Operation(new ServiceOperationDescriptor {
                        IsAction = false, Metadata = "./metadata", Target = "http://odata.org/target2", Title = "ActionTitle2"
                    })
                                     .WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + @""":""TestModel.CustomerWithImage"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataIdAnnotationName + @""":""CustomerId"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataETagAnnotationName + @""":""etag"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataEditLinkAnnotationName + @""":""http://odata.org/editlink"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataReadLinkAnnotationName + @""":""http://odata.org/readlink"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataMediaEditLinkAnnotationName + @""":""http://odata.org/streameditlink"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataMediaReadLinkAnnotationName + @""":""http://odata.org/streamreadlink"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataMediaContentTypeAnnotationName + @""":""image/jpg"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataMediaETagAnnotationName + @""":""stream-etag"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataActionsAnnotationName + @""":{ ""./metadata"":[{ ""title"":""ActionTitle"", ""target"":""http://odata.org/target""}], ""./metadata2"":[{ ""title"":""ActionTitle2"", ""target"":""http://odata.org/target2""}]},
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataFunctionsAnnotationName + @""":{ ""./metadata"":[{ ""title"":""ActionTitle"", ""target"":""http://odata.org/target""}, { ""title"":""ActionTitle2"", ""target"":""http://odata.org/target2""}]},
                          ""ID"":42
                        }"
                },
                // Entry with deferred navigation and association properties
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.Entity("TestModel.Customer")
                                     .PrimitiveProperty("ID", (long)42)
                                     .NavigationProperty("NavProp1", "http://odata.org/NavProp1", "http://odata.org/AssocProp1")
                                     .NavigationProperty("NavProp2", "http://odata.org/NavProp2")
                                     .NavigationProperty("NavProp3", null, "http://odata.org/AssocProp3")
                                     .WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + @""":""TestModel.Customer"",
                          ""ID"":42,
                          """ + JsonLightUtils.GetPropertyAnnotationName("NavProp1", JsonLightConstants.ODataNavigationLinkUrlAnnotationName) + @""":""http://odata.org/NavProp1"",
                          """ + JsonLightUtils.GetPropertyAnnotationName("NavProp1", JsonLightConstants.ODataAssociationLinkUrlAnnotationName) + @""":""http://odata.org/AssocProp1"",
                          """ + JsonLightUtils.GetPropertyAnnotationName("NavProp2", JsonLightConstants.ODataNavigationLinkUrlAnnotationName) + @""":""http://odata.org/NavProp2"",
                          """ + JsonLightUtils.GetPropertyAnnotationName("NavProp3", JsonLightConstants.ODataAssociationLinkUrlAnnotationName) + @""":""http://odata.org/AssocProp3""
                        }"
                },
                // Entry with navigation link with expanded entry
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.Entity("TestModel.Customer")
                                     .PrimitiveProperty("ID", (long)42)
                                     .ExpandedNavigationProperty("NavProp1", PayloadBuilder.Entity("TestModel.Order").PrimitiveProperty("ID", ((long)43)))
                                     .ExpandedNavigationProperty("NavProp2", PayloadBuilder.Entity("TestModel.Order").PrimitiveProperty("ID", ((long)43)), "http://odata.org/NavProp2")
                                     .ExpandedNavigationProperty("NavProp3", PayloadBuilder.Entity("TestModel.Order").PrimitiveProperty("ID", ((long)43)), new DeferredLink {
                        UriString = "http://odata.org/AssocProp3"
                    })
                                     .WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + @""":""TestModel.Customer"",
                          ""ID"":42,
                          ""NavProp1"":{ """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + @""":""TestModel.Order"",""ID"":43 },
                          """ + JsonLightUtils.GetPropertyAnnotationName("NavProp2", JsonLightConstants.ODataNavigationLinkUrlAnnotationName) + @""":""http://odata.org/NavProp2"",
                          ""NavProp2"":{ """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + @""":""TestModel.Order"",""ID"":43 },
                          """ + JsonLightUtils.GetPropertyAnnotationName("NavProp3", JsonLightConstants.ODataAssociationLinkUrlAnnotationName) + @""":""http://odata.org/AssocProp3"",
                          ""NavProp3"":{ """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + @""":""TestModel.Order"",""ID"":43 }
                        }"
                },
                // Entry with navigation link with expanded feed
                new JsonLightSerializerTestCase
                {
                    PayloadElement = PayloadBuilder.Entity("TestModel.Customer")
                                     .PrimitiveProperty("ID", (long)42)
                                     .ExpandedNavigationProperty("NavProp1", PayloadBuilder.EntitySet())
                                     .ExpandedNavigationProperty("NavProp2", PayloadBuilder.EntitySet(), "http://odata.org/NavProp2")
                                     .ExpandedNavigationProperty("NavProp3", PayloadBuilder.EntitySet(), new DeferredLink {
                        UriString = "http://odata.org/AssocProp3"
                    })
                                     .WithContextUri("http://odata.org/metadatauri"),
                    ExpectedJson = @"
                        {
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataContextAnnotationName + @""":""http://odata.org/metadatauri"",
                          """ + JsonLightConstants.ODataPropertyAnnotationSeparator + JsonLightConstants.ODataTypeAnnotationName + @""":""TestModel.Customer"",
                          ""ID"":42,
                          ""NavProp1"":[],
                          """ + JsonLightUtils.GetPropertyAnnotationName("NavProp2", JsonLightConstants.ODataNavigationLinkUrlAnnotationName) + @""":""http://odata.org/NavProp2"",
                          ""NavProp2"":[],
                          """ + JsonLightUtils.GetPropertyAnnotationName("NavProp3", JsonLightConstants.ODataAssociationLinkUrlAnnotationName) + @""":""http://odata.org/AssocProp3"",
                          ""NavProp3"":[]
                        }"
                },
            };

            this.CombinatorialEngineProvider.RunCombinations(
                testCases,
                (testCase) =>
            {
                PayloadFormatVersionAnnotatingVisitor.AnnotateJsonLight(testCase.PayloadElement, DataServiceProtocolVersion.Unspecified, false);
                JsonValue actualValue   = this.JsonLightSerializer.ConvertToJsonLightValue(testCase.PayloadElement);
                JsonValue expectedValue = JsonTextPreservingParser.ParseValue(new StringReader(testCase.ExpectedJson));

                this.JsonValueComparer.Compare(expectedValue, actualValue);
            });
        }