Skip to content
Open
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
7 changes: 6 additions & 1 deletion .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
│ └── ValueCollections.fs – `Seq`, `List` and `Array` functions that return `voption` and struct tuples
├── tests/Cosmos.Tests/ – MSTest integration test project
├── tests/Cosmos.Tests.Infrastructure/ – shared test fixtures, emulator settings and assertion helpers
├── tests/Hedgehog.MSTest/ – Hedgehog MSTest adapter for [<Property>] test methods (from hedgehogqa/fsharp-hedgehog)
├── tests/Hedgehog.MSTest.Tests/ – the adapter's own test suite
├── build/ – FAKE build scripts
└── docsSrc/ – FSharp.Formatting documentation source
```
Expand All @@ -40,6 +42,7 @@
* [`FSharp.Control.Reactive`](https://github.com/fsprojects/FSharp.Reactive) – Rx extensions for F#
* [`FsToolkit.ErrorHandling`](https://github.com/demystifyfp/FsToolkit.ErrorHandling) – `taskResult`, `Result`, `voption` CEs
* [`Unquote`](https://github.com/SwensenSoftware/unquote) – test assertions
* [`Hedgehog`](https://github.com/hedgehogqa/fsharp-hedgehog) – property-based testing through the `tests/Hedgehog.MSTest` adapter
* [`MSTest`](https://github.com/microsoft/testfx) – test framework

Use GitHub MCP tools for code search in these repositories when needed.
Expand Down Expand Up @@ -238,7 +241,9 @@ module MyTypeExtensions =
* `COSMOS_EMULATOR_PARTITION_COUNT` is the number of partitions the emulator offers (default `25`, the Windows emulator's default `/PartitionCount`); the fixtures keep at most that many test containers at a time, one partition each.
* `COSMOS_TEST_LEFTOVER_AGE_MINUTES` is how many minutes a `fsac-test-` database must stay unmodified before the leftover sweep of `[<AssemblyInitialize>]` and `[<AssemblyCleanup>]` deletes it (default `60`), so that the live databases of another test process on the same emulator are kept; `0` deletes every test database and is safe only while no other test process uses the emulator.
* `COSMOS_REWRITE_BASELINES` set to `1` or `true` makes a test that compares SQL with its golden baseline (`Baseline.assertMatches`, files under `Baselines/<suite>/` of the test project) write what it produced into the baseline instead of comparing; the test then reports itself inconclusive, the rewritten files are reviewed in the diff, and CI refuses to rewrite.
* Every test project under `tests/` references `tests/Cosmos.Tests.Infrastructure` through `tests/Directory.Build.props`; a new test project gets it without a `ProjectReference` of its own.
* Every test project under `tests/` references `tests/Cosmos.Tests.Infrastructure` through `tests/Directory.Build.props`; a new test project gets it without a `ProjectReference` of its own. The Hedgehog MSTest adapter and its suite are the exception: they stay free of the Cosmos projects, and the suite references the adapter alone.
* Property tests are methods of `[<TestClass>]` types marked `[<Property>]` (from `tests/Hedgehog.MSTest`), whose parameters Hedgehog generates; never call `Property.check` inside a `[<TestMethod>]`. A property is an instance method that returns `unit`, `Task` or `ValueTask` and fails by throwing: MSTest 4 rejects static methods and other return types, and one such method fails the discovery of the whole assembly, which `--list-tests` shows before a run. MSTest creates the test class and runs `[<TestInitialize>]` and `[<TestCleanup>]` for every generated case and every shrink step. A failed property reports a `[<Recheck("…")>]` to add next to its `Property` attribute, which then replays the counterexample. A parameter of type `DateOnly` or `TimeOnly`, or of a type that holds one, is generated like any other, and `[<DateOnly>]` and `[<TimeOnly>]` bound its value: Hedgehog 2.0.4 has no generator of the two types, so the adapter registers the ones that [hedgehogqa/fsharp-hedgehog#488](https://github.com/hedgehogqa/fsharp-hedgehog/pull/488) adds to Hedgehog, until a release has them. `Gen.auto` outside a property does not know the two types before that release.
* `tests/Hedgehog.MSTest` and `tests/Hedgehog.MSTest.Tests` are ported from hedgehogqa/fsharp-hedgehog and proposed there too ([hedgehogqa/fsharp-hedgehog#487](https://github.com/hedgehogqa/fsharp-hedgehog/pull/487)). Their code follows the rules of this file, formatting with Fantomas and nullness checking included; the copy in the upstream pull request keeps upstream's style, so a change of behaviour goes into both. Copied files keep their Apache-2.0 header, which records every change made to them, and `THIRD-PARTY-NOTICES.md` lists them.
* `CollectionAssert` cannot work with F# lists – use F# array syntax (`[| ... |]`) instead.
* `StringAssert` has overloads with `StringComparison`.
* Use `Assert.Contains` instead of `Assert.IsTrue (str.Contains ..., "message")`, and do not put the actual value into the message.
Expand Down
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<PackageVersion Include="Fake.DotNet.Paket" Version="6.1.5" />
<PackageVersion Include="Fake.IO.FileSystem" Version="6.1.5" />
<PackageVersion Include="Fake.Tools.Git" Version="6.1.5" />
<PackageVersion Include="Hedgehog" Version="2.0.4" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
<PackageVersion Include="Microsoft.SourceLink.GitHub" Version="10.0.401" />
<PackageVersion Include="MSTest" Version="4.2.3" />
Expand Down
4 changes: 3 additions & 1 deletion FSharp.Azure.Cosmos.slnf
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
"projects": [
"src\\Cosmos\\FSharp.Azure.Cosmos.fsproj",
"tests\\Cosmos.Tests.Infrastructure\\FSharp.Azure.Cosmos.Tests.Infrastructure.fsproj",
"tests\\Cosmos.Tests\\FSharp.Azure.Cosmos.Tests.fsproj"
"tests\\Cosmos.Tests\\FSharp.Azure.Cosmos.Tests.fsproj",
"tests\\Hedgehog.MSTest\\Hedgehog.MSTest.fsproj",
"tests\\Hedgehog.MSTest.Tests\\Hedgehog.MSTest.Tests.fsproj"
]
}
}
3 changes: 3 additions & 0 deletions FSharp.Azure.Cosmos.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,12 @@
<File Path="Directory.Packages.props" />
<File Path="global.json" />
<File Path="README.md" />
<File Path="THIRD-PARTY-NOTICES.md" />
</Folder>
<Project Path="build/build.fsproj" />
<Project Path="src/Cosmos/FSharp.Azure.Cosmos.fsproj" />
<Project Path="tests/Cosmos.Tests.Infrastructure/FSharp.Azure.Cosmos.Tests.Infrastructure.fsproj" />
<Project Path="tests/Cosmos.Tests/FSharp.Azure.Cosmos.Tests.fsproj" />
<Project Path="tests/Hedgehog.MSTest/Hedgehog.MSTest.fsproj" />
<Project Path="tests/Hedgehog.MSTest.Tests/Hedgehog.MSTest.Tests.fsproj" />
</Solution>
35 changes: 35 additions & 0 deletions THIRD-PARTY-NOTICES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Third-party notices

This repository contains code copied from the projects below. Each copied file names its origin and the changes made
to it in a header comment. The rest of the repository is covered by [LICENSE](LICENSE).

## fsharp-hedgehog

* Source: <https://github.com/hedgehogqa/fsharp-hedgehog>, release commit
[`a46977278db9a60542e3df3fe0fcd74b90f38ee3`](https://github.com/hedgehogqa/fsharp-hedgehog/tree/a46977278db9a60542e3df3fe0fcd74b90f38ee3)
(Hedgehog 2.0.4; the repository has no tag for this release)
* Copied into: `tests/Hedgehog.MSTest` (the Hedgehog MSTest adapter), from `src/Hedgehog.NUnit`: `Prelude.fs`,
`ReflectionHelpers.fs`, `AutoGenConfig.fs`, `IPropertyAttribute.fs`, `RecheckAttribute.fs`, `GenAttribute.fs`,
`GenAttribute.Prelude.fs`, `PropertyContext.fs`, `InternalLogic.fs`, `PropertiesAttribute.fs` and, adapted from
NUnit to MSTest, `PropertyAttribute.fs`
* Ported into: `tests/Hedgehog.MSTest.Tests` (the adapter's suite), rewritten for MSTest, from
`tests/Hedgehog.Xunit.Tests.FSharp/PropertyTests.fs`, `tests/Hedgehog.NUnit.Tests.FSharp/PropertyTests.fs` and
`tests/Hedgehog.NUnit.Tests.FSharp/GenAttributePreludeTests.fs`: `Common.fs`, `PropertyTests.fs` and
`GenAttributePreludeTests.fs`
* License: Apache License, Version 2.0

```text
Copyright (c) 2016 Jacob Stanley, Nikos Baxevanis

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
```
58 changes: 43 additions & 15 deletions build/build.fs
Original file line number Diff line number Diff line change
Expand Up @@ -353,16 +353,42 @@ let fsharpAnalyzers _ =
dotnet.fsharpAnalyzer id args
)

/// <summary>
/// Runs <c>dotnet test</c> without building for every test application, in the configuration of the executing targets
/// and with the given arguments.
/// </summary>
/// <remarks>
/// The arguments are written by hand, because
/// <see cref="M:Fake.DotNet.DotNet.test(Microsoft.FSharp.Core.FSharpFunc{Fake.DotNet.DotNet.TestOptions,Fake.DotNet.DotNet.TestOptions},System.String)"/>
/// cannot serve the Microsoft.Testing.Platform runner of the .NET 10 SDK: it adds MSBuild switches such as
/// <c>/nodeReuse:False</c>, which that runner hands to the test application, where they are an invalid command line,
/// and it offers the options of VSTest, which that runner does not have (https://github.com/fsprojects/FAKE/issues/2896).
/// https://github.com/fsprojects/FAKE/pull/2903 adds a function for the runner; once FAKE releases it, it replaces
/// this one.
/// </remarks>
let dotnetTestApplications ctx (args : string list) =
Comment thread
xperiandri marked this conversation as resolved.
let dotnetConfiguration = configuration (ctx.Context.AllExecutingTargets) |> string

!!testsGlob
|> Seq.iter (fun testProject ->
[
"--project"
quoted testProject
"--no-build"
"--configuration"
dotnetConfiguration
yield! args
]
|> String.concat " "
|> DotNet.exec id "test"
|> failOnBadExitAndPrint
)

let dotnetTest ctx =
// Create test results directory if it doesn't exist
Directory.create testResultsDir

let dotnetConfiguration = configuration (ctx.Context.AllExecutingTargets) |> string

let args = [
"--no-build"
"--configuration"
dotnetConfiguration
dotnetTestApplications ctx [
if enableCodeCoverage then
"--coverage"
"--coverage-output-format"
Expand All @@ -371,13 +397,12 @@ let dotnetTest ctx =
quoted testResultsDir
]

!!testsGlob
|> Seq.iter (fun testProject ->
[ "--project"; quoted testProject; yield! args ]
|> String.concat " "
|> DotNet.exec id "test"
|> failOnBadExitAndPrint
)
/// <summary>
/// Lists the tests of every test application without running them. MSTest 4 fails the discovery of a whole assembly
/// when one test method has a signature that it cannot run, such as a property method that returns a value, and the F#
/// build gives no warning for it; listing reports that before the run, which needs the emulator, starts.
/// </summary>
let dotnetListTests ctx = dotnetTestApplications ctx [ "--list-tests" ]

let generateCoverageReport _ =

Expand All @@ -392,8 +417,8 @@ let generateCoverageReport _ =
sprintf "-targetdir:\"%s\"" coverageReportDir
// Add source dir
sprintf "-sourcedirs:\"%s\"" sourceDirs
// Ignore test assemblies and the helper libraries they share
sprintf "-assemblyfilters:\"%s\"" "-*.Tests;-*.Tests.Infrastructure"
// Ignore test assemblies, the helper libraries they share, the Hedgehog MSTest adapter and Hedgehog itself
sprintf "-assemblyfilters:\"%s\"" "-*.Tests;-*.Tests.Infrastructure;-Hedgehog;-Hedgehog.MSTest"
// Generate HTML and Cobertura reports
sprintf "-reporttypes:%s" "Html;Cobertura"
]
Expand Down Expand Up @@ -639,6 +664,7 @@ let initTargets (ctx : Context.FakeExecutionContext) =
Target.createFinal "DeleteChangelogBackupFile" deleteChangelogBackupFile // Do NOT put this in the dependency chain
Target.create "DotnetBuild" dotnetBuild
Target.create "FSharpAnalyzers" fsharpAnalyzers
Target.create "DotnetListTests" dotnetListTests
Target.create "DotnetTest" dotnetTest
Target.create "GenerateCoverageReport" generateCoverageReport
Target.create "ShowCoverageReport" showCoverageReport
Expand Down Expand Up @@ -700,6 +726,7 @@ let initTargets (ctx : Context.FakeExecutionContext) =

"DotnetRestore" =?> ("CheckFormatCode", isCI.Value)
==> "DotnetBuild"
==> "DotnetListTests"
==> "DotnetTest"
==> "DotnetPack"
==> "PublishToNuGet"
Expand All @@ -710,6 +737,7 @@ let initTargets (ctx : Context.FakeExecutionContext) =
=?> ("CheckFormatCode", isCI.Value)
=?> ("GenerateAssemblyInfo", isPublishToGitHub)
==> "DotnetBuild"
==> "DotnetListTests"
==> "DotnetTest"
==> "DotnetPack"
==>! "PublishToGitHub"
Expand Down
10 changes: 7 additions & 3 deletions tests/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@
</PropertyGroup>

<!--
Every test project shares the test infrastructure (fixtures, emulator budget, assertion helpers); the
infrastructure project itself is excluded, because a project cannot reference itself.
Every test project shares the test infrastructure (fixtures, emulator budget, assertion helpers). Excluded are
the infrastructure project itself, because a project cannot reference itself, and the Hedgehog MSTest adapter
and its suite, which stay free of this repository's projects: the adapter is also proposed to
hedgehogqa/fsharp-hedgehog, and its package replaces both once upstream publishes it.
-->
<ItemGroup Condition="'$(MSBuildProjectName)' != 'FSharp.Azure.Cosmos.Tests.Infrastructure'">
<ItemGroup Condition="'$(MSBuildProjectName)' != 'FSharp.Azure.Cosmos.Tests.Infrastructure'
AND '$(MSBuildProjectName)' != 'Hedgehog.MSTest'
AND '$(MSBuildProjectName)' != 'Hedgehog.MSTest.Tests'">
<ProjectReference Include="$(MSBuildThisFileDirectory)Cosmos.Tests.Infrastructure/FSharp.Azure.Cosmos.Tests.Infrastructure.fsproj" />
</ItemGroup>
</Project>
57 changes: 57 additions & 0 deletions tests/Hedgehog.MSTest.Tests/Common.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
// The configurations and generator attributes that the tests share, from the suites of hedgehogqa/fsharp-hedgehog at
// the Hedgehog 2.0.4 release commit a46977278db9a60542e3df3fe0fcd74b90f38ee3 (tests/Hedgehog.Xunit.Tests.FSharp and
// tests/Hedgehog.NUnit.Tests.FSharp, PropertyTests.fs).
// Copyright (c) 2016 Jacob Stanley, Nikos Baxevanis. Licensed under the Apache License, Version 2.0
// (http://www.apache.org/licenses/LICENSE-2.0); see THIRD-PARTY-NOTICES.md at the root of this repository.
// Changes: the generator attributes carry the Attribute suffix; upstream declares PropertyInt13Attribute and
// PropertiesInt13Attribute next to their tests.
// The file is formatted with Fantomas, under the settings of this repository.

namespace Hedgehog.MSTest.Tests

open System
open Hedgehog
open Hedgehog.FSharp
open Hedgehog.MSTest

/// An AutoGenConfig type whose every int is 13.
type Int13 =
static member __ =
AutoGenConfig.defaults
|> AutoGenConfig.addGenerator (Gen.constant 13)

/// An AutoGenConfig type whose every int is 2718.
type Int2718 =
static member __ =
AutoGenConfig.empty
|> AutoGenConfig.addGenerator (Gen.constant 2718)

/// An AutoGenConfig type whose every int is 13 and every string is "A".
type Int13A =
static member __ =
AutoGenConfig.empty
|> AutoGenConfig.addGenerator (Gen.constant 13)
|> AutoGenConfig.addGenerator (Gen.constant "A")

/// Sets an int parameter to 5.
type Int5Attribute () =
inherit GenAttribute<int> ()
override _.Generator = Gen.constant 5

/// Sets an int parameter to 6.
type Int6Attribute () =
inherit GenAttribute<int> ()
override _.Generator = Gen.constant 6

/// Generates an int parameter from a constant range.
type IntConstantRangeAttribute (min : int, max : int) =
inherit GenAttribute<int> ()
override _.Generator = Range.constant min max |> Gen.int32

/// A PropertyAttribute subclass that names Int13 itself.
type PropertyInt13Attribute () =
inherit PropertyAttribute (typeof<Int13>)

/// A PropertiesAttribute subclass that names Int13 itself.
type PropertiesInt13Attribute () =
inherit PropertiesAttribute (typeof<Int13>)
Loading
Loading