@@ -69,4 +69,147 @@ public function testChangeContentAfterEncoderModifyRestoresShortcodes()
6969
7070 $ this ->assertEquals ('Test content ' , $ result );
7171 }
72+
73+ public function testShortcodeInsideHtmlAttributeIsNotProcessed ()
74+ {
75+ $ content = '<a title="[apbct_encode_data]test[/apbct_encode_data]">X</a> ' ;
76+
77+ $ result = $ this ->shortcode ->changeContentBeforeEncoderModify ($ content );
78+
79+ // shortcode should NOT be replaced because it's inside HTML tag
80+ $ this ->assertEquals ($ content , $ result );
81+ }
82+
83+ public function testShortcodeOutsideHtmlIsProcessed ()
84+ {
85+ $ content = '[apbct_encode_data]Test content[/apbct_encode_data] ' ;
86+
87+ $ result = $ this ->shortcode ->changeContentBeforeEncoderModify ($ content );
88+
89+ $ this ->assertStringContainsString (
90+ '%%APBCT_SHORT_CODE_INCLUDE_EE_0%% ' ,
91+ $ result
92+ );
93+
94+ $ this ->assertNotEquals ($ content , $ result );
95+ }
96+
97+ public function testMultipleShortcodesAreHandled ()
98+ {
99+ $ content =
100+ '[apbct_encode_data]A[/apbct_encode_data] ' .
101+ ' middle ' .
102+ '[apbct_encode_data]B[/apbct_encode_data] ' ;
103+
104+ $ result = $ this ->shortcode ->changeContentBeforeEncoderModify ($ content );
105+
106+ $ this ->assertStringContainsString ('%%APBCT_SHORT_CODE_INCLUDE_EE_0%% ' , $ result );
107+ $ this ->assertStringContainsString ('%%APBCT_SHORT_CODE_INCLUDE_EE_1%% ' , $ result );
108+ }
109+
110+ public function testHtmlAttributeBreakPayloadDoesNotExplode ()
111+ {
112+ $ content = '<a href="http://x" title="[/apbct_encode_data]">Test</a> ' ;
113+
114+ $ result = $ this ->shortcode ->changeContentBeforeEncoderModify ($ content );
115+
116+ // must remain stable, no corruption, no placeholder injection inside tag
117+ $ this ->assertStringContainsString ('<a ' , $ result );
118+ $ this ->assertStringContainsString ('</a> ' , $ result );
119+ }
120+
121+ public function testOffsetDetectionInsideHtmlTag ()
122+ {
123+ $ content = '<a title="[apbct_encode_data]">X</a> ' ;
124+
125+ $ pos = strpos ($ content , '[apbct_encode_data] ' );
126+
127+ $ this ->assertTrue (
128+ $ this ->shortcode ->isOffsetInsideHtmlTag ($ content , $ pos )
129+ );
130+ }
131+
132+ public function testOffsetDetectionOutsideHtmlTag ()
133+ {
134+ $ content = '[apbct_encode_data]test[/apbct_encode_data] ' ;
135+
136+ $ pos = strpos ($ content , '[apbct_encode_data] ' );
137+
138+ $ this ->assertFalse (
139+ $ this ->shortcode ->isOffsetInsideHtmlTag ($ content , $ pos )
140+ );
141+ }
142+
143+ public function testShortcodeWithAttributesIsProcessed ()
144+ {
145+ $ content = '[apbct_encode_data mode="blur"]Test[/apbct_encode_data] ' ;
146+
147+ $ result = $ this ->shortcode ->changeContentBeforeEncoderModify ($ content );
148+
149+ $ this ->assertStringContainsString (
150+ '%%APBCT_SHORT_CODE_INCLUDE_EE_0%% ' ,
151+ $ result
152+ );
153+
154+ $ this ->assertNotEquals ($ content , $ result );
155+ }
156+
157+ public function testShortcodeWithAttributesIsDetectedInHtmlContext ()
158+ {
159+ $ content = '<a title="[apbct_encode_data mode=\"blur\"]test[/apbct_encode_data]">X</a> ' ;
160+
161+ $ result = $ this ->shortcode ->changeContentBeforeEncoderModify ($ content );
162+
163+ // must be blocked due to HTML attribute context
164+ $ this ->assertEquals ($ content , $ result );
165+ }
166+
167+ public function testMixedShortcodesSafeAndUnsafe ()
168+ {
169+ $ content =
170+ '[apbct_encode_data]SAFE[/apbct_encode_data] ' .
171+ '<a title="[apbct_encode_data]BAD[/apbct_encode_data]"> ' .
172+ 'X</a> ' ;
173+
174+ $ result = $ this ->shortcode ->changeContentBeforeEncoderModify ($ content );
175+
176+ // because of current design: full block is skipped if ANY HTML-unsafe shortcode exists
177+ $ this ->assertEquals ($ content , $ result );
178+ }
179+
180+ public function testPlaceholderNeverAppearsInsideHtmlAttribute ()
181+ {
182+ $ content = '<a title="[apbct_encode_data]Test[/apbct_encode_data]">X</a> ' ;
183+
184+ $ result = $ this ->shortcode ->changeContentBeforeEncoderModify ($ content );
185+
186+ $ this ->assertStringNotContainsString ('%%APBCT_SHORT_CODE_INCLUDE_EE_0%% ' , $ result );
187+ }
188+
189+ public function testCallbackEscapesReplacingText ()
190+ {
191+ $ result = $ this ->shortcode ->callback (
192+ ['replacing_text ' => '<script>alert(1)</script> ' ],
193+ 'content ' ,
194+ 'apbct_encode_data '
195+ );
196+
197+ $ this ->assertStringNotContainsString ('<script> ' , $ result );
198+ }
199+
200+ public function testRestoreIntegrityWithMultiplePlaceholders ()
201+ {
202+ $ this ->shortcode ->shortcode_replacements = [
203+ '%%APBCT_SHORT_CODE_INCLUDE_EE_0%% ' => '[apbct_encode_data]A[/apbct_encode_data] ' ,
204+ '%%APBCT_SHORT_CODE_INCLUDE_EE_1%% ' => '[apbct_encode_data]B[/apbct_encode_data] ' ,
205+ ];
206+
207+ $ content = '%%APBCT_SHORT_CODE_INCLUDE_EE_0%% and %%APBCT_SHORT_CODE_INCLUDE_EE_1%% ' ;
208+
209+ $ result = $ this ->shortcode ->changeContentAfterEncoderModify ($ content );
210+
211+ $ this ->assertStringContainsString ('A ' , $ result );
212+ $ this ->assertStringContainsString ('B ' , $ result );
213+ }
214+
72215}
0 commit comments