Skip to content

Commit 6b898a0

Browse files
committed
test: add UUID parse error path validation tests
- Test rejection of malformed UUIDs (too short/long, missing dashes, wrong dash positions) - Verify non-hexadecimal character detection - Validate URN format requirements (prefix and UUID part) - Confirm case-insensitive parsing per RFC 4122 - Test AVUuidParseRange with incorrect length - All error paths return negative error codes (-22 EINVAL) - Prevents silent corruption from accepting invalid UUID data
1 parent 6136b7b commit 6b898a0

1 file changed

Lines changed: 241 additions & 0 deletions

File tree

bindings_test.go

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,247 @@ func TestUUID(t *testing.T) {
355355
})
356356
}
357357

358+
// =============================================================================
359+
// Test: UUID Parse Error Paths
360+
// =============================================================================
361+
362+
// TestUUID_ParseErrorPaths tests error detection in UUID parsing functions.
363+
// This validates that malformed UUIDs are properly rejected and return error codes,
364+
// preventing silent corruption from accepting invalid data.
365+
func TestUUID_ParseErrorPaths(t *testing.T) {
366+
t.Run("invalid_uuid_format_too_short", func(t *testing.T) {
367+
// UUID must be exactly 36 characters (plus NUL)
368+
tooShort := "550e8400-e29b-41d4-a716-44665544"
369+
var uuid AVUUID
370+
371+
cStr := ToCStr(tooShort)
372+
defer cStr.Free()
373+
374+
ret, err := AVUuidParse(cStr, &uuid)
375+
if ret == 0 || err == nil {
376+
t.Errorf("AVUuidParse should fail for too-short UUID, got ret=%d err=%v", ret, err)
377+
}
378+
379+
t.Logf("Correctly rejected too-short UUID: ret=%d", ret)
380+
})
381+
382+
t.Run("invalid_uuid_format_too_long", func(t *testing.T) {
383+
// Too many characters
384+
tooLong := "550e8400-e29b-41d4-a716-446655440000-extra"
385+
var uuid AVUUID
386+
387+
cStr := ToCStr(tooLong)
388+
defer cStr.Free()
389+
390+
ret, err := AVUuidParse(cStr, &uuid)
391+
if ret == 0 || err == nil {
392+
t.Errorf("AVUuidParse should fail for too-long UUID, got ret=%d err=%v", ret, err)
393+
}
394+
395+
t.Logf("Correctly rejected too-long UUID: ret=%d", ret)
396+
})
397+
398+
t.Run("invalid_uuid_missing_dashes", func(t *testing.T) {
399+
// Correct length but missing dashes
400+
noDashes := "550e8400e29b41d4a716446655440000"
401+
var uuid AVUUID
402+
403+
cStr := ToCStr(noDashes)
404+
defer cStr.Free()
405+
406+
ret, err := AVUuidParse(cStr, &uuid)
407+
if ret == 0 || err == nil {
408+
t.Errorf("AVUuidParse should fail for UUID without dashes, got ret=%d err=%v", ret, err)
409+
}
410+
411+
t.Logf("Correctly rejected UUID without dashes: ret=%d", ret)
412+
})
413+
414+
t.Run("invalid_uuid_wrong_dash_positions", func(t *testing.T) {
415+
// Dashes in wrong positions
416+
wrongDashes := "550e8400e29b-41d4-a716-446655440000"
417+
var uuid AVUUID
418+
419+
cStr := ToCStr(wrongDashes)
420+
defer cStr.Free()
421+
422+
ret, err := AVUuidParse(cStr, &uuid)
423+
if ret == 0 || err == nil {
424+
t.Errorf("AVUuidParse should fail for UUID with wrong dash positions, got ret=%d err=%v", ret, err)
425+
}
426+
427+
t.Logf("Correctly rejected UUID with wrong dashes: ret=%d", ret)
428+
})
429+
430+
t.Run("invalid_uuid_non_hex_characters", func(t *testing.T) {
431+
// Contains non-hex characters
432+
invalidChars := "550e8400-e29b-41d4-a716-44665544GGGG"
433+
var uuid AVUUID
434+
435+
cStr := ToCStr(invalidChars)
436+
defer cStr.Free()
437+
438+
ret, err := AVUuidParse(cStr, &uuid)
439+
if ret == 0 || err == nil {
440+
t.Errorf("AVUuidParse should fail for non-hex characters, got ret=%d err=%v", ret, err)
441+
}
442+
443+
t.Logf("Correctly rejected UUID with non-hex chars: ret=%d", ret)
444+
})
445+
446+
t.Run("invalid_uuid_empty_string", func(t *testing.T) {
447+
// Empty string
448+
var uuid AVUUID
449+
450+
cStr := ToCStr("")
451+
defer cStr.Free()
452+
453+
ret, err := AVUuidParse(cStr, &uuid)
454+
if ret == 0 || err == nil {
455+
t.Errorf("AVUuidParse should fail for empty string, got ret=%d err=%v", ret, err)
456+
}
457+
458+
t.Logf("Correctly rejected empty UUID string: ret=%d", ret)
459+
})
460+
461+
t.Run("valid_uuid_uppercase_accepted", func(t *testing.T) {
462+
// RFC 4122 specifies parsing should be case-insensitive
463+
uppercaseUUID := "550E8400-E29B-41D4-A716-446655440000"
464+
var uuid AVUUID
465+
466+
cStr := ToCStr(uppercaseUUID)
467+
defer cStr.Free()
468+
469+
ret, err := AVUuidParse(cStr, &uuid)
470+
if ret != 0 || err != nil {
471+
t.Fatalf("AVUuidParse should accept uppercase UUID, got ret=%d err=%v", ret, err)
472+
}
473+
474+
// Verify by unparsing (should be lowercase)
475+
outStr := AllocCStr(37)
476+
defer outStr.Free()
477+
AVUuidUnparse(&uuid, outStr)
478+
479+
result := outStr.String()
480+
expected := "550e8400-e29b-41d4-a716-446655440000"
481+
if result != expected {
482+
t.Errorf("Unparsed UUID mismatch: got %s, want %s", result, expected)
483+
}
484+
485+
t.Logf("Uppercase UUID correctly parsed and normalized: %s -> %s", uppercaseUUID, result)
486+
})
487+
488+
t.Run("urn_invalid_format_missing_prefix", func(t *testing.T) {
489+
// URN must start with "urn:uuid:"
490+
noPrefix := "550e8400-e29b-41d4-a716-446655440000"
491+
var uuid AVUUID
492+
493+
cStr := ToCStr(noPrefix)
494+
defer cStr.Free()
495+
496+
ret, err := AVUuidUrnParse(cStr, &uuid)
497+
if ret == 0 || err == nil {
498+
t.Errorf("AVUuidUrnParse should fail without urn:uuid: prefix, got ret=%d err=%v", ret, err)
499+
}
500+
501+
t.Logf("Correctly rejected URN without prefix: ret=%d", ret)
502+
})
503+
504+
t.Run("urn_invalid_format_wrong_prefix", func(t *testing.T) {
505+
// Wrong URN prefix
506+
wrongPrefix := "uuid:uuid:550e8400-e29b-41d4-a716-446655440000"
507+
var uuid AVUUID
508+
509+
cStr := ToCStr(wrongPrefix)
510+
defer cStr.Free()
511+
512+
ret, err := AVUuidUrnParse(cStr, &uuid)
513+
if ret == 0 || err == nil {
514+
t.Errorf("AVUuidUrnParse should fail with wrong prefix, got ret=%d err=%v", ret, err)
515+
}
516+
517+
t.Logf("Correctly rejected URN with wrong prefix: ret=%d", ret)
518+
})
519+
520+
t.Run("urn_invalid_uuid_part", func(t *testing.T) {
521+
// URN with invalid UUID part
522+
invalidURN := "urn:uuid:550e8400-e29b-41d4-a716-GGGGGGGGGGGG"
523+
var uuid AVUUID
524+
525+
cStr := ToCStr(invalidURN)
526+
defer cStr.Free()
527+
528+
ret, err := AVUuidUrnParse(cStr, &uuid)
529+
if ret == 0 || err == nil {
530+
t.Errorf("AVUuidUrnParse should fail with invalid UUID part, got ret=%d err=%v", ret, err)
531+
}
532+
533+
t.Logf("Correctly rejected URN with invalid UUID: ret=%d", ret)
534+
})
535+
536+
t.Run("urn_case_insensitive", func(t *testing.T) {
537+
// URN parsing should be case-insensitive for the "urn:uuid:" prefix
538+
mixedCase := "URN:UUID:550e8400-e29b-41d4-a716-446655440000"
539+
var uuid AVUUID
540+
541+
cStr := ToCStr(mixedCase)
542+
defer cStr.Free()
543+
544+
// This may or may not be accepted depending on FFmpeg's strictness
545+
// Document the actual behaviour
546+
ret, _ := AVUuidUrnParse(cStr, &uuid)
547+
548+
if ret == 0 {
549+
t.Logf("Mixed-case URN prefix accepted: %s", mixedCase)
550+
} else {
551+
t.Logf("Mixed-case URN prefix rejected (ret=%d) - prefix is case-sensitive", ret)
552+
}
553+
})
554+
555+
t.Run("parse_range_exact_length", func(t *testing.T) {
556+
// AVUuidParseRange requires exact 36-character range
557+
uuidStr := "550e8400-e29b-41d4-a716-446655440000"
558+
var uuid AVUUID
559+
560+
// Create start and end pointers into the UUID string
561+
start := ToCStr(uuidStr)
562+
defer start.Free()
563+
564+
// End pointer should be exactly 36 chars after start
565+
ret, err := AVUuidParseRange(start, start, &uuid)
566+
if ret == 0 || err == nil {
567+
t.Errorf("AVUuidParseRange should fail with zero-length range, got ret=%d err=%v", ret, err)
568+
}
569+
570+
t.Logf("Correctly rejected zero-length range: ret=%d", ret)
571+
})
572+
573+
t.Run("error_code_is_negative", func(t *testing.T) {
574+
// All UUID parse errors should return negative codes
575+
testCases := []string{
576+
"", // empty
577+
"invalid", // too short
578+
"550e8400-e29b-41d4-a716-44665544XXXX", // invalid chars
579+
}
580+
581+
for _, testStr := range testCases {
582+
var uuid AVUUID
583+
cStr := ToCStr(testStr)
584+
ret, err := AVUuidParse(cStr, &uuid)
585+
cStr.Free()
586+
587+
if ret >= 0 && ret != 0 {
588+
t.Errorf("Error code should be negative or zero, got %d for %q", ret, testStr)
589+
}
590+
if ret < 0 && err == nil {
591+
t.Errorf("Negative return code should have non-nil error, got nil for %q", testStr)
592+
}
593+
}
594+
595+
t.Log("All UUID parse errors correctly return negative codes")
596+
})
597+
}
598+
358599
// TestGeneratorCharVsUint8 verifies that char parameters use C.char, not C.uint8_t
359600
// This is a regression test for the av_match_list compilation error.
360601
func TestGeneratorCharVsUint8(t *testing.T) {

0 commit comments

Comments
 (0)