namespace ZB.MOM.WW.MxGateway.IntegrationTests; public sealed class IntegrationTestEnvironmentTests { /// Verifies that live MXAccess tests use correct environment variable name. [Fact] public void LiveMxAccessTests_AreOptInByEnvironmentVariable() { Assert.Equal( "MXGATEWAY_RUN_LIVE_MXACCESS_TESTS", IntegrationTestEnvironment.LiveMxAccessVariableName); } /// Verifies that worker executable uses correct environment variable name. [Fact] public void LiveMxAccessWorkerExecutable_UsesDocumentedEnvironmentVariable() { Assert.Equal( "MXGATEWAY_LIVE_MXACCESS_WORKER_EXE", IntegrationTestEnvironment.LiveMxAccessWorkerExecutableVariableName); } /// Verifies that repository root resolution accepts git worktree files. [Fact] public void ResolveRepositoryRoot_AcceptsGitWorktreeFile() { string temporaryRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); string nestedDirectory = Path.Combine(temporaryRoot, "tests", "bin"); try { Directory.CreateDirectory(nestedDirectory); Directory.CreateDirectory(Path.Combine(temporaryRoot, "src")); File.WriteAllText(Path.Combine(temporaryRoot, ".git"), "gitdir: ../.git/worktrees/test"); // Pass temporaryRoot as the stop-boundary so the walker can never leak // into ambient ancestors of Path.GetTempPath() (IntegrationTests-025). string repositoryRoot = IntegrationTestEnvironment.ResolveRepositoryRoot( nestedDirectory, stopBoundary: temporaryRoot); Assert.Equal(temporaryRoot, repositoryRoot); } finally { if (Directory.Exists(temporaryRoot)) { Directory.Delete(temporaryRoot, recursive: true); } } } /// /// Verifies that /// throws with a diagnostic message when /// the walk exhausts without finding a repository root. The previous silent /// fallback to Directory.GetCurrentDirectory() masked misconfiguration /// (IntegrationTests-022); operators get a clear, actionable failure instead. /// The stopBoundary isolates the walker from ambient ancestors of /// (a redirected TMP, a co-located checkout /// at C:\src, etc.) that could otherwise satisfy /// IsRepositoryRoot and make this assertion flake on contributor or CI /// boxes — see IntegrationTests-025. /// [Fact] public void ResolveRepositoryRoot_NoMarkers_ThrowsInvalidOperationExceptionNamingStartAndMarkers() { string isolatedRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); string isolatedStart = Path.Combine(isolatedRoot, "nested"); try { Directory.CreateDirectory(isolatedStart); InvalidOperationException ex = Assert.Throws( () => IntegrationTestEnvironment.ResolveRepositoryRoot( isolatedStart, stopBoundary: isolatedRoot)); Assert.Contains(isolatedStart, ex.Message, StringComparison.Ordinal); Assert.Contains(".git", ex.Message, StringComparison.Ordinal); Assert.Contains(".sln", ex.Message, StringComparison.Ordinal); Assert.Contains( IntegrationTestEnvironment.LiveMxAccessWorkerExecutableVariableName, ex.Message, StringComparison.Ordinal); } finally { if (Directory.Exists(isolatedRoot)) { Directory.Delete(isolatedRoot, recursive: true); } } } /// /// Verifies the stopBoundary parameter on /// isolates the /// walker from ambient ancestors that happen to satisfy IsRepositoryRoot /// — the precise failure mode IntegrationTests-025 describes. The test /// deliberately constructs an outer directory that *does* carry repository-root /// markers (src/ + .git) and an inner isolated chain that does /// not. Without the boundary the walker would happily stop at the outer /// directory; with the boundary it must throw because the chain it can see /// carries no markers. A future refactor that dropped or mis-honored the /// boundary would surface here as a failed assertion instead of a silent flake /// in CI. /// [Fact] public void ResolveRepositoryRoot_StopBoundary_IsolatesWalkerFromAmbientAncestorMarkers() { string outerRoot = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); string innerBoundary = Path.Combine(outerRoot, "inner"); string isolatedStart = Path.Combine(innerBoundary, "nested"); try { // Outer directory satisfies IsRepositoryRoot — it is the "ambient // ancestor" the production walker would otherwise stop at. Directory.CreateDirectory(Path.Combine(outerRoot, "src")); File.WriteAllText(Path.Combine(outerRoot, ".git"), "gitdir: ../.git/worktrees/test"); // Inner chain carries no markers. The boundary sits between the inner // chain and the outer marker-bearing ancestor. Directory.CreateDirectory(isolatedStart); // Sanity: without the boundary the production walker reaches outerRoot // and silently returns it — the exact ambient-ancestor leak. string leakedRoot = IntegrationTestEnvironment.ResolveRepositoryRoot(isolatedStart); Assert.Equal(outerRoot, leakedRoot); // With the boundary the walker is sealed inside the inner chain and // must throw — the marker on outerRoot is invisible to it. InvalidOperationException ex = Assert.Throws( () => IntegrationTestEnvironment.ResolveRepositoryRoot( isolatedStart, stopBoundary: innerBoundary)); Assert.Contains(isolatedStart, ex.Message, StringComparison.Ordinal); } finally { if (Directory.Exists(outerRoot)) { Directory.Delete(outerRoot, recursive: true); } } } }