Files
zeekay 2aa8261f86 rebrand: complete capnp → ZAP across all C# source/build files
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.
2026-06-19 23:46:57 -07:00

243 lines
11 KiB
C#

using Zap;
using Model = ZapC.CSharp.Generator.Model;
using CodeGen = ZapC.CSharp.Generator.CodeGen;
using CodeGeneratorRequest = ZapC.CSharp.Generator.Schema.CodeGeneratorRequest;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Collections.Generic;
using System.Linq;
namespace ZapC.CSharp.Generator.Tests
{
[TestClass]
[TestCategory("Coverage")]
public class CodeGeneratorUnitTests
{
[TestMethod]
public void Test00Enumerant()
{
var model = Load("UnitTest1.zap.bin");
Assert.AreEqual("@byte", GetTypeDef(0xc8461867c409f5d4, model).Enumerants[0].Literal);
}
[TestMethod]
public void Test01NestedClash()
{
var (model, codegen, _) = LoadAndGenerate("UnitTest1.zap.bin");
var structFoo = GetTypeDef(0x93db6ba5509bac24, model);
var names = codegen.GetNames();
var fieldName = names.GetCodeIdentifier(structFoo.Fields[0]).ToString();
Assert.AreEqual("Foo", structFoo.Name);
Assert.AreNotEqual(structFoo.Name, fieldName);
}
[TestMethod]
public void Test02ForwardInheritance()
{
LoadAndGenerate("UnitTest2.zap.bin");
}
[TestMethod]
public void Test03NonGeneratedNodeSkip()
{
LoadAndGenerate("UnitTest3.zap.bin");
}
[TestMethod]
public void Test04MutualDependencies()
{
LoadAndGenerate("UnitTest4.zap.bin", "UnitTest4b.zap.bin");
}
[TestMethod]
public void Test10ImportedNamespaces()
{
var (model, codegen, _) = LoadAndGenerate("UnitTest10.zap.bin", "UnitTest10b.zap.bin");
var outerTypeDef = GetGeneratedFile("UnitTest10.zap", model).NestedTypes.First();
var outerType = Model.Types.FromDefinition(outerTypeDef);
var innerType = outerTypeDef.Fields[0].Type;
var innerTypeDef = innerType.Definition;
var names = codegen.GetNames();
var outerNameSyntax = names.GetQName(outerType, outerTypeDef);
var innerNameSyntax = names.GetQName(innerType, outerTypeDef);
string[] outerNamespace = { "Foo", "Bar", "Baz" };
string[] innerNamespace = { "Foo", "Garf", "Snarf" };
CollectionAssert.AreEqual(outerNamespace, (outerTypeDef.DeclaringElement as Model.GenFile).Namespace);
CollectionAssert.AreEqual(innerNamespace, (innerType.Definition.DeclaringElement as Model.GenFile).Namespace);
string outerNSStr = String.Join('.', outerNamespace);
string innerNSStr = String.Join('.', innerNamespace);
Assert.AreEqual($"{outerNSStr}.Outer", outerNameSyntax.ToString());
Assert.AreEqual($"{innerNSStr}.Inner", innerNameSyntax.ToString());
}
[TestMethod]
public void Test11ImportedConst()
{
LoadAndGenerate("UnitTest11.zap.bin", "UnitTest11b.zap.bin");
}
[TestMethod]
public void Test12ConstEnum()
{
LoadAndGenerate("UnitTest12.zap.bin");
}
[TestMethod]
public void Test13CSharpNamespace()
{
var (model, _, _) = LoadAndGenerate("UnitTest13.zap.bin");
var outerTypeDef = GetGeneratedFile("UnitTest13.zap", model).NestedTypes.First();
string[] outerNamespace = { "Foo", "Bar", "Baz" };
CollectionAssert.AreEqual(outerNamespace, (outerTypeDef.DeclaringElement as Model.GenFile).Namespace);
}
[TestMethod]
public void Test14CSharpNamespacePrecedesCxxNamespace()
{
var (model, _, _) = LoadAndGenerate("UnitTest14.zap.bin");
var outerTypeDef = GetGeneratedFile("UnitTest14.zap", model).NestedTypes.First();
string[] outerNamespace = { "Foo", "Bar", "Baz" };
CollectionAssert.AreEqual(outerNamespace, (outerTypeDef.DeclaringElement as Model.GenFile).Namespace);
}
[TestMethod]
public void Test15CSharpMemberNames()
{
var (_, _, code) = LoadAndGenerate("UnitTest15.zap.bin");
try
{
Assert.IsTrue(code.Contains("CsStruct", StringComparison.Ordinal), "Generated code must contain C# struct name");
Assert.IsFalse(code.Contains("SomeStruct", StringComparison.Ordinal), "Generated code must not contain original struct name");
Assert.IsTrue(code.Contains("CsField", StringComparison.Ordinal), "Generated code must contain C# field name");
Assert.IsFalse(code.Contains("someField", StringComparison.OrdinalIgnoreCase), "Generated code must not contain original field name");
Assert.IsTrue(code.Contains("CsUnion", StringComparison.Ordinal), "Generated code must contain C# union name");
Assert.IsFalse(code.Contains("someUnion", StringComparison.OrdinalIgnoreCase), "Generated code must not contain original union name");
Assert.IsTrue(code.Contains("CsGroup", StringComparison.Ordinal), "Generated code must contain C# group name");
Assert.IsFalse(code.Contains("someGroup", StringComparison.OrdinalIgnoreCase), "Generated code must not contain original group name");
Assert.IsTrue(code.Contains("CsEnum", StringComparison.Ordinal), "Generated code must contain C# enum name");
Assert.IsFalse(code.Contains("SomeEnum", StringComparison.Ordinal), "Generated code must not contain original enum name");
Assert.IsTrue(code.Contains("CsEnumerant", StringComparison.Ordinal), "Generated code must contain C# enumerant name");
Assert.IsFalse(code.Contains("someEnumerant", StringComparison.OrdinalIgnoreCase), "Generated code must not contain original enumerant name");
Assert.IsTrue(code.Contains("CsField", StringComparison.Ordinal), "Generated code must contain C# field name");
Assert.IsFalse(code.Contains("someField", StringComparison.OrdinalIgnoreCase), "Generated code must not contain original field name");
Assert.IsTrue(code.Contains("CsInterface", StringComparison.Ordinal), "Generated code must contain C# interface name");
Assert.IsFalse(code.Contains("SomeInterface", StringComparison.Ordinal), "Generated code must not contain original interface name");
Assert.IsTrue(code.Contains("CsMethod", StringComparison.Ordinal), "Generated code must contain C# method name");
Assert.IsFalse(code.Contains("someMethod", StringComparison.OrdinalIgnoreCase), "Generated code must not contain original method name");
Assert.IsTrue(code.Contains("CsField", StringComparison.Ordinal), "Generated code must contain C# field name");
Assert.IsFalse(code.Contains("someField", StringComparison.OrdinalIgnoreCase), "Generated code must not contain original field name");
Assert.IsTrue(code.Contains("CsResult", StringComparison.Ordinal), "Generated code must contain C# method parameter name");
Assert.IsFalse(code.Contains("someResult", StringComparison.OrdinalIgnoreCase), "Generated code must not contain original method parameter name");
}
catch (AssertFailedException)
{
Console.WriteLine(code);
throw;
}
}
[TestMethod]
public void Test20AnnotationAndConst()
{
LoadAndGenerate("UnitTest20.zap.bin");
}
[TestMethod]
public void Test30SchemaZap()
{
LoadAndGenerate("schema-with-offsets.zap.bin");
}
[TestMethod]
public void Issue45()
{
var input = CodeGeneratorSteps.LoadResource("Issue45.zap.bin");
using (input)
{
var frame = Framing.ReadSegments(input);
var ds = DeserializerState.CreateRoot(frame);
var cgr = ZapSerializable.Create<CodeGeneratorRequest>(ds);
Assert.IsTrue(cgr.Nodes.Count > 0);
}
}
static (Model.SchemaModel, CodeGen.CodeGenerator, string) LoadAndGenerate(params string[] inputNames)
{
Model.SchemaModel firstModel = null;
CodeGen.CodeGenerator firstCodeGen = null;
Model.SchemaModel LocalLoad(string name)
{
var model = Load(name);
firstModel = firstModel ?? model;
return model;
}
CodeGen.CodeGenerator CreateCodeGen(Model.SchemaModel model)
{
var codegen = new CodeGen.CodeGenerator(model, new CodeGen.GeneratorOptions());
firstCodeGen = firstCodeGen ?? codegen;
return codegen;
}
var codes = (
from name in inputNames
let model = LocalLoad(name)
let codegen = CreateCodeGen(model)
from file in model.FilesToGenerate
select codegen.Transform(file)).ToArray();
Assert.AreEqual(
Util.InlineAssemblyCompiler.CompileSummary.Success,
Util.InlineAssemblyCompiler.TryCompileZap(
Microsoft.CodeAnalysis.NullableContextOptions.Disable,
codes),
"Compilation was not successful with no warnings");
return (firstModel, firstCodeGen, codes[0]);
}
static Model.GenFile GetGeneratedFile(string name, Model.SchemaModel model)
{
var file = model.FilesToGenerate.SingleOrDefault(f => f.Name.EndsWith(name));
Assert.IsNotNull(file, $"Could not find '{name}' in generated files");
return file;
}
static Model.TypeDefinition GetTypeDef(ulong id, Model.SchemaModel model)
{
foreach (var defs in model.FilesToGenerate.Select(f => f.NestedTypes))
{
if (GetTypeDef(id, defs) is Model.TypeDefinition def) return def;
}
return null;
}
static Model.TypeDefinition GetTypeDef(ulong id, IEnumerable<Model.TypeDefinition> defs)
{
foreach (var def in defs)
{
if (def.Id == id) return def;
var sub = GetTypeDef(id, def.NestedTypes);
if (sub != null) return sub;
}
return null;
}
static Model.SchemaModel Load(string inputName)
{
WireFrame segments;
var input = CodeGeneratorSteps.LoadResource(inputName);
using (input)
{
segments = Framing.ReadSegments(input);
}
var dec = DeserializerState.CreateRoot(segments);
var reader = CodeGeneratorRequest.READER.create(dec);
var model = Model.SchemaModel.Create(reader);
return model;
}
}
}