Skip to main content
Glama

MCP Xcode

by Stefan-Nitu
BuildArtifactLocatorAdapter.unit.test.ts7.56 kB
import { describe, it, expect, jest, beforeEach } from '@jest/globals'; import { BuildArtifactLocatorAdapter } from '../../infrastructure/BuildArtifactLocatorAdapter.js'; import { ICommandExecutor, ExecutionResult, ExecutionOptions } from '../../../../application/ports/CommandPorts.js'; import { existsSync } from 'fs'; // Mock fs module jest.mock('fs', () => ({ existsSync: jest.fn<(path: string) => boolean>() })); const mockExistsSync = existsSync as jest.MockedFunction<typeof existsSync>; describe('BuildArtifactLocator', () => { // Factory method for creating the SUT with its dependencies function createSUT() { const mockExecute = jest.fn<(command: string, options?: ExecutionOptions) => Promise<ExecutionResult>>(); const mockExecutor: ICommandExecutor = { execute: mockExecute }; const sut = new BuildArtifactLocatorAdapter(mockExecutor); return { sut, mockExecutor, mockExecute }; } beforeEach(() => { jest.clearAllMocks(); }); describe('findApp', () => { describe('when app is found', () => { it('should return app path when app exists', async () => { // Arrange const { sut, mockExecutor, mockExecute } = createSUT(); const derivedDataPath = '/path/to/DerivedData'; const appPath = '/path/to/DerivedData/Build/Products/Debug-iphonesimulator/MyApp.app'; mockExecute.mockResolvedValue({ stdout: appPath + '\n', stderr: '', exitCode: 0 }); mockExistsSync.mockReturnValue(true); // Act const result = await sut.findApp(derivedDataPath); // Assert expect(result).toBe(appPath); expect(mockExecutor.execute).toHaveBeenCalledWith( 'find "/path/to/DerivedData" -name "*.app" -type d | head -1', { timeout: 5000 } ); expect(mockExistsSync).toHaveBeenCalledWith(appPath); }); it('should handle paths with spaces correctly', async () => { // Arrange const { sut, mockExecutor, mockExecute } = createSUT(); const derivedDataPath = '/path/with spaces/DerivedData'; const appPath = '/path/with spaces/DerivedData/MyApp.app'; mockExecute.mockResolvedValue({ stdout: appPath, stderr: '', exitCode: 0 }); mockExistsSync.mockReturnValue(true); // Act const result = await sut.findApp(derivedDataPath); // Assert expect(result).toBe(appPath); expect(mockExecutor.execute).toHaveBeenCalledWith( 'find "/path/with spaces/DerivedData" -name "*.app" -type d | head -1', { timeout: 5000 } ); }); it('should trim whitespace from command output', async () => { // Arrange const { sut, mockExecutor, mockExecute } = createSUT(); const appPath = '/path/to/MyApp.app'; mockExecute.mockResolvedValue({ stdout: ' ' + appPath + ' \n\n', stderr: '', exitCode: 0 }); mockExistsSync.mockReturnValue(true); // Act const result = await sut.findApp('/path'); // Assert expect(result).toBe(appPath); expect(mockExistsSync).toHaveBeenCalledWith(appPath); }); }); describe('when app is not found', () => { it('should return undefined when find returns empty', async () => { // Arrange const { sut, mockExecutor, mockExecute } = createSUT(); mockExecute.mockResolvedValue({ stdout: '', stderr: '', exitCode: 0 }); // Act const result = await sut.findApp('/path/to/DerivedData'); // Assert expect(result).toBeUndefined(); expect(existsSync).not.toHaveBeenCalled(); }); it('should return undefined when app path does not exist', async () => { // Arrange const { sut, mockExecutor, mockExecute } = createSUT(); const appPath = '/path/to/NonExistent.app'; mockExecute.mockResolvedValue({ stdout: appPath, stderr: '', exitCode: 0 }); mockExistsSync.mockReturnValue(false); // Act const result = await sut.findApp('/path/to/DerivedData'); // Assert expect(result).toBeUndefined(); expect(mockExistsSync).toHaveBeenCalledWith(appPath); }); it('should return undefined when find command fails', async () => { // Arrange const { sut, mockExecutor, mockExecute } = createSUT(); mockExecute.mockResolvedValue({ stdout: '', stderr: 'find: /path/to/DerivedData: No such file or directory', exitCode: 1 }); // Act const result = await sut.findApp('/path/to/DerivedData'); // Assert expect(result).toBeUndefined(); expect(existsSync).not.toHaveBeenCalled(); }); }); describe('error handling', () => { it('should return undefined when executor throws', async () => { // Arrange const { sut, mockExecutor, mockExecute } = createSUT(); mockExecute.mockRejectedValue( new Error('Command execution failed') ); // Act const result = await sut.findApp('/path/to/DerivedData'); // Assert expect(result).toBeUndefined(); expect(existsSync).not.toHaveBeenCalled(); }); it('should handle timeout gracefully', async () => { // Arrange const { sut, mockExecutor, mockExecute } = createSUT(); mockExecute.mockRejectedValue( new Error('Command timed out') ); // Act const result = await sut.findApp('/path/to/DerivedData'); // Assert expect(result).toBeUndefined(); }); }); describe('command construction', () => { it('should use correct find command', async () => { // Arrange const { sut, mockExecutor, mockExecute } = createSUT(); const derivedDataPath = '/Users/dev/DerivedData'; mockExecute.mockResolvedValue({ stdout: '/some/app.app', stderr: '', exitCode: 0 }); mockExistsSync.mockReturnValue(true); // Act await sut.findApp(derivedDataPath); // Assert expect(mockExecutor.execute).toHaveBeenCalledWith( 'find "/Users/dev/DerivedData" -name "*.app" -type d | head -1', { timeout: 5000 } ); }); it('should escape quotes in path', async () => { // Arrange const { sut, mockExecutor, mockExecute } = createSUT(); const derivedDataPath = '/path/with"quote'; mockExecute.mockResolvedValue({ stdout: '', stderr: '', exitCode: 0 }); // Act await sut.findApp(derivedDataPath); // Assert // Note: The current implementation doesn't escape quotes properly // This test documents the current behavior expect(mockExecutor.execute).toHaveBeenCalledWith( 'find "/path/with"quote" -name "*.app" -type d | head -1', { timeout: 5000 } ); }); }); }); });

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Stefan-Nitu/mcp-xcode'

If you have feedback or need assistance with the MCP directory API, please join our Discord server