@@ -710,6 +710,204 @@ func TestGeneratorFieldAccessors(t *testing.T) {
710710 })
711711}
712712
713+ // =============================================================================
714+ // Test: Array Bounds Behaviour Documentation
715+ // =============================================================================
716+
717+ // TestArray_BoundsBehaviour documents and verifies the bounds behaviour of the
718+ // Array[T] type. This is a critical safety documentation test.
719+ //
720+ // IMPORTANT: The Array type has NO bounds checking, matching C behaviour.
721+ // Out-of-bounds access leads to undefined behaviour (memory corruption, crashes,
722+ // or silent data corruption). This is by design to match FFmpeg's C semantics.
723+ //
724+ // Users MUST track array lengths themselves, just as in C code.
725+ func TestArray_BoundsBehaviour (t * testing.T ) {
726+ t .Run ("valid_indices_work_correctly" , func (t * testing.T ) {
727+ // Allocate array of 3 elements
728+ arr := AllocAVCodecIDArray (3 )
729+ if arr == nil {
730+ t .Fatal ("AllocAVCodecIDArray returned nil" )
731+ }
732+ defer AVFree (arr .RawPtr ())
733+
734+ // Valid indices: 0, 1, 2
735+ arr .Set (0 , AVCodecIdH264 )
736+ arr .Set (1 , AVCodecIdHevc )
737+ arr .Set (2 , AVCodecIdAV1 )
738+
739+ if arr .Get (0 ) != AVCodecIdH264 {
740+ t .Errorf ("Get(0) = %v, want AVCodecIdH264" , arr .Get (0 ))
741+ }
742+ if arr .Get (1 ) != AVCodecIdHevc {
743+ t .Errorf ("Get(1) = %v, want AVCodecIdHevc" , arr .Get (1 ))
744+ }
745+ if arr .Get (2 ) != AVCodecIdAV1 {
746+ t .Errorf ("Get(2) = %v, want AVCodecIdAV1" , arr .Get (2 ))
747+ }
748+ })
749+
750+ t .Run ("documents_no_bounds_checking" , func (t * testing.T ) {
751+ // This test documents that Array has NO bounds checking.
752+ // We cannot safely test out-of-bounds access as it causes undefined behaviour.
753+ //
754+ // DO NOT uncomment the following - it will cause memory corruption:
755+ // arr := AllocAVCodecIDArray(3)
756+ // arr.Get(100) // UNDEFINED BEHAVIOUR - reads arbitrary memory
757+ // arr.Set(100, AVCodecIdH264) // UNDEFINED BEHAVIOUR - writes arbitrary memory
758+ //
759+ // Users must track array lengths themselves. This matches C semantics where
760+ // arrays are just pointers with no length information.
761+
762+ t .Log ("Array[T] has NO bounds checking - matches C semantics" )
763+ t .Log ("Out-of-bounds access causes undefined behaviour (crash or corruption)" )
764+ t .Log ("Users MUST track array lengths themselves" )
765+ })
766+
767+ t .Run ("zero_index_is_valid" , func (t * testing.T ) {
768+ // Verify index 0 works for any non-empty array
769+ arr := AllocAVCodecIDArray (1 )
770+ if arr == nil {
771+ t .Fatal ("AllocAVCodecIDArray returned nil" )
772+ }
773+ defer AVFree (arr .RawPtr ())
774+
775+ arr .Set (0 , AVCodecIdMpeg2Video )
776+ if arr .Get (0 ) != AVCodecIdMpeg2Video {
777+ t .Errorf ("Get(0) = %v, want AVCodecIdMpeg2Video" , arr .Get (0 ))
778+ }
779+ })
780+
781+ t .Run ("last_valid_index" , func (t * testing.T ) {
782+ // Verify the last valid index (size-1) works correctly
783+ const size = 5
784+ arr := AllocAVCodecIDArray (size )
785+ if arr == nil {
786+ t .Fatal ("AllocAVCodecIDArray returned nil" )
787+ }
788+ defer AVFree (arr .RawPtr ())
789+
790+ // Set last element (index size-1)
791+ arr .Set (size - 1 , AVCodecIdVp9 )
792+ if arr .Get (size - 1 ) != AVCodecIdVp9 {
793+ t .Errorf ("Get(%d) = %v, want AVCodecIdVp9" , size - 1 , arr .Get (size - 1 ))
794+ }
795+ })
796+
797+ t .Run ("primitive_arrays_same_behaviour" , func (t * testing.T ) {
798+ // Verify primitive type arrays also have no bounds checking
799+ // Test with int array using ToIntArray
800+
801+ // Allocate raw memory for 3 ints
802+ ptr := AVMalloc (uint64 (3 * intSize ))
803+ if ptr == nil {
804+ t .Fatal ("AVMalloc returned nil" )
805+ }
806+ defer AVFree (ptr )
807+
808+ arr := ToIntArray (ptr )
809+ if arr == nil {
810+ t .Fatal ("ToIntArray returned nil" )
811+ }
812+
813+ // Valid access
814+ arr .Set (0 , 42 )
815+ arr .Set (1 , 100 )
816+ arr .Set (2 , - 1 )
817+
818+ if arr .Get (0 ) != 42 {
819+ t .Errorf ("int array Get(0) = %v, want 42" , arr .Get (0 ))
820+ }
821+ if arr .Get (1 ) != 100 {
822+ t .Errorf ("int array Get(1) = %v, want 100" , arr .Get (1 ))
823+ }
824+ if arr .Get (2 ) != - 1 {
825+ t .Errorf ("int array Get(2) = %v, want -1" , arr .Get (2 ))
826+ }
827+
828+ t .Log ("Primitive arrays (ToIntArray, ToUint8Array, etc.) also have no bounds checking" )
829+ })
830+
831+ t .Run ("nil_array_panics" , func (t * testing.T ) {
832+ // Nil array should panic on access - this IS checked
833+ var arr * Array [AVCodecID ] = nil
834+
835+ defer func () {
836+ if r := recover (); r == nil {
837+ t .Error ("Expected panic when accessing nil array, but none occurred" )
838+ } else {
839+ t .Logf ("Nil array access correctly panics: %v" , r )
840+ }
841+ }()
842+
843+ // This should panic
844+ _ = arr .Get (0 )
845+ })
846+ }
847+
848+ // TestArray_SafeUsagePatterns documents safe patterns for using Array[T]
849+ func TestArray_SafeUsagePatterns (t * testing.T ) {
850+ t .Run ("track_length_manually" , func (t * testing.T ) {
851+ // Safe pattern: always track length alongside array
852+ const length = 3
853+ arr := AllocAVCodecIDArray (length )
854+ if arr == nil {
855+ t .Fatal ("AllocAVCodecIDArray returned nil" )
856+ }
857+ defer AVFree (arr .RawPtr ())
858+
859+ // Safe iteration using tracked length
860+ values := []AVCodecID {AVCodecIdH264 , AVCodecIdHevc , AVCodecIdAV1 }
861+ for i := 0 ; i < length ; i ++ {
862+ arr .Set (uintptr (i ), values [i ])
863+ }
864+
865+ // Safe read using tracked length
866+ for i := 0 ; i < length ; i ++ {
867+ if arr .Get (uintptr (i )) != values [i ] {
868+ t .Errorf ("Get(%d) mismatch" , i )
869+ }
870+ }
871+
872+ t .Log ("Safe pattern: track array length in a separate variable" )
873+ })
874+
875+ t .Run ("use_sentinel_values" , func (t * testing.T ) {
876+ // Safe pattern: use sentinel value to mark end (like null-terminated strings)
877+ // Many FFmpeg APIs use AVCodecIdNone or -1 as sentinel
878+ arr := AllocAVCodecIDArray (4 )
879+ if arr == nil {
880+ t .Fatal ("AllocAVCodecIDArray returned nil" )
881+ }
882+ defer AVFree (arr .RawPtr ())
883+
884+ // Store values with sentinel
885+ arr .Set (0 , AVCodecIdH264 )
886+ arr .Set (1 , AVCodecIdHevc )
887+ arr .Set (2 , AVCodecIdAV1 )
888+ arr .Set (3 , AVCodecIdNone ) // Sentinel
889+
890+ // Safe iteration using sentinel
891+ count := 0
892+ for i := uintptr (0 ); ; i ++ {
893+ val := arr .Get (i )
894+ if val == AVCodecIdNone {
895+ break
896+ }
897+ count ++
898+ if count > 100 { // Safety limit
899+ t .Fatal ("Sentinel not found within reasonable range" )
900+ }
901+ }
902+
903+ if count != 3 {
904+ t .Errorf ("Found %d elements before sentinel, want 3" , count )
905+ }
906+
907+ t .Log ("Safe pattern: use sentinel value (e.g., AVCodecIdNone) to mark end" )
908+ })
909+ }
910+
713911// TestGeneratorEnumArrayHelpers validates that enum array helpers work correctly
714912// This tests the AllocXArray generation pattern for enums
715913func TestGeneratorEnumArrayHelpers (t * testing.T ) {
0 commit comments