This commit is contained in:
SimonCropp 2020-01-06 21:38:28 +11:00
Родитель bec69af890
Коммит bcf2f85fdf
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: C75A8447313A3D69
13 изменённых файлов: 336 добавлений и 81 удалений

140
readme.md
Просмотреть файл

@ -7,17 +7,19 @@ To change this file edit the source file and then run MarkdownSnippets.
# <img src="/src/icon.png" height="30px"> Verify.EntityFramework
[![Build status](https://ci.appveyor.com/api/projects/status/eedjhmx5o3082tyq?svg=true)](https://ci.appveyor.com/project/SimonCropp/verify-entityframework)
[![Build status](https://ci.appveyor.com/api/projects/status/g6njwv0aox62atu0?svg=true)](https://ci.appveyor.com/project/SimonCropp/verify-entityframework)
[![NuGet Status](https://img.shields.io/nuget/v/Verify.EntityFramework.svg)](https://www.nuget.org/packages/Verify.EntityFramework/)
Extends [Verify](https://github.com/SimonCropp/Verify) to allow verification of web bits.
Extends [Verify](https://github.com/SimonCropp/Verify) to allow verification of EntityFramewok bits.
<!-- toc -->
## Contents
* [Usage](#usage)
* [Controller](#controller)<!-- endtoc -->
* [Added entry](#added-entry)
* [Deleted entry](#deleted-entry)
* [Modified entry](#modified-entry)<!-- endtoc -->
## NuGet package
@ -27,7 +29,7 @@ https://nuget.org/packages/Verify.EntityFramework/
## Usage
Enable VerifyWeb once at assembly load time:
Enable VerifyEntityFramewok once at assembly load time:
<!-- snippet: Enable -->
<a id='snippet-enable'/></a>
@ -38,21 +40,137 @@ VerifyEntityFramework.Enable();
<!-- endsnippet -->
### Controller
Given the following controller:
//snippet: MyController.cs
### Added entry
This test:
//snippet: MyControllerTest
<!-- snippet: Added -->
<a id='snippet-added'/></a>
```cs
[Fact]
public async Task Added()
{
var options = DbContextOptions();
await using var context = new SampleDbContext(options);
context.Companies.Add(new Company {Content = "before"});
await Verify(context);
}
```
<sup><a href='/src/Tests/Tests.cs#L12-L22' title='File snippet `added` was extracted from'>snippet source</a> | <a href='#snippet-added' title='Navigate to start of snippet `added`'>anchor</a></sup>
<!-- endsnippet -->
Will result in the following verified file:
//snippet: MyControllerTests.Test.verified.txt
<!-- snippet: Tests.Added.verified.txt -->
<a id='snippet-Tests.Added.verified.txt'/></a>
```txt
{
Added: {
Company: {
Id: 0
}
}
}
```
<sup><a href='/src/Tests/Tests.Added.verified.txt#L1-L7' title='File snippet `Tests.Added.verified.txt` was extracted from'>snippet source</a> | <a href='#snippet-Tests.Added.verified.txt' title='Navigate to start of snippet `Tests.Added.verified.txt`'>anchor</a></sup>
<!-- endsnippet -->
### Deleted entry
This test:
<!-- snippet: Deleted -->
<a id='snippet-deleted'/></a>
```cs
[Fact]
public async Task Deleted()
{
var options = DbContextOptions();
await using (var context = new SampleDbContext(options))
{
context.Companies.Add(new Company {Content = "before"});
context.SaveChanges();
}
await using (var context = new SampleDbContext(options))
{
var company = context.Companies.Single();
context.Companies.Remove(company);
await Verify(context);
}
}
```
<sup><a href='/src/Tests/Tests.cs#L24-L43' title='File snippet `deleted` was extracted from'>snippet source</a> | <a href='#snippet-deleted' title='Navigate to start of snippet `deleted`'>anchor</a></sup>
<!-- endsnippet -->
Will result in the following verified file:
<!-- snippet: Tests.Deleted.verified.txt -->
<a id='snippet-Tests.Deleted.verified.txt'/></a>
```txt
{
Deleted: {
Company: {
Id: 0
}
}
}
```
<sup><a href='/src/Tests/Tests.Deleted.verified.txt#L1-L7' title='File snippet `Tests.Deleted.verified.txt` was extracted from'>snippet source</a> | <a href='#snippet-Tests.Deleted.verified.txt' title='Navigate to start of snippet `Tests.Deleted.verified.txt`'>anchor</a></sup>
<!-- endsnippet -->
### Modified entry
This test:
<!-- snippet: Modified -->
<a id='snippet-modified'/></a>
```cs
[Fact]
public async Task Modified()
{
var options = DbContextOptions();
await using (var context = new SampleDbContext(options))
{
context.Companies.Add(new Company {Content = "before"});
context.SaveChanges();
}
await using (var context = new SampleDbContext(options))
{
context.Companies.Single().Content = "after";
await Verify(context);
}
}
```
<sup><a href='/src/Tests/Tests.cs#L45-L63' title='File snippet `modified` was extracted from'>snippet source</a> | <a href='#snippet-modified' title='Navigate to start of snippet `modified`'>anchor</a></sup>
<!-- endsnippet -->
Will result in the following verified file:
<!-- snippet: Tests.Modified.verified.txt -->
<a id='snippet-Tests.Modified.verified.txt'/></a>
```txt
{
Modified: {
Company: {
Id: 0,
Content: {
Original: 'before',
Current: 'after'
}
}
}
}
```
<sup><a href='/src/Tests/Tests.Modified.verified.txt#L1-L11' title='File snippet `Tests.Modified.verified.txt` was extracted from'>snippet source</a> | <a href='#snippet-Tests.Modified.verified.txt' title='Navigate to start of snippet `Tests.Modified.verified.txt`'>anchor</a></sup>
<!-- endsnippet -->
## Icon

Просмотреть файл

@ -1,9 +1,9 @@
# <img src="/src/icon.png" height="30px"> Verify.EntityFramework
[![Build status](https://ci.appveyor.com/api/projects/status/eedjhmx5o3082tyq?svg=true)](https://ci.appveyor.com/project/SimonCropp/verify-entityframework)
[![Build status](https://ci.appveyor.com/api/projects/status/g6njwv0aox62atu0?svg=true)](https://ci.appveyor.com/project/SimonCropp/verify-entityframework)
[![NuGet Status](https://img.shields.io/nuget/v/Verify.EntityFramework.svg)](https://www.nuget.org/packages/Verify.EntityFramework/)
Extends [Verify](https://github.com/SimonCropp/Verify) to allow verification of web bits.
Extends [Verify](https://github.com/SimonCropp/Verify) to allow verification of EntityFramewok bits.
toc
@ -16,26 +16,43 @@ https://nuget.org/packages/Verify.EntityFramework/
## Usage
Enable VerifyWeb once at assembly load time:
Enable VerifyEntityFramewok once at assembly load time:
snippet: Enable
### Controller
Given the following controller:
//snippet: MyController.cs
### Added entry
This test:
//snippet: MyControllerTest
snippet: Added
Will result in the following verified file:
//snippet: MyControllerTests.Test.verified.txt
snippet: Tests.Added.verified.txt
### Deleted entry
This test:
snippet: Deleted
Will result in the following verified file:
snippet: Tests.Deleted.verified.txt
### Modified entry
This test:
snippet: Modified
Will result in the following verified file:
snippet: Tests.Modified.verified.txt
## Icon

Просмотреть файл

Просмотреть файл

@ -1,19 +0,0 @@
{
result: [
{
Value: 'Value1'
},
{
Value: 'Value2'
}
],
context: {
Headers: {
headerKey: 'headerValue',
receivedInput: 'inputValue'
},
Cookies: {
cookieKey: 'cookieValue'
}
}
}

Просмотреть файл

@ -1,24 +0,0 @@
using System.Threading.Tasks;
using VerifyXunit;
using Xunit;
using Xunit.Abstractions;
public class Usage :
VerifyBase
{
#region MyControllerTest
[Fact]
public async Task ChangeTracked()
{
var database = await DbContextBuilder.GetDatabase("ChangeTracked");
var employee = await database.Context.Employees.FindAsync(3);
employee.Age++;
await Verify(database.Context);
}
#endregion
public Usage(ITestOutputHelper output) :
base(output)
{
}
}

Просмотреть файл

@ -0,0 +1,7 @@
{
Added: {
Company: {
Id: 0
}
}
}

Просмотреть файл

@ -1,9 +0,0 @@
{
result: {
ResultType: 'ChallengeResult',
Scheme: 'scheme',
Properties: {
key: 'value'
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
{
Deleted: {
Company: {
Id: 0
}
}
}

Просмотреть файл

@ -0,0 +1,11 @@
{
Modified: {
Company: {
Id: 0,
Content: {
Original: 'before',
Current: 'after'
}
}
}
}

Просмотреть файл

@ -1,9 +1,75 @@
using VerifyXunit;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using VerifyXunit;
using Xunit;
using Xunit.Abstractions;
public class Tests :
VerifyBase
{
#region Added
[Fact]
public async Task Added()
{
var options = DbContextOptions();
await using var context = new SampleDbContext(options);
context.Companies.Add(new Company {Content = "before"});
await Verify(context);
}
#endregion
#region Deleted
[Fact]
public async Task Deleted()
{
var options = DbContextOptions();
await using (var context = new SampleDbContext(options))
{
context.Companies.Add(new Company {Content = "before"});
context.SaveChanges();
}
await using (var context = new SampleDbContext(options))
{
var company = context.Companies.Single();
context.Companies.Remove(company);
await Verify(context);
}
}
#endregion
#region Modified
[Fact]
public async Task Modified()
{
var options = DbContextOptions();
await using (var context = new SampleDbContext(options))
{
context.Companies.Add(new Company {Content = "before"});
context.SaveChanges();
}
await using (var context = new SampleDbContext(options))
{
context.Companies.Single().Content = "after";
await Verify(context);
}
}
#endregion
static DbContextOptions<SampleDbContext> DbContextOptions(
[CallerMemberName] string databaseName = "")
{
return new DbContextOptionsBuilder<SampleDbContext>()
.UseInMemoryDatabase(databaseName)
.Options;
}
public Tests(ITestOutputHelper output) :
base(output)
{

Просмотреть файл

@ -15,10 +15,6 @@
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" />
<PackageReference Include="ProjectDefaults" Version="1.0.40" PrivateAssets="All" />
<ProjectReference Include="..\Verify.EntityFramework\Verify.EntityFramework.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Snippets\Usage.Test.verified.txt">
<DependentUpon>Usage.cs</DependentUpon>
</None>
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.0" />
</ItemGroup>
</Project>

Просмотреть файл

@ -18,12 +18,64 @@ class DbContextConverter :
writer.WriteStartObject();
var entries = context.ChangeTracker.Entries().ToList();
HandleModified(entries,writer, serializer);
HandleAdded(entries, writer, serializer);
HandleModified(entries, writer, serializer);
HandleDeleted(entries, writer, serializer);
writer.WriteEndObject();
}
void HandleModified(List<EntityEntry> entries,JsonWriter writer, JsonSerializer serializer)
static void HandleDeleted(List<EntityEntry> entries,JsonWriter writer, JsonSerializer serializer)
{
var deleted = entries
.Where(x => x.State == EntityState.Deleted)
.ToList();
if (!deleted.Any())
{
return;
}
writer.WritePropertyName("Deleted");
writer.WriteStartObject();
foreach (var entry in deleted)
{
writer.WritePropertyName(entry.Metadata.DisplayName());
writer.WriteStartObject();
WriteId(writer, serializer, entry);
writer.WriteEndObject();
}
writer.WriteEndObject();
}
static void HandleAdded(List<EntityEntry> entries, JsonWriter writer, JsonSerializer serializer)
{
var added = entries
.Where(x => x.State == EntityState.Added)
.ToList();
if (!added.Any())
{
return;
}
writer.WritePropertyName("Added");
writer.WriteStartObject();
foreach (var entry in added)
{
writer.WritePropertyName(entry.Metadata.DisplayName());
writer.WriteStartObject();
foreach (var property in entry.Properties)
{
writer.WritePropertyName(property.Metadata.Name);
serializer.Serialize(writer, property.OriginalValue);
}
writer.WriteEndObject();
}
writer.WriteEndObject();
}
static void HandleModified(List<EntityEntry> entries,JsonWriter writer, JsonSerializer serializer)
{
var modified = entries
.Where(x => x.State == EntityState.Modified)
@ -45,6 +97,8 @@ class DbContextConverter :
{
writer.WritePropertyName(entry.Metadata.DisplayName());
writer.WriteStartObject();
WriteId(writer, serializer, entry);
foreach (var property in entry.ChangedProperties())
{
writer.WritePropertyName(property.Metadata.Name);
@ -58,4 +112,25 @@ class DbContextConverter :
}
writer.WriteEndObject();
}
static void WriteId(JsonWriter writer, JsonSerializer serializer, EntityEntry entry)
{
var ids = entry.FindPrimaryKeyValues().ToList();
if (!ids.Any())
{
return;
}
if (ids.Count == 1)
{
var (name, value) = ids.Single();
writer.WritePropertyName(name);
serializer.Serialize(writer, value);
}
else
{
writer.WritePropertyName("Ids");
serializer.Serialize(writer, ids);
}
}
}

Просмотреть файл

@ -10,4 +10,14 @@ static class Extensions
.Where(x => x.IsModified);
}
public static IEnumerable<(string name, object value)> FindPrimaryKeyValues(this EntityEntry entry)
{
var primaryKey = entry.Metadata.FindPrimaryKey();
foreach (var property in primaryKey.Properties)
{
var name = property.Name;
var value = entry.Property(name).CurrentValue;
yield return (name, value);
}
}
}