Skip to content

Commit

Permalink
Convert Fusion Snapshots to Markdown (#6770)
Browse files Browse the repository at this point in the history
  • Loading branch information
tobias-tengler authored Mar 4, 2024
1 parent 9479306 commit ab3909e
Show file tree
Hide file tree
Showing 125 changed files with 3,027 additions and 2,113 deletions.
1 change: 1 addition & 0 deletions src/CookieCrumble/src/CookieCrumble/CookieCrumble.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

<ItemGroup Condition="'$(TargetFramework)' == 'net7.0' OR '$(TargetFramework)' == 'net8.0'">
<ProjectReference Include="..\..\..\HotChocolate\Fusion\src\Core\HotChocolate.Fusion.csproj" />
<ProjectReference Include="..\..\..\HotChocolate\Skimmed\src\Skimmed\Skimmed.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public static void MatchInlineSnapshot(

public static void MatchSnapshot(this Snapshot value)
=> value.Match();

public static void MatchSnapshot(
this object? value,
object? postFix = null,
Expand All @@ -30,6 +30,9 @@ public static void MatchMarkdownSnapshot(
ISnapshotValueFormatter? formatter = null)
=> Snapshot.Create(postFix?.ToString(), extension).Add(value, formatter: formatter).MatchMarkdown();

public static void MatchMarkdownSnapshot(this Snapshot value)
=> value.MatchMarkdown();

public static void MatchSnapshot(
this ISyntaxNode? value,
string? postFix = null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@

namespace CookieCrumble.Formatters;

internal sealed class JsonElementSnapshotValueFormatter : SnapshotValueFormatter<JsonElement>
internal sealed class JsonElementSnapshotValueFormatter() : SnapshotValueFormatter<JsonElement>("json")
{
private readonly JsonSerializerOptions _options =
new(JsonSerializerDefaults.Web)
{
WriteIndented = true,
WriteIndented = true,
Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping,
};

Expand All @@ -20,14 +20,4 @@ protected override void Format(IBufferWriter<byte> snapshot, JsonElement value)
buffer.AsSpan().CopyTo(span);
snapshot.Advance(buffer.Length);
}

protected override void FormatMarkdown(IBufferWriter<byte> snapshot, JsonElement value)
{
snapshot.Append("```json");
snapshot.AppendLine();
Format(snapshot, value);
snapshot.AppendLine();
snapshot.Append("```");
snapshot.AppendLine();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,9 @@

namespace CookieCrumble.Formatters;

internal sealed class QueryPlanSnapshotValueFormatter : SnapshotValueFormatter<QueryPlan>
internal sealed class QueryPlanSnapshotValueFormatter() : SnapshotValueFormatter<QueryPlan>("json")
{
protected override void Format(IBufferWriter<byte> snapshot, QueryPlan value)
{
value.Format(snapshot);
}
=> value.Format(snapshot);
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,8 @@

namespace CookieCrumble.Formatters;

internal sealed class SchemaSnapshotValueFormatter : SnapshotValueFormatter<ISchema>
internal sealed class SchemaSnapshotValueFormatter() : SnapshotValueFormatter<ISchema>("graphql")
{
protected override void Format(IBufferWriter<byte> snapshot, ISchema value)
=> snapshot.Append(value.ToString());

protected override void FormatMarkdown(IBufferWriter<byte> snapshot, ISchema value)
{
snapshot.Append("```graphql");
snapshot.AppendLine();
Format(snapshot, value);
snapshot.AppendLine();
snapshot.Append("```");
snapshot.AppendLine();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#if NET7_0_OR_GREATER
using System.Buffers;
using HotChocolate.Skimmed;
using HotChocolate.Skimmed.Serialization;

namespace CookieCrumble.Formatters;

internal sealed class SkimmedSchemaSnapshotValueFormatter() : SnapshotValueFormatter<Schema>("graphql")
{
protected override void Format(IBufferWriter<byte> snapshot, Schema value)
=> snapshot.Append(SchemaFormatter.FormatAsString(value));
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ namespace CookieCrumble.Formatters;
/// <summary>
/// Formats a snapshot segment value for the snapshot file.
/// </summary>
public abstract class SnapshotValueFormatter<TValue>
: ISnapshotValueFormatter
public abstract class SnapshotValueFormatter<TValue>(string markdownKind = "text") : ISnapshotValueFormatter
, IMarkdownSnapshotValueFormatter
{
public bool CanHandle(object? value)
Expand All @@ -17,15 +16,15 @@ protected virtual bool CanHandle(TValue? value)

public void Format(IBufferWriter<byte> snapshot, object? value)
=> Format(snapshot, (TValue)value!);

public void FormatMarkdown(IBufferWriter<byte> snapshot, object? value)
=> FormatMarkdown(snapshot, (TValue)value!);

protected abstract void Format(IBufferWriter<byte> snapshot, TValue value);

protected virtual void FormatMarkdown(IBufferWriter<byte> snapshot, TValue value)
{
snapshot.Append("```text");
snapshot.Append($"```{markdownKind}");
snapshot.AppendLine();
Format(snapshot, value);
snapshot.AppendLine();
Expand Down
58 changes: 48 additions & 10 deletions src/CookieCrumble/src/CookieCrumble/Snapshot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public class Snapshot
new JsonElementSnapshotValueFormatter(),
#if NET7_0_OR_GREATER
new QueryPlanSnapshotValueFormatter(),
new SkimmedSchemaSnapshotValueFormatter(),
#endif
});
private static readonly JsonSnapshotValueFormatter _defaultFormatter = new();
Expand All @@ -54,7 +55,7 @@ public Snapshot(string? postFix = null, string? extension = null)

public static Snapshot Create(string? postFix = null, string? extension = null)
=> new(postFix, extension);

public static DisposableSnapshot Start(string? postFix = null, string? extension = null)
=> new(postFix, extension);

Expand Down Expand Up @@ -257,15 +258,52 @@ public void Match()
}
}
}


public async ValueTask MatchMarkdownAsync(CancellationToken cancellationToken = default)
{
var writer = new ArrayBufferWriter<byte>();

writer.Append($"# {_title}");
writer.AppendLine();
writer.AppendLine();

WriteMarkdownSegments(writer);

var snapshotFile = Combine(CreateSnapshotDirectoryName(), CreateMarkdownSnapshotFileName());

if (!File.Exists(snapshotFile))
{
EnsureDirectoryExists(snapshotFile);
await using var stream = File.Create(snapshotFile);
await stream.WriteAsync(writer.WrittenMemory, cancellationToken);
}
else
{
var mismatchFile = Combine(CreateMismatchDirectoryName(), CreateMarkdownSnapshotFileName());
EnsureFileDoesNotExist(mismatchFile);
var before = await File.ReadAllTextAsync(snapshotFile, cancellationToken);
var after = _encoding.GetString(writer.WrittenSpan);

if (MatchSnapshot(before, after, false, out var diff))
{
return;
}

EnsureDirectoryExists(mismatchFile);
await using var stream = File.Create(mismatchFile);
await stream.WriteAsync(writer.WrittenMemory, cancellationToken);
throw new Xunit.Sdk.XunitException(diff);
}
}

public void MatchMarkdown()
{
var writer = new ArrayBufferWriter<byte>();

writer.Append($"# {_title}");
writer.AppendLine();
writer.AppendLine();

WriteMarkdownSegments(writer);

var snapshotFile = Combine(CreateSnapshotDirectoryName(), CreateMarkdownSnapshotFileName());
Expand All @@ -287,7 +325,7 @@ public void MatchMarkdown()
{
return;
}

EnsureDirectoryExists(mismatchFile);
using var stream = File.Create(mismatchFile);
stream.Write(writer.WrittenSpan);
Expand Down Expand Up @@ -344,7 +382,7 @@ private void WriteSegments(IBufferWriter<byte> writer)
next = true;
}
}

private void WriteMarkdownSegments(IBufferWriter<byte> writer)
{
if (_segments.Count == 1)
Expand Down Expand Up @@ -488,11 +526,11 @@ private string CreateSnapshotFileName()
? string.Concat(fileName, _extension)
: string.Concat(fileName, "_", _postFix, _extension);
}

private string CreateMarkdownSnapshotFileName()
{
var extension = _extension.EqualsOrdinal(".snap") ? ".md" : _extension;

var fileName = GetFileNameWithoutExtension(_fileName);

return string.IsNullOrEmpty(_postFix)
Expand Down Expand Up @@ -532,7 +570,7 @@ private static string CreateFileName(StackFrame[] frames)
"get the snapshot name, then reach this name to your " +
"Snapshot.Match method.");
}

private static string CreateMarkdownTitle(StackFrame[] frames)
{
foreach (var stackFrame in frames)
Expand Down Expand Up @@ -618,4 +656,4 @@ public sealed class DisposableSnapshot(string? postFix = null, string? extension
, IDisposable
{
public void Dispose() => Match();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ await PackageHelper.CreateSubgraphPackageAsync(
snapshot.Add(subgraph, $"{subgraph.Name} Subgraph Configuration");
}

snapshot.MatchSnapshot();
await snapshot.MatchMarkdownAsync();
}

[Fact]
Expand Down Expand Up @@ -111,7 +111,7 @@ await app.InvokeAsync(
snapshot.Add(subgraph, $"{subgraph.Name} Subgraph Configuration");
}

snapshot.MatchSnapshot();
await snapshot.MatchMarkdownAsync();
}

[Fact]
Expand Down Expand Up @@ -263,7 +263,7 @@ public async Task Compose_Loose_Subgraph_Files()
snapshot.Add(subgraph, $"{subgraph.Name} Subgraph Configuration");
}

snapshot.MatchSnapshot();
await snapshot.MatchMarkdownAsync();
}

[Fact]
Expand Down Expand Up @@ -326,9 +326,9 @@ await app.InvokeAsync(
snapshot.Add(subgraph, $"{subgraph.Name} Subgraph Configuration");
}

snapshot.MatchSnapshot();
await snapshot.MatchMarkdownAsync();
}

[Fact]
public async Task Compose_With_Tag()
{
Expand All @@ -344,10 +344,10 @@ public async Task Compose_With_Tag()

var packageFile = CreateTempFile(Extensions.FusionPackage);
var gatewayConfig = Path.Combine(
Path.GetDirectoryName(packageFile)!,
Path.GetDirectoryName(packageFile)!,
Path.GetFileNameWithoutExtension(packageFile) + "-settings.json");
File.Delete(packageFile);

await File.WriteAllTextAsync(gatewayConfig, FileResource.Open("test2.gateway-config.json"), Encoding.UTF8);

// act
Expand All @@ -373,6 +373,6 @@ public async Task Compose_With_Tag()
snapshot.Add(subgraph, $"{subgraph.Name} Subgraph Configuration");
}

snapshot.MatchSnapshot();
await snapshot.MatchMarkdownAsync();
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
Schema Document
---------------
# Compose_Fusion_Graph

## Schema Document

```graphql
schema {
query: Query
mutation: Mutation
}

type Query {
errorField: String
userById(id: ID!): User
users: [User!]!
usersById(ids: [ID!]!): [User!]!
Expand All @@ -26,6 +30,7 @@ type SomeData {

type User implements Node {
birthdate: Date!
errorField: String
id: ID!
name: String!
username: String!
Expand All @@ -49,16 +54,18 @@ input AddUserInput {

"The `Date` scalar represents an ISO-8601 compliant date type."
scalar Date
---------------
```

## Fusion Graph Document

Fusion Graph Document
---------------
```graphql
schema @fusion(version: 1) @transport(subgraph: "Accounts", group: "Fusion", location: "http:\/\/localhost:5000\/graphql", kind: "HTTP") @transport(subgraph: "Accounts", group: "Fusion", location: "ws:\/\/localhost:5000\/graphql", kind: "WebSocket") {
query: Query
mutation: Mutation
}

type Query {
errorField: String @resolver(subgraph: "Accounts", select: "{ errorField }")
userById(id: ID!): User @variable(subgraph: "Accounts", name: "id", argument: "id") @resolver(subgraph: "Accounts", select: "{ userById(id: $id) }", arguments: [ { name: "id", type: "ID!" } ])
users: [User!]! @resolver(subgraph: "Accounts", select: "{ users }")
usersById(ids: [ID!]!): [User!]! @variable(subgraph: "Accounts", name: "ids", argument: "ids") @resolver(subgraph: "Accounts", select: "{ usersById(ids: $ids) }", arguments: [ { name: "ids", type: "[ID!]!" } ])
Expand All @@ -79,6 +86,7 @@ type SomeData {

type User implements Node @variable(subgraph: "Accounts", name: "User_id", select: "id") @resolver(subgraph: "Accounts", select: "{ userById(id: $User_id) }", arguments: [ { name: "User_id", type: "ID!" } ]) @resolver(subgraph: "Accounts", select: "{ usersById(ids: $User_id) }", arguments: [ { name: "User_id", type: "[ID!]!" } ], kind: "BATCH") {
birthdate: Date! @source(subgraph: "Accounts")
errorField: String @source(subgraph: "Accounts")
id: ID! @source(subgraph: "Accounts")
name: String! @source(subgraph: "Accounts")
username: String! @source(subgraph: "Accounts")
Expand All @@ -102,13 +110,14 @@ input AddUserInput {

"The `Date` scalar represents an ISO-8601 compliant date type."
scalar Date
---------------
```

Accounts Subgraph Configuration
---------------
## Accounts Subgraph Configuration

```json
{
"Name": "Accounts",
"Schema": "schema {\n query: Query\n mutation: Mutation\n}\n\n\"The node interface is implemented by entities that have a global unique identifier.\"\ninterface Node {\n id: ID!\n}\n\ntype Query {\n \"Fetches an object given its ID.\"\n node(\"ID of the object.\" id: ID!): Node\n \"Lookup nodes by a list of IDs.\"\n nodes(\"The list of node IDs.\" ids: [ID!]!): [Node]!\n users: [User!]!\n userById(id: ID!): User\n usersById(ids: [ID!]!): [User!]!\n viewer: Viewer!\n}\n\ntype Mutation {\n addUser(input: AddUserInput!): AddUserPayload!\n}\n\n\"The `Date` scalar represents an ISO-8601 compliant date type.\"\nscalar Date\n\ntype Viewer {\n user: User\n data: SomeData!\n}\n\ntype User implements Node {\n id: ID!\n name: String!\n birthdate: Date!\n username: String!\n}\n\ntype SomeData {\n accountValue: String!\n}\n\ninput AddUserInput {\n name: String!\n username: String!\n birthdate: Date!\n}\n\ntype AddUserPayload {\n user: User\n}",
"Schema": "schema {\n query: Query\n mutation: Mutation\n}\n\n\"The node interface is implemented by entities that have a global unique identifier.\"\ninterface Node {\n id: ID!\n}\n\ntype Query {\n \"Fetches an object given its ID.\"\n node(\"ID of the object.\" id: ID!): Node\n \"Lookup nodes by a list of IDs.\"\n nodes(\"The list of node IDs.\" ids: [ID!]!): [Node]!\n users: [User!]!\n userById(id: ID!): User\n usersById(ids: [ID!]!): [User!]!\n errorField: String\n viewer: Viewer!\n}\n\ntype Mutation {\n addUser(input: AddUserInput!): AddUserPayload!\n}\n\n\"The `Date` scalar represents an ISO-8601 compliant date type.\"\nscalar Date\n\ntype Viewer {\n user: User\n data: SomeData!\n}\n\ntype User implements Node {\n errorField: String\n id: ID!\n name: String!\n birthdate: Date!\n username: String!\n}\n\ntype SomeData {\n accountValue: String!\n}\n\ninput AddUserInput {\n name: String!\n username: String!\n birthdate: Date!\n}\n\ntype AddUserPayload {\n user: User\n}",
"Extensions": [
"extend type Query {\n userById(id: ID!\n @is(field: \"id\")): User!\n usersById(ids: [ID!]!\n @is(field: \"id\")): [User!]!\n}"
],
Expand All @@ -124,4 +133,5 @@ Accounts Subgraph Configuration
],
"ConfigurationExtensions": null
}
---------------
```

Loading

0 comments on commit ab3909e

Please sign in to comment.