mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-03-21 03:21:11 -07:00
feat(auth): improve API key authentication flow (#11760)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
@@ -14,6 +14,7 @@ import type {
|
||||
TextBufferState,
|
||||
TextBufferAction,
|
||||
VisualLayout,
|
||||
TextBufferOptions,
|
||||
} from './text-buffer.js';
|
||||
import {
|
||||
useTextBuffer,
|
||||
@@ -101,6 +102,43 @@ describe('textBufferReducer', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('insert action with options', () => {
|
||||
it('should filter input using inputFilter option', () => {
|
||||
const action: TextBufferAction = { type: 'insert', payload: 'a1b2c3' };
|
||||
const options: TextBufferOptions = {
|
||||
inputFilter: (text) => text.replace(/[0-9]/g, ''),
|
||||
};
|
||||
const state = textBufferReducer(initialState, action, options);
|
||||
expect(state.lines).toEqual(['abc']);
|
||||
expect(state.cursorCol).toBe(3);
|
||||
});
|
||||
|
||||
it('should strip newlines when singleLine option is true', () => {
|
||||
const action: TextBufferAction = {
|
||||
type: 'insert',
|
||||
payload: 'hello\nworld',
|
||||
};
|
||||
const options: TextBufferOptions = { singleLine: true };
|
||||
const state = textBufferReducer(initialState, action, options);
|
||||
expect(state.lines).toEqual(['helloworld']);
|
||||
expect(state.cursorCol).toBe(10);
|
||||
});
|
||||
|
||||
it('should apply both inputFilter and singleLine options', () => {
|
||||
const action: TextBufferAction = {
|
||||
type: 'insert',
|
||||
payload: 'h\ne\nl\nl\no\n1\n2\n3',
|
||||
};
|
||||
const options: TextBufferOptions = {
|
||||
singleLine: true,
|
||||
inputFilter: (text) => text.replace(/[0-9]/g, ''),
|
||||
};
|
||||
const state = textBufferReducer(initialState, action, options);
|
||||
expect(state.lines).toEqual(['hello']);
|
||||
expect(state.cursorCol).toBe(5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('backspace action', () => {
|
||||
it('should remove a character', () => {
|
||||
const stateWithText: TextBufferState = {
|
||||
@@ -1520,6 +1558,75 @@ Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots
|
||||
});
|
||||
});
|
||||
|
||||
describe('inputFilter', () => {
|
||||
it('should filter input based on the provided filter function', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useTextBuffer({
|
||||
viewport,
|
||||
isValidPath: () => false,
|
||||
inputFilter: (text) => text.replace(/[^0-9]/g, ''),
|
||||
}),
|
||||
);
|
||||
|
||||
act(() => result.current.insert('a1b2c3'));
|
||||
expect(getBufferState(result).text).toBe('123');
|
||||
});
|
||||
|
||||
it('should handle empty result from filter', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useTextBuffer({
|
||||
viewport,
|
||||
isValidPath: () => false,
|
||||
inputFilter: (text) => text.replace(/[^0-9]/g, ''),
|
||||
}),
|
||||
);
|
||||
|
||||
act(() => result.current.insert('abc'));
|
||||
expect(getBufferState(result).text).toBe('');
|
||||
});
|
||||
|
||||
it('should filter pasted text', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useTextBuffer({
|
||||
viewport,
|
||||
isValidPath: () => false,
|
||||
inputFilter: (text) => text.toUpperCase(),
|
||||
}),
|
||||
);
|
||||
|
||||
act(() => result.current.insert('hello', { paste: true }));
|
||||
expect(getBufferState(result).text).toBe('HELLO');
|
||||
});
|
||||
|
||||
it('should not filter newlines if they are allowed by the filter', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useTextBuffer({
|
||||
viewport,
|
||||
isValidPath: () => false,
|
||||
inputFilter: (text) => text, // Allow everything including newlines
|
||||
}),
|
||||
);
|
||||
|
||||
act(() => result.current.insert('a\nb'));
|
||||
// The insert function splits by newline and inserts separately if it detects them.
|
||||
// If the filter allows them, they should be handled correctly by the subsequent logic in insert.
|
||||
expect(getBufferState(result).text).toBe('a\nb');
|
||||
});
|
||||
|
||||
it('should filter before newline check in insert', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useTextBuffer({
|
||||
viewport,
|
||||
isValidPath: () => false,
|
||||
inputFilter: (text) => text.replace(/\n/g, ''), // Filter out newlines
|
||||
}),
|
||||
);
|
||||
|
||||
act(() => result.current.insert('a\nb'));
|
||||
expect(getBufferState(result).text).toBe('ab');
|
||||
});
|
||||
});
|
||||
|
||||
describe('stripAnsi', () => {
|
||||
it('should correctly strip ANSI escape codes', () => {
|
||||
const textWithAnsi = '\x1B[31mHello\x1B[0m World';
|
||||
@@ -1587,6 +1694,74 @@ Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots
|
||||
expect(getBufferState(result).text).toBe('hello world');
|
||||
});
|
||||
});
|
||||
|
||||
describe('singleLine mode', () => {
|
||||
it('should not insert a newline character when singleLine is true', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useTextBuffer({
|
||||
viewport,
|
||||
isValidPath: () => false,
|
||||
singleLine: true,
|
||||
}),
|
||||
);
|
||||
act(() => result.current.insert('\n'));
|
||||
const state = getBufferState(result);
|
||||
expect(state.text).toBe('');
|
||||
expect(state.lines).toEqual(['']);
|
||||
});
|
||||
|
||||
it('should not create a new line when newline() is called and singleLine is true', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useTextBuffer({
|
||||
initialText: 'ab',
|
||||
viewport,
|
||||
isValidPath: () => false,
|
||||
singleLine: true,
|
||||
}),
|
||||
);
|
||||
act(() => result.current.move('end')); // cursor at [0,2]
|
||||
act(() => result.current.newline());
|
||||
const state = getBufferState(result);
|
||||
expect(state.text).toBe('ab');
|
||||
expect(state.lines).toEqual(['ab']);
|
||||
expect(state.cursor).toEqual([0, 2]);
|
||||
});
|
||||
|
||||
it('should not handle "Enter" key as newline when singleLine is true', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useTextBuffer({
|
||||
viewport,
|
||||
isValidPath: () => false,
|
||||
singleLine: true,
|
||||
}),
|
||||
);
|
||||
act(() =>
|
||||
result.current.handleInput({
|
||||
name: 'return',
|
||||
ctrl: false,
|
||||
meta: false,
|
||||
shift: false,
|
||||
paste: false,
|
||||
sequence: '\r',
|
||||
}),
|
||||
);
|
||||
expect(getBufferState(result).lines).toEqual(['']);
|
||||
});
|
||||
|
||||
it('should strip newlines from pasted text when singleLine is true', () => {
|
||||
const { result } = renderHook(() =>
|
||||
useTextBuffer({
|
||||
viewport,
|
||||
isValidPath: () => false,
|
||||
singleLine: true,
|
||||
}),
|
||||
);
|
||||
act(() => result.current.insert('hello\nworld', { paste: true }));
|
||||
const state = getBufferState(result);
|
||||
expect(state.text).toBe('helloworld');
|
||||
expect(state.lines).toEqual(['helloworld']);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('offsetToLogicalPos', () => {
|
||||
|
||||
Reference in New Issue
Block a user