├── .github
├── dotnet.json
├── workflows
│ ├── changelog.config
│ ├── dotnet-file.yml
│ ├── dotnet-env.yml
│ ├── changelog.yml
│ ├── includes.yml
│ ├── publish.yml
│ ├── build.yml
│ └── triage.yml
├── release.yml
└── dependabot.yml
├── assets
├── 32.png
├── icon.png
├── img
│ ├── ciretry.png
│ ├── comment.png
│ ├── timings.png
│ └── progress.png
├── css
│ └── style.scss
└── icon.svg
├── _config.yml
├── src
├── dotnet-retest
│ ├── icon.png
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Extensions.cs
│ ├── readme.md
│ ├── DotnetMuxer.cs
│ ├── help.md
│ ├── dotnet-retest.csproj
│ ├── Process.cs
│ ├── Program.cs
│ ├── RetestCommand.cs
│ └── TrxCommand.cs
├── Directory.props
├── Sample2
│ ├── Sample2.csproj
│ └── NUnitTest.cs
├── Sample
│ ├── Sample.csproj
│ └── UnitTest1.cs
├── nuget.config
├── Directory.Build.props
└── Directory.Build.targets
├── Directory.Build.rsp
├── .gitattributes
├── .gitignore
├── license.txt
├── dotnet-retest.sln
├── osmfeula.txt
├── .editorconfig
├── .netconfig
├── readme.md
└── changelog.md
/.github/dotnet.json:
--------------------------------------------------------------------------------
1 | [
2 | "8.x"
3 | ]
4 |
--------------------------------------------------------------------------------
/assets/32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devlooped/dotnet-retest/HEAD/assets/32.png
--------------------------------------------------------------------------------
/assets/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devlooped/dotnet-retest/HEAD/assets/icon.png
--------------------------------------------------------------------------------
/assets/img/ciretry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devlooped/dotnet-retest/HEAD/assets/img/ciretry.png
--------------------------------------------------------------------------------
/assets/img/comment.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devlooped/dotnet-retest/HEAD/assets/img/comment.png
--------------------------------------------------------------------------------
/assets/img/timings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devlooped/dotnet-retest/HEAD/assets/img/timings.png
--------------------------------------------------------------------------------
/assets/img/progress.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devlooped/dotnet-retest/HEAD/assets/img/progress.png
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-slate
2 |
3 | exclude: [ 'src/', '*.sln', '*.slnx', 'Gemfile*', '*.rsp' ]
4 |
--------------------------------------------------------------------------------
/src/dotnet-retest/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devlooped/dotnet-retest/HEAD/src/dotnet-retest/icon.png
--------------------------------------------------------------------------------
/src/Directory.props:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | dotnet-retest
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Directory.Build.rsp:
--------------------------------------------------------------------------------
1 | # See https://docs.microsoft.com/en-us/visualstudio/msbuild/msbuild-response-files
2 | -nr:false
3 | -m:1
4 | -v:m
5 | -clp:Summary;ForceNoAlign
6 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # normalize by default
2 | * text=auto encoding=UTF-8
3 | *.sh text eol=lf
4 | *.sbn eol=lf
5 |
6 | # These are windows specific files which we may as well ensure are
7 | # always crlf on checkout
8 | *.bat text eol=crlf
9 | *.cmd text eol=crlf
10 |
--------------------------------------------------------------------------------
/src/dotnet-retest/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "dotnet-retest": {
4 | "commandName": "Project",
5 | "commandLineArgs": "-v verbose -- --filter \"FullyQualifiedName!=Sample.UnitTest1.FailsAlways\"",
6 | "workingDirectory": "..\\Sample"
7 | }
8 | }
9 | }
--------------------------------------------------------------------------------
/.github/workflows/changelog.config:
--------------------------------------------------------------------------------
1 | usernames-as-github-logins=true
2 | issues_wo_labels=true
3 | pr_wo_labels=true
4 | exclude-labels=bydesign,dependencies,duplicate,discussion,question,invalid,wontfix,need info,docs
5 | enhancement-label=:sparkles: Implemented enhancements:
6 | bugs-label=:bug: Fixed bugs:
7 | issues-label=:hammer: Other:
8 | pr-label=:twisted_rightwards_arrows: Merged:
9 | unreleased=false
10 |
--------------------------------------------------------------------------------
/src/dotnet-retest/Extensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 |
4 | namespace Devlooped;
5 |
6 | static class Extensions
7 | {
8 | public static StringBuilder AppendLineIndented(this StringBuilder builder, string value, string indent)
9 | {
10 | foreach (var line in value.ReplaceLineEndings().Split(Environment.NewLine))
11 | builder.Append(indent).AppendLine(line);
12 |
13 | return builder;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/assets/css/style.scss:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 | @import "jekyll-theme-slate";
5 |
6 | .inner {
7 | max-width: 960px;
8 | }
9 |
10 | pre, code {
11 | background-color: unset;
12 | font-size: unset;
13 | }
14 |
15 | code {
16 | font-size: 0.80em;
17 | }
18 |
19 | h1 > img {
20 | border: unset;
21 | box-shadow: unset;
22 | vertical-align: middle;
23 | -moz-box-shadow: unset;
24 | -o-box-shadow: unset;
25 | -ms-box-shadow: unset;
26 | }
27 |
--------------------------------------------------------------------------------
/.github/workflows/dotnet-file.yml:
--------------------------------------------------------------------------------
1 | # Synchronizes .netconfig-configured files with dotnet-file
2 | name: dotnet-file
3 | on:
4 | workflow_dispatch:
5 | schedule:
6 | - cron: "0 0 * * *"
7 | push:
8 | branches: [ 'dotnet-file' ]
9 |
10 | env:
11 | DOTNET_NOLOGO: true
12 |
13 | jobs:
14 | run:
15 | permissions:
16 | contents: write
17 | uses: devlooped/oss/.github/workflows/dotnet-file-core.yml@main
18 | secrets:
19 | BOT_NAME: ${{ secrets.BOT_NAME }}
20 | BOT_EMAIL: ${{ secrets.BOT_EMAIL }}
21 | GH_TOKEN: ${{ secrets.GH_TOKEN }}
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | bin
2 | obj
3 | artifacts
4 | pack
5 | TestResults
6 | results
7 | BenchmarkDotNet.Artifacts
8 | /app
9 | .vs
10 | .vscode
11 | .genaiscript
12 | .idea
13 | local.settings.json
14 | .env
15 |
16 | *.suo
17 | *.sdf
18 | *.userprefs
19 | *.user
20 | *.nupkg
21 | *.metaproj
22 | *.tmp
23 | *.log
24 | *.cache
25 | *.binlog
26 | *.zip
27 | __azurite*.*
28 | __*__
29 |
30 | .nuget
31 | *.lock.json
32 | *.nuget.props
33 | *.nuget.targets
34 |
35 | node_modules
36 | _site
37 | .jekyll-metadata
38 | .jekyll-cache
39 | .sass-cache
40 | Gemfile.lock
41 | package-lock.json
42 |
--------------------------------------------------------------------------------
/src/Sample2/Sample2.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/Sample/Sample.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net8.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/.github/release.yml:
--------------------------------------------------------------------------------
1 | changelog:
2 | exclude:
3 | labels:
4 | - bydesign
5 | - dependencies
6 | - duplicate
7 | - question
8 | - invalid
9 | - wontfix
10 | - need info
11 | - techdebt
12 | authors:
13 | - devlooped-bot
14 | - dependabot
15 | - github-actions
16 | categories:
17 | - title: ✨ Implemented enhancements
18 | labels:
19 | - enhancement
20 | - title: 🐛 Fixed bugs
21 | labels:
22 | - bug
23 | - title: 📝 Documentation updates
24 | labels:
25 | - docs
26 | - documentation
27 | - title: 🔨 Other
28 | labels:
29 | - '*'
30 | exclude:
31 | labels:
32 | - dependencies
33 |
--------------------------------------------------------------------------------
/src/Sample2/NUnitTest.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Cryptography;
2 | using NUnit.Framework;
3 | using Assert = NUnit.Framework.Assert;
4 |
5 | namespace Sample;
6 |
7 | [TestFixture]
8 | public class NUnitTest
9 | {
10 | [TestCase("this test, shouldn't break")]
11 | [TestCase("successful case")]
12 | public void ParameterEscapingRetries(string value)
13 | {
14 | // get a simple sha from the string to use as filename using the hex value from the sha1 of the value
15 | var file = "failed" + string.Concat(SHA1.HashData(System.Text.Encoding.UTF8.GetBytes(value)).Select(b => b.ToString("x2"))) + ".txt";
16 |
17 | if (!File.Exists(file))
18 | {
19 | File.WriteAllText(file, "");
20 | Assert.Fail("Fails once");
21 | }
22 |
23 | File.Delete(file);
24 | }
25 |
26 | }
27 |
--------------------------------------------------------------------------------
/src/dotnet-retest/readme.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Open Source Maintenance Fee
4 |
5 | To ensure the long-term sustainability of this project, use of dotnet-retest requires an
6 | [Open Source Maintenance Fee](https://opensourcemaintenancefee.org). While the source
7 | code is freely available under the terms of the [MIT License](https://github.com/devlooped/dotnet-retest/blob/main/license.txt), all other aspects of the
8 | project --including opening or commenting on issues, participating in discussions and
9 | downloading releases-- require [adherence to the Maintenance Fee](https://github.com/devlooped/dotnet-retest/blob/main/osmfeula.txt).
10 |
11 | In short, if you use this project to generate revenue, the [Maintenance Fee is required](https://github.com/devlooped/dotnet-retest/blob/main/osmfeula.txt).
12 |
13 | To pay the Maintenance Fee, [become a Sponsor](https://github.com/sponsors/devlooped) at the corresponding OSMF tier (starting at just $10!).
14 |
15 |
16 |
--------------------------------------------------------------------------------
/license.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) Daniel Cazzulino and Contributors
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/src/dotnet-retest/DotnetMuxer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.IO;
3 | using System.Runtime.InteropServices;
4 |
5 | namespace Devlooped;
6 |
7 | static class DotnetMuxer
8 | {
9 | public static FileInfo? Path { get; }
10 |
11 | static DotnetMuxer()
12 | {
13 | var muxerFileName = ExecutableName("dotnet");
14 | var fxDepsFile = GetDataFromAppDomain("FX_DEPS_FILE");
15 |
16 | if (string.IsNullOrEmpty(fxDepsFile))
17 | return;
18 |
19 | var muxerDir = new FileInfo(fxDepsFile).Directory?.Parent?.Parent?.Parent;
20 | if (muxerDir == null)
21 | return;
22 |
23 | var muxerCandidate = new FileInfo(System.IO.Path.Combine(muxerDir.FullName, muxerFileName));
24 | if (muxerCandidate.Exists)
25 | Path = muxerCandidate;
26 | }
27 |
28 | public static string? GetDataFromAppDomain(string propertyName)
29 | => AppContext.GetData(propertyName) as string;
30 |
31 | public static string ExecutableName(this string withoutExtension)
32 | => RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
33 | ? withoutExtension + ".exe"
34 | : withoutExtension;
35 | }
--------------------------------------------------------------------------------
/.github/workflows/dotnet-env.yml:
--------------------------------------------------------------------------------
1 | name: dotnet-env
2 | on:
3 | workflow_dispatch:
4 | push:
5 | branches:
6 | - main
7 | paths:
8 | - '**/*.*proj'
9 |
10 | jobs:
11 | which-dotnet:
12 | runs-on: ubuntu-latest
13 | permissions:
14 | contents: write
15 | pull-requests: write
16 |
17 | steps:
18 | - name: 🤖 defaults
19 | uses: devlooped/actions-bot@v1
20 | with:
21 | name: ${{ secrets.BOT_NAME }}
22 | email: ${{ secrets.BOT_EMAIL }}
23 | gh_token: ${{ secrets.GH_TOKEN }}
24 | github_token: ${{ secrets.GITHUB_TOKEN }}
25 |
26 | - name: 🤘 checkout
27 | uses: actions/checkout@v4
28 | with:
29 | token: ${{ env.GH_TOKEN }}
30 |
31 | - name: 🤌 dotnet
32 | uses: devlooped/actions-which-dotnet@v1
33 |
34 | - name: ✍ pull request
35 | uses: peter-evans/create-pull-request@v7
36 | with:
37 | base: main
38 | branch: which-dotnet
39 | delete-branch: true
40 | labels: dependencies
41 | title: "⚙ Update dotnet versions"
42 | body: "Update dotnet versions"
43 | commit-message: "Update dotnet versions"
44 | token: ${{ env.GH_TOKEN }}
--------------------------------------------------------------------------------
/.github/workflows/changelog.yml:
--------------------------------------------------------------------------------
1 | name: changelog
2 | on:
3 | workflow_dispatch:
4 | release:
5 | types: [released]
6 |
7 | jobs:
8 | changelog:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: 🤖 defaults
12 | uses: devlooped/actions-bot@v1
13 | with:
14 | name: ${{ secrets.BOT_NAME }}
15 | email: ${{ secrets.BOT_EMAIL }}
16 | gh_token: ${{ secrets.GH_TOKEN }}
17 | github_token: ${{ secrets.GITHUB_TOKEN }}
18 |
19 | - name: 🤘 checkout
20 | uses: actions/checkout@v4
21 | with:
22 | fetch-depth: 0
23 | ref: main
24 | token: ${{ env.GH_TOKEN }}
25 |
26 | - name: ⚙ ruby
27 | uses: ruby/setup-ruby@v1
28 | with:
29 | ruby-version: 3.0.3
30 |
31 | - name: ⚙ changelog
32 | run: |
33 | gem install github_changelog_generator
34 | github_changelog_generator --user ${GITHUB_REPOSITORY%/*} --project ${GITHUB_REPOSITORY##*/} --token $GH_TOKEN --o changelog.md --config-file .github/workflows/changelog.config
35 |
36 | - name: 🚀 changelog
37 | run: |
38 | git add changelog.md
39 | (git commit -m "🖉 Update changelog with ${GITHUB_REF#refs/*/}" && git push) || echo "Done"
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Please see the documentation for all configuration options:
2 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
3 |
4 | version: 2
5 | updates:
6 | - package-ecosystem: nuget
7 | directory: /
8 | schedule:
9 | interval: daily
10 | groups:
11 | Azure:
12 | patterns:
13 | - "Azure*"
14 | - "Microsoft.Azure*"
15 | Identity:
16 | patterns:
17 | - "System.IdentityModel*"
18 | - "Microsoft.IdentityModel*"
19 | System:
20 | patterns:
21 | - "System*"
22 | exclude-patterns:
23 | - "System.IdentityModel*"
24 | Extensions:
25 | patterns:
26 | - "Microsoft.Extensions*"
27 | exclude-patterns:
28 | - "Microsoft.Extensions.AI*"
29 | ExtensionsAI:
30 | patterns:
31 | - "Microsoft.Extensions.AI*"
32 | Web:
33 | patterns:
34 | - "Microsoft.AspNetCore*"
35 | Tests:
36 | patterns:
37 | - "Microsoft.NET.Test*"
38 | - "xunit*"
39 | - "coverlet*"
40 | ThisAssembly:
41 | patterns:
42 | - "ThisAssembly*"
43 | ProtoBuf:
44 | patterns:
45 | - "protobuf-*"
46 | Spectre:
47 | patterns:
48 | - "Spectre.Console*"
49 |
--------------------------------------------------------------------------------
/src/dotnet-retest/help.md:
--------------------------------------------------------------------------------
1 | ```shell
2 | USAGE:
3 | dotnet retest [OPTIONS] [-- [dotnet test options]]
4 |
5 | OPTIONS:
6 | DEFAULT
7 | -h, --help Prints help information
8 | --version Prints version information
9 | --retries 3 Maximum retries when re-running failed tests
10 | --no-summary Whether to emit a summary to console/GitHub
11 | --output Include test output in report
12 | -v, --verbosity Quiet Output display verbosity:
13 | - quiet: only failed tests are displayed
14 | - normal: failed and skipped tests are
15 | displayed
16 | - verbose: failed, skipped and passed tests
17 | are displayed
18 | --gh-comment True Report as GitHub PR comment
19 | --gh-summary True Report as GitHub step summary
20 | ```
21 |
--------------------------------------------------------------------------------
/src/nuget.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.github/workflows/includes.yml:
--------------------------------------------------------------------------------
1 | name: +Mᐁ includes
2 | on:
3 | workflow_dispatch:
4 | push:
5 | branches:
6 | - 'main'
7 | paths:
8 | - '**.md'
9 | - '!changelog.md'
10 | - 'osmfeula.txt'
11 |
12 | jobs:
13 | includes:
14 | runs-on: ubuntu-latest
15 | permissions:
16 | contents: write
17 | pull-requests: write
18 | steps:
19 | - name: 🤖 defaults
20 | uses: devlooped/actions-bot@v1
21 | with:
22 | name: ${{ secrets.BOT_NAME }}
23 | email: ${{ secrets.BOT_EMAIL }}
24 | gh_token: ${{ secrets.GH_TOKEN }}
25 | github_token: ${{ secrets.GITHUB_TOKEN }}
26 |
27 | - name: 🤘 checkout
28 | uses: actions/checkout@v4
29 | with:
30 | token: ${{ env.GH_TOKEN }}
31 |
32 | - name: +Mᐁ includes
33 | uses: devlooped/actions-includes@v1
34 |
35 | - name: 📝 OSMF EULA
36 | shell: pwsh
37 | run: |
38 | $file = "osmfeula.txt"
39 | $props = "src/Directory.Build.props"
40 | if (-not (test-path $file) -or -not (test-path $props)) {
41 | exit 0
42 | }
43 |
44 | $product = dotnet msbuild $props -getproperty:Product
45 | if (-not $product) {
46 | write-error "To use OSMF EULA, ensure the $(Product) property is set in Directory.props"
47 | exit 1
48 | }
49 |
50 | ((get-content -raw $file) -replace '\$product\$',$product).trim() | set-content $file
51 |
52 | - name: ✍ pull request
53 | uses: peter-evans/create-pull-request@v6
54 | with:
55 | add-paths: |
56 | **.md
57 | osmfeula.txt
58 | base: main
59 | branch: markdown-includes
60 | delete-branch: true
61 | labels: docs
62 | author: ${{ env.BOT_AUTHOR }}
63 | committer: ${{ env.BOT_AUTHOR }}
64 | commit-message: +Mᐁ includes
65 | title: +Mᐁ includes
66 | body: +Mᐁ includes
67 | token: ${{ env.GH_TOKEN }}
68 |
--------------------------------------------------------------------------------
/dotnet-retest.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.11.35005.142
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-retest", "src\dotnet-retest\dotnet-retest.csproj", "{30849648-147D-41B7-ACBE-D54AD360E0C8}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample", "src\Sample\Sample.csproj", "{5A647D73-B3A8-49E8-A8A3-AC3CAD00DF48}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sample2", "src\Sample2\Sample2.csproj", "{0F3664F5-4955-4D04-9DBA-FA144E3621F1}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {30849648-147D-41B7-ACBE-D54AD360E0C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {30849648-147D-41B7-ACBE-D54AD360E0C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {30849648-147D-41B7-ACBE-D54AD360E0C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {30849648-147D-41B7-ACBE-D54AD360E0C8}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {5A647D73-B3A8-49E8-A8A3-AC3CAD00DF48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {5A647D73-B3A8-49E8-A8A3-AC3CAD00DF48}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {5A647D73-B3A8-49E8-A8A3-AC3CAD00DF48}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {5A647D73-B3A8-49E8-A8A3-AC3CAD00DF48}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {0F3664F5-4955-4D04-9DBA-FA144E3621F1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {0F3664F5-4955-4D04-9DBA-FA144E3621F1}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {0F3664F5-4955-4D04-9DBA-FA144E3621F1}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {0F3664F5-4955-4D04-9DBA-FA144E3621F1}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {36DBDAFF-AF65-47FF-847A-A2BBD8AB8A95}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/src/Sample/UnitTest1.cs:
--------------------------------------------------------------------------------
1 | using System.Security.Cryptography;
2 |
3 | namespace Sample;
4 |
5 | public class UnitTest1
6 | {
7 | [Fact]
8 | public void FailsAlways()
9 | {
10 | throw new InvalidOperationException("Always fails");
11 | }
12 |
13 | [Theory]
14 | [InlineData(1)]
15 | [InlineData(2)]
16 | public void Test1(int value)
17 | {
18 | Assert.True(value > 0);
19 | }
20 |
21 | [Theory]
22 | [InlineData("this test, shouldn't break")]
23 | [InlineData("successful case")]
24 | public void ParameterEscapingRetries(string value)
25 | {
26 | // get a simple sha from the string to use as filename using the hex value from the sha1 of the value
27 | var file = "failed" + string.Concat(SHA1.HashData(System.Text.Encoding.UTF8.GetBytes(value)).Select(b => b.ToString("x2"))) + ".txt";
28 |
29 | if (!File.Exists(file))
30 | {
31 | File.WriteAllText(file, "");
32 | Assert.Fail("Fails once");
33 | }
34 |
35 | File.Delete(file);
36 | }
37 |
38 | [Fact]
39 | public void FailsOnce()
40 | {
41 | if (!File.Exists("failsonce.txt"))
42 | {
43 | File.WriteAllText("failsonce.txt", "");
44 | Assert.Fail("Fails once");
45 | }
46 |
47 | File.Delete("failsonce.txt");
48 | }
49 |
50 | [Fact]
51 | public void FailsTwice()
52 | {
53 | // Add random delay to simulate actual test execution
54 | Thread.Sleep(Random.Shared.Next(1000, 5000));
55 |
56 | var attempt = int.Parse(
57 | File.Exists("failstwice.txt") ?
58 | File.ReadAllText("failstwice.txt") :
59 | "0");
60 |
61 | if (attempt < 2)
62 | {
63 | File.WriteAllText("failstwice.txt", (attempt + 1).ToString());
64 | Assert.Fail("Fails twice");
65 | }
66 |
67 | // Succeeds
68 | File.Delete("failstwice.txt");
69 | }
70 |
71 | public static IEnumerable