/** * @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(''); }); 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