Skip to content

Commit 539dad8

Browse files
committed
test(binding): add regression tests for type handling in generator
- Add tests to validate correct C type mappings for different primitive types - Verify that char parameters use C.char instead of C.uint8_t - Test struct field type preservation (uint8_t, uint64_t) - Document manual bindings for variadic functions and iterators - Add regression tests for previously fixed compilation issues
1 parent 9085327 commit 539dad8

1 file changed

Lines changed: 170 additions & 0 deletions

File tree

bindings_test.go

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,3 +352,173 @@ func TestUUID(t *testing.T) {
352352
t.Logf("UUID URN parse test passed: %s", result)
353353
})
354354
}
355+
356+
// TestGeneratorCharVsUint8 verifies that char parameters use C.char, not C.uint8_t
357+
// This is a regression test for the av_match_list compilation error.
358+
func TestGeneratorCharVsUint8(t *testing.T) {
359+
// av_match_list has signature: int av_match_list(const char *name, const char *list, char separator)
360+
// The third parameter 'separator' is type char (not uint8_t)
361+
362+
// Test that the function accepts uint8 (Go's char mapping) and compiles without error
363+
name := ToCStr("test")
364+
defer name.Free()
365+
list := ToCStr("test,foo,bar")
366+
defer list.Free()
367+
368+
// If this compiles, the char→C.char mapping is working correctly
369+
// (Previously this would fail: cannot use _Ctype_uint8_t as _Ctype_char)
370+
result, err := AVMatchList(name, list, ',')
371+
372+
if err != nil {
373+
t.Fatalf("AVMatchList failed: %v", err)
374+
}
375+
if result != 1 {
376+
t.Errorf("Expected match result 1, got %d", result)
377+
}
378+
}
379+
380+
// TestGeneratorPixFmtDescriptorTypes validates that AVPixFmtDescriptor fields use correct C types
381+
// This is a regression test for uint8_t fields being incorrectly cast to C.int
382+
func TestGeneratorPixFmtDescriptorTypes(t *testing.T) {
383+
// Get a pixel format descriptor (any format will do)
384+
desc := AVPixFmtDescGet(AVPixFmtRgb24)
385+
if desc == nil {
386+
t.Fatal("RGB24 pixel format should exist")
387+
}
388+
389+
// Test uint8_t fields (nb_components, log2_chroma_w, log2_chroma_h)
390+
// These should use C.uint8_t casts, not C.int
391+
// The fact that these compile and run proves the types are correct
392+
nbComponents := desc.NbComponents()
393+
if nbComponents <= 0 || nbComponents > 4 {
394+
t.Errorf("RGB24 components should be 1-4, got %d", nbComponents)
395+
}
396+
397+
log2ChromaW := desc.Log2ChromaW()
398+
log2ChromaH := desc.Log2ChromaH()
399+
// RGB24 has no chroma subsampling
400+
if log2ChromaW != 0 {
401+
t.Errorf("RGB24 log2_chroma_w should be 0, got %d", log2ChromaW)
402+
}
403+
if log2ChromaH != 0 {
404+
t.Errorf("RGB24 log2_chroma_h should be 0, got %d", log2ChromaH)
405+
}
406+
407+
// Test uint64_t field (flags)
408+
// This should use C.uint64_t cast, not C.int
409+
flags := desc.Flags()
410+
if flags < 0 {
411+
t.Errorf("flags should be readable, got %d", flags)
412+
}
413+
// RGB24 should have RGB flag set
414+
if (flags & AVPixFmtFlagRgb) == 0 {
415+
t.Error("RGB24 should have RGB flag set")
416+
}
417+
}
418+
419+
// TestGeneratorPrimitiveTypeMapping validates that primitive types map to correct CGO types
420+
// This is a smoke test for the getCType() function
421+
func TestGeneratorPrimitiveTypeMapping(t *testing.T) {
422+
t.Run("ptrdiff_t", func(t *testing.T) {
423+
// av_image_copy_plane_uc_from uses ptrdiff_t (mapped to int64)
424+
// Verify it compiles and doesn't panic
425+
dst := make([]byte, 100)
426+
src := make([]byte, 100)
427+
AVImageCopyPlaneUcFrom(
428+
unsafe.Pointer(&dst[0]), 10,
429+
unsafe.Pointer(&src[0]), 10,
430+
10, 10,
431+
)
432+
t.Log("ptrdiff_t parameters map to C.int64_t correctly")
433+
})
434+
435+
t.Run("size_t", func(t *testing.T) {
436+
// AVMalloc uses size_t
437+
ptr := AVMalloc(1024)
438+
if ptr != nil {
439+
AVFree(ptr)
440+
}
441+
t.Log("size_t parameters map to C.size_t correctly")
442+
})
443+
}
444+
445+
// TestGeneratorManualBindings documents which patterns are intentionally skipped and have manual bindings
446+
func TestGeneratorManualBindings(t *testing.T) {
447+
t.Run("variadic_functions", func(t *testing.T) {
448+
// av_log is variadic and intentionally skipped in favor of manual binding
449+
// Just verify that our manual logging system works
450+
callback := func(ctx *LogCtx, level int, msg string) {
451+
// Test callback
452+
}
453+
AVLogSetCallback(callback)
454+
// If we reach here without panic, logging system initialized correctly
455+
t.Log("Variadic logging functions have manual bindings")
456+
})
457+
458+
t.Run("iterator_functions", func(t *testing.T) {
459+
// Iterator functions with opaque pointers are manually bound
460+
// Verify at least one iterator works
461+
var opaque unsafe.Pointer
462+
codec := AVCodecIterate(&opaque)
463+
if codec == nil {
464+
t.Error("codec iterator should return at least one codec")
465+
}
466+
t.Log("Iterator functions with opaque pointers have manual bindings")
467+
})
468+
}
469+
470+
// TestGeneratorTypePreservation validates that the CTypeName field preservation works
471+
// This is a meta-test that the generator correctly handles typedef preservation
472+
func TestGeneratorTypePreservation(t *testing.T) {
473+
t.Run("char_params_compile", func(t *testing.T) {
474+
// Functions with char parameters should compile
475+
// (regression test for char→uint8_t→C.uint8_t bug)
476+
name := ToCStr("rgb24")
477+
defer name.Free()
478+
479+
pixFmt := AVGetPixFmt(name)
480+
if pixFmt != AVPixFmtRgb24 {
481+
t.Errorf("Expected AVPixFmtRgb24, got %v", pixFmt)
482+
}
483+
})
484+
485+
t.Run("uint8_fields_compile", func(t *testing.T) {
486+
// Struct fields with uint8_t should use C.uint8_t
487+
// (regression test for uint8_t→int→C.int bug)
488+
desc := AVPixFmtDescGet(AVPixFmtYuv420P)
489+
if desc == nil {
490+
t.Fatal("YUV420P pixel format should exist")
491+
}
492+
493+
// YUV420P has 3 components
494+
components := desc.NbComponents()
495+
if components != 3 {
496+
t.Errorf("YUV420P should have 3 components, got %d", components)
497+
}
498+
499+
// And chroma subsampling (log2_chroma_w/h should be 1)
500+
chromaW := desc.Log2ChromaW()
501+
chromaH := desc.Log2ChromaH()
502+
if chromaW != 1 {
503+
t.Errorf("YUV420P log2_chroma_w should be 1, got %d", chromaW)
504+
}
505+
if chromaH != 1 {
506+
t.Errorf("YUV420P log2_chroma_h should be 1, got %d", chromaH)
507+
}
508+
})
509+
510+
t.Run("uint64_fields_compile", func(t *testing.T) {
511+
// Struct fields with uint64_t should use C.uint64_t
512+
// (regression test for uint64_t→int→C.int bug)
513+
desc := AVPixFmtDescGet(AVPixFmtRgb24)
514+
if desc == nil {
515+
t.Fatal("RGB24 pixel format should exist")
516+
}
517+
518+
flags := desc.Flags()
519+
// RGB24 should have RGB flag set
520+
if (flags & AVPixFmtFlagRgb) == 0 {
521+
t.Error("RGB24 should have RGB flag set")
522+
}
523+
})
524+
}

0 commit comments

Comments
 (0)