diff --git a/src/Akavache.Core/BlobCache/InMemoryBlobCache.cs b/src/Akavache.Core/BlobCache/InMemoryBlobCache.cs index cf12d2363..24c2974da 100644 --- a/src/Akavache.Core/BlobCache/InMemoryBlobCache.cs +++ b/src/Akavache.Core/BlobCache/InMemoryBlobCache.cs @@ -31,6 +31,7 @@ public class InMemoryBlobCache : ISecureBlobCache, IObjectBlobCache, IEnableLogg private Dictionary _cache = new Dictionary(); private bool _disposed; private DateTimeKind? _dateTimeKind; + private JsonDateTimeContractResolver _jsonDateTimeContractResolver = new JsonDateTimeContractResolver(); // This will make us use ticks instead of json ticks for DateTime. /// /// Initializes a new instance of the class. @@ -91,7 +92,16 @@ internal InMemoryBlobCache( public DateTimeKind? ForcedDateTimeKind { get => _dateTimeKind ?? BlobCache.ForcedDateTimeKind; - set => _dateTimeKind = value; + + set + { + _dateTimeKind = value; + + if (_jsonDateTimeContractResolver != null) + { + _jsonDateTimeContractResolver.ForceDateTimeKindOverride = value; + } + } } /// @@ -442,7 +452,8 @@ protected virtual void Dispose(bool isDisposing) private byte[] SerializeObject(T value) { var settings = Locator.Current.GetService() ?? new JsonSerializerSettings(); - settings.ContractResolver = new JsonDateTimeContractResolver(settings.ContractResolver, ForcedDateTimeKind); // This will make us use ticks instead of json ticks for DateTime. + _jsonDateTimeContractResolver.ExistingContractResolver = settings.ContractResolver; + settings.ContractResolver = _jsonDateTimeContractResolver; var serializer = JsonSerializer.Create(settings); using (var ms = new MemoryStream()) { @@ -457,7 +468,8 @@ private byte[] SerializeObject(T value) private T DeserializeObject(byte[] data) { var settings = Locator.Current.GetService() ?? new JsonSerializerSettings(); - settings.ContractResolver = new JsonDateTimeContractResolver(settings.ContractResolver, ForcedDateTimeKind); // This will make us use ticks instead of json ticks for DateTime. + _jsonDateTimeContractResolver.ExistingContractResolver = settings.ContractResolver; + settings.ContractResolver = _jsonDateTimeContractResolver; var serializer = JsonSerializer.Create(settings); using (var reader = new BsonDataReader(new MemoryStream(data))) { diff --git a/src/Akavache.Core/Json/JsonDateTimeContractResolver.cs b/src/Akavache.Core/Json/JsonDateTimeContractResolver.cs index 3bcb769d3..9374a24e4 100644 --- a/src/Akavache.Core/Json/JsonDateTimeContractResolver.cs +++ b/src/Akavache.Core/Json/JsonDateTimeContractResolver.cs @@ -14,8 +14,13 @@ namespace Akavache /// internal class JsonDateTimeContractResolver : DefaultContractResolver { - private readonly IContractResolver _existingContractResolver; - private readonly DateTimeKind? _forceDateTimeKindOverride; + /// + /// Initializes a new instance of the class. + /// + public JsonDateTimeContractResolver() + : this(null, null) + { + } /// /// Initializes a new instance of the class. @@ -24,14 +29,18 @@ internal class JsonDateTimeContractResolver : DefaultContractResolver /// If we should override the . public JsonDateTimeContractResolver(IContractResolver contractResolver, DateTimeKind? forceDateTimeKindOverride) { - _existingContractResolver = contractResolver; - _forceDateTimeKindOverride = forceDateTimeKindOverride; + ExistingContractResolver = contractResolver; + ForceDateTimeKindOverride = forceDateTimeKindOverride; } + public IContractResolver ExistingContractResolver { get; set; } + + public DateTimeKind? ForceDateTimeKindOverride { get; set; } + /// public override JsonContract ResolveContract(Type type) { - var contract = _existingContractResolver?.ResolveContract(type); + var contract = ExistingContractResolver?.ResolveContract(type); if (contract?.Converter != null) { return contract; @@ -44,7 +53,7 @@ public override JsonContract ResolveContract(Type type) if (type == typeof(DateTime) || type == typeof(DateTime?)) { - contract.Converter = _forceDateTimeKindOverride == DateTimeKind.Local ? JsonDateTimeTickConverter.LocalDateTimeKindDefault : JsonDateTimeTickConverter.Default; + contract.Converter = ForceDateTimeKindOverride == DateTimeKind.Local ? JsonDateTimeTickConverter.LocalDateTimeKindDefault : JsonDateTimeTickConverter.Default; } else if (type == typeof(DateTimeOffset) || type == typeof(DateTimeOffset?)) { diff --git a/src/Akavache.Sqlite3/SqlLiteCache/SqlRawPersistentBlobCache.cs b/src/Akavache.Sqlite3/SqlLiteCache/SqlRawPersistentBlobCache.cs index db0937b4b..8937d03d6 100644 --- a/src/Akavache.Sqlite3/SqlLiteCache/SqlRawPersistentBlobCache.cs +++ b/src/Akavache.Sqlite3/SqlLiteCache/SqlRawPersistentBlobCache.cs @@ -36,6 +36,7 @@ public class SqlRawPersistentBlobCache : IObjectBlobCache, IEnableLogger, IObjec private IDisposable _queueThread; private DateTimeKind? _dateTimeKind; private bool _disposed; + private JsonDateTimeContractResolver _jsonDateTimeContractResolver = new JsonDateTimeContractResolver(); // This will make us use ticks instead of json ticks for DateTime. /// /// Initializes a new instance of the class. @@ -56,7 +57,16 @@ public SqlRawPersistentBlobCache(string databaseFile, IScheduler scheduler = nul public DateTimeKind? ForcedDateTimeKind { get => _dateTimeKind ?? BlobCache.ForcedDateTimeKind; - set => _dateTimeKind = value; + + set + { + _dateTimeKind = value; + + if (_jsonDateTimeContractResolver != null) + { + _jsonDateTimeContractResolver.ForceDateTimeKindOverride = value; + } + } } /// @@ -672,7 +682,8 @@ protected virtual IObservable AfterReadFromDiskFilter(byte[] data, ISche private byte[] SerializeObject(T value) { var settings = Locator.Current.GetService() ?? new JsonSerializerSettings(); - settings.ContractResolver = new JsonDateTimeContractResolver(settings.ContractResolver, ForcedDateTimeKind); // This will make us use ticks instead of json ticks for DateTime. + _jsonDateTimeContractResolver.ExistingContractResolver = settings.ContractResolver; + settings.ContractResolver = _jsonDateTimeContractResolver; var serializer = JsonSerializer.Create(settings); using (var ms = new MemoryStream()) { @@ -687,7 +698,8 @@ private byte[] SerializeObject(T value) private IObservable DeserializeObject(byte[] data) { var settings = Locator.Current.GetService() ?? new JsonSerializerSettings(); - settings.ContractResolver = new JsonDateTimeContractResolver(settings.ContractResolver, ForcedDateTimeKind); // This will make us use ticks instead of json ticks for DateTime. + _jsonDateTimeContractResolver.ExistingContractResolver = settings.ContractResolver; + settings.ContractResolver = _jsonDateTimeContractResolver; var serializer = JsonSerializer.Create(settings); using (var reader = new BsonDataReader(new MemoryStream(data))) { diff --git a/src/Akavache.Tests/TestBases/DateTimeTestBase.cs b/src/Akavache.Tests/TestBases/DateTimeTestBase.cs index bf187d1d1..e1291d8ed 100644 --- a/src/Akavache.Tests/TestBases/DateTimeTestBase.cs +++ b/src/Akavache.Tests/TestBases/DateTimeTestBase.cs @@ -16,11 +16,6 @@ namespace Akavache.Tests /// public abstract class DateTimeTestBase { - /// - /// Time zone for when testing UTC vs local time operations. Just has to be something that doesn't match UTC. - /// - private const string TestTimeZone = "Pacific Standard Time"; - /// /// Gets the date time offsets used in theory tests. /// @@ -56,7 +51,7 @@ public abstract class DateTimeTestBase /// /// Gets the date time when the tests are done to keep them consistent. /// - private static DateTime LocalTestNow { get; } = TimeZoneInfo.ConvertTimeFromUtc(TestNow.ToUniversalTime(), TimeZoneInfo.FindSystemTimeZoneById(TestTimeZone)); + private static DateTime LocalTestNow { get; } = TimeZoneInfo.ConvertTimeFromUtc(TestNow.ToUniversalTime(), TimeZoneInfo.CreateCustomTimeZone("testTimeZone", TimeSpan.FromHours(6), "Test Time Zone", "Test Time Zone")); /// /// Gets the date time off set when the tests are done to keep them consistent. diff --git a/src/Akavache.Tests/UtilityTests.cs b/src/Akavache.Tests/UtilityTests.cs index 4ce0dd266..b75c7596e 100644 --- a/src/Akavache.Tests/UtilityTests.cs +++ b/src/Akavache.Tests/UtilityTests.cs @@ -7,6 +7,7 @@ using System.IO; using System.Linq; using System.Reactive.Subjects; +using System.Runtime.InteropServices; using Xunit; namespace Akavache.Tests @@ -36,6 +37,11 @@ public void DirectoryCreateCreatesDirectories() [Fact] public void DirectoryCreateThrowsIOExceptionForNonexistentNetworkPaths() { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return; + } + var exception = Assert.Throws(() => new DirectoryInfo(@"\\does\not\exist").CreateRecursive()); Assert.StartsWith("The network path was not found", exception.Message); } @@ -46,7 +52,21 @@ public void DirectoryCreateThrowsIOExceptionForNonexistentNetworkPaths() [Fact] public void UtilitySplitsAbsolutePaths() { - Assert.Equal(new[] { @"c:\", "foo", "bar" }, new DirectoryInfo(@"c:\foo\bar").SplitFullPath()); + string path; + string expectedRoot; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + path = @"c:\foo\bar"; + expectedRoot = @"c:\"; + } + else + { + path = "/foo/bar"; + expectedRoot = "/"; + } + + Assert.Equal(new[] { expectedRoot, "foo", "bar" }, new DirectoryInfo(path).SplitFullPath()); } /// @@ -55,7 +75,18 @@ public void UtilitySplitsAbsolutePaths() [Fact] public void UtilityResolvesAndSplitsRelativePaths() { - var components = new DirectoryInfo(@"foo\bar").SplitFullPath().ToList(); + string path; + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + path = @"foo\bar"; + } + else + { + path = "foo/bar"; + } + + var components = new DirectoryInfo(path).SplitFullPath().ToList(); Assert.True(components.Count > 2); Assert.Equal(new[] { "foo", "bar" }, components.Skip(components.Count - 2)); } @@ -66,6 +97,11 @@ public void UtilityResolvesAndSplitsRelativePaths() [Fact] public void UtilitySplitsUncPaths() { + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return; + } + Assert.Equal(new[] { @"\\foo\bar", "baz" }, new DirectoryInfo(@"\\foo\bar\baz").SplitFullPath()); }