diff options
| author | HyeongHo Jun <[email protected]> | 2025-07-23 08:57:06 +0900 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-07-22 23:57:06 +0000 |
| commit | a00f1bb916b551fc17fa5bab80fb51dcdc88f00d (patch) | |
| tree | 301797288462e03f8e954f03d526cc6ddaf0a7ab /packages/core/src/utils/partUtils.test.ts | |
| parent | 487debe525fa20c7bbfb3393ce455fbbae1aab3f (diff) | |
feat(core): add partUtils module with unit tests (#4575)
Co-authored-by: Jacob Richman <[email protected]>
Diffstat (limited to 'packages/core/src/utils/partUtils.test.ts')
| -rw-r--r-- | packages/core/src/utils/partUtils.test.ts | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/packages/core/src/utils/partUtils.test.ts b/packages/core/src/utils/partUtils.test.ts new file mode 100644 index 00000000..eda85df2 --- /dev/null +++ b/packages/core/src/utils/partUtils.test.ts @@ -0,0 +1,166 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { describe, it, expect } from 'vitest'; +import { partToString, getResponseText } from './partUtils.js'; +import { GenerateContentResponse, Part } from '@google/genai'; + +const mockResponse = ( + parts?: Array<{ text?: string; functionCall?: unknown }>, +): GenerateContentResponse => ({ + candidates: parts + ? [{ content: { parts: parts as Part[], role: 'model' }, index: 0 }] + : [], + promptFeedback: { safetyRatings: [] }, + text: undefined, + data: undefined, + functionCalls: undefined, + executableCode: undefined, + codeExecutionResult: undefined, +}); + +describe('partUtils', () => { + describe('partToString (default behavior)', () => { + it('should return empty string for undefined or null', () => { + // @ts-expect-error Testing invalid input + expect(partToString(undefined)).toBe(''); + // @ts-expect-error Testing invalid input + expect(partToString(null)).toBe(''); + }); + + it('should return string input unchanged', () => { + expect(partToString('hello')).toBe('hello'); + }); + + it('should concatenate strings from an array', () => { + expect(partToString(['a', 'b'])).toBe('ab'); + }); + + it('should return text property when provided a text part', () => { + expect(partToString({ text: 'hi' })).toBe('hi'); + }); + + it('should return empty string for non-text parts', () => { + const part: Part = { inlineData: { mimeType: 'image/png', data: '' } }; + expect(partToString(part)).toBe(''); + const part2: Part = { functionCall: { name: 'test' } }; + expect(partToString(part2)).toBe(''); + }); + }); + + describe('partToString (verbose)', () => { + const verboseOptions = { verbose: true }; + + it('should return empty string for undefined or null', () => { + // @ts-expect-error Testing invalid input + expect(partToString(undefined, verboseOptions)).toBe(''); + // @ts-expect-error Testing invalid input + expect(partToString(null, verboseOptions)).toBe(''); + }); + + it('should return string input unchanged', () => { + expect(partToString('hello', verboseOptions)).toBe('hello'); + }); + + it('should join parts if the value is an array', () => { + const parts = ['hello', { text: ' world' }]; + expect(partToString(parts, verboseOptions)).toBe('hello world'); + }); + + it('should return the text property if the part is an object with text', () => { + const part: Part = { text: 'hello world' }; + expect(partToString(part, verboseOptions)).toBe('hello world'); + }); + + it('should return descriptive string for videoMetadata part', () => { + const part = { videoMetadata: {} } as Part; + expect(partToString(part, verboseOptions)).toBe('[Video Metadata]'); + }); + + it('should return descriptive string for thought part', () => { + const part = { thought: 'thinking' } as unknown as Part; + expect(partToString(part, verboseOptions)).toBe('[Thought: thinking]'); + }); + + it('should return descriptive string for codeExecutionResult part', () => { + const part = { codeExecutionResult: {} } as Part; + expect(partToString(part, verboseOptions)).toBe( + '[Code Execution Result]', + ); + }); + + it('should return descriptive string for executableCode part', () => { + const part = { executableCode: {} } as Part; + expect(partToString(part, verboseOptions)).toBe('[Executable Code]'); + }); + + it('should return descriptive string for fileData part', () => { + const part = { fileData: {} } as Part; + expect(partToString(part, verboseOptions)).toBe('[File Data]'); + }); + + it('should return descriptive string for functionCall part', () => { + const part = { functionCall: { name: 'myFunction' } } as Part; + expect(partToString(part, verboseOptions)).toBe( + '[Function Call: myFunction]', + ); + }); + + it('should return descriptive string for functionResponse part', () => { + const part = { functionResponse: { name: 'myFunction' } } as Part; + expect(partToString(part, verboseOptions)).toBe( + '[Function Response: myFunction]', + ); + }); + + it('should return descriptive string for inlineData part', () => { + const part = { inlineData: { mimeType: 'image/png', data: '' } } as Part; + expect(partToString(part, verboseOptions)).toBe('<image/png>'); + }); + + it('should return an empty string for an unknown part type', () => { + const part: Part = {}; + expect(partToString(part, verboseOptions)).toBe(''); + }); + + it('should handle complex nested arrays with various part types', () => { + const parts = [ + 'start ', + { text: 'middle' }, + [ + { functionCall: { name: 'func1' } }, + ' end', + { inlineData: { mimeType: 'audio/mp3', data: '' } }, + ], + ]; + expect(partToString(parts as Part, verboseOptions)).toBe( + 'start middle[Function Call: func1] end<audio/mp3>', + ); + }); + }); + + describe('getResponseText', () => { + it('should return null when no candidates exist', () => { + const response = mockResponse(undefined); + expect(getResponseText(response)).toBeNull(); + }); + + it('should return concatenated text from first candidate', () => { + const result = mockResponse([{ text: 'a' }, { text: 'b' }]); + expect(getResponseText(result)).toBe('ab'); + }); + + it('should ignore parts without text', () => { + const result = mockResponse([{ functionCall: {} }, { text: 'hello' }]); + expect(getResponseText(result)).toBe('hello'); + }); + + it('should return null when candidate has no parts', () => { + const result = mockResponse([]); + expect(getResponseText(result)).toBeNull(); + }); + }); +}); |
