Skip to content

test: compare SQL with golden baselines that can be rewritten - #46

Merged
xperiandri merged 1 commit into
mainfrom
test/golden-baselines
Oct 10, 2026
Merged

xperiandri merged 1 commit into
mainfrom
test/golden-baselines

Conversation

@xperiandri

Copy link
Copy Markdown
Collaborator

Proposed Changes

The planned translator (ADR 0001, #34) turns F# quotations into SQL, and its tests need to say "this quotation becomes exactly this SQL with these parameters". Written inline, hundreds of such expected strings are hard to read and to update when a rule changes on purpose. ADR 0001 therefore plans golden baselines: the expected SQL lives in files checked into the test project, a test compares what it produced with its file, and a deliberate change is accepted by rewriting the files from a test run and reviewing them in the diff, instead of editing strings by hand. This pull request adds that mechanism to the shared test infrastructure, before its first users: the printer tests of the SQL model (#42) and later the translator tests.

tests/Cosmos.Tests.Infrastructure/Baseline.fs:

  • Baseline.assertMatches directory suite caseName sql parameters compares the SQL with Baselines/<suite>/<case>.sql, ignoring whitespace, so a baseline may be laid out over several lines. It compares the parameters with <case>.params.json as JSON. A query without parameters has no parameter file.
  • With COSMOS_REWRITE_BASELINES=1 the test writes both files instead of comparing. It keeps the layout of the SQL, writes the JSON indented with LF line breaks, and reports itself inconclusive, so a rewriting run never looks like a passing one. On CI (CI=true) rewriting is refused.
  • Baseline.directoryOf assembly finds the Baselines directory next to the project file of a test assembly by walking up from where the assembly runs. Unlike [<CallerFilePath>], this does not depend on how the compiler records source paths.

tests/Cosmos.Tests/BaselineTests.fs (12 emulator-free cases) covers matching despite layout, a different SQL, different parameters, a missing baseline, rewriting with and without parameters, invalid case names and finding the directory. .github/copilot-instructions.md lists the new environment variable with the other test variables.

Types of changes

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Test infrastructure only; the package is unchanged.

Checklist

  • Build and tests pass locally
  • I have added tests that prove my fix is effective or that my feature works (if appropriate)
  • I have added necessary documentation (if appropriate)

Further comments

  • The new tests: Debug 12/12 and Release 12/12. No new warnings; Fantomas is clean.
  • Nothing uses the baselines yet, so no Baselines directory exists so far. The first test that calls assertMatches creates its files through a rewriting run.

🤖 Generated with Claude Code

Copilot AI balanced review requested due to automatic review settings October 10, 2026 01:34

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

SQL normalization can hide semantic differences, and suite-name validation permits escaping the baseline directory.

1 open finding
What changed in this PR

Adds reusable golden-baseline infrastructure for forthcoming SQL printer and quotation-translator tests.

Changes:

  • Adds SQL/parameter comparison and baseline rewriting.
  • Adds 12 emulator-free baseline tests.
  • Documents the rewrite environment variable.
File Description
tests/​Cosmos.Tests.Infrastructure/​Baseline.fs Implements baseline handling.
tests/​Cosmos.Tests.Infrastructure/​FSharp.Azure.Cosmos.Tests.Infrastructure.fsproj Includes the infrastructure module.
tests/​Cosmos.Tests/​BaselineTests.fs Tests baseline behavior.
tests/​Cosmos.Tests/​FSharp.Azure.Cosmos.Tests.fsproj Includes the new tests.
.github/​copilot-instructions.md Documents baseline rewriting.

🧠 Review effort: Balanced


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread tests/Cosmos.Tests.Infrastructure/Baseline.fs Outdated
@xperiandri
xperiandri force-pushed the test/golden-baselines branch from 7ce3d6f to 207aa53 Compare October 10, 2026 01:46
@xperiandri

Copy link
Copy Markdown
Collaborator Author

Should we use Literal type provider?

@xperiandri

Copy link
Copy Markdown
Collaborator Author

Should we use Literal type provider?

I tried it: FSharp.Data.LiteralProviders 1.0.3 with its TextFile provider, in a prototype on SDK 10.0.401 with MSTest 4. It works there, but it does not fit the baselines, so I would keep the files that are read at run time.

  • The literal is frozen at compile time. After COSMOS_REWRITE_BASELINES=1 rewrites a baseline, the next dotnet build does not recompile, and the test compares with the old text. It recompiles only when the files are declared as compile inputs (CustomAdditionalCompileInputs or EmbeddedResource), and then every rewrite costs a rebuild before the next run.
  • A case cannot be looked up by a name known at run time. TextFile<caseName> needs a constant (FS0267), and the provided types are erased, so there is nothing to reflect over. The data-driven tests, whose DynamicData rows carry a case name, would need a hand-written match from every case name to its literal.
  • The provider resolves paths against the project being compiled. In the shared test infrastructure project the baselines of a test project do not exist: Text is "" and Exists is false, without an error. So Baseline could not own the lookup; every test project would spell every literal and pass it in.
  • A new case cannot be started with the rewrite switch. The navigation form, TextFile.Baselines.Suite.case.sql.Text, does not compile until the file exists, and the path form gives an empty string without an error.
  • The literal keeps the line endings of the checkout, CRLF on Windows and LF on Linux. That is harmless only because the comparison normalizes whitespace.

What it would give: a compile error for a mistyped case name that is written in the code, and literals that an attribute argument can take. That fits inputs that are written by hand and only read, not outputs that the tests rewrite.

If the build should fail for a missing baseline, <EmbeddedResource Include="Baselines/**/*" /> did that in the prototype without a package. The rewrite switch still needs the source directory then, as it does now.

Not checked: Linux (the prototype ran on Windows only) and the IDE; the package has no release since 2022, and its own CI does not cover .NET 10.

xperiandri added a commit that referenced this pull request Oct 10, 2026
The maintainer's reviews of 2026-10-10 changed several things the record
describes, and it now says so where each belongs.

The Hedgehog MSTest adapter (#43): the in-repository copy follows the
coding guidelines of this repository, while the upstream pull request
keeps upstream's style in a copy of its own, so a change of behaviour
goes into both; an invocation that MSTest could not run stops the run
instead of being shrunk; Odd and Even stay inside their range; DateOnly
and TimeOnly get generators, upstream through
hedgehogqa/fsharp-hedgehog#488. The open question of the adapter's code
style is answered, with formatting and nullness checking still open.

Collections (section 4): the shared collection functions of #47 that
return voption and struct tuples, tested with properties in #50, and the
rule of one module per pipeline of #49.

Build (section 5): why FAKE's DotNet.test cannot run the test
applications, and fsprojects/FAKE#2903, which adds DotNet.testMTP.

The spec model (sections 6 and 16): EquatableArray and the ImmutableArray
patterns are #48 and the model itself #42; the validator returns an
ImmutableArray of struct errors.

Golden baselines (section 13): a literal type provider was evaluated on
the question asked in #46 and rejected, with the reasons.

Tests (section 22): test category attributes sorted by name, Pascal-case
assertion functions and ImmutableArray for shared test data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xperiandri added a commit that referenced this pull request Oct 10, 2026
The maintainer's reviews of 2026-10-10 changed several things the record
describes, and it now says so where each belongs.

The Hedgehog MSTest adapter (#43): the in-repository copy follows the
coding guidelines of this repository, while the upstream pull request
keeps upstream's style in a copy of its own, so a change of behaviour
goes into both; an invocation that MSTest could not run stops the run
instead of being shrunk; the cancellation token is checked after every
invocation, whatever its outcome, which the automatic review of #50
asked for; Odd and Even stay inside their range; DateOnly and TimeOnly
get generators, upstream through hedgehogqa/fsharp-hedgehog#488. The open question of the adapter's code
style is answered, with formatting and nullness checking still open.

Collections (section 4): the shared collection functions of #47 that
return voption and struct tuples, tested with properties in #50, and the
rule of one module per pipeline of #49.

Build (section 5): why FAKE's DotNet.test cannot run the test
applications, and fsprojects/FAKE#2903, which adds DotNet.testMTP.

The spec model (sections 6 and 16): EquatableArray and the ImmutableArray
patterns are #48 and the model itself #42; the validator returns an
ImmutableArray of struct errors.

Golden baselines (section 13): a literal type provider was evaluated on
the question asked in #46 and rejected, with the reasons.

Tests (section 22): test category attributes sorted by name, Pascal-case
assertion functions and ImmutableArray for shared test data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@xperiandri
xperiandri force-pushed the test/golden-baselines branch 2 times, most recently from 2fdda3b to 76b3f0b Compare October 10, 2026 16:23
xperiandri added a commit that referenced this pull request Oct 10, 2026
The maintainer's reviews of 2026-10-10 changed several things the record
describes, and it now says so where each belongs.

The Hedgehog MSTest adapter (#43): the in-repository copy follows the
coding guidelines of this repository, while the upstream pull request
keeps upstream's style in a copy of its own, so a change of behaviour
goes into both; an invocation that MSTest could not run stops the run
instead of being shrunk; the cancellation token is checked after every
invocation, whatever its outcome, which the automatic review of #50
asked for; Odd and Even stay inside their range; DateOnly and TimeOnly
get generators, upstream through hedgehogqa/fsharp-hedgehog#488. The open question of the adapter's code
style is answered, with formatting and nullness checking still open.

Collections (section 4): the shared collection functions of #47 that
return voption and struct tuples, tested with properties in #50, and the
rule of one module per pipeline of #49.

Build (section 5): why FAKE's DotNet.test cannot run the test
applications, and fsprojects/FAKE#2903, which adds DotNet.testMTP.

The spec model (sections 6 and 16): EquatableArray and the ImmutableArray
patterns are #48 and the model itself #42; the validator returns an
ImmutableArray of struct errors.

Golden baselines (section 13): a literal type provider was evaluated on
the question asked in #46 and rejected, with the reasons.

Tests (section 22): test category attributes sorted by name, Pascal-case
assertion functions and ImmutableArray for shared test data.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xperiandri added a commit that referenced this pull request Oct 10, 2026
The maintainer's reviews of 2026-10-10 changed several things the record
describes, and it now says so where each belongs.

The Hedgehog MSTest adapter (#43): the in-repository copy follows the
coding guidelines of this repository, while the upstream pull request
keeps upstream's style in a copy of its own, so a change of behaviour
goes into both; an invocation that MSTest could not run stops the run
instead of being shrunk; the cancellation token is checked after every
invocation, whatever its outcome, which the automatic review of #50
asked for; Odd and Even stay inside their range; DateOnly and TimeOnly
get generators, upstream through hedgehogqa/fsharp-hedgehog#488. The
open question of the adapter's code style is answered, formatting and
nullness checking included: the two projects are formatted with Fantomas
and build with nullness checking on, and only the verbatim port keeps
upstream's settings.

Collections (section 4): the shared collection functions of #47 that
return voption and struct tuples, tested with properties in #50, and the
rule of one module per pipeline of #49.

Build (section 5): why FAKE's DotNet.test cannot run the test
applications, and fsprojects/FAKE#2903, which adds DotNet.testMTP.

The spec model (sections 6 and 16): EquatableArray and the ImmutableArray
patterns are #48 and the model itself #42; the validator returns an
ImmutableArray of struct errors.

Golden baselines (section 13): a literal type provider was evaluated on
the question asked in #46 and rejected, with the reasons.

Tests (section 22): test category attributes sorted by name, in #51
with an instruction scoped to those files, Pascal-case assertion
functions and ImmutableArray for shared test data.

Two more answers of the same day: the Windows emulator lane of #45 runs
weekly instead of nightly (section 2), and the shared collection
functions of #47 are in the namespace FSharp.Azure.Cosmos instead of the
global one (section 4).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ADR 0001 plans golden baselines for the SQL the translator produces:
files checked into the test project, compared regardless of whitespace,
and rewritten on request instead of edited by hand. Baseline in the
shared test infrastructure provides them before their first users
arrive, the printer tests of the SQL model and later the translator
tests.

Baseline.assertMatches compares the SQL with Baselines/<suite>/<case>.sql
after collapsing whitespace, and the parameters with <case>.params.json
as JSON; a query without parameters has no parameter file. With
COSMOS_REWRITE_BASELINES=1 it writes both files instead, keeping the
layout of the SQL and writing the JSON indented with LF line breaks,
and reports the test inconclusive, so that a rewriting run never looks
like a passing one. A run on CI, where CI is true, refuses to rewrite.
Baseline.directoryOf finds the Baselines directory next to the project
file of a test assembly by walking up from where the assembly runs,
which does not depend on how the compiler records source paths.

BaselineTests covers matching, both kinds of difference, a missing
baseline, rewriting with and without parameters, invalid case names and
finding the directory. The agent instructions list the new environment
variable.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xperiandri added a commit that referenced this pull request Oct 10, 2026
The maintainer's reviews of 2026-10-10 changed several things the record
describes, and it now says so where each belongs.

The Hedgehog MSTest adapter (#43): the in-repository copy follows the
coding guidelines of this repository, while the upstream pull request
keeps upstream's style in a copy of its own, so a change of behaviour
goes into both; an invocation that MSTest could not run stops the run
instead of being shrunk; the cancellation token is checked after every
invocation, whatever its outcome, which the automatic review of #50
asked for; Odd and Even stay inside their range; DateOnly and TimeOnly
get generators, upstream through hedgehogqa/fsharp-hedgehog#488. The
open question of the adapter's code style is answered, formatting and
nullness checking included: the two projects are formatted with Fantomas
and build with nullness checking on, and only the verbatim port keeps
upstream's settings.

Collections (section 4): the shared collection functions of #47 that
return voption and struct tuples, tested with properties in #50, and the
rule of one module per pipeline of #49.

Build (section 5): why FAKE's DotNet.test cannot run the test
applications, and fsprojects/FAKE#2903, which adds DotNet.testMTP.

The spec model (sections 6 and 16): EquatableArray and the ImmutableArray
patterns are #48 and the model itself #42; the validator returns an
ImmutableArray of struct errors.

Golden baselines (section 13): a literal type provider was evaluated on
the question asked in #46 and rejected, with the reasons.

Tests (section 22): test category attributes sorted by name, in #51
with an instruction scoped to those files, Pascal-case assertion
functions and ImmutableArray for shared test data.

Two more answers of the same day: the Windows emulator lane of #45 runs
weekly instead of nightly (section 2), and the shared collection
functions of #47 are in the namespace FSharp.Azure.Cosmos instead of the
global one (section 4).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@xperiandri
xperiandri force-pushed the test/golden-baselines branch from 76b3f0b to 3f8776b Compare October 10, 2026 21:15
@xperiandri
xperiandri merged commit d95b908 into main Oct 10, 2026
7 checks passed
@xperiandri
xperiandri deleted the test/golden-baselines branch October 10, 2026 23:58
xperiandri added a commit that referenced this pull request Oct 11, 2026
The maintainer's reviews of 2026-10-10 changed several things the record
describes, and it now says so where each belongs.

The Hedgehog MSTest adapter (#43): the in-repository copy follows the
coding guidelines of this repository, while the upstream pull request
keeps upstream's style in a copy of its own, so a change of behaviour
goes into both; an invocation that MSTest could not run stops the run
instead of being shrunk; the cancellation token is checked after every
invocation, whatever its outcome, which the automatic review of #50
asked for; Odd and Even stay inside their range; DateOnly and TimeOnly
get generators, upstream through hedgehogqa/fsharp-hedgehog#488. The
open question of the adapter's code style is answered, formatting and
nullness checking included: the two projects are formatted with Fantomas
and build with nullness checking on, and only the verbatim port keeps
upstream's settings.

Collections (section 4): the shared collection functions of #47 that
return voption and struct tuples, tested with properties in #50, and the
rule of one module per pipeline of #49.

Build (section 5): why FAKE's DotNet.test cannot run the test
applications, and fsprojects/FAKE#2903, which adds DotNet.testMTP.

The spec model (sections 6 and 16): EquatableArray and the ImmutableArray
patterns are #48 and the model itself #42; the validator returns an
ImmutableArray of struct errors.

Golden baselines (section 13): a literal type provider was evaluated on
the question asked in #46 and rejected, with the reasons.

Tests (section 22): test category attributes sorted by name, in #51
with an instruction scoped to those files, Pascal-case assertion
functions and ImmutableArray for shared test data.

Two more answers of the same day: the Windows emulator lane of #45 runs
weekly instead of nightly (section 2), and the shared collection
functions of #47 are in the namespace FSharp.Azure.Cosmos instead of the
global one (section 4).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xperiandri added a commit that referenced this pull request Oct 11, 2026
The maintainer's reviews of 2026-10-10 changed several things the record
describes, and it now says so where each belongs.

The Hedgehog MSTest adapter (#43): the in-repository copy follows the
coding guidelines of this repository, while the upstream pull request
keeps upstream's style in a copy of its own, so a change of behaviour
goes into both; an invocation that MSTest could not run stops the run
instead of being shrunk; the cancellation token is checked after every
invocation, whatever its outcome, which the automatic review of #50
asked for; Odd and Even stay inside their range; DateOnly and TimeOnly
get generators, upstream through hedgehogqa/fsharp-hedgehog#488. The
open question of the adapter's code style is answered, formatting and
nullness checking included: the two projects are formatted with Fantomas
and build with nullness checking on, and only the verbatim port keeps
upstream's settings.

Collections (section 4): the shared collection functions of #47 that
return voption and struct tuples, tested with properties in #50, and the
rule of one module per pipeline of #49.

Build (section 5): why FAKE's DotNet.test cannot run the test
applications, and fsprojects/FAKE#2903, which adds DotNet.testMTP.

The spec model (sections 6 and 16): EquatableArray and the ImmutableArray
patterns are #48 and the model itself #42; the validator returns an
ImmutableArray of struct errors.

Golden baselines (section 13): a literal type provider was evaluated on
the question asked in #46 and rejected, with the reasons.

Tests (section 22): test category attributes sorted by name, in #51
with an instruction scoped to those files, Pascal-case assertion
functions and ImmutableArray for shared test data.

Two more answers of the same day: the Windows emulator lane of #45 runs
weekly instead of nightly (section 2), and the shared collection
functions of #47 are in the namespace FSharp.Azure.Cosmos instead of the
global one (section 4).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants