Skip to content

Commit

Permalink
Implemented snapshot stream support. (#173)
Browse files Browse the repository at this point in the history
  • Loading branch information
nscheibe authored Feb 28, 2023
1 parent 11a986a commit 904a252
Show file tree
Hide file tree
Showing 14 changed files with 278 additions and 51 deletions.
36 changes: 36 additions & 0 deletions src/Snapshooter/Core/Serialization/MemoryStreamJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using System;
using System.IO;
using Newtonsoft.Json;

namespace Snapshooter.Core.Serialization;

public class MemoryStreamJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(MemoryStream).IsAssignableFrom(objectType);
}

public override object ReadJson(
JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
var bytes = serializer.Deserialize<byte[]>(reader);

return bytes != null ?
new MemoryStream(bytes) :
new MemoryStream();
}

public override void WriteJson(
JsonWriter writer,
object value,
JsonSerializer serializer)
{
var bytes = ((MemoryStream)value).ToArray();

serializer.Serialize(writer, bytes);
}
}
83 changes: 44 additions & 39 deletions src/Snapshooter/Core/Serialization/SnapshotSerializerSettings.cs
Original file line number Diff line number Diff line change
@@ -1,60 +1,65 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using Snapshooter.Extensions;

namespace Snapshooter.Core.Serialization
namespace Snapshooter.Core.Serialization;

/// <summary>
/// </summary>
public abstract class SnapshotSerializerSettings
{
/// <summary>
/// </summary>
public abstract class SnapshotSerializerSettings
{
public virtual int Order { get; } = 1;
public virtual int Order { get; } = 1;

public virtual bool Active { get; } = true;
public virtual bool Active { get; } = true;

/// <summary>
/// </summary>
public static JsonSerializerSettings DefaultJsonSerializerSettings =>
new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Include,
DateFormatHandling = DateFormatHandling.IsoDateFormat,
Culture = CultureInfo.InvariantCulture,
ContractResolver = ChildFirstContractResolver.Instance,
Converters = new List<JsonConverter> {new StringEnumConverter()}
};

public abstract JsonSerializerSettings Extend(JsonSerializerSettings settings);

private class ChildFirstContractResolver : DefaultContractResolver
/// <summary>
/// </summary>
public static JsonSerializerSettings DefaultJsonSerializerSettings =>
new JsonSerializerSettings
{
static ChildFirstContractResolver() { Instance = new ChildFirstContractResolver(); }
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Include,
DateFormatHandling = DateFormatHandling.IsoDateFormat,
Culture = CultureInfo.InvariantCulture,
ContractResolver = ChildFirstContractResolver.Instance,
Converters = new List<JsonConverter>
{
new StringEnumConverter(),
new MemoryStreamJsonConverter(),
new StreamJsonConverter()
}
};

public static ChildFirstContractResolver Instance { get; }
public abstract JsonSerializerSettings Extend(JsonSerializerSettings settings);

protected override IList<JsonProperty> CreateProperties(
Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
private class ChildFirstContractResolver : DefaultContractResolver
{
public static ChildFirstContractResolver Instance { get; }
= new ChildFirstContractResolver();

if (properties != null)
{
properties = properties.OrderBy(p =>
{
IEnumerable<Type> d = ((Type)p.DeclaringType).BaseTypesAndSelf().ToList();
return 1000 - d.Count();
}).ToList();
}
protected override IList<JsonProperty> CreateProperties(
Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> properties =
base.CreateProperties(type, memberSerialization);

return properties;
if (properties != null)
{
properties = properties
.OrderBy(p => 1000 - ((Type)p.DeclaringType)
.BaseTypesAndSelf()
.Count())
.ToList();
}

return properties;
}
}
}
39 changes: 39 additions & 0 deletions src/Snapshooter/Core/Serialization/StreamJsonConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System;
using System.IO;
using Newtonsoft.Json;

namespace Snapshooter.Core.Serialization;

public class StreamJsonConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return typeof(Stream).IsAssignableFrom(objectType);
}

public override object ReadJson(
JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
{
var bytes = serializer.Deserialize<byte[]>(reader);

return bytes != null ?
new MemoryStream(bytes) :
new MemoryStream();
}

public override void WriteJson(
JsonWriter writer,
object value,
JsonSerializer serializer)
{
using var stream = (Stream)value;

byte[] bytes = new byte[stream.Length];
stream.Read(bytes, 0, bytes.Length);

serializer.Serialize(writer, bytes);
}
}
10 changes: 8 additions & 2 deletions test/Snapshooter.Tests.Data/TestFileLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ public static string LoadTextFile(string fileName)
}

private static T LoadResourceFile<T>(string fileName, Func<Stream, T> streamConverter)
{
Stream resourceStream = LoadResourceFile(fileName);

return streamConverter(resourceStream);
}

private static Stream LoadResourceFile(string fileName)
{
Assembly assembly = typeof(TestFileLoader).GetTypeInfo().Assembly;

Expand All @@ -79,8 +86,7 @@ private static T LoadResourceFile<T>(string fileName, Func<Stream, T> streamConv
$"for file {resourceName} could be found.");
}

return streamConverter(resourceStream);

return resourceStream;
}
}
}
23 changes: 13 additions & 10 deletions test/Snapshooter.Xunit.Tests/Helpers/SnapshotDefaultNameResolver.cs
Original file line number Diff line number Diff line change
@@ -1,22 +1,13 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Snapshooter.Xunit.Tests.Helpers
{
internal static class SnapshotDefaultNameResolver
{
public static string ResolveSnapshotDefaultName()
{
var snapshotFullNameResolver =
new SnapshotFullNameResolver(
new XunitSnapshotFullNameReader());

SnapshotFullName snapshotFullName =
snapshotFullNameResolver.ResolveSnapshotFullName();
ResolveSnapshotDefaultFullName();

string snapshotFileName = Path.Combine(
snapshotFullName.FolderPath,
Expand All @@ -25,5 +16,17 @@ public static string ResolveSnapshotDefaultName()

return snapshotFileName;
}

public static SnapshotFullName ResolveSnapshotDefaultFullName()
{
var snapshotFullNameResolver =
new SnapshotFullNameResolver(
new XunitSnapshotFullNameReader());

SnapshotFullName snapshotFullName =
snapshotFullNameResolver.ResolveSnapshotFullName();

return snapshotFullName;
}
}
}
113 changes: 113 additions & 0 deletions test/Snapshooter.Xunit.Tests/SnapshotTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using FluentAssertions;
using Snapshooter.Exceptions;
using Snapshooter.Tests.Data;
using Snapshooter.Xunit.Tests.Helpers;
using Xunit;
using Xunit.Sdk;

Expand Down Expand Up @@ -901,6 +903,117 @@ public void Match_FactMatchScalarIntegerValueSnapshot_IgnoreOptionFails()

#endregion

#region Match Snapshots - Stream Types Tests

[Fact]
public void Match_FactMatchMemoryStreamSnapshot_SuccessfulMatch()
{
// arrange
MemoryStream testMemoryStream =
new MemoryStream(Encoding.ASCII.GetBytes("Foo Bar 35"));

// act & assert
Snapshot.Match(testMemoryStream);
}

[Fact]
public void Match_FactMatchObjectWithMemoryStreamSnapshot_SuccessfulMatch()
{
// arrange
var testUser = new
{
FirstName = "Foo",
Age = 35,
Picture = new MemoryStream(Encoding.ASCII.GetBytes("Foo Bar 35"))
};

// act & assert
Snapshot.Match(testUser);
}

[Fact]
public void Match_FactMatchStreamSnapshot_SuccessfulMatch()
{
// arrange
Stream testStream =
TestFileLoader.LoadFileStream("mona-lisa.jpg");

// act & assert
Snapshot.Match(testStream);
}

[Fact]
public void Match_FactMatchObjectWithStreamSnapshot_SuccessfulMatch()
{
// arrange
var testUser = new
{
FirstName = "Foo",
Age = 35,
Picture = TestFileLoader.LoadFileStream("mona-lisa.jpg")
};

// act & assert
Snapshot.Match(testUser);
}

[Fact]
public void Match_FactMatchFileStreamSnapshot_SuccessfulMatch()
{
// arrange
string folderPath = SnapshotDefaultNameResolver
.ResolveSnapshotDefaultFullName()
.FolderPath;

Stream testStream =
File.OpenRead($"{folderPath}/__testsources__/mona-lisa.jpg");

// act & assert
Snapshot.Match(testStream);
}

[Fact]
public void Match_FactMatchObjectWithFileStreamSnapshot_SuccessfulMatch()
{
// arrange
string folderPath = SnapshotDefaultNameResolver
.ResolveSnapshotDefaultFullName()
.FolderPath;

var testUser = new
{
FirstName = "Foo",
Age = 35,
Picture = File.OpenRead($"{folderPath}/__testsources__/mona-lisa.jpg")
};

// act & assert
Snapshot.Match(testUser);
}

[Fact]
public void Match_FactMatchObjectWithAllStreamsSnapshot_SuccessfulMatch()
{
// arrange
string folderPath = SnapshotDefaultNameResolver
.ResolveSnapshotDefaultFullName()
.FolderPath;

var testUser = new
{
FirstName = "Foo",
Age = 35,
MemoryStreamName = new MemoryStream(Encoding.ASCII.GetBytes("Foo Bar 35")),
EmbeddedStreamPicture = TestFileLoader.LoadFileStream("mona-lisa.jpg"),
FileStreamPicture = File.OpenRead($"{folderPath}/__testsources__/mona-lisa.jpg")
};

// act & assert
Snapshot.Match(testUser);
}

#endregion

#region Match Snapshots - Crlf Tests

[Fact]
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"Rm9vIEJhciAzNQ=="

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"FirstName": "Foo",
"Age": 35,
"Picture": "Rm9vIEJhciAzNQ=="
}

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 904a252

Please sign in to comment.