public WriterTypeNameEndToEndTests()
        {
            var model = new EdmModel();
            var type = new EdmEntityType("TestModel", "TestEntity", /* baseType */ null, /* isAbstract */ false, /* isOpen */ true);
            var keyProperty = type.AddStructuralProperty("DeclaredInt16", EdmPrimitiveTypeKind.Int16);
            type.AddKeys(new[] { keyProperty });

            // Note: DerivedPrimitive is declared as a Geography, but its value below will be set to GeographyPoint, which is derived from Geography.
            type.AddStructuralProperty("DerivedPrimitive", EdmPrimitiveTypeKind.Geography);
            var container = new EdmEntityContainer("TestModel", "Container");
            var set = container.AddEntitySet("Set", type);
            model.AddElement(type);
            model.AddElement(container);

            var writerStream = new MemoryStream();
            this.settings = new ODataMessageWriterSettings();
            this.settings.SetServiceDocumentUri(ServiceDocumentUri);

            // Make the message writer and entry writer lazy so that individual tests can tweak the settings before the message writer is created.
            this.messageWriter = new Lazy<ODataMessageWriter>(() =>
                new ODataMessageWriter(
                    (IODataResponseMessage)new InMemoryMessage { Stream = writerStream },
                    this.settings,
                    model));

            var entryWriter = new Lazy<ODataWriter>(() => this.messageWriter.Value.CreateODataEntryWriter(set, type));

            var valueWithAnnotation = new ODataPrimitiveValue(45);
            valueWithAnnotation.SetAnnotation(new SerializationTypeNameAnnotation { TypeName = "TypeNameFromSTNA" });

            var propertiesToWrite = new List<ODataProperty>
            {
                new ODataProperty
                {
                    Name = "DeclaredInt16", Value = (Int16)42
                }, 
                new ODataProperty
                {
                    Name = "UndeclaredDecimal", Value = (Decimal)4.5
                }, 
                new ODataProperty
                {
                    // Note: value is more derived than the declared type.
                    Name = "DerivedPrimitive", Value = Microsoft.Spatial.GeographyPoint.Create(42, 45)
                },
                new ODataProperty()
                {
                    Name = "PropertyWithSTNA", Value = valueWithAnnotation
                }
            };

            this.writerOutput = new Lazy<string>(() =>
            {
                entryWriter.Value.WriteStart(new ODataEntry { Properties = propertiesToWrite });
                entryWriter.Value.WriteEnd();
                entryWriter.Value.Flush();
                writerStream.Seek(0, SeekOrigin.Begin);
                return new StreamReader(writerStream).ReadToEnd();
            });
        }
예제 #2
0
        /// <summary>
        /// Determines if the given primitive value is of a basic type where we can rely on just the JSON representation to convey type information.
        /// If so, we don't have to write the type name.
        /// </summary>
        /// <param name="primitiveValue">The primitive value in question.</param>
        /// <param name="valueTypeReference">The type of the primitive value.</param>
        /// <returns>true if the given primitive value is of a basic JSON type, false otherwise.</returns>
        internal static bool ValueTypeMatchesJsonType(ODataPrimitiveValue primitiveValue, IEdmPrimitiveTypeReference valueTypeReference)
        {
#if ODATALIB
#endif

            switch (valueTypeReference.PrimitiveKind())
            {
                // If the value being serialized is of a basic type where we can rely on just the JSON representation to convey type information, then never write the type name.
                case EdmPrimitiveTypeKind.Int32:
                case EdmPrimitiveTypeKind.String:
                case EdmPrimitiveTypeKind.Boolean:
                    return true;

                case EdmPrimitiveTypeKind.Double:
                    double doubleValue = (double)primitiveValue.Value;

                    // If a double value is positive infinity, negative infinity, or NaN, we serialize the double as a string.
                    // Thus the reader can't infer the type from the JSON representation, and we must write the type name explicitly 
                    // (i.e., if the property is open or the property type is assumed to be unknown, as is the case when writing in full metadata mode).
                    return !IsDoubleValueSerializedAsString(doubleValue);
                
                default:
                    return false;
            }
        }
        internal static void AddTypeNameAnnotationAsNeeded(ODataPrimitiveValue primitive,
            ODataMetadataLevel metadataLevel)
        {
            Contract.Assert(primitive != null);

            object value = primitive.Value;

            // Don't add a type name annotation for Atom or JSON verbose.
            if (metadataLevel != ODataMetadataLevel.Default)
            {
                string typeName;

                if (ShouldSuppressTypeNameSerialization(value, metadataLevel))
                {
                    typeName = null;
                }
                else
                {
                    typeName = GetTypeName(value);
                }

                primitive.SetAnnotation<SerializationTypeNameAnnotation>(new SerializationTypeNameAnnotation
                {
                    TypeName = typeName
                });
            }
        }
예제 #4
0
        public void CreateODataValue_PrimitiveValue()
        {
            // Arrange
            IEdmPrimitiveTypeReference edmPrimitiveType = typeof(int).GetEdmPrimitiveTypeReference();
            var serializer = new ODataPrimitiveSerializer();

            // Act
            var odataValue = serializer.CreateODataValue(20, edmPrimitiveType, writeContext: null);

            // Assert
            Assert.NotNull(odataValue);
            ODataPrimitiveValue primitiveValue = Assert.IsType <ODataPrimitiveValue>(odataValue);

            Assert.Equal(20, primitiveValue.Value);
        }
        public void AddTypeNameAnnotationAsNeeded_AddsAnnotation_InJsonLightMetadataMode()
        {
            // Arrange
            IEdmPrimitiveTypeReference edmPrimitiveType = EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(typeof(short));
            ODataPrimitiveValue        primitive        = new ODataPrimitiveValue((short)1);

            // Act
            ODataPrimitiveSerializer.AddTypeNameAnnotationAsNeeded(primitive, edmPrimitiveType, ODataMetadataLevel.FullMetadata);

            // Assert
            ODataTypeAnnotation annotation = primitive.TypeAnnotation;

            Assert.NotNull(annotation); // Guard
            Assert.Equal("Edm.Int16", annotation.TypeName);
        }
예제 #6
0
        public void CreateODataValue_ReturnsDateTimeOffset_ForDateTime_ByDefault()
        {
            // Arrange
            IEdmPrimitiveTypeReference edmPrimitiveType = typeof(DateTime).GetEdmPrimitiveTypeReference();
            ODataPrimitiveSerializer   serializer       = new ODataPrimitiveSerializer();
            DateTime dt = new DateTime(2014, 10, 27);

            // Act
            ODataValue odataValue = serializer.CreateODataValue(dt, edmPrimitiveType, new ODataSerializerContext());

            // Assert
            ODataPrimitiveValue primitiveValue = Assert.IsType <ODataPrimitiveValue>(odataValue);

            Assert.Equal(new DateTimeOffset(dt), primitiveValue.Value);
        }
예제 #7
0
        /// <inheritdoc/>
        public sealed override ODataValue CreateODataValue(object graph, IEdmTypeReference expectedType, ODataSerializerContext writeContext)
        {
            if (!expectedType.IsPrimitive())
            {
                throw Error.InvalidOperation(SRResources.CannotWriteType, typeof(ODataPrimitiveSerializer), expectedType.FullName());
            }

            ODataPrimitiveValue value = CreateODataPrimitiveValue(graph, expectedType.AsPrimitive(), writeContext);

            if (value == null)
            {
                return(new ODataNullValue());
            }

            return(value);
        }
        /// <summary>
        /// Writes a primitive property.
        /// </summary>
        /// <param name="property">The property to write out.</param>
        /// <param name="primitiveValue">The primitive value to be written</param>
        /// <param name="propertyTypeReference">The metadata type reference of the property.</param>
        /// <param name="isTopLevel">true when writing a top-level property; false for nested properties.</param>
        /// <param name="isOpenPropertyType">If the property is open.</param>
        private void WritePrimitiveProperty(
            ODataProperty property,
            ODataPrimitiveValue primitiveValue,
            IEdmTypeReference propertyTypeReference,
            bool isTopLevel,
            bool isOpenPropertyType)
        {
            string wirePropertyName = GetWirePropertyName(isTopLevel, property.Name);

            IEdmTypeReference typeFromValue   = TypeNameOracle.ResolveAndValidateTypeForPrimitiveValue(primitiveValue);
            string            typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(primitiveValue, propertyTypeReference, typeFromValue, isOpenPropertyType);

            this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel);
            this.JsonWriter.WriteName(wirePropertyName);
            this.JsonLightValueSerializer.WritePrimitiveValue(primitiveValue.Value, propertyTypeReference);
        }
예제 #9
0
        public void WriteTopLevelErrorWithDateInstanceAnnotation()
        {
            var result = SetupSerializerAndRunTest(null, serializer =>
            {
                ODataError error                   = new ODataError();
                var instanceAnnotations            = new Collection <ODataInstanceAnnotation>();
                var primitiveValue                 = new ODataPrimitiveValue(new Date(2014, 8, 8));
                ODataInstanceAnnotation annotation = new ODataInstanceAnnotation("sample.primitive", primitiveValue);
                instanceAnnotations.Add(annotation);
                error.InstanceAnnotations = instanceAnnotations;

                serializer.WriteTopLevelError(error, false);
            });

            Assert.Contains("\"[email protected]\":\"#Date\",\"@sample.primitive\":\"2014-08-08\"", result);
        }
예제 #10
0
            public override ODataFeed CreateODataFeed(IEnumerable feedInstance, IEdmCollectionTypeReference feedType,
                                                      ODataSerializerContext writeContext)
            {
                ODataFeed feed = base.CreateODataFeed(feedInstance, feedType, writeContext);

                // Int32
                ODataPrimitiveValue intValue = new ODataPrimitiveValue(321);

                feed.InstanceAnnotations.Add(new ODataInstanceAnnotation("Custom.Int32Annotation", intValue));

                // String
                ODataPrimitiveValue stringValue = new ODataPrimitiveValue("My amazing feed");

                feed.InstanceAnnotations.Add(new ODataInstanceAnnotation("Custom.StringAnnotation", stringValue));
                return(feed);
            }
예제 #11
0
        /// <summary>
        /// Converts an ODataValue to the old style of representing values, where null values are null and primitive values are just the direct primitive (no longer wrapped by ODataPrimitiveValue).
        /// All other value types, such as ODataCollectionValue are returned unchanged.
        /// </summary>
        /// <param name="odataValue">The value to convert.</param>
        /// <returns>The value behind the given ODataValue.</returns>
        internal static object FromODataValue(this ODataValue odataValue)
        {
            if (odataValue is ODataNullValue)
            {
                return(null);
            }

            ODataPrimitiveValue primitiveValue = odataValue as ODataPrimitiveValue;

            if (primitiveValue != null)
            {
                return(primitiveValue.Value);
            }

            return(odataValue);
        }
예제 #12
0
        public static object GetInnerValue(this ODataValue odataValue)
        {
            if (odataValue is ODataNullValue)
            {
                return(null);
            }

            ODataPrimitiveValue oDataPrimitiveValue = odataValue as ODataPrimitiveValue;

            if (oDataPrimitiveValue != null)
            {
                return(oDataPrimitiveValue.Value);
            }

            return(odataValue);
        }
        public void CreateODataValue_ReturnsTimeOfDay_ForTimeSpan()
        {
            // Arrange
            IEdmPrimitiveTypeReference edmPrimitiveType = typeof(TimeOfDay).GetEdmPrimitiveTypeReference();
            ODataPrimitiveSerializer   serializer       = new ODataPrimitiveSerializer();
            TimeSpan ts = new TimeSpan(0, 10, 11, 12, 13);

            // Act
            ODataValue odataValue = serializer.CreateODataValue(ts, edmPrimitiveType, new ODataSerializerContext());

            // Assert
            ODataPrimitiveValue primitiveValue = Assert.IsType <ODataPrimitiveValue>(odataValue);

            Assert.IsType <TimeOfDay>(primitiveValue.Value);
            Assert.Equal(new TimeOfDay(ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds), primitiveValue.Value);
        }
예제 #14
0
        public void WriteTopLevelErrorWithTimeOfDayInstanceAnnotation()
        {
            var result = SetupSerializerAndRunTest(null, serializer =>
            {
                ODataError error                   = new ODataError();
                var instanceAnnotations            = new Collection <ODataInstanceAnnotation>();
                var primitiveValue                 = new ODataPrimitiveValue(new TimeOfDay(12, 30, 5, 90));
                ODataInstanceAnnotation annotation = new ODataInstanceAnnotation("sample.primitive", primitiveValue);
                instanceAnnotations.Add(annotation);
                error.InstanceAnnotations = instanceAnnotations;

                serializer.WriteTopLevelError(error, false);
            });

            Assert.Contains("\"[email protected]\":\"#TimeOfDay\",\"@sample.primitive\":\"12:30:05.0900000\"", result);
        }
예제 #15
0
        public void WriteTopLevelErrorWithDateTimeInstanceAnnotation()
        {
            var result = SetupSerializerAndRunTest(null, serializer =>
            {
                ODataError error                   = new ODataError();
                var instanceAnnotations            = new Collection <ODataInstanceAnnotation>();
                var primitiveValue                 = new ODataPrimitiveValue(new DateTimeOffset(2000, 1, 1, 12, 30, 0, new TimeSpan()));
                ODataInstanceAnnotation annotation = new ODataInstanceAnnotation("sample.primitive", primitiveValue);
                instanceAnnotations.Add(annotation);
                error.InstanceAnnotations = instanceAnnotations;

                serializer.WriteTopLevelError(error, false);
            });

            Assert.Contains("\"[email protected]\":\"#DateTimeOffset\",\"@sample.primitive\":\"2000-01-01T12:30:00Z\"", result);
        }
        public void CreateODataValue_ReturnsDate_ForDateTime()
        {
            // Arrange
            IEdmPrimitiveTypeReference edmPrimitiveType = EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(typeof(Date));
            ODataPrimitiveSerializer   serializer       = new ODataPrimitiveSerializer();
            DateTime dt = new DateTime(2014, 10, 27);

            // Act
            ODataValue odataValue = serializer.CreateODataValue(dt, edmPrimitiveType, new ODataSerializerContext());

            // Assert
            ODataPrimitiveValue primitiveValue = Assert.IsType <ODataPrimitiveValue>(odataValue);

            Assert.IsType <Date>(primitiveValue.Value);
            Assert.Equal(new Date(dt.Year, dt.Month, dt.Day), primitiveValue.Value);
        }
예제 #17
0
        public static void AssertODataValueAreEqual(ODataValue value1, ODataValue value2)
        {
            if (value1.IsNullValue && value2.IsNullValue)
            {
                return;
            }

            ODataPrimitiveValue primitiveValue1 = value1 as ODataPrimitiveValue;
            ODataPrimitiveValue primitiveValue2 = value2 as ODataPrimitiveValue;

            if (primitiveValue1 != null && primitiveValue2 != null)
            {
                AssertODataPrimitiveValueAreEqual(primitiveValue1, primitiveValue2);
            }
            else
            {
                ODataResourceValue resourceValue1 = value1 as ODataResourceValue;
                ODataResourceValue resourceValue2 = value2 as ODataResourceValue;
                if (resourceValue1 != null && resourceValue2 != null)
                {
                    AssertODataResourceValueAreEqual(resourceValue1, resourceValue2);
                    return;
                }

                ODataEnumValue enumValue1 = value1 as ODataEnumValue;
                ODataEnumValue enumValue2 = value2 as ODataEnumValue;
                if (enumValue1 != null && enumValue2 != null)
                {
                    AssertODataEnumValueAreEqual(enumValue1, enumValue2);
                }
                else
                {
                    ODataCollectionValue collectionValue1 = value1 as ODataCollectionValue;
                    ODataCollectionValue collectionValue2 = value2 as ODataCollectionValue;
                    if (collectionValue1 != null && collectionValue2 != null)
                    {
                        AssertODataCollectionValueAreEqual(collectionValue1, collectionValue2);
                    }
                    else
                    {
                        ODataUntypedValue untyped1 = value1 as ODataUntypedValue;
                        ODataUntypedValue untyped2 = value2 as ODataUntypedValue;
                        Assert.Equal(untyped1.RawValue, untyped2.RawValue);
                    }
                }
            }
        }
            /// <summary>
            /// Visits a primitive value.
            /// </summary>
            /// <param name="primitiveValue">The primitive value to visit.</param>
            protected override ODataPayloadElement VisitPrimitiveValue(object primitiveValue)
            {
                if (primitiveValue == null)
                {
                    return(new PrimitiveValue(null, null));
                }
                else
                {
                    ODataPrimitiveValue odataPrimitiveValue = primitiveValue as ODataPrimitiveValue;
                    if (odataPrimitiveValue != null)
                    {
                        primitiveValue = odataPrimitiveValue.Value;
                    }

                    return(new PrimitiveValue(EntityModelUtils.GetPrimitiveEdmType(primitiveValue.GetType()).FullEdmName(), primitiveValue));
                }
            }
예제 #19
0
        public override ODataPrimitiveValue CreateODataPrimitiveValue(object graph,
                                                                      IEdmPrimitiveTypeReference primitiveType, ODataSerializerContext writeContext)
        {
            ODataPrimitiveValue result = base.CreateODataPrimitiveValue(graph, primitiveType, writeContext);

            if (result?.Value is DateTimeOffset date)
            {
                IDependencyResolver dependencyResolver = writeContext.Request.GetOwinContext()
                                                         .GetDependencyResolver();

                ITimeZoneManager timeZoneManager = dependencyResolver.Resolve <ITimeZoneManager>();

                result = new ODataPrimitiveValue(timeZoneManager.MapFromServerToClient(date));
            }

            return(result);
        }
예제 #20
0
        public void WriteTopLevelErrorWithStringInstanceAnnotationWithTypeNameAttribute()
        {
            var result = SetupSerializerAndRunTest(null, serializer =>
            {
                ODataError error                   = new ODataError();
                var instanceAnnotations            = new Collection <ODataInstanceAnnotation>();
                var primitiveValue                 = new ODataPrimitiveValue("stringValue");
                primitiveValue.TypeAnnotation      = new ODataTypeAnnotation("Custom.Type");
                ODataInstanceAnnotation annotation = new ODataInstanceAnnotation("sample.primitive", primitiveValue);
                instanceAnnotations.Add(annotation);
                error.InstanceAnnotations = instanceAnnotations;

                serializer.WriteTopLevelError(error, false);
            });

            Assert.Contains("\"[email protected]\":\"#Custom.Type\",\"@sample.primitive\":\"stringValue\"", result);
        }
예제 #21
0
            /// <summary>
            /// Gets the metadata URI type name based on the given property.
            /// </summary>
            /// <param name="property">The property.</param>
            /// <returns>The type name for the metadata URI.</returns>
            private static string GetMetadataUriTypeNameForValue(ODataProperty property)
            {
                Debug.Assert(property != null, "property != null");

                ODataValue value = property.ODataValue;

                Debug.Assert(value != null, "value != null");

                // special identifier for null values.
                if (value.IsNullValue)
                {
                    return(JsonLightConstants.MetadataUriFragmentNull);
                }

                var typeAnnotation = value.GetAnnotation <SerializationTypeNameAnnotation>();

                if (typeAnnotation != null && !string.IsNullOrEmpty(typeAnnotation.TypeName))
                {
                    return(typeAnnotation.TypeName);
                }

                var complexValue = value as ODataComplexValue;

                if (complexValue != null)
                {
                    return(complexValue.TypeName);
                }

                var collectionValue = value as ODataCollectionValue;

                if (collectionValue != null)
                {
                    return(collectionValue.TypeName);
                }

                ODataPrimitiveValue primitive = value as ODataPrimitiveValue;

                if (primitive == null)
                {
                    Debug.Assert(value is ODataStreamReferenceValue, "value is ODataStreamReferenceValue");
                    throw new ODataException(OData.Strings.ODataWriter_StreamPropertiesMustBePropertiesOfODataEntry(property.Name));
                }

                return(EdmLibraryExtensions.GetPrimitiveTypeReference(primitive.Value.GetType()).ODataFullName());
            }
예제 #22
0
        internal static ODataPrimitiveValue CreatePrimitive(object value, IEdmPrimitiveTypeReference primitiveType,
                                                            ODataSerializerContext writeContext)
        {
            if (value == null)
            {
                return(null);
            }

            object supportedValue         = ConvertPrimitiveValue(value, primitiveType);
            ODataPrimitiveValue primitive = new ODataPrimitiveValue(supportedValue);

            if (writeContext != null)
            {
                AddTypeNameAnnotationAsNeeded(primitive, primitiveType, writeContext.MetadataLevel);
            }

            return(primitive);
        }
예제 #23
0
        /// <summary>
        /// Converts an ODataValue to the old style of representing values, where null values are null and primitive values are just the direct primitive (no longer wrapped by ODataPrimitiveValue).
        /// All other value types, such as ODataComplexValue and ODataCollectionValue are returned unchanged.
        /// </summary>
        /// <param name="odataValue">The value to convert.</param>
        /// <returns>The value behind the given ODataValue.</returns>
        internal static object FromODataValue(this ODataValue odataValue)
        {
            DebugUtils.CheckNoExternalCallers();

            if (odataValue is ODataNullValue)
            {
                return(null);
            }

            ODataPrimitiveValue primitiveValue = odataValue as ODataPrimitiveValue;

            if (primitiveValue != null)
            {
                return(primitiveValue.Value);
            }

            return(odataValue);
        }
예제 #24
0
        internal static void AddTypeNameAnnotationAsNeeded(ODataPrimitiveValue primitive, IEdmPrimitiveTypeReference primitiveType,
                                                           ODataMetadataLevel metadataLevel)
        {
            // ODataLib normally has the caller decide whether or not to serialize properties by leaving properties
            // null when values should not be serialized. The TypeName property is different and should always be
            // provided to ODataLib to enable model validation. A separate annotation is used to decide whether or not
            // to serialize the type name (a null value prevents serialization).
            Contract.Assert(primitive != null);

            object value    = primitive.Value;
            string typeName = null; // Set null to force the type name not to serialize.

            // Provide the type name to serialize.
            if (!ShouldSuppressTypeNameSerialization(value, metadataLevel))
            {
                typeName = primitiveType.FullName();
            }

            primitive.TypeAnnotation = new ODataTypeAnnotation(typeName);
        }
예제 #25
0
        public ODataResource CreateEntry(Object entity)
        {
            for (int i = 0; i < _accessors.Length; i++)
            {
                OePropertyAccessor accessor = _accessors[i];
                Object             value    = accessor.Accessor(entity);
                if (value is DateTime)
                {
                    value = (DateTimeOffset)(DateTime)value;
                }
                ODataValue odataValue = null;
                if (value == null)
                {
                    odataValue = new ODataNullValue()
                    {
                        TypeAnnotation = accessor.TypeAnnotation
                    }
                }
                ;
                else
                {
                    if (value.GetType().GetTypeInfo().IsEnum)
                    {
                        odataValue = new ODataEnumValue(value.ToString());
                    }
                    else
                    {
                        odataValue = new ODataPrimitiveValue(value);
                    }
                    odataValue.TypeAnnotation = accessor.TypeAnnotation;
                }
                _odataProperties[i].Value = odataValue;
            }

            return(new ODataResource
            {
                TypeName = _typeName,
                Properties = _odataProperties
            });
        }
예제 #26
0
        public void WriteInstanceAnnotation_ForDateShouldUsePrimitiveCodePathWithTypeName()
        {
            var          date          = new ODataPrimitiveValue(new Date(2014, 11, 11));
            const string term          = "some.term";
            var          verifierCalls = 0;

            this.jsonWriter.WriteNameVerifier = (name) =>
            {
                if (verifierCalls == 0)
                {
                    Assert.Equal(term + "@odata.type", name);
                    verifierCalls++;
                }
                else if (verifierCalls == 2)
                {
                    Assert.Equal("@" + term, name);
                    verifierCalls++;
                }
                else
                {
                    throw new Exception("unexpected call to JsonWriter.WriteName");
                }
            };
            this.jsonWriter.WriteValueVerifier = (value) =>
            {
                Assert.Equal(1, verifierCalls);
                verifierCalls++;
            };
            this.valueWriter.WritePrimitiveVerifier = (value, reference) =>
            {
                Assert.Equal(date.Value, value);
                Assert.Null(reference);
                Assert.Equal(3, verifierCalls);
                verifierCalls++;
            };

            this.jsonLightInstanceAnnotationWriter.WriteInstanceAnnotation(new ODataInstanceAnnotation(term, date));
            Assert.Equal(4, verifierCalls);
        }
        public void WriteInstanceAnnotation_ForTimeOfDayShouldUsePrimitiveCodePathWithTypeName()
        {
            var          time          = new ODataPrimitiveValue(new TimeOfDay(12, 5, 0, 90));
            const string term          = "some.term";
            var          verifierCalls = 0;

            this.jsonWriter.WriteNameVerifier = (name) =>
            {
                if (verifierCalls == 0)
                {
                    name.Should().Be(term + "@odata.type");
                    verifierCalls++;
                }
                else if (verifierCalls == 2)
                {
                    name.Should().Be("@" + term);
                    verifierCalls++;
                }
                else
                {
                    throw new Exception("unexpected call to JsonWriter.WriteName");
                }
            };
            this.jsonWriter.WriteValueVerifier = (value) =>
            {
                verifierCalls.Should().Be(1);
                verifierCalls++;
            };
            this.valueWriter.WritePrimitiveVerifier = (value, reference) =>
            {
                value.Should().Be(time.Value);
                reference.Should().BeNull();
                verifierCalls.Should().Be(3);
                verifierCalls++;
            };

            this.jsonLightInstanceAnnotationWriter.WriteInstanceAnnotation(new ODataInstanceAnnotation(term, time));
            verifierCalls.Should().Be(4);
        }
예제 #28
0
        public static void AssertODataValueAreEqual(ODataValue value1, ODataValue value2)
        {
            if (value1.IsNullValue && value2.IsNullValue)
            {
                return;
            }

            ODataPrimitiveValue primitiveValue1 = value1 as ODataPrimitiveValue;
            ODataPrimitiveValue primitiveValue2 = value2 as ODataPrimitiveValue;

            if (primitiveValue1 != null && primitiveValue2 != null)
            {
                AssertODataPrimitiveValueAreEqual(primitiveValue1, primitiveValue2);
            }
            else
            {
                ODataComplexValue complexValue1 = value1 as ODataComplexValue;
                ODataComplexValue complexValue2 = value2 as ODataComplexValue;
                if (complexValue1 != null && complexValue2 != null)
                {
                    AssertODataComplexValueAreEqual(complexValue1, complexValue2);
                }
                else
                {
                    ODataEnumValue enumValue1 = value1 as ODataEnumValue;
                    ODataEnumValue enumValue2 = value2 as ODataEnumValue;
                    if (enumValue1 != null && enumValue2 != null)
                    {
                        AssertODataEnumValueAreEqual(enumValue1, enumValue2);
                    }
                    else
                    {
                        ODataCollectionValue collectionValue1 = (ODataCollectionValue)value1;
                        ODataCollectionValue collectionValue2 = (ODataCollectionValue)value2;
                        AssertODataCollectionValueAreEqual(collectionValue1, collectionValue2);
                    }
                }
            }
        }
예제 #29
0
        public void WriteInstanceAnnotation_ForIntegerShouldUsePrimitiveCodePath()
        {
            var          integerValue  = new ODataPrimitiveValue(123);
            const string term          = "some.term";
            var          verifierCalls = 0;

            this.jsonWriter.WriteNameVerifier = (name) =>
            {
                Assert.Equal("@" + term, name);
                verifierCalls++;
            };
            this.valueWriter.WritePrimitiveVerifier = (value, reference) =>
            {
                Assert.Equal(integerValue.Value, value);
                Assert.Null(reference);
                Assert.Equal(1, verifierCalls);
                verifierCalls++;
            };

            this.jsonLightInstanceAnnotationWriter.WriteInstanceAnnotation(new ODataInstanceAnnotation(term, integerValue));
            Assert.Equal(2, verifierCalls);
        }
        public void WriteInstanceAnnotation_ForSpatialShouldUsePrimitiveCodePathWithTypeName()
        {
            var          point         = new ODataPrimitiveValue(GeographyPoint.Create(10.5, 5.25));
            const string term          = "some.term";
            var          verifierCalls = 0;

            this.jsonWriter.WriteNameVerifier = (name) =>
            {
                if (verifierCalls == 0)
                {
                    name.Should().Be(term + "@odata.type");
                    verifierCalls++;
                }
                else if (verifierCalls == 2)
                {
                    name.Should().Be("@" + term);
                    verifierCalls++;
                }
                else
                {
                    throw new Exception("unexpected call to JsonWriter.WriteName");
                }
            };
            this.jsonWriter.WriteValueVerifier = (value) =>
            {
                verifierCalls.Should().Be(1);
                verifierCalls++;
            };
            this.valueWriter.WritePrimitiveVerifier = (value, reference) =>
            {
                value.Should().Be(point.Value);
                reference.Should().BeNull();
                verifierCalls.Should().Be(3);
                verifierCalls++;
            };

            this.jsonLightInstanceAnnotationWriter.WriteInstanceAnnotation(new ODataInstanceAnnotation(term, point));
            verifierCalls.Should().Be(4);
        }
        public void WriteInstanceAnnotation_ForIntegerShouldUsePrimitiveCodePath()
        {
            var          integerValue  = new ODataPrimitiveValue(123);
            const string term          = "some.term";
            var          verifierCalls = 0;

            this.jsonWriter.WriteNameVerifier = (name) =>
            {
                name.Should().Be("@" + term);
                verifierCalls++;
            };
            this.valueWriter.WritePrimitiveVerifier = (value, reference) =>
            {
                value.Should().Be(integerValue.Value);
                reference.Should().BeNull();
                verifierCalls.Should().Be(1);
                verifierCalls++;
            };

            this.jsonLightInstanceAnnotationWriter.WriteInstanceAnnotation(new ODataInstanceAnnotation(term, integerValue));
            verifierCalls.Should().Be(2);
        }
예제 #32
0
        /// <summary>
        /// Writes the value of a primitive instance annotation.
        /// </summary>
        /// <param name="primitiveValue">The primitive value to write.</param>
        /// <param name="expectedTypeReference">The expected type of the annotation from the metadata.</param>
        private void WritePrimitiveInstanceAnnotationValue(ODataPrimitiveValue primitiveValue, IEdmTypeReference expectedTypeReference)
        {
            object clrValue = primitiveValue.Value;
            IEdmPrimitiveTypeReference primitiveTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(clrValue.GetType());
            string attributeValueNotationName = AtomInstanceAnnotation.LookupAttributeValueNotationNameByEdmTypeKind(primitiveTypeReference.PrimitiveKind());

            // Some primitive values can be specified more concisely via an attribute rather than in the content of the xml element. This is called "attribute value notation".
            // If we're writing a type that supports this, then we always prefer attribute value notation over writing the value in the element content.
            if (attributeValueNotationName != null)
            {
                if (expectedTypeReference != null)
                {
                    ValidationUtils.ValidateIsExpectedPrimitiveType(primitiveValue.Value, primitiveTypeReference, expectedTypeReference);
                }

                this.XmlWriter.WriteAttributeString(attributeValueNotationName, AtomValueUtils.ConvertPrimitiveToString(clrValue));
            }
            else
            {
                this.WritePrimitiveValue(clrValue, /*collectionValidator*/ null, expectedTypeReference, primitiveValue.GetAnnotation <SerializationTypeNameAnnotation>());
            }
        }
예제 #33
0
        internal static bool ValueTypeMatchesJsonType(ODataPrimitiveValue primitiveValue, EdmPrimitiveTypeKind primitiveTypeKind)
        {
            switch (primitiveTypeKind)
            {
            // If the value being serialized is of a basic type where we can rely on just the JSON representation to convey type information, then never write the type name.
            case EdmPrimitiveTypeKind.Int32:
            case EdmPrimitiveTypeKind.String:
            case EdmPrimitiveTypeKind.Boolean:
                return(true);

            case EdmPrimitiveTypeKind.Double:
                double doubleValue = (double)primitiveValue.Value;

                // If a double value is positive infinity, negative infinity, or NaN, we serialize the double as a string.
                // Thus the reader can't infer the type from the JSON representation, and we must write the type name explicitly
                // (i.e., if the property is open or the property type is assumed to be unknown, as is the case when writing in full metadata mode).
                return(!IsDoubleValueSerializedAsString(doubleValue));

            default:
                return(false);
            }
        }
        internal static void AddTypeNameAnnotationAsNeeded(ODataPrimitiveValue primitive,
            ODataMetadataLevel metadataLevel)
        {
            // ODataLib normally has the caller decide whether or not to serialize properties by leaving properties
            // null when values should not be serialized. The TypeName property is different and should always be
            // provided to ODataLib to enable model validation. A separate annotation is used to decide whether or not
            // to serialize the type name (a null value prevents serialization).

            // Note that this annotation should not be used for Atom or JSON verbose formats, as it will interfere with
            // the correct default behavior for those formats.

            Contract.Assert(primitive != null);

            object value = primitive.Value;

            // Only add an annotation if we want to override ODataLib's default type name serialization behavior.
            if (ShouldAddTypeNameAnnotation(metadataLevel))
            {
                string typeName;

                // Provide the type name to serialize (or null to force it not to serialize).
                if (ShouldSuppressTypeNameSerialization(value, metadataLevel))
                {
                    typeName = null;
                }
                else
                {
                    typeName = GetTypeName(value);
                }

                primitive.SetAnnotation<SerializationTypeNameAnnotation>(new SerializationTypeNameAnnotation
                {
                    TypeName = typeName
                });
            }
        }
        public void AddTypeNameAnnotationAsNeeded_DoesNotAddAnnotation_InDefaultMetadataMode()
        {
            // Arrange
            ODataPrimitiveValue primitive = new ODataPrimitiveValue(0);

            // Act
            ODataPrimitiveSerializer.AddTypeNameAnnotationAsNeeded(primitive, ODataMetadataLevel.Default);

            // Assert
            Assert.Null(primitive.GetAnnotation<SerializationTypeNameAnnotation>());
        }
예제 #36
0
 public void PrimitiveValueShouldSupportUInt64()
 {
     ODataPrimitiveValue valueUInt64 = new ODataPrimitiveValue((UInt64)123);
     this.property.Value = valueUInt64;
     this.property.ODataValue.Should().BeSameAs(valueUInt64);
 }
예제 #37
0
 public void IfValueIsODataPrimitiveValueThenODataValueShouldBeReferenceEqual()
 {
     ODataPrimitiveValue primitiveValue = new ODataPrimitiveValue(42);
     this.property.Value = primitiveValue;
     this.property.ODataValue.Should().BeSameAs(primitiveValue);
 }
        public void WriteTopLevelErrorWithStringInstanceAnnotationWithTypeNameAttribute()
        {
            var result = SetupSerializerAndRunTest(null, serializer =>
            {
                ODataError error = new ODataError();
                var instanceAnnotations = new Collection<ODataInstanceAnnotation>();
                var primitiveValue = new ODataPrimitiveValue("stringValue");
                primitiveValue.SetAnnotation(new SerializationTypeNameAnnotation() { TypeName = "Custom.Type" });
                ODataInstanceAnnotation annotation = new ODataInstanceAnnotation("sample.primitive", primitiveValue);
                instanceAnnotations.Add(annotation);
                error.InstanceAnnotations = instanceAnnotations;

                serializer.WriteTopLevelError(error, false);
            });

            result.Should().Contain("\"[email protected]\":\"#Custom.Type\",\"@sample.primitive\":\"stringValue\"");
        }
        internal static ODataValue CreatePrimitive(object value, ODataMetadataLevel metadataLevel)
        {
            if (value == null)
            {
                return new ODataNullValue();
            }

            object supportedValue = ConvertUnsupportedPrimitives(value);
            ODataPrimitiveValue primitive = new ODataPrimitiveValue(supportedValue);
            AddTypeNameAnnotationAsNeeded(primitive, metadataLevel);
            return primitive;
        }
 public void BuildPropertyContextUriForIntegerPropertyValueWithNonNullAnnotation()
 {
     ODataValue value = new ODataPrimitiveValue(1);
     value.SetAnnotation(new SerializationTypeNameAnnotation { TypeName = "FQNS.FromAnnotation" });
     var contextUri = this.CreatePropertyContextUri(value);
     contextUri.OriginalString.Should().Be(BuildExpectedContextUri("#FQNS.FromAnnotation"));
 }
        public void WriteTopLevelErrorWithDateTimeInstanceAnnotation()
        {
            var result = SetupSerializerAndRunTest(null, serializer =>
            {
                ODataError error = new ODataError();
                var instanceAnnotations = new Collection<ODataInstanceAnnotation>();
                var primitiveValue = new ODataPrimitiveValue(new DateTimeOffset(2000, 1, 1, 12, 30, 0, new TimeSpan()));
                ODataInstanceAnnotation annotation = new ODataInstanceAnnotation("sample.primitive", primitiveValue);
                instanceAnnotations.Add(annotation);
                error.InstanceAnnotations = instanceAnnotations;

                serializer.WriteTopLevelError(error, false);
            });

            result.Should().Contain("\"[email protected]\":\"#DateTimeOffset\",\"@sample.primitive\":\"2000-01-01T12:30:00Z\"");
        }
        public void WriteTopLevelErrorWithDateInstanceAnnotation()
        {
            var result = SetupSerializerAndRunTest(null, serializer =>
            {
                ODataError error = new ODataError();
                var instanceAnnotations = new Collection<ODataInstanceAnnotation>();
                var primitiveValue = new ODataPrimitiveValue(new Date(2014, 8, 8));
                ODataInstanceAnnotation annotation = new ODataInstanceAnnotation("sample.primitive", primitiveValue);
                instanceAnnotations.Add(annotation);
                error.InstanceAnnotations = instanceAnnotations;

                serializer.WriteTopLevelError(error, false);
            });

            result.Should().Contain("\"[email protected]\":\"#Date\",\"@sample.primitive\":\"2014-08-08\"");
        }
        public void WriteTopLevelErrorWithTimeOfDayInstanceAnnotation()
        {
            var result = SetupSerializerAndRunTest(null, serializer =>
            {
                ODataError error = new ODataError();
                var instanceAnnotations = new Collection<ODataInstanceAnnotation>();
                var primitiveValue = new ODataPrimitiveValue(new TimeOfDay(12, 30, 5, 90));
                ODataInstanceAnnotation annotation = new ODataInstanceAnnotation("sample.primitive", primitiveValue);
                instanceAnnotations.Add(annotation);
                error.InstanceAnnotations = instanceAnnotations;

                serializer.WriteTopLevelError(error, false);
            });

            result.Should().Contain("\"[email protected]\":\"#TimeOfDay\",\"@sample.primitive\":\"12:30:05.0900000\"");
        }
        public void AddTypeNameAnnotationAsNeeded_DoesNotAddAnnotation_InDefaultMetadataMode()
        {
            // Arrange
            IEdmPrimitiveTypeReference edmPrimitiveType = EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(typeof(int));
            ODataPrimitiveValue primitive = new ODataPrimitiveValue(0);

            // Act
            ODataPrimitiveSerializer.AddTypeNameAnnotationAsNeeded(primitive, edmPrimitiveType, ODataMetadataLevel.Default);

            // Assert
            Assert.Null(primitive.GetAnnotation<SerializationTypeNameAnnotation>());
        }
        /// <summary>
        /// Writes a primitive property.
        /// </summary>
        /// <param name="property">The property to write out.</param>
        /// <param name="primitiveValue">The primitive value to be written</param>
        /// <param name="propertyTypeReference">The metadata type reference of the property.</param>
        /// <param name="isTopLevel">true when writing a top-level property; false for nested properties.</param>
        /// <param name="isOpenPropertyType">If the property is open.</param>
        private void WritePrimitiveProperty(
            ODataProperty property,
            ODataPrimitiveValue primitiveValue,
            IEdmTypeReference propertyTypeReference,
            bool isTopLevel,
            bool isOpenPropertyType)
        {
            string wirePropertyName = GetWirePropertyName(isTopLevel, property.Name);

            IEdmTypeReference typeFromValue = TypeNameOracle.ResolveAndValidateTypeForPrimitiveValue(primitiveValue);
            string typeNameToWrite = this.JsonLightOutputContext.TypeNameOracle.GetValueTypeNameForWriting(primitiveValue, propertyTypeReference, typeFromValue, isOpenPropertyType);

            this.WritePropertyTypeName(wirePropertyName, typeNameToWrite, isTopLevel);
            this.JsonWriter.WriteName(wirePropertyName);
            this.JsonLightValueSerializer.WritePrimitiveValue(primitiveValue.Value, propertyTypeReference);
        }
        /// <summary>
        /// Writes the value of a primitive instance annotation.
        /// </summary>
        /// <param name="primitiveValue">The primitive value to write.</param>
        /// <param name="expectedTypeReference">The expected type of the annotation from the metadata.</param>
        private void WritePrimitiveInstanceAnnotationValue(ODataPrimitiveValue primitiveValue, IEdmTypeReference expectedTypeReference)
        {
            object clrValue = primitiveValue.Value;
            IEdmPrimitiveTypeReference primitiveTypeReference = EdmLibraryExtensions.GetPrimitiveTypeReference(clrValue.GetType());
            string attributeValueNotationName = AtomInstanceAnnotation.LookupAttributeValueNotationNameByEdmTypeKind(primitiveTypeReference.PrimitiveKind());

            // Some primitive values can be specified more concisely via an attribute rather than in the content of the xml element. This is called "attribute value notation".
            // If we're writing a type that supports this, then we always prefer attribute value notation over writing the value in the element content.
            if (attributeValueNotationName != null)
            {
                if (expectedTypeReference != null)
                {
                    ValidationUtils.ValidateIsExpectedPrimitiveType(primitiveValue.Value, primitiveTypeReference, expectedTypeReference);
                }

                this.XmlWriter.WriteAttributeString(attributeValueNotationName, AtomValueUtils.ConvertPrimitiveToString(clrValue));
            }
            else
            {
                this.WritePrimitiveValue(clrValue, /*collectionValidator*/ null, expectedTypeReference, primitiveValue.GetAnnotation<SerializationTypeNameAnnotation>());
            }
        }
        public void AddTypeNameAnnotationAsNeeded_AddsAnnotation_InJsonLightMetadataMode()
        {
            // Arrange
            IEdmPrimitiveTypeReference edmPrimitiveType = EdmLibHelpers.GetEdmPrimitiveTypeReferenceOrNull(typeof(short));
            ODataPrimitiveValue primitive = new ODataPrimitiveValue((short)1);

            // Act
            ODataPrimitiveSerializer.AddTypeNameAnnotationAsNeeded(primitive, edmPrimitiveType, ODataMetadataLevel.FullMetadata);

            // Assert
            SerializationTypeNameAnnotation annotation = primitive.GetAnnotation<SerializationTypeNameAnnotation>();
            Assert.NotNull(annotation); // Guard
            Assert.Equal("Edm.Int16", annotation.TypeName);
        }
예제 #48
0
 public void TypeNameShouldComeFromSerializationTypeNameAnnotationForPrimitiveValue()
 {
     var stna = new SerializationTypeNameAnnotation() {TypeName = "FromSTNA"};
     var value = new ODataPrimitiveValue(42);
     value.SetAnnotation(stna);
     this.typeNameOracle.GetValueTypeNameForWriting(value,
         EdmCoreModel.Instance.GetInt32(true),
         EdmCoreModel.Instance.GetInt32(false),
         /* isOpenProperty*/ false).Should().Be("FromSTNA");
 }
예제 #49
0
 public void CreatingNestedODataPrimitiveValueShouldFail()
 {
     ODataPrimitiveValue innerPrimitiveValue = new ODataPrimitiveValue(42);
     Action testSubject = () => new ODataPrimitiveValue(innerPrimitiveValue);
     testSubject.ShouldThrow<ODataException>().WithMessage(ErrorStrings.ODataPrimitiveValue_CannotCreateODataPrimitiveValueFromUnsupportedValueType("Microsoft.OData.Core.ODataPrimitiveValue"));
 }