@@ -211,6 +211,88 @@ public function test_boolean_sanitizer_works_correctly(): void {
211211 $ this ->assertFalse ( $ sanitizer ( 'no ' ) );
212212 }
213213
214+ public function test_field_type_registry_has_map_types (): void {
215+ $ registry = new FieldTypeRegistry ();
216+
217+ $ this ->assertTrue ( $ registry ->has_type ( 'map ' ) );
218+ $ this ->assertTrue ( $ registry ->has_type ( 'boolean_map ' ) );
219+
220+ $ this ->assertEquals ( DataSet::TYPE_ARRAY , $ registry ->get_dataset_type ( 'map ' ) );
221+ $ this ->assertEquals ( DataSet::TYPE_ARRAY , $ registry ->get_dataset_type ( 'boolean_map ' ) );
222+ }
223+
224+ public function test_map_sanitizer_keeps_nested_shape (): void {
225+ $ registry = new FieldTypeRegistry ();
226+ $ sanitizer = $ registry ->get_sanitizer ( 'map ' );
227+
228+ $ result = $ sanitizer ( [
229+ 'name ' => '<b>Hello</b> ' ,
230+ 'count ' => 3 ,
231+ 'nested ' => [ 'flag ' => true , 'label ' => 'ok ' ],
232+ ] );
233+
234+ $ this ->assertSame ( 'Hello ' , $ result ['name ' ] );
235+ $ this ->assertSame ( 3 , $ result ['count ' ] );
236+ $ this ->assertSame ( true , $ result ['nested ' ]['flag ' ] );
237+ $ this ->assertSame ( 'ok ' , $ result ['nested ' ]['label ' ] );
238+ }
239+
240+ public function test_map_sanitizer_returns_empty_array_for_non_array (): void {
241+ $ registry = new FieldTypeRegistry ();
242+ $ sanitizer = $ registry ->get_sanitizer ( 'map ' );
243+
244+ $ this ->assertSame ( [], $ sanitizer ( 'not-an-array ' ) );
245+ $ this ->assertSame ( [], $ sanitizer ( null ) );
246+ }
247+
248+ public function test_boolean_map_sanitizer_coerces_values_to_real_booleans (): void {
249+ $ registry = new FieldTypeRegistry ();
250+ $ sanitizer = $ registry ->get_sanitizer ( 'boolean_map ' );
251+
252+ // Values arrive as "1"/"0" strings from hidden form inputs.
253+ $ result = $ sanitizer ( [
254+ 'posts ' => '1 ' ,
255+ 'pages ' => '0 ' ,
256+ 'media ' => 'on ' ,
257+ 'groups ' => '' ,
258+ ] );
259+
260+ $ this ->assertSame ( true , $ result ['posts ' ] );
261+ $ this ->assertSame ( false , $ result ['pages ' ], 'String "0" must become real false, not a truthy string ' );
262+ $ this ->assertSame ( true , $ result ['media ' ] );
263+ $ this ->assertSame ( false , $ result ['groups ' ] );
264+ }
265+
266+ public function test_array_field_round_trips_through_dataview_and_option_storage (): void {
267+ // Proves the TYPE_ARRAY primitive: a nested array value passes through
268+ // coercion untouched and is persisted as a nested array by OptionStorage.
269+ // (Boolean coercion is the sanitizer's job, exercised in extract_post_data;
270+ // here the handler receives already-sanitized values.)
271+ $ config = [
272+ 'slug ' => 'dv_test_map_roundtrip ' ,
273+ 'label ' => 'Settings ' ,
274+ 'mode ' => 'singular ' ,
275+ 'storage ' => 'option ' ,
276+ 'fields ' => [
277+ 'post_types ' => 'boolean_map ' ,
278+ ],
279+ ];
280+
281+ $ view = new DataView ( $ config );
282+ $ handler = $ view ->get_handler ();
283+
284+ $ result = $ handler ->update ( [
285+ 'post_types ' => [ 'posts ' => true , 'pages ' => false ],
286+ ] );
287+
288+ $ this ->assertTrue ( $ result ->is_success () );
289+
290+ $ stored = get_option ( 'dv_test_map_roundtrip ' );
291+ $ this ->assertIsArray ( $ stored ['post_types ' ] );
292+ $ this ->assertSame ( true , $ stored ['post_types ' ]['posts ' ] );
293+ $ this ->assertSame ( false , $ stored ['post_types ' ]['pages ' ] );
294+ }
295+
214296 public function test_field_type_registry_has_repeater_type (): void {
215297 $ registry = new FieldTypeRegistry ();
216298
0 commit comments