Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
dd8667c
Add support for Microsoft.Testing.Platform
Evangelink Feb 19, 2024
288aaba
Update test and fix infra
Evangelink Feb 19, 2024
0a50cf2
Merge branch 'main' into microsoft-testing-platform
Evangelink Jun 24, 2024
f5901b8
Update PR
Evangelink Jun 24, 2024
0f8f90d
Merge branch 'main' into microsoft-testing-platform
Evangelink Jul 30, 2024
4b58410
Fix missing parts
Evangelink Jul 30, 2024
e76696c
Remove whitespaces
Evangelink Jul 30, 2024
0d0ac6f
Refactor tests to depends on nuget produced by build
Evangelink Aug 1, 2024
642d532
fix ci
Alxandr Aug 25, 2024
d15d33c
Merge branch 'main' into microsoft-testing-platform
Alxandr Aug 25, 2024
8a41bbf
clean
Alxandr Aug 25, 2024
ca99581
Bump version to 1.3.2
Evangelink Aug 26, 2024
9af6410
Update project to enable properties based on CLI
Evangelink Aug 26, 2024
5034051
chore: add ability to run failing tests
Alxandr Aug 31, 2024
084d411
check failing tests
Alxandr Aug 31, 2024
6c447cf
ci: use bash instead of pwsh
Alxandr Aug 31, 2024
a142595
Change default of some properties
Evangelink Sep 10, 2024
b0a4df9
Merge branch 'main' into microsoft-testing-platform
Evangelink Sep 10, 2024
dbc8f68
Update Directory.Packages.props
Evangelink Sep 11, 2024
6c3553f
Update opt-out condition
Evangelink Sep 11, 2024
d87e225
Merge branch 'main' into microsoft-testing-platform
Evangelink Nov 1, 2024
739bb2c
Remove nullable disable
Evangelink Nov 1, 2024
5ac9596
Handle last few issues
Evangelink Nov 1, 2024
3bce11a
Update src/YoloDev.Expecto.TestSdk/build/net6.0/YoloDev.Expecto.TestS…
Evangelink Nov 4, 2024
718ffa0
Merge branch 'main' into microsoft-testing-platform
Evangelink Jan 14, 2025
fef67cc
Fix nullability issues
Evangelink Jan 14, 2025
1c4389d
EnableExpectoRunner -> EnableExpectoTestingPlatformIntegration
Evangelink Jan 17, 2025
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
15 changes: 4 additions & 11 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,14 @@ jobs:
- name: 🔽 Setup dotnet from global.json
uses: actions/setup-dotnet@v3

- name: 🔽 Setup just
uses: extractions/setup-just@v1

- name: 🔍 Print dotnet info
run: dotnet --info

- name: 🔽 Restore
run: dotnet restore -p:Configuration=Release

- name: 🔨 Build
run: dotnet build --configuration Release

- name: 🧪 Test
run: dotnet test --no-build --configuration Release

- name: 📦 Pack
run: dotnet pack --configuration Release --no-build
if: ${{ matrix.os == 'ubuntu-latest' }}
run: just test

- name: 🔼 Upload packages as artifact
uses: actions/upload-artifact@v3
Expand Down
58 changes: 58 additions & 0 deletions .justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
[private]
@list:
just --list

restore:
dotnet restore -p:Configuration=Release

build: restore
dotnet build --configuration Release --no-restore

pack: build
dotnet pack --configuration Release --no-build

test-platform: pack
dotnet clean ./test/Sample.Test/Sample.Test.fsproj -v:quiet
dotnet test ./test/Sample.Test/Sample.Test.fsproj -p:EnableExpectoTestingPlatformIntegration=true -p:IncludeFailingTests=false

test-platform-failing: pack
dotnet clean ./test/Sample.Test/Sample.Test.fsproj -v:quiet
dotnet test ./test/Sample.Test/Sample.Test.fsproj -p:EnableExpectoTestingPlatformIntegration=true -p:IncludeFailingTests=true

test-legacy: pack
dotnet clean ./test/Sample.Test/Sample.Test.fsproj -v:quiet
dotnet test ./test/Sample.Test/Sample.Test.fsproj -p:EnableExpectoTestingPlatformIntegration=false -p:IncludeFailingTests=false

test-legacy-failing: pack
dotnet clean ./test/Sample.Test/Sample.Test.fsproj -v:quiet
dotnet test ./test/Sample.Test/Sample.Test.fsproj -p:EnableExpectoTestingPlatformIntegration=false -p:IncludeFailingTests=true

@check-platform:
#!/usr/bin/env bash
just test-platform

just test-platform-failing
status=$?

if [ $status -eq 0 ]; then
echo "Expected tests to fail, but they passed (status code: $Status)"
exit 1
fi

echo "Test run worked as expected"

@check-legacy:
#!/usr/bin/env bash
just test-legacy

just test-legacy-failing
status=$?

if [ $status -eq 0 ]; then
echo "Expected tests to fail, but they passed (status code: $Status)"
exit 1
fi

echo "Test run worked as expected"

@test: check-platform check-legacy
4 changes: 2 additions & 2 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<Project>

<ItemGroup>
<PackageVersion Include="Expecto" Version="[10.0, 11.0)" />
<PackageVersion Include="FSharp.Core" Version="[7.0.200,)" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
<PackageVersion Include="Microsoft.Testing.Extensions.VSTestBridge" Version="1.5.1" />
<PackageVersion Include="Microsoft.Testing.Platform.MSBuild" Version="1.5.1" />
<PackageVersion Include="Microsoft.TestPlatform.ObjectModel" Version="17.12.0" />
<PackageVersion Include="System.Collections.Immutable" Version="[6.0.1,)" />
</ItemGroup>

</Project>
28 changes: 5 additions & 23 deletions YoloDev.Expecto.TestSdk.sln
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26124.0
# Visual Studio Version 17
VisualStudioVersion = 17.12.35129.301
MinimumVisualStudioVersion = 15.0.26124.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{FCE4C28E-CF2A-423F-9E7A-8A13DAACBF96}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "YoloDev.Expecto.TestSdk", "src\YoloDev.Expecto.TestSdk\YoloDev.Expecto.TestSdk.fsproj", "{06D3B976-762E-4645-B70E-C87B1EDE1CEE}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{C5F68231-8575-44BC-B2CD-5163268E8A45}"
EndProject
Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "Sample.Test", "test\Sample.Test\Sample.Test.fsproj", "{2DADC6BD-672C-4B40-B0DA-0C6AD4F372BE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -20,9 +15,6 @@ Global
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{06D3B976-762E-4645-B70E-C87B1EDE1CEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{06D3B976-762E-4645-B70E-C87B1EDE1CEE}.Debug|Any CPU.Build.0 = Debug|Any CPU
Expand All @@ -36,21 +28,11 @@ Global
{06D3B976-762E-4645-B70E-C87B1EDE1CEE}.Release|x64.Build.0 = Release|x64
{06D3B976-762E-4645-B70E-C87B1EDE1CEE}.Release|x86.ActiveCfg = Release|x86
{06D3B976-762E-4645-B70E-C87B1EDE1CEE}.Release|x86.Build.0 = Release|x86
{2DADC6BD-672C-4B40-B0DA-0C6AD4F372BE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2DADC6BD-672C-4B40-B0DA-0C6AD4F372BE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2DADC6BD-672C-4B40-B0DA-0C6AD4F372BE}.Debug|x64.ActiveCfg = Debug|x64
{2DADC6BD-672C-4B40-B0DA-0C6AD4F372BE}.Debug|x64.Build.0 = Debug|x64
{2DADC6BD-672C-4B40-B0DA-0C6AD4F372BE}.Debug|x86.ActiveCfg = Debug|x86
{2DADC6BD-672C-4B40-B0DA-0C6AD4F372BE}.Debug|x86.Build.0 = Debug|x86
{2DADC6BD-672C-4B40-B0DA-0C6AD4F372BE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2DADC6BD-672C-4B40-B0DA-0C6AD4F372BE}.Release|Any CPU.Build.0 = Release|Any CPU
{2DADC6BD-672C-4B40-B0DA-0C6AD4F372BE}.Release|x64.ActiveCfg = Release|x64
{2DADC6BD-672C-4B40-B0DA-0C6AD4F372BE}.Release|x64.Build.0 = Release|x64
{2DADC6BD-672C-4B40-B0DA-0C6AD4F372BE}.Release|x86.ActiveCfg = Release|x86
{2DADC6BD-672C-4B40-B0DA-0C6AD4F372BE}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{06D3B976-762E-4645-B70E-C87B1EDE1CEE} = {FCE4C28E-CF2A-423F-9E7A-8A13DAACBF96}
{2DADC6BD-672C-4B40-B0DA-0C6AD4F372BE} = {C5F68231-8575-44BC-B2CD-5163268E8A45}
EndGlobalSection
EndGlobal
22 changes: 22 additions & 0 deletions src/YoloDev.Expecto.TestSdk/TestApplicationHelpers.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace YoloDev.Expecto.TestSdk

open System.Reflection

open Microsoft.Testing.Extensions.VSTestBridge.Capabilities
open Microsoft.Testing.Extensions.VSTestBridge.Helpers
open Microsoft.Testing.Platform.Builder
open Microsoft.Testing.Platform.Capabilities.TestFramework

module TestApplicationBuilderExtensions =
let addExpectoFramework (getTestAssemblies: unit -> Assembly seq) (builder: ITestApplicationBuilder) =
let expectoExtension = ExpectoExtension()
builder.AddRunSettingsService expectoExtension
builder.AddTestCaseFilterService expectoExtension
builder.RegisterTestFramework (
(fun _ -> TestFrameworkCapabilities(VSTestBridgeExtensionBaseCapabilities())),
(fun capabilities serviceProvider -> new ExpectoTestFramework(expectoExtension, getTestAssemblies, serviceProvider, capabilities))
) |> ignore

module TestingPlatformBuilderHook =
let AddExtensions(builder: ITestApplicationBuilder, arguments: string array) =
TestApplicationBuilderExtensions.addExpectoFramework (fun () -> [ Assembly.GetEntryAssembly() ]) builder
7 changes: 6 additions & 1 deletion src/YoloDev.Expecto.TestSdk/YoloDev.Expecto.TestSdk.fsproj
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<Project Sdk="YoloDev.Sdk">
<Project Sdk="YoloDev.Sdk">

<PropertyGroup>
<AssemblyName>expecto.visualstudio.dotnetcore.testadapter</AssemblyName>
<!-- puts build outputs in build folder in nupkg -->
<BuildOutputTargetFolder>build</BuildOutputTargetFolder>
<OutputType>Exe</OutputType>
<PackageId>$(MSBuildProjectName)</PackageId>
<IsTestingPlatformApplication>false</IsTestingPlatformApplication>
</PropertyGroup>

<ItemGroup>
Expand All @@ -16,17 +17,21 @@
<Compile Include="discovery.fs" />
<Compile Include="execution.fs" />
<Compile Include="adapter.fs" />
<Compile Include="TestApplicationHelpers.fs" />
<Compile Include="main.fs" />
</ItemGroup>

<ItemGroup>
<None Include="build/net6.0/YoloDev.Expecto.TestSdk.props" Pack="true" PackagePath="build\net6.0\" />
<None Include="build/net6.0/YoloDev.Expecto.TestSdk.targets" Pack="true" PackagePath="build\net6.0\" />
<None Include="build/net6.0/_._" Pack="true" PackagePath="lib\net6.0\" Visible="false" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="FSharp.Core" />
<PackageReference Include="Expecto" />
<PackageReference Include="Microsoft.Testing.Extensions.VSTestBridge" />
<PackageReference Include="Microsoft.Testing.Platform.MSBuild" />
<PackageReference Include="Microsoft.TestPlatform.ObjectModel" PrivateAssets="all" />
<PackageReference Include="System.Collections.Immutable" />
</ItemGroup>
Expand Down
56 changes: 42 additions & 14 deletions src/YoloDev.Expecto.TestSdk/adapter.fs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
namespace YoloDev.Expecto.TestSdk

open Expecto.Impl
open Expecto.Tests
open System.IO
open System.Threading
open System.Diagnostics
open Microsoft.Testing.Extensions.VSTestBridge
open Microsoft.Testing.Extensions.VSTestBridge.Requests
open Microsoft.VisualStudio.TestPlatform.ObjectModel
open Microsoft.VisualStudio.TestPlatform.ObjectModel.Adapter
open Microsoft.VisualStudio.TestPlatform.ObjectModel.Logging
open System.Threading.Tasks
open System.Reflection

[<FileExtension(".dll")>]
[<FileExtension(".exe")>]
Expand All @@ -34,24 +35,17 @@ type VsTestAdapter() =

interface System.IDisposable with
member x.Dispose() =
match cts with
| null -> ()
| s -> s.Dispose()
cts.Dispose()

interface ITestDiscoverer with
member x.DiscoverTests(sources, discoveryContext, logger, discoverySink) =
x.Breakpoint()

let sources = Guard.argNotNull "sources" sources
let logger = Guard.argNotNull "logger" logger
let discoverySink = Guard.argNotNull "discoverySink" discoverySink

let stopwatch = Stopwatch.StartNew()
let logger = Logger(logger, stopwatch)

let runSettings =
Option.ofObj discoveryContext
|> Option.bind (fun c -> Option.ofObj c.RunSettings)
Option.ofObj discoveryContext.RunSettings
|> Option.map (RunSettings.read logger)
|> Option.defaultValue RunSettings.defaultSettings

Expand All @@ -62,7 +56,7 @@ type VsTestAdapter() =
interface ITestExecutor with
member x.Cancel() = cts.Cancel()

member x.RunTests(tests: TestCase seq, runContext: IRunContext, frameworkHandle: IFrameworkHandle) : unit =
member x.RunTests(tests: TestCase seq, runContext: IRunContext | null, frameworkHandle: IFrameworkHandle | null) : unit =
x.Breakpoint()
let tests = Guard.argNotNull "tests" tests
let runContext = Guard.argNotNull "runContext" runContext
Expand All @@ -80,7 +74,7 @@ type VsTestAdapter() =
Execution.runSpecifiedTests logger runSettings frameworkHandle tests
|> Async.RunSynchronously

member x.RunTests(sources: string seq, runContext: IRunContext, frameworkHandle: IFrameworkHandle) : unit =
member x.RunTests(sources: string seq, runContext: IRunContext | null, frameworkHandle: IFrameworkHandle | null) : unit =
x.Breakpoint()
let sources = Guard.argNotNull "sources" sources
let runContext = Guard.argNotNull "runContext" runContext
Expand All @@ -102,3 +96,37 @@ type VsTestAdapter() =

Execution.runTests logger runSettings frameworkHandle sources
|> Async.RunSynchronously

/// Defines the identity of the Expecto extension for Microsoft.Testing.Platform.
type ExpectoExtension() =
interface Microsoft.Testing.Platform.Extensions.IExtension with
member _.Uid = nameof(ExpectoExtension)
member _.Version =
match Assembly.GetExecutingAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>() with
| null -> "0.0.0"
| x -> x.InformationalVersion
member _.DisplayName = "Expecto"
member _.Description = "Expecto test adapter for Microsoft Testing Platform"
member _.IsEnabledAsync() = System.Threading.Tasks.Task.FromResult true

/// Defines the ITestFramework extension of Microsoft.Testing.Platform for Expecto using the VSTest bridge.
type ExpectoTestFramework(extension, getTestAssemblies, serviceProvider, capabilities) =
inherit SynchronizedSingleSessionVSTestBridgedTestFramework(extension, getTestAssemblies, serviceProvider, capabilities) with

let vstestAdapter = new VsTestAdapter()

let discoverTests (request: VSTestDiscoverTestExecutionRequest) =
let discoverer = vstestAdapter :> ITestDiscoverer
discoverer.DiscoverTests(request.AssemblyPaths, request.DiscoveryContext, request.MessageLogger, request.DiscoverySink)
Task.CompletedTask

let runTests (request: VSTestRunTestExecutionRequest) (token: CancellationToken) =
let runner = vstestAdapter :> ITestExecutor
use _ = token.Register (fun _ -> runner.Cancel())
match request.VSTestFilter.TestCases |> Option.ofNullable with
| Some testCases -> runner.RunTests(testCases, request.RunContext, request.FrameworkHandle)
| None -> runner.RunTests(request.AssemblyPaths, request.RunContext, request.FrameworkHandle)
Task.CompletedTask

override _.SynchronizedDiscoverTestsAsync(request, _, _) = discoverTests request
override _.SynchronizedRunTestsAsync(request, _, token) = runTests request token
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
<Project>

<PropertyGroup>
<!-- Makes the new platform/runner opt-in feature -->
<EnableExpectoTestingPlatformIntegration Condition=" '$(EnableExpectoTestingPlatformIntegration)' == '' ">false</EnableExpectoTestingPlatformIntegration>
<!-- Defines the new platform capability -->
<IsTestingPlatformApplication>$(EnableExpectoTestingPlatformIntegration)</IsTestingPlatformApplication>
</PropertyGroup>

<ItemGroup>
<!--
!!! IMPORTANT !!!
DO NOT CHANGE THE GUID, IT'S A WELL KNOWN EXTENSION POINT AND THIS EXTENSION NEEDS TO BE REGISTERED AT THE END
WE HAVE CODE INSIDE THE TASK 'TestingPlatformEntryPoint' TO ENSURE THE ORDER OF THE REGISTRATION BASED ON THIS GUID
-->
<TestingPlatformBuilderHook Include="CFC308E5-E1A5-4B99-8002-17EF4D55D043">
<DisplayName>Expecto</DisplayName>
<TypeFullName>YoloDev.Expecto.TestSdk.TestingPlatformBuilderHook</TypeFullName>
</TestingPlatformBuilderHook>
</ItemGroup>

<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)expecto.visualstudio.dotnetcore.testadapter.dll">
<Link>expecto.visualstudio.dotnetcore.testadapter.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
</None>
<ProjectCapability Include="TestContainer" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<Project>

<!-- Handle the coexistance between testing platform and Microsoft.NET.Test.Sdk -->
<PropertyGroup>
<GenerateTestingPlatformEntryPoint Condition=" '$(GenerateTestingPlatformEntryPoint)' == '' ">$(EnableExpectoTestingPlatformIntegration)</GenerateTestingPlatformEntryPoint>
<GenerateSelfRegisteredExtensions Condition=" '$(GenerateSelfRegisteredExtensions)' == '' ">$(EnableExpectoTestingPlatformIntegration)</GenerateSelfRegisteredExtensions>
<GenerateProgramFile Condition=" '$(EnableExpectoTestingPlatformIntegration)' == 'true' ">false</GenerateProgramFile>
<DisableTestingPlatformServerCapability Condition=" '$(EnableExpectoTestingPlatformIntegration)' != 'true' " >true</DisableTestingPlatformServerCapability>
</PropertyGroup>

<Choose>
<!-- Avoid false warning about missing reference (msbuild bug) -->
<!-- https://github.com/dotnet/msbuild/issues/9698#issuecomment-1945763467 -->
<When Condition=" '$(EnableExpectoTestingPlatformIntegration)' == 'true' ">
<ItemGroup>
<Reference Include="expecto.visualstudio.dotnetcore.testadapter">
<HintPath>$(MSBuildThisFileDirectory)expecto.visualstudio.dotnetcore.testadapter.dll</HintPath>
</Reference>
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<None Include="$(MSBuildThisFileDirectory)expecto.visualstudio.dotnetcore.testadapter.dll">
<Link>expecto.visualstudio.dotnetcore.testadapter.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<Visible>False</Visible>
</None>
</ItemGroup>
</Otherwise>
</Choose>

</Project>
2 changes: 0 additions & 2 deletions src/YoloDev.Expecto.TestSdk/discovery.fs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ module internal Discovery =
let internal discoverTestForSource logger source =
let assembly = System.Reflection.Assembly.LoadFile source

if isNull assembly then failwithf "LoadFile %s returned null" source

getTestForAssembly logger assembly source

let discoverTests logger = Seq.choose (discoverTestForSource logger)
Expand Down
2 changes: 1 addition & 1 deletion src/YoloDev.Expecto.TestSdk/settings.fs
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ module RunSettings =
args |> Map.toSeq |> Seq.choose snd |> List.ofSeq


let read logger (runSettings: IRunSettings) =
let read logger (runSettings: IRunSettings | null) =
let settings = defaultSettings

let runSettingsNode =
Expand Down
1 change: 1 addition & 0 deletions test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.packages/
Loading
Loading