@@ -236,23 +236,29 @@ func TestFromVeoOperation(t *testing.T) {
236236 t .Parallel ()
237237
238238 tests := []struct {
239- name string
240- veoOp * genai.GenerateVideosOperation
241- expectedID string
242- expectedDone bool
243- expectedError error
244- expectedHasOutput bool
239+ name string
240+ veoOp * genai.GenerateVideosOperation
241+ expectedID string
242+ expectedDone bool
243+ expectedError error
244+ expectedHasOutput bool
245+ expectedStatusMsg string
246+ expectedFinishReason ai.FinishReason
247+ expectedMediaParts int
245248 }{
246249 {
247250 name : "pending operation" ,
248251 veoOp : & genai.GenerateVideosOperation {
249252 Name : "operations/test-operation-123" ,
250253 Done : false ,
251254 },
252- expectedID : "operations/test-operation-123" ,
253- expectedDone : false ,
254- expectedError : nil ,
255- expectedHasOutput : false ,
255+ expectedID : "operations/test-operation-123" ,
256+ expectedDone : false ,
257+ expectedError : nil ,
258+ expectedHasOutput : true ,
259+ expectedStatusMsg : "Video generation in progress..." ,
260+ expectedFinishReason : "" ,
261+ expectedMediaParts : 0 ,
256262 },
257263 {
258264 name : "completed operation with video" ,
@@ -269,10 +275,13 @@ func TestFromVeoOperation(t *testing.T) {
269275 },
270276 },
271277 },
272- expectedID : "operations/test-operation-456" ,
273- expectedDone : true ,
274- expectedError : nil ,
275- expectedHasOutput : true ,
278+ expectedID : "operations/test-operation-456" ,
279+ expectedDone : true ,
280+ expectedError : nil ,
281+ expectedHasOutput : true ,
282+ expectedStatusMsg : "" ,
283+ expectedFinishReason : ai .FinishReasonStop ,
284+ expectedMediaParts : 1 ,
276285 },
277286 {
278287 name : "operation with error" ,
@@ -284,10 +293,13 @@ func TestFromVeoOperation(t *testing.T) {
284293 "code" : 400 ,
285294 },
286295 },
287- expectedID : "operations/test-operation-error" ,
288- expectedDone : true ,
289- expectedError : fmt .Errorf ("%s" , "Video generation failed due to content policy" ),
290- expectedHasOutput : false ,
296+ expectedID : "operations/test-operation-error" ,
297+ expectedDone : true ,
298+ expectedError : fmt .Errorf ("%s" , "Video generation failed due to content policy" ),
299+ expectedHasOutput : false ,
300+ expectedStatusMsg : "" ,
301+ expectedFinishReason : "" ,
302+ expectedMediaParts : 0 ,
291303 },
292304 {
293305 name : "operation with malformed error" ,
@@ -297,13 +309,15 @@ func TestFromVeoOperation(t *testing.T) {
297309 Error : map [string ]any {
298310 "code" : 500 ,
299311 "details" : "Internal error" ,
300- // No "message" field
301312 },
302313 },
303- expectedID : "operations/test-operation-bad-error" ,
304- expectedDone : true ,
305- expectedError : fmt .Errorf ("operation error: map[code:500 details:Internal error]" ),
306- expectedHasOutput : false ,
314+ expectedID : "operations/test-operation-bad-error" ,
315+ expectedDone : true ,
316+ expectedError : fmt .Errorf ("operation error: map[code:500 details:Internal error]" ),
317+ expectedHasOutput : false ,
318+ expectedStatusMsg : "" ,
319+ expectedFinishReason : "" ,
320+ expectedMediaParts : 0 ,
307321 },
308322 {
309323 name : "completed operation with multiple videos" ,
@@ -325,10 +339,30 @@ func TestFromVeoOperation(t *testing.T) {
325339 },
326340 },
327341 },
328- expectedID : "operations/test-operation-multi" ,
329- expectedDone : true ,
330- expectedError : nil ,
331- expectedHasOutput : true ,
342+ expectedID : "operations/test-operation-multi" ,
343+ expectedDone : true ,
344+ expectedError : nil ,
345+ expectedHasOutput : true ,
346+ expectedStatusMsg : "" ,
347+ expectedFinishReason : ai .FinishReasonStop ,
348+ expectedMediaParts : 2 ,
349+ },
350+ {
351+ name : "completed operation without videos" ,
352+ veoOp : & genai.GenerateVideosOperation {
353+ Name : "operations/test-operation-no-videos" ,
354+ Done : true ,
355+ Response : & genai.GenerateVideosResponse {
356+ GeneratedVideos : []* genai.GeneratedVideo {},
357+ },
358+ },
359+ expectedID : "operations/test-operation-no-videos" ,
360+ expectedDone : true ,
361+ expectedError : nil ,
362+ expectedHasOutput : true ,
363+ expectedStatusMsg : "Video generation completed but no videos were generated" ,
364+ expectedFinishReason : ai .FinishReasonStop ,
365+ expectedMediaParts : 0 ,
332366 },
333367 }
334368
@@ -345,7 +379,12 @@ func TestFromVeoOperation(t *testing.T) {
345379 t .Errorf ("fromVeoOperation() Done = %t, want %t" , result .Done , tt .expectedDone )
346380 }
347381
348- // Compare errors properly - both nil or both non-nil with same message
382+ // Check metadata is initialized
383+ if result .Metadata == nil {
384+ t .Error ("fromVeoOperation() Metadata is nil, expected initialized map" )
385+ }
386+
387+ // Compare errors
349388 if (result .Error == nil ) != (tt .expectedError == nil ) {
350389 t .Errorf ("fromVeoOperation() Error nil mismatch: got %v, want %v" , result .Error , tt .expectedError )
351390 } else if result .Error != nil && tt .expectedError != nil {
@@ -360,31 +399,51 @@ func TestFromVeoOperation(t *testing.T) {
360399 t .Errorf ("fromVeoOperation() has output = %t, want %t" , hasOutput , tt .expectedHasOutput )
361400 }
362401
363- // If we expect output, validate it's a ModelResponse with correct structure
364- if tt .expectedHasOutput && result .Output != nil {
365- modelResp := result .Output
366- if modelResp .Message == nil {
367- t .Error ("fromVeoOperation() ModelResponse.Message is nil" )
368- } else {
369- if modelResp .Message .Role != ai .RoleModel {
370- t .Errorf ("fromVeoOperation() Message.Role = %v, want %v" , modelResp .Message .Role , ai .RoleModel )
371- }
372-
373- if len (modelResp .Message .Content ) == 0 {
374- t .Error ("fromVeoOperation() Message.Content is empty" )
375- } else {
376- // Verify first content part is a media part
377- firstPart := modelResp .Message .Content [0 ]
378- if ! firstPart .IsMedia () {
379- t .Error ("fromVeoOperation() first content part is not media" )
380- }
381- }
382-
383- if modelResp .FinishReason != ai .FinishReasonStop {
384- t .Errorf ("fromVeoOperation() FinishReason = %v, want %v" , modelResp .FinishReason , ai .FinishReasonStop )
385- }
402+ // Only validate output structure if we expect output
403+ if ! tt .expectedHasOutput {
404+ return
405+ }
406+
407+ // Validate output structure
408+ if result .Output == nil {
409+ t .Fatal ("fromVeoOperation() Output is nil, expected ModelResponse" )
410+ }
411+
412+ if result .Output .Message == nil {
413+ t .Fatal ("fromVeoOperation() ModelResponse.Message is nil" )
414+ }
415+
416+ if result .Output .Message .Role != ai .RoleModel {
417+ t .Errorf ("fromVeoOperation() Message.Role = %v, want %v" , result .Output .Message .Role , ai .RoleModel )
418+ }
419+
420+ if len (result .Output .Message .Content ) == 0 {
421+ t .Fatal ("fromVeoOperation() Message.Content is empty" )
422+ }
423+
424+ // Check status message for text-based responses
425+ if tt .expectedStatusMsg != "" {
426+ firstPart := result .Output .Message .Content [0 ]
427+ if firstPart .Text != tt .expectedStatusMsg {
428+ t .Errorf ("fromVeoOperation() status message = %q, want %q" , firstPart .Text , tt .expectedStatusMsg )
386429 }
387430 }
431+
432+ // Check media parts count
433+ mediaCount := 0
434+ for _ , part := range result .Output .Message .Content {
435+ if part .IsMedia () {
436+ mediaCount ++
437+ }
438+ }
439+ if mediaCount != tt .expectedMediaParts {
440+ t .Errorf ("fromVeoOperation() media parts count = %d, want %d" , mediaCount , tt .expectedMediaParts )
441+ }
442+
443+ // Check finish reason
444+ if result .Output .FinishReason != tt .expectedFinishReason {
445+ t .Errorf ("fromVeoOperation() FinishReason = %v, want %v" , result .Output .FinishReason , tt .expectedFinishReason )
446+ }
388447 })
389448 }
390449}
0 commit comments