Skip to main content
Glama
position.test.ts8.56 kB
import { describe, it, expect } from 'vitest'; import { createOneBasedPosition, createZeroBasedPosition, toZeroBased, toOneBased, unsafeOneBasedPosition, unsafeZeroBasedPosition, } from '../../src/types/position.js'; describe('Position Utilities', () => { describe('createOneBasedPosition', () => { it('should create valid 1-based position', () => { const pos = createOneBasedPosition(1, 1); expect(pos.line).toBe(1); expect(pos.character).toBe(1); }); it('should create position with larger coordinates', () => { const pos = createOneBasedPosition(10, 25); expect(pos.line).toBe(10); expect(pos.character).toBe(25); }); it('should throw error for line less than 1', () => { expect(() => createOneBasedPosition(0, 1)).toThrow( 'Invalid 1-based position: line=0, character=1. Both must be >= 1.' ); expect(() => createOneBasedPosition(-1, 1)).toThrow( 'Invalid 1-based position: line=-1, character=1. Both must be >= 1.' ); }); it('should throw error for character less than 1', () => { expect(() => createOneBasedPosition(1, 0)).toThrow( 'Invalid 1-based position: line=1, character=0. Both must be >= 1.' ); expect(() => createOneBasedPosition(1, -1)).toThrow( 'Invalid 1-based position: line=1, character=-1. Both must be >= 1.' ); }); it('should throw error for both coordinates less than 1', () => { expect(() => createOneBasedPosition(0, 0)).toThrow( 'Invalid 1-based position: line=0, character=0. Both must be >= 1.' ); expect(() => createOneBasedPosition(-5, -10)).toThrow( 'Invalid 1-based position: line=-5, character=-10. Both must be >= 1.' ); }); }); describe('createZeroBasedPosition', () => { it('should create valid 0-based position', () => { const pos = createZeroBasedPosition(0, 0); expect(pos.line).toBe(0); expect(pos.character).toBe(0); }); it('should create position with larger coordinates', () => { const pos = createZeroBasedPosition(9, 24); expect(pos.line).toBe(9); expect(pos.character).toBe(24); }); it('should throw error for line less than 0', () => { expect(() => createZeroBasedPosition(-1, 0)).toThrow( 'Invalid 0-based position: line=-1, character=0. Both must be >= 0.' ); expect(() => createZeroBasedPosition(-10, 5)).toThrow( 'Invalid 0-based position: line=-10, character=5. Both must be >= 0.' ); }); it('should throw error for character less than 0', () => { expect(() => createZeroBasedPosition(0, -1)).toThrow( 'Invalid 0-based position: line=0, character=-1. Both must be >= 0.' ); expect(() => createZeroBasedPosition(5, -10)).toThrow( 'Invalid 0-based position: line=5, character=-10. Both must be >= 0.' ); }); it('should throw error for both coordinates less than 0', () => { expect(() => createZeroBasedPosition(-1, -1)).toThrow( 'Invalid 0-based position: line=-1, character=-1. Both must be >= 0.' ); expect(() => createZeroBasedPosition(-5, -10)).toThrow( 'Invalid 0-based position: line=-5, character=-10. Both must be >= 0.' ); }); }); describe('coordinate conversion', () => { describe('toZeroBased', () => { it('should convert 1-based to 0-based position', () => { const oneBased = createOneBasedPosition(1, 1); const zeroBased = toZeroBased(oneBased); expect(zeroBased.line).toBe(0); expect(zeroBased.character).toBe(0); }); it('should convert larger coordinates correctly', () => { const oneBased = createOneBasedPosition(10, 25); const zeroBased = toZeroBased(oneBased); expect(zeroBased.line).toBe(9); expect(zeroBased.character).toBe(24); }); it('should handle edge case of minimum valid 1-based position', () => { const oneBased = createOneBasedPosition(1, 1); const zeroBased = toZeroBased(oneBased); expect(zeroBased.line).toBe(0); expect(zeroBased.character).toBe(0); }); it('should handle conversion that would result in negative coordinates', () => { // This test ensures toZeroBased handles the edge case correctly // Since we pass a valid 1-based position, the conversion should always be valid const oneBased = createOneBasedPosition(1, 1); const zeroBased = toZeroBased(oneBased); // Should not throw and should result in (0,0) expect(zeroBased.line).toBe(0); expect(zeroBased.character).toBe(0); }); }); describe('toOneBased', () => { it('should convert 0-based to 1-based position', () => { const zeroBased = createZeroBasedPosition(0, 0); const oneBased = toOneBased(zeroBased); expect(oneBased.line).toBe(1); expect(oneBased.character).toBe(1); }); it('should convert larger coordinates correctly', () => { const zeroBased = createZeroBasedPosition(9, 24); const oneBased = toOneBased(zeroBased); expect(oneBased.line).toBe(10); expect(oneBased.character).toBe(25); }); it('should handle edge case of minimum valid 0-based position', () => { const zeroBased = createZeroBasedPosition(0, 0); const oneBased = toOneBased(zeroBased); expect(oneBased.line).toBe(1); expect(oneBased.character).toBe(1); }); }); describe('round-trip conversions', () => { it('should maintain values in one-based to zero-based to one-based conversion', () => { const original = createOneBasedPosition(5, 10); const converted = toOneBased(toZeroBased(original)); expect(converted.line).toBe(original.line); expect(converted.character).toBe(original.character); }); it('should maintain values in zero-based to one-based to zero-based conversion', () => { const original = createZeroBasedPosition(4, 9); const converted = toZeroBased(toOneBased(original)); expect(converted.line).toBe(original.line); expect(converted.character).toBe(original.character); }); }); }); describe('unsafe position creators', () => { describe('unsafeOneBasedPosition', () => { it('should create 1-based position without validation', () => { const pos = unsafeOneBasedPosition(1, 1); expect(pos.line).toBe(1); expect(pos.character).toBe(1); }); it('should create position with invalid coordinates without throwing', () => { // This is the "unsafe" behavior - it allows invalid coordinates const pos = unsafeOneBasedPosition(0, 0); expect(pos.line).toBe(0); expect(pos.character).toBe(0); }); it('should create position with negative coordinates without throwing', () => { const pos = unsafeOneBasedPosition(-1, -5); expect(pos.line).toBe(-1); expect(pos.character).toBe(-5); }); }); describe('unsafeZeroBasedPosition', () => { it('should create 0-based position without validation', () => { const pos = unsafeZeroBasedPosition(0, 0); expect(pos.line).toBe(0); expect(pos.character).toBe(0); }); it('should create position with negative coordinates without throwing', () => { // This is the "unsafe" behavior - it allows negative coordinates const pos = unsafeZeroBasedPosition(-1, -5); expect(pos.line).toBe(-1); expect(pos.character).toBe(-5); }); it('should create position with any coordinates without throwing', () => { const pos = unsafeZeroBasedPosition(100, -50); expect(pos.line).toBe(100); expect(pos.character).toBe(-50); }); }); }); describe('type branding', () => { it('should prevent direct assignment between position types', () => { // This test verifies TypeScript type checking at compile time // The actual runtime behavior is the same, but TypeScript should catch mixing types const oneBased = createOneBasedPosition(1, 1); const zeroBased = createZeroBasedPosition(0, 0); // These should be different branded types expect(oneBased).toBeDefined(); expect(zeroBased).toBeDefined(); // Runtime values are accessible expect(oneBased.line).toBe(1); expect(zeroBased.line).toBe(0); }); }); });

Latest Blog Posts

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/p1va/symbols-mcp'

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