diff --git a/.github/instructions/ComponentTests.instructions.md b/.github/instructions/ComponentTests.instructions.md new file mode 100644 index 00000000000..ecca1507aee --- /dev/null +++ b/.github/instructions/ComponentTests.instructions.md @@ -0,0 +1,132 @@ +--- +applyTo: + - "tests/FSharp.Compiler.ComponentTests/**/*.fs" +--- + +# ComponentTests DSL + +Tests use a pipeline: **Create → Configure → Action → Assert**. The action verb is mandatory — never pipe a `CompilationUnit` directly into an assertion. + +## Actions (pick the cheapest that covers what you're testing) + +```fsharp +// Type errors only, no codegen — fastest +FSharp "..." +|> typecheck +|> shouldSucceed + +// Full compile, produces assembly +FSharp "..." +|> compile +|> shouldSucceed + +// IL shape verification (needs compile) +FSharp "..." +|> compile +|> verifyILContains [".method"] + +// Compile + execute (needs EntryPoint and asExe) +FSharp "..." +|> compileExeAndRun +|> shouldSucceed + +// FSI in-process +Fsx "..." +|> eval +|> withEvalValueEquals 2 + +// FSI subprocess +Fsx "..." +|> runFsi +|> withStdOutContains "hello" +``` + +Use `typecheck` for anything that doesn't need IL or runtime. Use `compile` only when you need the assembly (IL checks, interop). Use `compileExeAndRun` only when testing runtime behavior. + +## Diagnostics + +```fsharp +// Exact diagnostic with location and message +FSharp "..." +|> typecheck +|> shouldFail +|> withDiagnostics [ + (Error 73, Line 3, Col 5, Line 3, Col 10, "internal error: ...") + (Warning 20, Line 5, Col 1, Line 5, Col 8, "The result of this expression...") +] + +// Just error code (when message/location don't matter) +FSharp "..." +|> typecheck +|> shouldFail +|> withErrorCode 73 +``` + +## C# interop + +```fsharp +let csLib = + CSharp """public interface I { void M(out int v); }""" + |> withName "CsLib" + +FSharp """ +open CsLib +type T() = interface I with member _.M(v) = v <- 42 +""" +|> withReferences [csLib] +|> compile +|> shouldSucceed +``` + +## Regression test template + +```fsharp +// https://github.com/dotnet/fsharp/issues/NNNNN +[] +let ``Issue NNNNN - brief description`` () = + FSharp """ +// minimal repro from issue + """ + |> asLibrary + |> typecheck + |> shouldSucceed +``` + +## Local helpers + +If configuration becomes long and boilerplate, extract a local helper or use an existing one in the same module: + +```fsharp +// Local helper for repeated configuration +let typecheckWithPreview source = + source + |> asLibrary + |> withLangVersionPreview + |> withOptions ["--test:ErrorRanges"] + |> typecheck + +// Usage +FSharp "..." +|> typecheckWithPreview +|> shouldSucceed +``` + +## Common mistakes + +- Missing action: `FSharp "..." |> shouldSucceed` — won't compile, `shouldSucceed` expects `CompilationResult` +- Missing `asExe` for runtime tests: `FSharp "..." |> compile |> run` fails on library output +- Using `compile` when `typecheck` suffices — wastes CI time + +## Platform attributes + +Use `[]` unless the test requires a specific runtime: +- `[]` — .NET Core only +- `[]` — .NET Framework only +- `[]` — Windows only + +## Workflow + +1. Write test with explicit pipeline +2. Build: `dotnet build tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj -c Release` +3. Run: `dotnet test --project tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj -c Release --no-build -- --filter-method "*TestName*"` +4. Format: `dotnet fantomas ` diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Constants/Constants.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Constants/Constants.fs index fd1d8440aef..b61a9043e5f 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Constants/Constants.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/UnitsOfMeasure/Constants/Constants.fs @@ -40,3 +40,20 @@ module Constants = (Error 636, Line 22, Col 9, Line 22, Col 15, "Units-of-measure are only supported on float, float32, decimal, and integer types.") (Error 636, Line 23, Col 9, Line 23, Col 15, "Units-of-measure are only supported on float, float32, decimal, and integer types.") ] + + // https://github.com/dotnet/fsharp/issues/6929 + [] + let ``Issue 6929 - Literal bindings preserve units of measure`` () = + FSharp + """ +[] type rad + +[] +let pi = 3.14 + +let a = pi + +let f (x: float) = x +let _ = f a + """ + |> shouldSucceed