using System.IO; using NUnit.Framework; using MCPForUnity.Editor.Services.Server; using MCPForUnity.Editor.Constants; using UnityEditor; using UnityEngine; namespace MCPForUnityTests.Editor.Services.Server { /// /// Unit tests for PidFileManager component. /// [TestFixture] public class PidFileManagerTests { private PidFileManager _manager; private string _testPidFilePath; [SetUp] public void SetUp() { _manager = new PidFileManager(); // Clear any test state ClearTestEditorPrefs(); } [TearDown] public void TearDown() { // Clean up test files if (!string.IsNullOrEmpty(_testPidFilePath) && File.Exists(_testPidFilePath)) { try { File.Delete(_testPidFilePath); } catch { } } // Clear test state ClearTestEditorPrefs(); } private void ClearTestEditorPrefs() { try { EditorPrefs.DeleteKey(EditorPrefKeys.LastLocalHttpServerPid); } catch { } try { EditorPrefs.DeleteKey(EditorPrefKeys.LastLocalHttpServerPort); } catch { } try { EditorPrefs.DeleteKey(EditorPrefKeys.LastLocalHttpServerStartedUtc); } catch { } try { EditorPrefs.DeleteKey(EditorPrefKeys.LastLocalHttpServerPidArgsHash); } catch { } try { EditorPrefs.DeleteKey(EditorPrefKeys.LastLocalHttpServerPidFilePath); } catch { } try { EditorPrefs.DeleteKey(EditorPrefKeys.LastLocalHttpServerInstanceToken); } catch { } } #region GetPidFilePath Tests [Test] public void GetPidFilePath_ValidPort_ReturnsCorrectPath() { // Act string path = _manager.GetPidFilePath(8080); // Assert Assert.IsNotNull(path); Assert.That(path, Does.Contain("mcp_http_8080.pid")); Assert.That(path, Does.Contain("MCPForUnity")); } [Test] public void GetPidFilePath_DifferentPorts_ReturnsDifferentPaths() { // Act string path1 = _manager.GetPidFilePath(8080); string path2 = _manager.GetPidFilePath(9090); // Assert Assert.AreNotEqual(path1, path2); } [Test] public void GetPidDirectory_ReturnsValidPath() { // Act string dir = _manager.GetPidDirectory(); // Assert Assert.IsNotNull(dir); Assert.That(dir, Does.Contain("MCPForUnity")); Assert.That(dir, Does.Contain("RunState")); } #endregion #region TryReadPid Tests [Test] public void TryReadPid_ValidFile_ReturnsTrueWithPid() { // Arrange _testPidFilePath = _manager.GetPidFilePath(59998); File.WriteAllText(_testPidFilePath, "12345"); // Act bool result = _manager.TryReadPid(_testPidFilePath, out int pid); // Assert Assert.IsTrue(result); Assert.AreEqual(12345, pid); } [Test] public void TryReadPid_FileWithWhitespace_ParsesCorrectly() { // Arrange _testPidFilePath = _manager.GetPidFilePath(59997); File.WriteAllText(_testPidFilePath, " 12345 \n"); // Act bool result = _manager.TryReadPid(_testPidFilePath, out int pid); // Assert Assert.IsTrue(result); Assert.AreEqual(12345, pid); } [Test] public void TryReadPid_MissingFile_ReturnsFalse() { // Act bool result = _manager.TryReadPid("/nonexistent/path/file.pid", out int pid); // Assert Assert.IsFalse(result); Assert.AreEqual(0, pid); } [Test] public void TryReadPid_NullPath_ReturnsFalse() { // Act bool result = _manager.TryReadPid(null, out int pid); // Assert Assert.IsFalse(result); Assert.AreEqual(0, pid); } [Test] public void TryReadPid_EmptyPath_ReturnsFalse() { // Act bool result = _manager.TryReadPid(string.Empty, out int pid); // Assert Assert.IsFalse(result); Assert.AreEqual(0, pid); } [Test] public void TryReadPid_InvalidContent_ReturnsFalse() { // Arrange _testPidFilePath = _manager.GetPidFilePath(59996); File.WriteAllText(_testPidFilePath, "not a number"); // Act bool result = _manager.TryReadPid(_testPidFilePath, out int pid); // Assert Assert.IsFalse(result); Assert.AreEqual(0, pid); } [Test] public void TryReadPid_ZeroPid_ReturnsFalse() { // Arrange _testPidFilePath = _manager.GetPidFilePath(59995); File.WriteAllText(_testPidFilePath, "0"); // Act bool result = _manager.TryReadPid(_testPidFilePath, out int pid); // Assert Assert.IsFalse(result, "Zero PID should be rejected"); } [Test] public void TryReadPid_NegativePid_ReturnsFalse() { // Arrange _testPidFilePath = _manager.GetPidFilePath(59994); File.WriteAllText(_testPidFilePath, "-1"); // Act bool result = _manager.TryReadPid(_testPidFilePath, out int pid); // Assert Assert.IsFalse(result, "Negative PID should be rejected"); } #endregion #region TryGetPortFromPidFilePath Tests [Test] public void TryGetPortFromPidFilePath_ValidPath_ReturnsTrue() { // Arrange string path = "/some/path/mcp_http_8080.pid"; // Act bool result = _manager.TryGetPortFromPidFilePath(path, out int port); // Assert Assert.IsTrue(result); Assert.AreEqual(8080, port); } [Test] public void TryGetPortFromPidFilePath_DifferentPort_ParsesCorrectly() { // Arrange string path = "/path/to/mcp_http_9999.pid"; // Act bool result = _manager.TryGetPortFromPidFilePath(path, out int port); // Assert Assert.IsTrue(result); Assert.AreEqual(9999, port); } [Test] public void TryGetPortFromPidFilePath_NullPath_ReturnsFalse() { // Act bool result = _manager.TryGetPortFromPidFilePath(null, out int port); // Assert Assert.IsFalse(result); Assert.AreEqual(0, port); } [Test] public void TryGetPortFromPidFilePath_InvalidPrefix_ReturnsFalse() { // Arrange string path = "/some/path/wrong_prefix_8080.pid"; // Act bool result = _manager.TryGetPortFromPidFilePath(path, out int port); // Assert Assert.IsFalse(result); } #endregion #region Handshake Tests [Test] public void StoreHandshake_ValidData_StoresInEditorPrefs() { // Arrange string pidFilePath = "/test/path.pid"; string instanceToken = "test-token-123"; // Act _manager.StoreHandshake(pidFilePath, instanceToken); bool result = _manager.TryGetHandshake(out var storedPath, out var storedToken); // Assert Assert.IsTrue(result); Assert.AreEqual(pidFilePath, storedPath); Assert.AreEqual(instanceToken, storedToken); } [Test] public void TryGetHandshake_NoHandshake_ReturnsFalse() { // Act bool result = _manager.TryGetHandshake(out var pidFilePath, out var instanceToken); // Assert Assert.IsFalse(result); Assert.IsNull(pidFilePath); Assert.IsNull(instanceToken); } [Test] public void StoreHandshake_NullValues_DoesNotThrow() { // Act & Assert Assert.DoesNotThrow(() => { _manager.StoreHandshake(null, null); }); } #endregion #region Tracking Tests [Test] public void StoreTracking_ValidData_CanBeRetrieved() { // Arrange int pid = 12345; int port = 8080; // Act _manager.StoreTracking(pid, port); bool result = _manager.TryGetStoredPid(port, out int storedPid); // Assert Assert.IsTrue(result); Assert.AreEqual(pid, storedPid); } [Test] public void TryGetStoredPid_WrongPort_ReturnsFalse() { // Arrange _manager.StoreTracking(12345, 8080); // Act bool result = _manager.TryGetStoredPid(9090, out int storedPid); // Assert Assert.IsFalse(result, "Should return false for wrong port"); } [Test] public void TryGetStoredPid_NoTracking_ReturnsFalse() { // Act bool result = _manager.TryGetStoredPid(8080, out int storedPid); // Assert Assert.IsFalse(result); Assert.AreEqual(0, storedPid); } [Test] public void ClearTracking_RemovesAllKeys() { // Arrange _manager.StoreTracking(12345, 8080, "somehash"); _manager.StoreHandshake("/path.pid", "token"); // Act _manager.ClearTracking(); bool hasTracking = _manager.TryGetStoredPid(8080, out _); bool hasHandshake = _manager.TryGetHandshake(out _, out _); // Assert Assert.IsFalse(hasTracking); Assert.IsFalse(hasHandshake); } [Test] public void GetStoredArgsHash_WithHash_ReturnsHash() { // Arrange _manager.StoreTracking(12345, 8080, "testhash123"); // Act string hash = _manager.GetStoredArgsHash(); // Assert Assert.AreEqual("testhash123", hash); } [Test] public void GetStoredArgsHash_NoHash_ReturnsEmpty() { // Act string hash = _manager.GetStoredArgsHash(); // Assert Assert.AreEqual(string.Empty, hash); } #endregion #region ComputeShortHash Tests [Test] public void ComputeShortHash_ValidInput_Returns16CharHash() { // Arrange string input = "test input string"; // Act string hash = _manager.ComputeShortHash(input); // Assert Assert.IsNotNull(hash); Assert.AreEqual(16, hash.Length); } [Test] public void ComputeShortHash_SameInput_ReturnsSameHash() { // Arrange string input = "consistent input"; // Act string hash1 = _manager.ComputeShortHash(input); string hash2 = _manager.ComputeShortHash(input); // Assert Assert.AreEqual(hash1, hash2); } [Test] public void ComputeShortHash_DifferentInput_ReturnsDifferentHash() { // Act string hash1 = _manager.ComputeShortHash("input1"); string hash2 = _manager.ComputeShortHash("input2"); // Assert Assert.AreNotEqual(hash1, hash2); } [Test] public void ComputeShortHash_NullInput_ReturnsEmpty() { // Act string hash = _manager.ComputeShortHash(null); // Assert Assert.AreEqual(string.Empty, hash); } [Test] public void ComputeShortHash_EmptyInput_ReturnsEmpty() { // Act string hash = _manager.ComputeShortHash(string.Empty); // Assert Assert.AreEqual(string.Empty, hash); } #endregion #region DeletePidFile Tests [Test] public void DeletePidFile_ExistingFile_DeletesFile() { // Arrange _testPidFilePath = _manager.GetPidFilePath(59993); File.WriteAllText(_testPidFilePath, "12345"); Assert.IsTrue(File.Exists(_testPidFilePath)); // Act _manager.DeletePidFile(_testPidFilePath); // Assert Assert.IsFalse(File.Exists(_testPidFilePath)); } [Test] public void DeletePidFile_NonExistentFile_DoesNotThrow() { // Act & Assert Assert.DoesNotThrow(() => { _manager.DeletePidFile("/nonexistent/file.pid"); }); } [Test] public void DeletePidFile_NullPath_DoesNotThrow() { // Act & Assert Assert.DoesNotThrow(() => { _manager.DeletePidFile(null); }); } #endregion #region Interface Implementation Tests [Test] public void PidFileManager_ImplementsIPidFileManager() { // Assert Assert.IsInstanceOf(_manager); } #endregion } }