mirror of
https://github.com/zap-proto/cs.git
synced 2026-10-30 15:05:32 +00:00
Finishes the in-flight capnp→ZAP rebrand on this branch. The prior commits
renamed identifiers/namespaces/files/projects (Capnp.Net.Runtime→Zap.Net.Runtime,
CapnpC→ZapC, .capnp→.zap) but left the human-readable brand name "Cap'n Proto"
throughout doc-comments, .csproj/.nuspec descriptions, README, MSBuild .xaml
rule display names, and the generated XML doc. This completes brand neutrality:
- Replace 154 "Cap'n Proto" / 4 "Cap'n-Proto" / 1 "Cap'n'p" prose occurrences
with "ZAP" across 32 first-party files (runtime, generator, zapc-csharp,
MSBuild integration, chocolatey nuspecs, README, docs, XML doc).
- Revert the LICENSE provenance URL to the real upstream fork
(c80k/capnproto-dotnetcore) — upstream-fork license headers must stay.
- Canonicalize project/repo URLs to github.com/zap-proto/cs (were fabricated
c80k/zap-dotnetcore) in csproj/nuspec/VERIFICATION/README badges.
- Canonicalize docs URLs zap-protocol(.github.io|/zap-cs|/zap-cpp-core)
→ zap-proto.dev / github.com/zap-proto/{cs,cpp-core}.
- Collapse redundant "zap \"ZAP\"" PackageTags to "zap".
Verified consistent (no toolchain on host): every .sln/.csproj ProjectReference
resolves; all namespaces are Zap*/ZapC*; MSBuild task chain
(GenerateZapFileCodeBehindTask, ZapFiles ItemGroup, _ZapcCsharp_TaskAssembly)
is uniformly renamed; props/targets/xaml/coverage/chocolatey carry no capnp.
Deliberately preserved as upstream-derived test data (not first-party source):
upstream Cap'n Proto schema fixtures (rpc.zap, rpc-twoparty.zap, json.zap,
rpc-csharp.zap), golden compiler-error outputs (errors.txt), and the
machine-generated DO-NOT-EDIT test.zap.{c++,h}. Their "Cap'n Proto" strings are
the literal output of the external schema compiler the compat test matches.
254 lines
9.7 KiB
C#
254 lines
9.7 KiB
C#
using Microsoft.CodeAnalysis;
|
|
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
|
using System;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using TechTalk.SpecFlow;
|
|
|
|
namespace ZapC.CSharp.Generator.Tests
|
|
{
|
|
[Binding]
|
|
public class CodeGeneratorSteps
|
|
{
|
|
Stream _inputStream;
|
|
string _inputSchemaFileName;
|
|
string _inputSchema;
|
|
string _referenceOutputContent;
|
|
bool _nullableGenEnable;
|
|
bool _nullableSupportEnable;
|
|
|
|
GenerationResult _result;
|
|
|
|
public static Stream LoadResource(string name)
|
|
{
|
|
var assembly = Assembly.GetExecutingAssembly();
|
|
string[] names = assembly.GetManifestResourceNames();
|
|
string urn = Array.Find(names, n => n.EndsWith(name, StringComparison.OrdinalIgnoreCase));
|
|
Assert.IsNotNull(urn, $"Test specification error: {name} does not exist");
|
|
return assembly.GetManifestResourceStream(urn);
|
|
}
|
|
|
|
internal static bool IsZapInstalled()
|
|
{
|
|
try
|
|
{
|
|
var startInfo = new ProcessStartInfo(ZapCompilation.ZapCompilerFilename, "--version");
|
|
startInfo.UseShellExecute = false;
|
|
startInfo.RedirectStandardOutput = true;
|
|
startInfo.RedirectStandardError = true;
|
|
|
|
using (var process = Process.Start(startInfo))
|
|
{
|
|
Assert.IsNotNull(process, $"Unable to start '{ZapCompilation.ZapCompilerFilename}'");
|
|
|
|
process.WaitForExit();
|
|
|
|
return process.ExitCode == 0;
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
[Given(@"I have a binary code generator request ""(.*)""")]
|
|
[Given(@"I have a binary code generator request (.*)")]
|
|
public void GivenIHaveABinaryCodeGeneratorRequest(string binaryRequestFileName)
|
|
{
|
|
_inputStream = LoadResource(binaryRequestFileName);
|
|
_nullableGenEnable = false; // Assume false by default, may be enabled later
|
|
}
|
|
|
|
[Given(@"my reference output is ""(.*)""")]
|
|
public void GivenMyReferenceOutputIs(string expectedOutputFileName)
|
|
{
|
|
using (var stream = LoadResource(expectedOutputFileName))
|
|
using (var reader = new StreamReader(stream))
|
|
{
|
|
_referenceOutputContent = reader.ReadToEnd();
|
|
}
|
|
}
|
|
|
|
[When(@"I invoke zapc-csharp")]
|
|
public void WhenIInvokeZapc_Csharp()
|
|
{
|
|
Console.WriteLine($"Generate nullable reference types? {_nullableGenEnable}");
|
|
|
|
using (_inputStream)
|
|
{
|
|
_result = ZapCompilation.GenerateFromStream(_inputStream, new CodeGen.GeneratorOptions()
|
|
{
|
|
NullableEnableDefault = _nullableGenEnable
|
|
});
|
|
}
|
|
}
|
|
|
|
[Then(@"the generated output must match the reference")]
|
|
public void ThenTheGeneratedOutputMustMatchTheReference()
|
|
{
|
|
Assert.IsTrue(_result.IsSuccess, $"Tool invocation failed: {_result.Exception?.Message}");
|
|
string generated = _result.GeneratedFiles.Single().GeneratedContent;
|
|
bool equals = _referenceOutputContent.Equals(generated);
|
|
if (!equals)
|
|
{
|
|
string path = Path.ChangeExtension(Path.GetTempFileName(), ".zap.cs");
|
|
File.WriteAllText(path, generated);
|
|
|
|
string[] refLines = _referenceOutputContent.Split(Environment.NewLine);
|
|
string[] actLines = generated.Split(Environment.NewLine);
|
|
int mismatchLine = 0;
|
|
|
|
for (int i = 0; i < Math.Min(refLines.Length, actLines.Length); i++)
|
|
{
|
|
if (!refLines[i].Equals(actLines[i]))
|
|
{
|
|
mismatchLine = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
Assert.Fail(
|
|
$"Reference output does not match. Expected: <{_referenceOutputContent.Substring(0, 100)}...>, actual: <{generated.Substring(0, 100)}...>, see {path}, first mismatch line: {mismatchLine}");
|
|
}
|
|
}
|
|
|
|
[Then(@"the invocation must fail")]
|
|
public void ThenTheInvocationMustFail()
|
|
{
|
|
Assert.IsFalse(_result.IsSuccess, "Tool invocation was supposed to fail, but it didn't");
|
|
Assert.IsNotNull(_result.Exception, "Expected an exception");
|
|
}
|
|
|
|
[Given(@"zap\.exe is installed on my system")]
|
|
public void GivenZap_ExeIsInstalledOnMySystem()
|
|
{
|
|
if (!IsZapInstalled())
|
|
{
|
|
Assert.Inconclusive("Zap compiler not found. Precondition of this test is not met.");
|
|
}
|
|
}
|
|
|
|
[Given(@"I have a schema ""(.*)""")]
|
|
public void GivenIHaveASchema(string zapFileName)
|
|
{
|
|
_inputSchemaFileName = zapFileName;
|
|
|
|
using (var stream = LoadResource(zapFileName))
|
|
using (var reader = new StreamReader(stream))
|
|
{
|
|
_inputSchema = reader.ReadToEnd();
|
|
}
|
|
}
|
|
|
|
[When(@"I try to generate code from that schema")]
|
|
public void WhenIWantToGenerateCodeFromThatSchema()
|
|
{
|
|
string path = Path.Combine(Path.GetTempPath(), _inputSchemaFileName);
|
|
File.WriteAllText(path, _inputSchema);
|
|
_result = ZapCompilation.InvokeZapAndGenerate(new string[] { path });
|
|
}
|
|
|
|
[Then(@"code generation must succeed")]
|
|
public void ThenCodeGenerationMustSucceed()
|
|
{
|
|
Assert.IsNotNull(_result, "expected generation result");
|
|
Assert.IsTrue(_result.IsSuccess, $"Tool invocation failed: {_result.Exception?.Message}");
|
|
Assert.IsTrue(_result.GeneratedFiles.Count == 1, "Expected exactly one file");
|
|
Assert.IsTrue(_result.GeneratedFiles[0].IsSuccess, $"Code generation failed: {_result.GeneratedFiles[0].Exception?.Message}");
|
|
Assert.IsFalse(string.IsNullOrEmpty(_result.GeneratedFiles[0].GeneratedContent), "Expected non-empty generated content");
|
|
}
|
|
|
|
[Given(@"zap\.exe is not installed on my system")]
|
|
public void GivenZap_ExeIsNotInstalledOnMySystem()
|
|
{
|
|
if (IsZapInstalled())
|
|
{
|
|
Assert.Inconclusive("Zap compiler found. Precondition of this test is not met.");
|
|
}
|
|
}
|
|
|
|
[Then(@"the reason must be bad input")]
|
|
public void ThenTheReasonMustBeBadInput()
|
|
{
|
|
Assert.IsTrue(_result.ErrorCategory == ZapProcessFailure.BadInput);
|
|
}
|
|
|
|
[Then(@"the error output must contain ""(.*)""")]
|
|
public void ThenTheErrorOutputMustContain(string p0)
|
|
{
|
|
Assert.IsTrue(_result.Messages.Any(m => m.FullMessage.Contains(p0)));
|
|
}
|
|
|
|
[Then(@"the error output must contain multiple messages")]
|
|
public void ThenTheErrorOutputMustContainMultipleMessages()
|
|
{
|
|
Assert.IsTrue(_result.Messages.Count >= 2);
|
|
}
|
|
|
|
[Given(@"I enable generation of nullable reference types according to (.*)")]
|
|
public void GivenIEnableGenerationOfNullableReferenceTypesAccordingTo(bool enable)
|
|
{
|
|
_nullableGenEnable = enable;
|
|
}
|
|
|
|
[Given(@"I enable the compiler support of nullable reference types according to (.*)")]
|
|
public void GivenIEnableTheCompilerSupportOfNullableReferenceTypesAccordingTo(bool enable)
|
|
{
|
|
_nullableSupportEnable = enable;
|
|
}
|
|
|
|
[Then(@"the invocation must succeed and attempting to compile the generated code gives (.*)")]
|
|
public void ThenTheInvocationMustSucceedAndAttemptingToCompileTheGeneratedCodeGives(string result)
|
|
{
|
|
Console.WriteLine($"Compiler supports nullable reference types? {_nullableSupportEnable}");
|
|
|
|
Assert.IsTrue(_result.IsSuccess, "Tool invocation was not successful");
|
|
var summary = Util.InlineAssemblyCompiler.TryCompileZap(
|
|
_nullableSupportEnable ? NullableContextOptions.Enable : NullableContextOptions.Disable,
|
|
_result.GeneratedFiles[0].GeneratedContent);
|
|
|
|
try
|
|
{
|
|
switch (result)
|
|
{
|
|
case "success":
|
|
Assert.AreEqual(
|
|
Util.InlineAssemblyCompiler.CompileSummary.Success,
|
|
summary,
|
|
"Compilation was expected to succeed");
|
|
break;
|
|
|
|
case "warnings":
|
|
Assert.AreEqual(
|
|
Util.InlineAssemblyCompiler.CompileSummary.SuccessWithWarnings,
|
|
summary,
|
|
"Compilation was expected to produce warnings");
|
|
break;
|
|
|
|
case "errors":
|
|
Assert.AreEqual(
|
|
Util.InlineAssemblyCompiler.CompileSummary.Error,
|
|
summary,
|
|
"Compilation was expected to fail");
|
|
break;
|
|
|
|
default:
|
|
Assert.Fail("Test case bug: unknown outcome specified");
|
|
break;
|
|
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
string generated = _result.GeneratedFiles.Single().GeneratedContent;
|
|
string path = Path.ChangeExtension(Path.GetTempFileName(), ".zap.cs");
|
|
File.WriteAllText(path, generated);
|
|
Console.WriteLine($"Generated code was saved to {path}");
|
|
}
|
|
}
|
|
}
|
|
}
|