Skip to content
Merged
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
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ System-wide microphone mute/unmute with hotkeys, an always-on-top overlay, sound
- Run (Windows): `dotnet run --project MicControl`. The app asks for elevation (`highestAvailable`), so run from an elevated terminal or Visual Studio started as administrator.
- Tests already run on both Windows and Linux. The Windows projects also build on Linux (`EnableWindowsTargeting`).
- Screenshots for the README and releases (the bundled icon font makes Linux renders match Windows, apart from the About page's system details): set `MICCONTROL_SCREENSHOTS=1` and run the tests; `ScreenshotTests` renders the real windows (headless Skia, sample data, light and dark, greyscale text) into `docs/screenshots`. Re-run after visible UI changes and commit the images.
- Fuzzing (from the repo root, after a build): `powershell -ExecutionPolicy Bypass -File tools\Fuzz.ps1 [-Scale 5] [-Seed N]` runs the opt-in suite in `MicControl.Tests/Fuzz/` (`MICCONTROL_FUZZ=1`, a new seed each run, printed with any failure) and `tools/FuzzWav.cs` (damaged WAVs through the playback decoder). `docs/fuzzing-report.md` logs each round: what it covered, up to which commit, and what to try next. A new round reads it first and attacks what earlier rounds missed or what changed since; fuzzers that find something graduate into `Fuzz/`.
- Setup (from the repo root): `installer\build.ps1 [-Version 1.0.0]` publishes the app as one self-contained file and writes `artifacts\MicControl-Setup-<version>.exe`. CI builds it for every push to `master`/`dev` and every PR; a signed `vMAJOR.MINOR.PATCH` tag on `master` drafts a GitHub release, which the developer signs and publishes (see "Branches").

## Installer and updates
Expand Down
34 changes: 34 additions & 0 deletions Sources/MicControl.Tests/Fuzz/FuzzRun.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
namespace MicControl.Tests.Fuzz;

/// <summary>
/// The opt-in fuzz suite: skipped unless MICCONTROL_FUZZ=1 (tools/Fuzz.ps1 sets it). Each run uses a new seed, printed
/// with every failure; MICCONTROL_FUZZ_SEED repeats a run and MICCONTROL_FUZZ_SCALE multiplies the case counts.
/// </summary>
internal static class FuzzRun
{
public static bool Enabled { get; } = Environment.GetEnvironmentVariable("MICCONTROL_FUZZ") == "1";

public static int Seed { get; } = int.TryParse(Environment.GetEnvironmentVariable("MICCONTROL_FUZZ_SEED"), out var seed)
? seed
: System.Random.Shared.Next();

private static readonly double Factor = double.TryParse(Environment.GetEnvironmentVariable("MICCONTROL_FUZZ_SCALE"),
System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out var factor) && factor > 0 ? factor : 1;

public static void Require() => Assert.SkipUnless(Enabled, "Set MICCONTROL_FUZZ=1 (or run tools/Fuzz.ps1) to fuzz.");

/// <summary>A generator for one test: the run's seed mixed with the test's own number, so tests don't share a sequence.</summary>
public static Random Random(int salt) => new(unchecked((Seed * 1_000_003) + salt));

public static int Scale(int cases) => Math.Max(1, (int)(cases * Factor));

/// <summary>Fails with every distinct problem found, and the seed that repeats the run.</summary>
public static void AssertNone(IReadOnlyDictionary<string, string> failures)
{
if (failures.Count > 0)
{
Assert.Fail($"Seed {Seed} (set MICCONTROL_FUZZ_SEED={Seed} to repeat this run)\n\n"
+ string.Join("\n\n", failures.Select(f => f.Key + "\n " + f.Value)));
}
}
}
Loading
Loading