Skip to content

Commit

Permalink
Merge pull request #28 from hanssens/vnext
Browse files Browse the repository at this point in the history
Release v2.0.0 - final
  • Loading branch information
hanssens authored Mar 19, 2019
2 parents aa54c62 + 0626ada commit 38edbd8
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 22 deletions.
19 changes: 19 additions & 0 deletions LocalStorage.Tests/Helpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using System;
using Hanssens.Net;

namespace LocalStorageTests
{
internal static class TestHelpers
{
/// <summary>
/// Configuration that can be used for initializing a unique LocalStorage instance.
/// </summary>
internal static ILocalStorageConfiguration UniqueInstance()
{
return new LocalStorageConfiguration()
{
Filename = Guid.NewGuid().ToString()
};
}
}
}
10 changes: 5 additions & 5 deletions LocalStorage.Tests/LocalStorage.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp1.0</TargetFramework>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RootNamespace>LocalStorageTests</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" Version="4.18.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.0.0-preview-20170106-08" />
<PackageReference Include="xunit" Version="2.2.0-beta5-build3474" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.2.0-beta5-build1225" />
<PackageReference Include="FluentAssertions" Version="5.6.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\LocalStorage\LocalStorage.csproj" />
Expand Down
81 changes: 80 additions & 1 deletion LocalStorage.Tests/LocalStorageTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Diagnostics;
using System.IO;
using System.Linq;
using FluentAssertions.Common;
using Hanssens.Net.Helpers;
using Xunit;
using LocalStorageTests.Stubs;
Expand Down Expand Up @@ -126,7 +127,7 @@ public void LocalStorage_Store_Should_Overwrite_Existing_Key()

// assert - last stored value should be the truth
target.Should().NotBeNull();
target.ShouldBeEquivalentTo(expected_value);
target.IsSameOrEqualTo(expected_value);
}

[Fact(DisplayName = "LocalStorage.Clear() should clear all in-memory content")]
Expand Down Expand Up @@ -236,6 +237,84 @@ public void LocalStorage_Should_Perform_Decently_With_Large_Collections()
// assert - make sure the entire operation is done in < 1sec. (psychological boundry, if you will)
stopwatch.ElapsedMilliseconds.Should().BeLessOrEqualTo(1000);
}

[Fact(DisplayName = "LocalStorage should perform decently with many iterations collections")]
public void LocalStorage_Should_Perform_Decently_With_Many_Opens_And_Writes()
{
// arrange - iterate a lot of times through open/persist/close
for (var i = 0; i < 1000; i++)
{
var storage = new LocalStorage();
// storage.Clear();
storage.Store(Guid.NewGuid().ToString(), i);
storage.Persist();
}

// cleanup
var store = new LocalStorage();
store.Destroy();
}

[Fact(DisplayName = "LocalStorage.Exists() should locate existing key")]
public void LocalStorage_Exists_Should_Locate_Existing_Key()
{
// arrange
var storage = new LocalStorage();
var expected_key = Guid.NewGuid().ToString();
storage.Store(expected_key, Guid.NewGuid().ToString());

// act
var target = storage.Exists(expected_key);

// assert
target.Should().BeTrue();
}

[Fact(DisplayName = "LocalStorage.Exists() should ignore non-existing key")]
public void LocalStorage_Exists_Should_Ignore_NonExisting_Key()
{
// arrange
var storage = new LocalStorage();
var nonexisting_key = Guid.NewGuid().ToString();

// act
var target = storage.Exists(nonexisting_key);

// assert
target.Should().BeFalse();
}

[Fact(DisplayName = "LocalStorage.Keys() should return collection of all keys")]
public void LocalStorage_Keys_Should_Return_Collection_Of_Keys()
{
// arrange
var storage = new LocalStorage(TestHelpers.UniqueInstance());
for (var i = 0; i < 10; i++)
storage.Store(Guid.NewGuid().ToString(), i);
var expected_keycount = storage.Count;

// act
var target = storage.Keys();

// assert
target.Should().NotBeNullOrEmpty();
target.Count.Should().Be(expected_keycount);
}

[Fact(DisplayName = "LocalStorage.Keys() should return 0 on empty collection")]
public void LocalStorage_Keys_Should_Return_Zero_On_Empty_Collection()
{
// arrange
var storage = new LocalStorage(TestHelpers.UniqueInstance());

// act
var target = storage.Keys();

// assert
target.Should().NotBeNull();
target.Should().BeEmpty();
target.Count.Should().Be(0, because: "nothing is added to the LocalStorage");
}

[Fact(DisplayName = "LocalStorage.Query() should cast to a collection")]
public void LocalStorage_Query_Should_Cast_Response_To_Collection()
Expand Down
5 changes: 5 additions & 0 deletions LocalStorage/ILocalStorageConfiguration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ public interface ILocalStorageConfiguration
/// </summary>
bool EnableEncryption { get; set; }

/// <summary>
/// [Optional] Add a custom salt to encryption, when EnableEncryption is enabled.
/// </summary>
string EncryptionSalt { get; set; }

/// <summary>
/// Filename for the persisted state on disk (defaults to ".localstorage").
/// </summary>
Expand Down
49 changes: 38 additions & 11 deletions LocalStorage/LocalStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public class LocalStorage : IDisposable
/// <summary>
/// Configurable behaviour for this LocalStorage instance.
/// </summary>
private readonly LocalStorageConfiguration _config;
private readonly ILocalStorageConfiguration _config;

/// <summary>
/// User-provided encryption key, used for encrypting/decrypting values.
Expand All @@ -31,16 +31,16 @@ public class LocalStorage : IDisposable
/// Most current actual, in-memory state representation of the LocalStorage.
/// </summary>
private Dictionary<string, string> Storage { get; set; } = new Dictionary<string, string>();

private object writeLock = new object();

public LocalStorage() : this(new LocalStorageConfiguration()) { }
public LocalStorage() : this(new LocalStorageConfiguration(), string.Empty) { }

public LocalStorage(LocalStorageConfiguration configuration) : this(configuration, string.Empty) { }
public LocalStorage(ILocalStorageConfiguration configuration) : this(configuration, string.Empty) { }

public LocalStorage(LocalStorageConfiguration configuration, string encryptionKey)
public LocalStorage(ILocalStorageConfiguration configuration, string encryptionKey)
{
if (configuration == null) throw new ArgumentNullException(nameof(configuration));

_config = configuration;
_config = configuration ?? throw new ArgumentNullException(nameof(configuration));

if (_config.EnableEncryption) {
if (string.IsNullOrEmpty(encryptionKey)) throw new ArgumentNullException(nameof(encryptionKey), "When EnableEncryption is enabled, an encryptionKey is required when initializing the LocalStorage.");
Expand Down Expand Up @@ -75,6 +75,16 @@ public void Destroy()
File.Delete(FileHelpers.GetLocalStoreFilePath(_config.Filename));
}

/// <summary>
/// Determines whether this LocalStorage instance contains the specified key.
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public bool Exists(string key)
{
return Storage.ContainsKey(key: key);
}

/// <summary>
/// Gets an object from the LocalStorage, without knowing its type.
/// </summary>
Expand All @@ -99,6 +109,14 @@ public T Get<T>(string key)
return JsonConvert.DeserializeObject<T>(raw);
}

/// <summary>
/// Gets a collection containing all the keys in the LocalStorage.
/// </summary>
public IReadOnlyCollection<string> Keys()
{
return Storage.Keys.OrderBy(x => x).ToList();
}

/// <summary>
/// Loads the persisted state from disk into memory, overriding the current memory instance.
/// </summary>
Expand Down Expand Up @@ -152,13 +170,22 @@ public IEnumerable<T> Query<T>(string key, Func<T, bool> predicate = null)
/// </summary>
public void Persist()
{
var serialized = JsonConvert.SerializeObject(Storage);
var serialized = JsonConvert.SerializeObject(Storage, Formatting.Indented);

using (var fileStream = new FileStream(FileHelpers.GetLocalStoreFilePath(_config.Filename), FileMode.OpenOrCreate, FileAccess.Write))
var writemode = File.Exists(FileHelpers.GetLocalStoreFilePath(_config.Filename))
? FileMode.Truncate
: FileMode.Create;

lock (writeLock)
{
using (var writer = new StreamWriter(fileStream))
using (var fileStream = new FileStream(FileHelpers.GetLocalStoreFilePath(_config.Filename),
mode: writemode,
access: FileAccess.Write))
{
writer.Write(serialized);
using (var writer = new StreamWriter(fileStream))
{
writer.Write(serialized);
}
}
}
}
Expand Down
13 changes: 8 additions & 5 deletions LocalStorage/LocalStorage.csproj
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp1.0;netstandard1.3;net46</TargetFrameworks>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
<Authors>Juliën Hanssens</Authors>
<Company />
<PackageProjectUrl>https://github.com/hanssens/localstorage-for-dotnet</PackageProjectUrl>
<RepositoryUrl>https://github.com/hanssens/localstorage-for-dotnet</RepositoryUrl>
<PackageTags>c#, dotnet, local, storage</PackageTags>
<PackageTags>c#, dotnet, storage, cache, nosql, lightweight</PackageTags>
<Description>A simple and lightweight tool for persisting data in dotnet (core) apps.</Description>
<RepositoryType>git</RepositoryType>
<PackageIconUrl>https://d17oy1vhnax1f7.cloudfront.net/items/1x2w321G3u3x2z0g120Q/hanssens-beer.png</PackageIconUrl>
<PackageLicenseUrl>https://github.com/hanssens/localstorage-for-dotnet/blob/master/LICENSE</PackageLicenseUrl>
<Version>1.1.0</Version>
<Title>LocalStorage</Title>
<Version>2.0.0</Version>
<RootNamespace>Hanssens.Net</RootNamespace>
<PackageReleaseNotes>See the releases page on GitHub for release notes:
https://github.com/hanssens/localstorage-for-dotnet/releases</PackageReleaseNotes>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<Folder Include="Helpers" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
</ItemGroup>
</Project>
1 change: 1 addition & 0 deletions build.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dotnet pack ./LocalStorage/LocalStorage.csproj -c Release --include-symbols

0 comments on commit 38edbd8

Please sign in to comment.