Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented snapshot stream support. #173

Merged
merged 4 commits into from
Feb 28, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}
79 changes: 42 additions & 37 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
{
public virtual int Order { get; } = 1;

public virtual bool Active { get; } = true;

/// <summary>
/// </summary>
public abstract class SnapshotSerializerSettings
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(),
new MemoryStreamJsonConverter(),
new StreamJsonConverter()
}
};

public abstract JsonSerializerSettings Extend(JsonSerializerSettings settings);

private class ChildFirstContractResolver : DefaultContractResolver
{
public virtual int Order { get; } = 1;
static ChildFirstContractResolver() { Instance = new ChildFirstContractResolver(); }
PascalSenn marked this conversation as resolved.
Show resolved Hide resolved

public virtual bool Active { get; } = true;
public static ChildFirstContractResolver Instance { get; }

/// <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
protected override IList<JsonProperty> CreateProperties(
Type type, MemberSerialization memberSerialization)
{
static ChildFirstContractResolver() { Instance = new ChildFirstContractResolver(); }
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);

public static ChildFirstContractResolver Instance { get; }

protected override IList<JsonProperty> CreateProperties(
Type type, MemberSerialization memberSerialization)
if (properties != null)
{
IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);

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

return properties;
IEnumerable<Type> d = ((Type)p.DeclaringType).BaseTypesAndSelf().ToList();
return 1000 - d.Count();
PascalSenn marked this conversation as resolved.
Show resolved Hide resolved
}).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.