From ebe42ffeba6b957990ed74dac45b6950ddd5cc94 Mon Sep 17 00:00:00 2001 From: Claude Date: Mon, 7 Sep 2026 01:48:53 +0000 Subject: [PATCH] test: make ScopeAfterManualDispose actually dispose while a scope is active [patch] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `ScopeAfterManualDisposeOfCodeBlockerShouldThrowException` was byte-identical to `ScopeWithDisposedCodeBlockerShouldThrowException`: it disposed the CodeBlocker and then asserted that *constructing* a Scope throws. Its name, and its own "Dispose the CodeBlocker while scope is still active" comment, promise something else — and that path was untested. It now opens a scope first, disposes the CodeBlocker out from under it, and asserts that closing the scope throws `ObjectDisposedException` when `EndScope` writes its brace to the disposed writer. CA2000 is suppressed on the one line, with justification: disposing the scope is the act under test and it throws, so a `using` block would let the exception escape the assert rather than reach it. Found by the local SonarCloud reproduction added for #88 (`S4144`), which is also the first end-to-end confirmation that the setup surfaces real findings. CLAUDE.md records what the run reports on `main` as a calibration baseline. The issue's remaining acceptance criterion still needs dashboard access. Full suite: 168 passed. The Sonar run is now clean apart from five pre-existing `S2699` warnings. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01N1cVfacJWw1uM42DUmPfUg --- CLAUDE.md | 7 ++++++- CodeBlocker.Test/ScopeTests.cs | 13 ++++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index f53305a..287dfe1 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,4 +1,4 @@ -# CLAUDE.md +# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. @@ -42,6 +42,11 @@ The opt-in lives in `.sonarlint/sonar-local.props` (the analyzer package) and analyzer package ships disabled). Nothing imports these automatically, so normal builds, the CI pipeline, and packaging are unaffected. +On current `main` the run is clean apart from five `S2699` warnings (test methods that assert +nothing) in `CodeBlocker.Test`. It found and named `S4144` on `ScopeTests.cs` — two test methods with +identical bodies, one of which did not test what its name claimed — which is the kind of finding the +setup exists for. + **Known gap:** SonarCloud reported one new issue on PR #87 that this configuration does not reproduce, and sonarcloud.io is not reachable from the agent sandbox to identify it. The rule behind it is either absent from the analyzer package or shipped disabled and not listed in the diff --git a/CodeBlocker.Test/ScopeTests.cs b/CodeBlocker.Test/ScopeTests.cs index 3592340..3647ed4 100644 --- a/CodeBlocker.Test/ScopeTests.cs +++ b/CodeBlocker.Test/ScopeTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) 2023-2026 ktsu-dev contributors +// Copyright (c) 2023-2026 ktsu-dev contributors namespace CodeBlocker.Tests; @@ -352,16 +352,19 @@ public void ScopeWithEmptyCustomIndentStringShouldWork() [TestMethod] public void ScopeAfterManualDisposeOfCodeBlockerShouldThrowException() { - // Arrange + // Arrange - open a scope, so there is one still active when the CodeBlocker goes away CodeBlocker codeBlocker = CodeBlocker.Create(); +#pragma warning disable CA2000 // Dispose objects before losing scope - disposing the scope is the act under test, and it throws, so a using block would let the exception escape the assert. + Scope scope = new(codeBlocker); +#pragma warning restore CA2000 - // Act - Dispose the CodeBlocker while scope is still active + // Act - Dispose the CodeBlocker while the scope is still active codeBlocker.Dispose(); - // Assert - Creating scope with disposed CodeBlocker should throw + // Assert - Closing the scope writes its brace to the disposed writer - Assert.ThrowsExactly(() => new Scope(codeBlocker)); + Assert.ThrowsExactly(scope.Dispose); } }