@@ -675,3 +675,178 @@ describe("rightIsInline - Real-World Scenarios", () => {
675675 expect ( child . props . style ) . toEqual ( [ { color : "#000" } , { fontSize : 14 } ] ) ;
676676 } ) ;
677677} ) ;
678+
679+ describe ( "rightIsInline - Red Team Edge Cases" , ( ) => {
680+ test ( "handles circular references with depth limit" , ( ) => {
681+ registerCSS ( `.container { padding: 10px; }` ) ;
682+
683+ const circular : any = { color : "red" , padding : 5 } ;
684+ circular . self = circular ;
685+
686+ const component = render (
687+ < View testID = { testID } className = "container" style = { circular } /> ,
688+ ) . getByTestId ( testID ) ;
689+
690+ // Should not crash, depth limit prevents infinite recursion
691+ expect ( component . props . style ) . toBeDefined ( ) ;
692+ // Circular reference is preserved up to depth limit, just verify no crash
693+ } ) ;
694+
695+ test ( "handles sparse arrays without crashes" , ( ) => {
696+ registerCSS ( `.base { margin: 5px; }` ) ;
697+
698+ const sparseArray = [
699+ { color : "red" } ,
700+ undefined ,
701+ undefined ,
702+ { padding : 10 } ,
703+ ] ;
704+
705+ const component = render (
706+ < View testID = { testID } className = "base" style = { sparseArray as any } /> ,
707+ ) . getByTestId ( testID ) ;
708+
709+ // Should handle undefined holes in array
710+ expect ( component . props . style ) . toBeDefined ( ) ;
711+ } ) ;
712+
713+ test ( "handles objects with only Symbol properties" , ( ) => {
714+ registerCSS ( `.text { font-size: 14px; }` ) ;
715+
716+ const onlySymbols = {
717+ [ Symbol ( "test" ) ] : "value" ,
718+ [ Symbol ( "another" ) ] : "data" ,
719+ } ;
720+
721+ const component = render (
722+ < Text testID = { testID } className = "text" style = { onlySymbols as any } /> ,
723+ ) . getByTestId ( testID ) ;
724+
725+ // Symbols should be filtered, only className remains
726+ expect ( component . props . style ) . toEqual ( { fontSize : 14 } ) ;
727+ } ) ;
728+
729+ test ( "handles mixed null/undefined/falsy values in arrays" , ( ) => {
730+ registerCSS ( `.container { width: 100px; }` ) ;
731+
732+ const mixedArray = [
733+ null ,
734+ undefined ,
735+ { opacity : 0 } , // 0 is valid
736+ { display : false as any } , // false might be valid
737+ { padding : 10 } ,
738+ ] ;
739+
740+ const component = render (
741+ < View testID = { testID } className = "container" style = { mixedArray as any } /> ,
742+ ) . getByTestId ( testID ) ;
743+
744+ // Should preserve falsy values like 0 and false in objects
745+ expect ( component . props . style ) . toBeDefined ( ) ;
746+ const flatStyle = Array . isArray ( component . props . style )
747+ ? component . props . style . flat ( )
748+ : [ component . props . style ] ;
749+ const hasOpacity = flatStyle . some (
750+ ( s ) => s && typeof s === "object" && "opacity" in s ,
751+ ) ;
752+ expect ( hasOpacity ) . toBe ( true ) ;
753+ } ) ;
754+
755+ test ( "handles frozen objects without modification errors" , ( ) => {
756+ registerCSS ( `.frozen { margin: 5px; }` ) ;
757+
758+ const frozen = Object . freeze ( { color : "blue" , padding : 10 } ) ;
759+
760+ const component = render (
761+ < View testID = { testID } className = "frozen" style = { frozen as any } /> ,
762+ ) . getByTestId ( testID ) ;
763+
764+ // Should not crash on frozen objects
765+ expect ( component . props . style ) . toBeDefined ( ) ;
766+ } ) ;
767+
768+ test ( "handles very deep nesting beyond depth limit" , ( ) => {
769+ registerCSS ( `.deep { color: red; }` ) ;
770+
771+ // Create nesting beyond the 100 level limit
772+ let veryDeep : any = { value : 1 } ;
773+ for ( let i = 0 ; i < 105 ; i ++ ) {
774+ veryDeep = { nested : veryDeep } ;
775+ }
776+
777+ const component = render (
778+ < View testID = { testID } className = "deep" style = { veryDeep } /> ,
779+ ) . getByTestId ( testID ) ;
780+
781+ // Should hit depth limit and return gracefully
782+ expect ( component . props . style ) . toBeDefined ( ) ;
783+ } ) ;
784+
785+ test ( "handles __proto__ without prototype pollution" , ( ) => {
786+ registerCSS ( `.safe { padding: 10px; }` ) ;
787+
788+ // Attempt prototype pollution
789+ const malicious = {
790+ color : "red" ,
791+ __proto__ : { isAdmin : true } ,
792+ } ;
793+
794+ const component = render (
795+ < View testID = { testID } className = "safe" style = { malicious as any } /> ,
796+ ) . getByTestId ( testID ) ;
797+
798+ // Should not pollute prototype
799+ expect ( component . props . style ) . toBeDefined ( ) ;
800+ expect ( ( { } as any ) . isAdmin ) . toBeUndefined ( ) ;
801+ } ) ;
802+
803+ test ( "handles arrays with custom properties" , ( ) => {
804+ registerCSS ( `.custom { margin: 5px; }` ) ;
805+
806+ const arrayWithProps : any = [ { color : "red" } , { padding : 10 } ] ;
807+ arrayWithProps . customProp = "should be ignored" ;
808+
809+ const component = render (
810+ < View testID = { testID } className = "custom" style = { arrayWithProps } /> ,
811+ ) . getByTestId ( testID ) ;
812+
813+ // Custom array properties should not cause issues
814+ expect ( component . props . style ) . toBeDefined ( ) ;
815+ } ) ;
816+
817+ test ( "handles empty arrays and objects correctly" , ( ) => {
818+ registerCSS ( `.empty { width: 50px; }` ) ;
819+
820+ const emptyArray : any [ ] = [ ] ;
821+ const emptyObject = { } ;
822+
823+ const component1 = render (
824+ < View testID = "test1" className = "empty" style = { emptyArray } /> ,
825+ ) . getByTestId ( "test1" ) ;
826+
827+ const component2 = render (
828+ < View testID = "test2" className = "empty" style = { emptyObject } /> ,
829+ ) . getByTestId ( "test2" ) ;
830+
831+ // Empty styles should not break rendering
832+ expect ( component1 . props . style ) . toBeDefined ( ) ;
833+ expect ( component2 . props . style ) . toBeDefined ( ) ;
834+ } ) ;
835+
836+ test ( "handles numeric string keys without issues" , ( ) => {
837+ registerCSS ( `.numeric { padding: 5px; }` ) ;
838+
839+ const numericKeys = {
840+ "0" : "value0" ,
841+ "1" : "value1" ,
842+ "color" : "red" ,
843+ } ;
844+
845+ const component = render (
846+ < View testID = { testID } className = "numeric" style = { numericKeys as any } /> ,
847+ ) . getByTestId ( testID ) ;
848+
849+ // Numeric string keys should be handled
850+ expect ( component . props . style ) . toBeDefined ( ) ;
851+ } ) ;
852+ } ) ;
0 commit comments