public static void Deserialize___Using_UTC_reduced_precision___Works()
        {
            // Arrange
            var serializedDateTimes = new[]
            {
                "2017-05-06T02:28:46.2704883Z",
                "2017-05-06T02:28:46.270484Z",
                "2017-05-06T02:28:46.27048Z",
                "2017-05-06T02:28:46.2704Z",
                "2017-05-06T02:28:46.271Z",
                "2017-05-06T02:28:46.27Z",
                "2017-05-06T02:28:46.2Z",
                "2017-05-06T02:28:46Z",
                "2017-05-06T02:28:00Z",
                "2017-05-06T02:00:00Z",
                "2017-05-06T00:00:00Z",
            };

            var expected = serializedDateTimes.Select(_ => DateTime.Parse(_, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)).ToList();

            var serializer = new NaosDateTimeStringSerializer();

            // Act
            var actual = serializedDateTimes.Select(_ => serializer.Deserialize <DateTime>(_));

            // Assert
            actual.Should().Equal(expected);
        }
        private string MakeStringFromPropertyValue(object propertyValue, Type serializerType, Type elementSerializerType)
        {
            new { propertyValue }.Must().NotBeNull();

            var propertyType = propertyValue.GetType();

            if (this.configuredTypeToSerializerMap.ContainsKey(propertyType))
            {
                var serializer = this.configuredTypeToSerializerMap[propertyType];
                var ret        = serializer.SerializeToString(propertyValue);
                return(ret);
            }
            else if (serializerType != null)
            {
                if (!this.cachedAttributeSerializerTypeToObjectMap.ContainsKey(serializerType))
                {
                    var newAttributeOnClassSerializer = serializerType.Construct <IStringSerializeAndDeserialize>();
                    this.cachedAttributeSerializerTypeToObjectMap.Add(serializerType, newAttributeOnClassSerializer);
                }

                var attributeOnClassSerializer = this.cachedAttributeSerializerTypeToObjectMap[serializerType];
                var ret = attributeOnClassSerializer.SerializeToString(propertyValue);
                return(ret);
            }
            else if (propertyValue is DateTime)
            {
                return(NaosDateTimeStringSerializer.SerializeDateTimeToString((DateTime)propertyValue));
            }
            else
            {
                if (propertyType != typeof(string) && propertyValue is IEnumerable propertyValueAsEnumerable)
                {
                    var values = new List <string>();
                    foreach (var item in propertyValueAsEnumerable)
                    {
                        var serializedItem = item == null
                                                 ? null
                                                 : this.MakeStringFromPropertyValue(
                            item,
                            elementSerializerType ?? item?.GetType().GetSerializerTypeFromAttribute(),
                            null);
                        values.Add(serializedItem);
                    }

                    return(values.ToCsv(this.dictionaryStringSerializer.NullValueEncoding));
                }
                else if (propertyValue is ISerializeToString propertyValueAsSerializeToString)
                {
                    return(propertyValueAsSerializeToString.SerializeToString());
                }
                else
                {
                    return(propertyValue.ToString());
                }
            }
        }
        public static void RoundtripSerializeDeserialize___Using_local_positive_offset___Works()
        {
            // Arrange
            var expected   = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow, TimeZoneInfo.FindSystemTimeZoneById("New Zealand Standard Time"));
            var serializer = new NaosDateTimeStringSerializer();

            // Act
            var serialized = serializer.SerializeToString(expected);
            var actual     = serializer.Deserialize <DateTime>(serialized);

            // Assert
            actual.Kind.Should().Be(expected.Kind);
            actual.Should().Be(expected);
        }
        public static void RoundtripSerializeDeserialize___Using_unspecified___Works()
        {
            // Arrange
            var expected   = DateTime.UtcNow.ToUnspecified();
            var serializer = new NaosDateTimeStringSerializer();

            // Act
            var serialized = serializer.SerializeToString(expected);
            var actual     = serializer.Deserialize <DateTime>(serialized);

            // Assert
            actual.Kind.Should().Be(expected.Kind);
            actual.Should().Be(expected);
        }
        public static void Deserialize___Null_type___Throws()
        {
            // Arrange
            var    serializer = new NaosDateTimeStringSerializer();
            Action action     = () => serializer.Deserialize(string.Empty, null);

            // Act
            var exception = Record.Exception(action);

            // Assert
            exception.Should().NotBeNull();
            exception.Should().BeOfType <ArgumentNullException>();
            exception.Message.Should().Be("Parameter 'type' is null.");
        }
        public static void Serialize___Not_date_time___Throws()
        {
            // Arrange
            var    serializer = new NaosDateTimeStringSerializer();
            Action action     = () => serializer.SerializeToString("not a datetime");

            // Act
            var exception = Record.Exception(action);

            // Assert
            exception.Should().NotBeNull();
            exception.Should().BeOfType <ArgumentException>();
            exception.Message.Should().Be("Parameter 'typeMustBeDateTimeOrNullableDateTime-System.String' is not true.  Parameter value is 'False'.");
        }
        private object MakeObjectFromString(string serializedString, Type type, Type serializerType, Type elementSerializerType)
        {
            new { serializedString }.Must().NotBeNull();

            if (serializedString == SerializationConfigurationBase.NullSerializedStringValue)
            {
                return(null);
            }

            if (this.configuredTypeToSerializerMap.ContainsKey(type))
            {
                var serializer = this.configuredTypeToSerializerMap[type];
                var ret        = serializer.Deserialize(serializedString, type);
                return(ret);
            }
            else if (serializerType != null)
            {
                if (!this.cachedAttributeSerializerTypeToObjectMap.ContainsKey(serializerType))
                {
                    var newAttributeOnClassSerializer = serializerType.Construct <IStringSerializeAndDeserialize>();
                    this.cachedAttributeSerializerTypeToObjectMap.Add(serializerType, newAttributeOnClassSerializer);
                }

                var attributeOnClassSerializer = this.cachedAttributeSerializerTypeToObjectMap[serializerType];
                var ret = attributeOnClassSerializer.Deserialize(serializedString, type);
                return(ret);
            }
            else if (type.IsEnum)
            {
                return(Enum.Parse(type, serializedString));
            }
            else if (type.IsArray)
            {
                var arrayItemType = type.GetElementType() ?? throw new ArgumentException(Invariant($"Found array type that cannot extract element type: {type}"));
                var asList        = (IList)this.MakeObjectFromString(
                    serializedString,
                    typeof(List <>).MakeGenericType(arrayItemType),
                    null,
                    elementSerializerType);
                var asArrayList = new ArrayList(asList);
                return(asArrayList.ToArray(arrayItemType));
            }
            else if (type == typeof(DateTime) || type == typeof(DateTime?))
            {
                return(NaosDateTimeStringSerializer.DeserializeToDateTime(serializedString));
            }
            else if (type != typeof(string) && typeof(IEnumerable).IsAssignableFrom(type))
            {
                var   itemType     = type.GetGenericArguments().SingleOrDefault() ?? throw new ArgumentException(Invariant($"Found {typeof(IEnumerable)} type that cannot extract element type: {type}"));
                var   stringValues = serializedString.FromCsv(this.dictionaryStringSerializer.NullValueEncoding);
                IList values       = (IList)typeof(List <>).MakeGenericType(itemType).Construct();
                foreach (var stringValue in stringValues)
                {
                    var itemValue = stringValue == null
                                        ? null
                                        : this.MakeObjectFromString(
                        stringValue,
                        itemType,
                        elementSerializerType ?? itemType.GetSerializerTypeFromAttribute(),
                        null);
                    values.Add(itemValue);
                }

                return(values);
            }
            else
            {
                var bindingFlags         = BindingFlags.Static | BindingFlags.Public | BindingFlags.Instance;
                var typeToSearchForParse = type;
                if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    typeToSearchForParse = type.GetGenericArguments().Single();
                }

                var parseMethod = typeToSearchForParse.GetMethods(bindingFlags).SingleOrDefault(
                    _ =>
                {
                    var parameters = _.GetParameters();
                    return(_.Name == "Parse" && parameters.Length == 1 && parameters.Single().ParameterType == typeof(string));
                });

                if (parseMethod == null)
                {
                    // nothing we can do here so return the string and hope...
                    return(serializedString);
                }
                else
                {
                    var ret = parseMethod.Invoke(null, new object[] { serializedString });
                    return(ret);
                }
            }
        }