@@ -177,6 +177,57 @@ FST_TEST_BEGIN(dup_uniq_bench)
177177}
178178FST_TEST_END ()
179179
180+ FST_TEST_BEGIN (dup_faithful_copy )
181+ {
182+ /* Regression for the switch_event_dup O(n^2)->O(n) change (suppressing the
183+ * per-add EF_UNIQ_HEADERS dedup scan while cloning). dup must reproduce the
184+ * source faithfully:
185+ * (1) a well-formed EF_UNIQ source stays unique through dup (the real case);
186+ * (2) a malformed source that already holds duplicate names (only possible
187+ * if headers were added before EF_UNIQ_HEADERS was set) is copied
188+ * faithfully -- dup PRESERVES the duplicates rather than silently
189+ * collapsing to the last value. A dup-bearing EF_UNIQ event is already
190+ * a bug upstream of here; a copy must not silently drop data. */
191+ switch_event_t * src = NULL , * dup = NULL ;
192+ switch_event_header_t * hp ;
193+ switch_status_t status ;
194+ int n ;
195+
196+ /* (1) well-formed EF_UNIQ source -> unique dup */
197+ status = switch_event_create (& src , SWITCH_EVENT_CHANNEL_DATA );
198+ fst_xcheck (status == SWITCH_STATUS_SUCCESS , "create CHANNEL_DATA" );
199+ fst_xcheck (switch_test_flag (src , EF_UNIQ_HEADERS ) != 0 , "CHANNEL_DATA is EF_UNIQ" );
200+ switch_event_add_header_string (src , SWITCH_STACK_BOTTOM , "k" , "v1" );
201+ switch_event_add_header_string (src , SWITCH_STACK_BOTTOM , "k" , "v2" );
202+ n = 0 ; for (hp = src -> headers ; hp ; hp = hp -> next ) { if (!strcmp (hp -> name , "k" )) n ++ ; }
203+ fst_xcheck (n == 1 , "EF_UNIQ source keeps 'k' unique (collapsed to last)" );
204+ status = switch_event_dup (& dup , src );
205+ fst_xcheck (status == SWITCH_STATUS_SUCCESS , "dup ok (unique)" );
206+ n = 0 ; for (hp = dup -> headers ; hp ; hp = hp -> next ) { if (!strcmp (hp -> name , "k" )) n ++ ; }
207+ fst_xcheck (n == 1 , "dup of unique source stays unique" );
208+ fst_check_string_equals (switch_event_get_header (dup , "k" ), "v2" );
209+ switch_event_destroy (& dup );
210+ switch_event_destroy (& src );
211+
212+ /* (2) malformed source (duplicate names under EF_UNIQ) -> faithful copy */
213+ status = switch_event_create (& src , SWITCH_EVENT_GENERAL );
214+ fst_xcheck (status == SWITCH_STATUS_SUCCESS , "create GENERAL" );
215+ fst_xcheck (switch_test_flag (src , EF_UNIQ_HEADERS ) == 0 , "GENERAL is not EF_UNIQ" );
216+ switch_event_add_header_string (src , SWITCH_STACK_BOTTOM , "dupkey" , "first" );
217+ switch_event_add_header_string (src , SWITCH_STACK_BOTTOM , "dupkey" , "second" );
218+ switch_set_flag (src , EF_UNIQ_HEADERS );
219+ n = 0 ; for (hp = src -> headers ; hp ; hp = hp -> next ) { if (!strcmp (hp -> name , "dupkey" )) n ++ ; }
220+ fst_xcheck (n == 2 , "malformed source holds 2 'dupkey' headers" );
221+ status = switch_event_dup (& dup , src );
222+ fst_xcheck (status == SWITCH_STATUS_SUCCESS , "dup ok (malformed)" );
223+ fst_xcheck (switch_test_flag (dup , EF_UNIQ_HEADERS ) != 0 , "dup keeps EF_UNIQ flag" );
224+ n = 0 ; for (hp = dup -> headers ; hp ; hp = hp -> next ) { if (!strcmp (hp -> name , "dupkey" )) n ++ ; }
225+ fst_xcheck (n == 2 , "dup faithfully preserves both 'dupkey' headers (no silent collapse)" );
226+ switch_event_destroy (& dup );
227+ switch_event_destroy (& src );
228+ }
229+ FST_TEST_END ()
230+
180231FST_SUITE_END ()
181232
182233FST_MINCORE_END ()
0 commit comments