import { describe, expect, test } from 'bun:test' import { parseArguments, parseArgumentNames, generateProgressiveArgumentHint, substituteArguments, } from '../argumentSubstitution' // ─── parseArguments ───────────────────────────────────────────────────── describe('parseArguments', () => { test('splits simple arguments', () => { expect(parseArguments('foo bar baz')).toEqual(['foo', 'bar', 'baz']) }) test('handles quoted strings', () => { expect(parseArguments('foo "hello world" baz')).toEqual([ 'foo', 'hello world', 'baz', ]) }) test('handles single-quoted strings', () => { expect(parseArguments("foo 'hello world' baz")).toEqual([ 'foo', 'hello world', 'baz', ]) }) test('handles escaped quotes inside quoted strings', () => { expect(parseArguments('foo "hello \\"world\\"" baz')).toEqual([ 'foo', 'hello "world"', 'baz', ]) }) test('returns empty for empty string', () => { expect(parseArguments('')).toEqual([]) }) test('returns empty for whitespace only', () => { expect(parseArguments(' ')).toEqual([]) }) }) // ─── parseArgumentNames ───────────────────────────────────────────────── describe('parseArgumentNames', () => { test('parses space-separated string', () => { expect(parseArgumentNames('foo bar baz')).toEqual(['foo', 'bar', 'baz']) }) test('accepts array input', () => { expect(parseArgumentNames(['foo', 'bar'])).toEqual(['foo', 'bar']) }) test('filters out numeric-only names', () => { expect(parseArgumentNames('foo 123 bar')).toEqual(['foo', 'bar']) }) test('filters out empty strings', () => { expect(parseArgumentNames(['foo', '', 'bar'])).toEqual(['foo', 'bar']) }) test('returns empty for undefined', () => { expect(parseArgumentNames(undefined)).toEqual([]) }) }) // ─── generateProgressiveArgumentHint ──────────────────────────────────── describe('generateProgressiveArgumentHint', () => { test('shows remaining arguments', () => { expect(generateProgressiveArgumentHint(['a', 'b', 'c'], ['x'])).toBe( '[b] [c]', ) }) test('returns undefined when all filled', () => { expect(generateProgressiveArgumentHint(['a'], ['x'])).toBeUndefined() }) test('shows all when none typed', () => { expect(generateProgressiveArgumentHint(['a', 'b'], [])).toBe('[a] [b]') }) }) // ─── substituteArguments ──────────────────────────────────────────────── describe('substituteArguments', () => { test('replaces $ARGUMENTS with full args', () => { expect(substituteArguments('run $ARGUMENTS', 'foo bar')).toBe('run foo bar') }) test('replaces indexed $ARGUMENTS[0]', () => { expect(substituteArguments('run $ARGUMENTS[0]', 'foo bar')).toBe('run foo') }) test('replaces shorthand $0, $1', () => { expect(substituteArguments('$0 and $1', 'hello world')).toBe( 'hello and world', ) }) test('replaces out-of-range index with empty string', () => { expect(substituteArguments('$5', 'hello world')).toBe('') }) test('reuses same placeholder multiple times', () => { expect(substituteArguments('cmd $0 $1 $0', 'alpha beta')).toBe( 'cmd alpha beta alpha', ) }) test('replaces named arguments', () => { expect(substituteArguments('file: $name', 'test.txt', true, ['name'])).toBe( 'file: test.txt', ) }) test('returns content unchanged for undefined args', () => { expect(substituteArguments('hello', undefined)).toBe('hello') }) test('appends ARGUMENTS when no placeholder found', () => { expect(substituteArguments('run this', 'extra')).toBe( 'run this\n\nARGUMENTS: extra', ) }) test('does not append when appendIfNoPlaceholder is false', () => { expect(substituteArguments('run this', 'extra', false)).toBe('run this') }) test('does not append for empty args string', () => { expect(substituteArguments('run this', '')).toBe('run this') }) })