Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
9 changes: 5 additions & 4 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Project Overview

Schema is a C# library for defining and managing data structure schemas. It consists of seven projects:
Schema is a C# library for defining and managing data structure schemas. It consists of eight projects:

- **Schema** - Core library providing schema definition types (classes, enums, members, types)
- **Schema.Test** - MSTest unit tests for the core library
- **Schema.Cpp** - The C++ generator, in its own project because `ktsu.Coder` ships no `net8.0`
- **Schema.Cpp.Test** - Its tests, including the three acceptance tests against Holotype's target document and one that compiles the generated reflection table
- **Schema.Editor** - ImGui-based visual editor application for creating and editing `.schema.json` files
- **Schema.Editor.Test** - Headless UI tests for the editor, driven through `ktsu.ImGui.App.Testing`
- **Schema.Editor.Test** - The editor's tests that need no frame: the recent-files list and reading and writing the document on disk. Ordinary unit tests, so they run on every platform - which is the point of keeping them out of the suite below, since those are the two parts of the editor whose behaviour differs by operating system
- **tests/Schema.Editor.UITests** - The editor's tests that drive real frames through `EditorHarness`/`WidgetHarness`. The shared `dotnet.yml` runs it on Linux only, as it does every other ktsu UI suite: the CPU rasterizer measures the same on any host, so the other platforms pay the cost without learning anything. **Both halves of the path are load-bearing** - `ktsubuild --exclude "**/*.UITests/*"` needs the `.UITests` suffix *and* a leading directory, because its `**/` does not match zero segments. A project at the repository root is never excluded, however it is named
- **Schema.Tool** - The `dotnet tool` (`kschema`) that validates schemas and runs their code generators

## Build Commands
Expand Down Expand Up @@ -519,8 +520,8 @@ as the property initialiser as well, so a generated instance starts at it.
- `Schema.Editor/EditorHost.cs` - Builds the `ImGuiAppConfig`; `CreateConfig` is what the tests drive too
- `Schema.Editor/EditorTheme.cs` - The ktsu.ThemeProvider theme, and the one definition of how a validation issue is coloured
- `Schema.Editor/Program.cs` - The entry point, and the only file excluded from coverage measurement
- `Schema.Editor.Test/EditorHarness.cs` - Runs a real editor headlessly, frames advanced by the test
- `Schema.Editor.Test/WidgetHarness.cs` - A headless frame containing only the widget under test, and an editor for a panel that is one
- `tests/Schema.Editor.UITests/EditorHarness.cs` - Runs a real editor headlessly, frames advanced by the test
- `tests/Schema.Editor.UITests/WidgetHarness.cs` - A headless frame containing only the widget under test, and an editor for a panel that is one

### Addressing the editor from a test

Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,15 @@ A C# library for defining, managing, and editing data structure schemas with a r

**ktsu.Schema** lets you define structured data models programmatically or visually, then serialize them to `.schema.json` files (documented in the [schema file format reference](docs/schema-format.md)). It provides a foundation for code generation, data validation, and tooling that needs to understand your data structures at a metadata level.

The solution contains seven projects:
The solution contains eight projects:

- **Schema** - Core library with schema definition types, a rich type system, and JSON serialization
- **Schema.Test** - Unit tests for the core library
- **Schema.Cpp** - The C++ generator, published separately as [`ktsu.Schema.Cpp`](https://nuget.org/packages/ktsu.Schema.Cpp)
- **Schema.Cpp.Test** - Its tests, including acceptance tests against a real target's document
- **Schema.Editor** - ImGui-based desktop application for visual schema editing
- **Schema.Editor.Test** - Headless UI tests that drive the editor with no window or display
- **Schema.Editor.Test** - The editor tests that need no frame: recent files, and reading and writing the document
- **tests/Schema.Editor.UITests** - Headless UI tests that drive the editor with no window or display
- **Schema.Tool** - Command line entry point for validating schemas and running their code generators

`Schema.Cpp` is a separate package rather than part of the library because the AST it builds on
Expand Down
1 change: 1 addition & 0 deletions Schema.Cpp.Test/ExemplarSemanticTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ public sealed class ExemplarSemanticTypeTests

#pragma once

#include <compare>
#include <cstdint>
#include <type_traits>

Expand Down
1 change: 1 addition & 0 deletions Schema.Cpp/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
// KTSU0002 asks a non-test project to expose its internals to the repository's test projects
// rather than to the one that happens to need them.
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ktsu.Schema.Test")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ktsu.Schema.Editor.UITests")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ktsu.Schema.Editor.Test")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ktsu.Schema.Cpp.Test")]
7 changes: 7 additions & 0 deletions Schema.Cpp/CppFileBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ public SourceFile SemanticType(SchemaSemanticType semanticType)
}

declaration.Members.Add(Comparison(name, "==", "bool"));

// A defaulted <=> answers with one of the ordering types, and those live in <compare>.
// libstdc++ happens to have declared them by the time this header is read and libc++ does
// not, so without this the generated type compiles under GCC and is refused by Clang -
// which is exactly the kind of difference a generator must not leave to whoever includes
// it.
mapper.Require("<compare>");
declaration.Members.Add(Comparison(name, "<=>", "auto"));
declaration.Members.Add(new FieldDeclaration(ValueField, UnderlyingAlias) { Visibility = Visibility.Private });

Expand Down
5 changes: 0 additions & 5 deletions Schema.Editor.Test/Schema.Editor.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,6 @@
</ItemGroup>

<ItemGroup>
<!-- The headless harness: it drives ImGuiApp frames through a software rasterizer, so the
editor's draw code runs with no window, no display and no GPU. -->
<PackageReference Include="ktsu.ImGui.App.Testing" />
<PackageReference Include="ktsu.ImGui.Styler" />
<PackageReference Include="ktsu.ThemeProvider" />
<!-- A mock file system for AppDataStorage, so a test never reads or writes the settings of
whoever is running it. -->
<PackageReference Include="TestableIO.System.IO.Abstractions.TestingHelpers" />
Expand Down
1 change: 1 addition & 0 deletions Schema.Editor/AppData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// ktsu.Sdk's KTSU0002 requires a non-test project to expose its internals to the repository's test
// projects, and there are two of them now; which of the two a given project actually needs is not
// what the rule is checking.
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ktsu.Schema.Editor.UITests")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ktsu.Schema.Editor.Test")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ktsu.Schema.Test")]

Expand Down
1 change: 1 addition & 0 deletions Schema.Tool/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// projects, and there are two of them now; which of the two a given project actually needs is not
// what the rule is checking.
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ktsu.Schema.Test")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ktsu.Schema.Editor.UITests")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ktsu.Schema.Editor.Test")]

namespace ktsu.Schema.Tool;
Expand Down
16 changes: 15 additions & 1 deletion Schema.sln
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Schema.Editor", "Schema.Edi
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Schema.Tool", "Schema.Tool\Schema.Tool.csproj", "{1EBD8E07-A2A3-4091-8748-ECFEB1D301F0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Schema.Editor.Test", "Schema.Editor.Test\Schema.Editor.Test.csproj", "{31DEE39F-3542-4B65-B744-74243D28D878}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Schema.Editor.UITests", "tests\Schema.Editor.UITests\Schema.Editor.UITests.csproj", "{31DEE39F-3542-4B65-B744-74243D28D878}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Schema.Cpp", "Schema.Cpp\Schema.Cpp.csproj", "{93D1BF5F-D2C4-46C4-A783-2F6F4B7AA6B7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Schema.Cpp.Test", "Schema.Cpp.Test\Schema.Cpp.Test.csproj", "{B331523C-35C3-456A-B5DA-678A6144A090}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Schema.Editor.Test", "Schema.Editor.Test\Schema.Editor.Test.csproj", "{5562D744-2ECE-47B5-9AB8-EA5F659ABAE8}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -111,6 +113,18 @@ Global
{B331523C-35C3-456A-B5DA-678A6144A090}.Release|x64.Build.0 = Release|Any CPU
{B331523C-35C3-456A-B5DA-678A6144A090}.Release|x86.ActiveCfg = Release|Any CPU
{B331523C-35C3-456A-B5DA-678A6144A090}.Release|x86.Build.0 = Release|Any CPU
{5562D744-2ECE-47B5-9AB8-EA5F659ABAE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5562D744-2ECE-47B5-9AB8-EA5F659ABAE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5562D744-2ECE-47B5-9AB8-EA5F659ABAE8}.Debug|x64.ActiveCfg = Debug|Any CPU
{5562D744-2ECE-47B5-9AB8-EA5F659ABAE8}.Debug|x64.Build.0 = Debug|Any CPU
{5562D744-2ECE-47B5-9AB8-EA5F659ABAE8}.Debug|x86.ActiveCfg = Debug|Any CPU
{5562D744-2ECE-47B5-9AB8-EA5F659ABAE8}.Debug|x86.Build.0 = Debug|Any CPU
{5562D744-2ECE-47B5-9AB8-EA5F659ABAE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5562D744-2ECE-47B5-9AB8-EA5F659ABAE8}.Release|Any CPU.Build.0 = Release|Any CPU
{5562D744-2ECE-47B5-9AB8-EA5F659ABAE8}.Release|x64.ActiveCfg = Release|Any CPU
{5562D744-2ECE-47B5-9AB8-EA5F659ABAE8}.Release|x64.Build.0 = Release|Any CPU
{5562D744-2ECE-47B5-9AB8-EA5F659ABAE8}.Release|x86.ActiveCfg = Release|Any CPU
{5562D744-2ECE-47B5-9AB8-EA5F659ABAE8}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
1 change: 1 addition & 0 deletions Schema/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@
// projects, and there are two of them now; which of the two a given project actually needs is not
// what the rule is checking.
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ktsu.Schema.Test")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ktsu.Schema.Editor.UITests")]
[assembly: System.Runtime.CompilerServices.InternalsVisibleTo("ktsu.Schema.Editor.Test")]
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ if (SchemaSerializer.TryDeserialize(File.ReadAllText("user.schema.json"), out Sc
- **[Schema](api/schema-core.md)** - Core library containing the schema definition system
- **[Schema.Editor](features/schema-editor.md)** - Visual editor application
- **Schema.Tool** - Command line validator and code generator runner
- **Schema.Test** / **Schema.Editor.Test** - MSTest suites for the library and the editor (see the [development guide](development/README.md))
- **Schema.Test** / **Schema.Editor.Test** / **Schema.Editor.UITests** - MSTest suites for the library and the editor (see the [development guide](development/README.md))

## Documentation

Expand Down
4 changes: 2 additions & 2 deletions docs/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ time. For what the library actually does, the tests in
recent-files list.
- **CLI** — `Schema.Tool` validates a schema or runs its code generators, exiting non-zero on
errors so it can gate a build.
- **Editor tests** — `Schema.Editor.Test` drives the editor headlessly through
- **Editor tests** — `tests/Schema.Editor.UITests` drives the editor headlessly through
`ktsu.ImGui.App.Testing`, which rasterizes in software and injects input straight into ImGui, so
the editor's real draw code runs on a continuous integration runner with no window or display.
- **CI/CD** — GitHub Actions with build, multi-framework test, SonarCloud analysis, CodeQL, NuGet
Expand Down Expand Up @@ -103,7 +103,7 @@ Outstanding: editor packaging via winget, and cutting the v2.0 milestone.

Not one of the original phases; added when the editor grew large enough to need one.

`Schema.Editor.Test` ([#128](https://github.com/ktsu-dev/Schema/issues/128)) drives the editor
`tests/Schema.Editor.UITests` ([#128](https://github.com/ktsu-dev/Schema/issues/128)) drives the editor
headlessly. It covers the recent-files list, the commit-once text field, the unsaved-changes guard
and the save-then-continue sequence, validation debouncing and click-to-navigate, and — by
addressing widgets through the names the editor marks them with — the schema tree, its context
Expand Down
5 changes: 3 additions & 2 deletions docs/development/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ dotnet run --project Schema.Editor
| `Schema/` | Core schema definition library |
| `Schema.Test/` | MSTest unit tests for the library |
| `Schema.Editor/` | ImGui-based visual editor |
| `Schema.Editor.Test/` | Headless UI tests for the editor |
| `Schema.Editor.Test/` | The editor tests that need no frame |
| `tests/Schema.Editor.UITests/` | Headless UI tests for the editor |
| `Schema.Tool/` | Command line validator and generator |
| `docs/` | Markdown documentation |
| `scripts/` | Build automation (PSBuild) |
Expand All @@ -69,7 +70,7 @@ Plain unit tests over the core library, run against every framework it publishes
suites (`SchemaTests`, `SchemaClassTests`, `SchemaEnumTests`, `TypeSystemTests`,
`SchemaSerializerTests`, `AddClassFromTypeTests`) show the conventions in use.

### The editor — `Schema.Editor.Test`
### The editor — `tests/Schema.Editor.UITests`

The editor's code is immediate-mode draw calls, so none of it executes without a live ImGui
context. `ktsu.ImGui.App.Testing` supplies one with no window, no display and no GPU: it rasterizes
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using System.Linq;
using System.Numerics;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using System;
using System.IO;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using System.Linq;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using System.Linq;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using System;
using System.IO;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using System;
using System.Numerics;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using System;
using System.IO.Abstractions.TestingHelpers;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using System;
using System.IO;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using System;
using System.IO;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

/// <summary>
/// That the harness itself works: without these, a failure anywhere else is ambiguous between the
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using System.Linq;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using ktsu.Schema.Models;
using ktsu.Schema.Models.Metadata;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using System;
using System.IO;
Expand Down
39 changes: 39 additions & 0 deletions tests/Schema.Editor.UITests/Schema.Editor.UITests.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<Project>
<Sdk Name="MSTest.Sdk" />
<Import Project="Sdk.props" Sdk="ktsu.Sdk" />

<PropertyGroup>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Schema.Editor\Schema.Editor.csproj" />
</ItemGroup>

<ItemGroup>
<!-- The headless harness: it drives ImGuiApp frames through a software rasterizer, so the
editor's draw code runs with no window, no display and no GPU. -->
<PackageReference Include="ktsu.ImGui.App.Testing" />
<PackageReference Include="ktsu.ImGui.Styler" />
<PackageReference Include="ktsu.ThemeProvider" />
<!-- A mock file system for AppDataStorage, so a test never reads or writes the settings of
whoever is running it. -->
<PackageReference Include="TestableIO.System.IO.Abstractions.TestingHelpers" />
</ItemGroup>

<ItemGroup>
<PackageReference Update="Microsoft.Testing.Extensions.CodeCoverage">
<VersionOverride>18.8.0</VersionOverride>
</PackageReference>
</ItemGroup>

<Import Project="Sdk.targets" Sdk="ktsu.Sdk" />

<!-- Schema.Editor is a net10.0-only application, so this suite is too. Placed after the explicit
Sdk.targets import so the project, not the SDK, has the last word - the same reason
Schema.Test states its frameworks there. -->
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<TargetFrameworks></TargetFrameworks>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using System;
using System.IO;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

/// <summary>
/// Picking a theme from the browser the Theme menu opens.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

/// <summary>
/// Which ktsu.ThemeProvider theme the editor runs under, and where that choice comes from.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using System.Linq;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using System.Linq;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using ktsu.Schema.Models;
using ktsu.Schema.Models.Names;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using ktsu.ImGui.App.Testing;
using ktsu.Schema.Models;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Copyright (c) 2023-2026 ktsu-dev contributors

namespace ktsu.Schema.Editor.Test;
namespace ktsu.Schema.Editor.UITests;

using ktsu.ImGui.App.Testing;
using ktsu.Schema.Models;
Expand Down
Loading
Loading