Changeset 61020
- Timestamp:
- 10/21/2025 12:07:16 PM (4 months ago)
- Location:
- trunk
- Files:
-
- 8 edited
-
src/wp-includes/interactivity-api/class-wp-interactivity-api.php (modified) (16 diffs)
-
tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-bind.php (modified) (1 diff)
-
tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-class.php (modified) (2 diffs)
-
tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-context.php (modified) (1 diff)
-
tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-each.php (modified) (3 diffs)
-
tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-style.php (modified) (2 diffs)
-
tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-text.php (modified) (3 diffs)
-
tests/phpunit/tests/interactivity-api/wpInteractivityAPI.php (modified) (16 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/interactivity-api/class-wp-interactivity-api.php
r61019 r61020 533 533 // Checks if there is a server directive processor registered for each directive. 534 534 foreach ( $p->get_attribute_names_with_prefix( 'data-wp-' ) as $attribute_name ) { 535 if ( ! preg_match( 536 /* 537 * This must align with the client-side regex used by the interactivity API. 538 * @see https://github.com/WordPress/gutenberg/blob/ca616014255efbb61f34c10917d52a2d86c1c660/packages/interactivity/src/vdom.ts#L20-L32 539 */ 540 '/' . 541 '^data-wp-' . 542 // Match alphanumeric characters including hyphen-separated 543 // segments. It excludes underscore intentionally to prevent confusion. 544 // E.g., "custom-directive". 545 '([a-z0-9]+(?:-[a-z0-9]+)*)' . 546 // (Optional) Match '--' followed by any alphanumeric charachters. It 547 // excludes underscore intentionally to prevent confusion, but it can 548 // contain multiple hyphens. E.g., "--custom-prefix--with-more-info". 549 '(?:--([a-z0-9_-]+))?$' . 550 '/i', 551 $attribute_name 552 ) ) { 535 $parsed_directive = $this->parse_directive_name( $attribute_name ); 536 if ( empty( $parsed_directive ) ) { 553 537 continue; 554 538 } 555 list( $directive_prefix ) = $this->extract_prefix_and_suffix( $attribute_name );539 $directive_prefix = 'data-wp-' . $parsed_directive['prefix']; 556 540 if ( array_key_exists( $directive_prefix, self::$directive_processors ) ) { 557 541 $directives_prefixes[] = $directive_prefix; … … 630 614 * It returns null if the HTML is unbalanced because unbalanced HTML is 631 615 * not safe to process. In that case, the Interactivity API runtime will 632 * update the HTML on the client side during the hydration. It will also633 * display a notice to the developerto inform them about the issue.616 * update the HTML on the client side during the hydration. It will display 617 * a notice to the developer in the console to inform them about the issue. 634 618 */ 635 619 if ( $unbalanced || 0 < count( $tag_stack ) ) { 636 $tag_errored = 0 < count( $tag_stack ) ? end( $tag_stack )[0] : $tag_name;637 /* translators: %1s: Namespace processed, %2s: The tag that caused the error; could be any HTML tag. */638 $message = sprintf( __( 'Interactivity directives failed to process in "%1$s" due to a missing "%2$s" end tag.' ), end( $this->namespace_stack ), $tag_errored );639 _doing_it_wrong( __METHOD__, $message, '6.6.0' );640 620 return null; 641 621 } … … 652 632 * @since 6.6.0 Removed `default_namespace` and `context` arguments. 653 633 * @since 6.6.0 Add support for derived state. 654 * 655 * @param string|true $directive_value The directive attribute value string or `true` when it's a boolean attribute. 634 * @since 6.9.0 Recieve $entry as an argument instead of the directive value string. 635 * 636 * @param array $entry An array containing a whole directive entry with its namespace, value, suffix, or unique ID. 656 637 * @return mixed|null The result of the evaluation. Null if the reference path doesn't exist or the namespace is falsy. 657 638 */ 658 private function evaluate( $directive_value ) { 659 $default_namespace = end( $this->namespace_stack ); 660 $context = end( $this->context_stack ); 661 662 list( $ns, $path ) = $this->extract_directive_value( $directive_value, $default_namespace ); 639 private function evaluate( $entry ) { 640 $context = end( $this->context_stack ); 641 ['namespace' => $ns, 'value' => $path] = $entry; 642 663 643 if ( ! $ns || ! $path ) { 664 644 /* translators: %s: The directive value referenced. */ 665 $message = sprintf( __( 'Namespace or reference path cannot be empty. Directive value referenced: %s' ), $directive_value);645 $message = sprintf( __( 'Namespace or reference path cannot be empty. Directive value referenced: %s' ), json_encode( $entry ) ); 666 646 _doing_it_wrong( __METHOD__, $message, '6.6.0' ); 667 647 return null; … … 767 747 768 748 /** 769 * Extracts the directive attribute name to separate and return the directive 770 * prefix and an optional suffix. 771 * 772 * The suffix is the string after the first double hyphen and the prefix is 773 * everything that comes before the suffix. 774 * 775 * Example: 776 * 777 * extract_prefix_and_suffix( 'data-wp-interactive' ) => array( 'data-wp-interactive', null ) 778 * extract_prefix_and_suffix( 'data-wp-bind--src' ) => array( 'data-wp-bind', 'src' ) 779 * extract_prefix_and_suffix( 'data-wp-foo--and--bar' ) => array( 'data-wp-foo', 'and--bar' ) 780 * 781 * @since 6.5.0 749 * Parse the directive name to extract the following parts: 750 * - Prefix: The main directive name without "data-wp-". 751 * - Suffix: An optional suffix used during directive processing, extracted after the first double hyphen "--". 752 * - Unique ID: An optional unique identifier, extracted after the first triple hyphen "---". 753 * 754 * This function has an equivalent version for the client side. 755 * See `parseDirectiveName` in https://github.com/WordPress/gutenberg/blob/trunk/packages/interactivity/src/vdom.ts.: 756 * 757 * See examples in the function unit tests `test_parse_directive_name`. 758 * 759 * @since 6.9.0 782 760 * 783 761 * @param string $directive_name The directive attribute name. 784 * @return array An array containing the directive prefix and optional suffix. 785 */ 786 private function extract_prefix_and_suffix( string $directive_name ): array { 787 return explode( '--', $directive_name, 2 ); 762 * @return array An array containing the directive prefix, optional suffix, and optional unique ID. 763 */ 764 private function parse_directive_name( string $directive_name ): ?array { 765 // Remove the first 8 characters (assumes "data-wp-" prefix) 766 $name = substr( $directive_name, 8 ); 767 768 // Check for invalid characters (anything not a-z, 0-9, -, or _) 769 if ( preg_match( '/[^a-z0-9\-_]/i', $name ) ) { 770 return null; 771 } 772 773 // Find the first occurrence of '--' to separate the prefix 774 $suffix_index = strpos( $name, '--' ); 775 776 if ( false === $suffix_index ) { 777 return array( 778 'prefix' => $name, 779 'suffix' => null, 780 'unique_id' => null, 781 ); 782 } 783 784 $prefix = substr( $name, 0, $suffix_index ); 785 $remaining = substr( $name, $suffix_index ); 786 787 // If remaining starts with '---' but not '----', it's a unique_id 788 if ( '---' === substr( $remaining, 0, 3 ) && '-' !== ( $remaining[3] ?? '' ) ) { 789 return array( 790 'prefix' => $prefix, 791 'suffix' => null, 792 'unique_id' => '---' !== $remaining ? substr( $remaining, 3 ) : null, 793 ); 794 } 795 796 // Otherwise, remove the first two dashes for a potential suffix 797 $suffix = substr( $remaining, 2 ); 798 799 // Look for '---' in the suffix for a unique_id 800 $unique_id_index = strpos( $suffix, '---' ); 801 802 if ( false !== $unique_id_index && '-' !== ( $suffix[ $unique_id_index + 3 ] ?? '' ) ) { 803 $unique_id = substr( $suffix, $unique_id_index + 3 ); 804 $suffix = substr( $suffix, 0, $unique_id_index ); 805 return array( 806 'prefix' => $prefix, 807 'suffix' => empty( $suffix ) ? null : $suffix, 808 'unique_id' => empty( $unique_id ) ? null : $unique_id, 809 ); 810 } 811 812 return array( 813 'prefix' => $prefix, 814 'suffix' => empty( $suffix ) ? null : $suffix, 815 'unique_id' => null, 816 ); 788 817 } 789 818 … … 835 864 836 865 return array( $default_namespace, $directive_value ); 866 } 867 868 /** 869 * Parse the HTML element and get all the valid directives with the given prefix. 870 * 871 * @since 6.9.0 872 * 873 * @param WP_Interactivity_API_Directives_Processor $p The directives processor instance. 874 * @param string $prefix The directive prefix to filter by. 875 * @return array An array of entries containing the directive namespace, value, suffix, and unique ID. 876 */ 877 private function get_directive_entries( WP_Interactivity_API_Directives_Processor $p, string $prefix ) { 878 $directive_attributes = $p->get_attribute_names_with_prefix( 'data-wp-' . $prefix ); 879 $entries = array(); 880 foreach ( $directive_attributes as $attribute_name ) { 881 [ 'prefix' => $attr_prefix, 'suffix' => $suffix, 'unique_id' => $unique_id] = $this->parse_directive_name( $attribute_name ); 882 // Ensure it is the desired directive. 883 if ( $prefix !== $attr_prefix ) { 884 continue; 885 } 886 list( $namespace, $value ) = $this->extract_directive_value( $p->get_attribute( $attribute_name ), end( $this->namespace_stack ) ); 887 $entries[] = array( 888 'namespace' => $namespace, 889 'value' => $value, 890 'suffix' => $suffix, 891 'unique_id' => $unique_id, 892 ); 893 } 894 // Sort directive entries to ensure stable ordering with the client. 895 // Put nulls first, then sort by suffix and finally by uniqueIds. 896 usort( 897 $entries, 898 function ( $a, $b ) { 899 $a_suffix = $a['suffix'] ?? ''; 900 $b_suffix = $b['suffix'] ?? ''; 901 if ( $a_suffix !== $b_suffix ) { 902 return $a_suffix < $b_suffix ? -1 : 1; 903 } 904 $a_id = $a['unique_id'] ?? ''; 905 $b_id = $b['unique_id'] ?? ''; 906 if ( $a_id === $b_id ) { 907 return 0; 908 } 909 return $a_id > $b_id ? 1 : -1; 910 } 911 ); 912 return $entries; 837 913 } 838 914 … … 918 994 } 919 995 920 $attribute_value = $p->get_attribute( 'data-wp-context' ); 921 $namespace_value = end( $this->namespace_stack ); 922 923 // Separates the namespace from the context JSON object. 924 list( $namespace_value, $decoded_json ) = is_string( $attribute_value ) && ! empty( $attribute_value ) 925 ? $this->extract_directive_value( $attribute_value, $namespace_value ) 926 : array( $namespace_value, null ); 927 928 /* 929 * If there is a namespace, it adds a new context to the stack merging the 930 * previous context with the new one. 931 */ 932 if ( is_string( $namespace_value ) ) { 933 $this->context_stack[] = array_replace_recursive( 934 end( $this->context_stack ) !== false ? end( $this->context_stack ) : array(), 935 array( $namespace_value => is_array( $decoded_json ) ? $decoded_json : array() ) 996 $entries = $this->get_directive_entries( $p, 'context' ); 997 $context = end( $this->context_stack ) !== false ? end( $this->context_stack ) : array(); 998 foreach ( $entries as $entry ) { 999 if ( null !== $entry['suffix'] ) { 1000 continue; 1001 } 1002 1003 $context = array_replace_recursive( 1004 $context, 1005 array( $entry['namespace'] => is_array( $entry['value'] ) ? $entry['value'] : array() ) 936 1006 ); 937 } else { 938 /* 939 * If there is no namespace, it pushes the current context to the stack. 940 * It needs to do so because the function pops out the current context 941 * from the stack whenever it finds a `data-wp-context`'s closing tag. 942 */ 943 $this->context_stack[] = end( $this->context_stack ); 944 } 1007 } 1008 $this->context_stack[] = $context; 945 1009 } 946 1010 … … 958 1022 private function data_wp_bind_processor( WP_Interactivity_API_Directives_Processor $p, string $mode ) { 959 1023 if ( 'enter' === $mode ) { 960 $all_bind_directives = $p->get_attribute_names_with_prefix( 'data-wp-bind--' ); 961 962 foreach ( $all_bind_directives as $attribute_name ) { 963 list( , $bound_attribute ) = $this->extract_prefix_and_suffix( $attribute_name ); 964 if ( empty( $bound_attribute ) ) { 965 return; 966 } 967 968 $attribute_value = $p->get_attribute( $attribute_name ); 969 $result = $this->evaluate( $attribute_value ); 1024 $entries = $this->get_directive_entries( $p, 'bind' ); 1025 foreach ( $entries as $entry ) { 1026 if ( empty( $entry['suffix'] ) || null !== $entry['unique_id'] ) { 1027 return; 1028 } 1029 1030 $result = $this->evaluate( $entry ); 970 1031 971 1032 if ( … … 973 1034 ( 974 1035 false !== $result || 975 ( strlen( $ bound_attribute ) > 5 && '-' === $bound_attribute[4] )1036 ( strlen( $entry['suffix'] ) > 5 && '-' === $entry['suffix'][4] ) 976 1037 ) 977 1038 ) { … … 985 1046 if ( 986 1047 is_bool( $result ) && 987 ( strlen( $ bound_attribute ) > 5 && '-' === $bound_attribute[4] )1048 ( strlen( $entry['suffix'] ) > 5 && '-' === $entry['suffix'][4] ) 988 1049 ) { 989 1050 $result = $result ? 'true' : 'false'; 990 1051 } 991 $p->set_attribute( $ bound_attribute, $result );1052 $p->set_attribute( $entry['suffix'], $result ); 992 1053 } else { 993 $p->remove_attribute( $ bound_attribute);1054 $p->remove_attribute( $entry['suffix'] ); 994 1055 } 995 1056 } … … 1011 1072 if ( 'enter' === $mode ) { 1012 1073 $all_class_directives = $p->get_attribute_names_with_prefix( 'data-wp-class--' ); 1013 1014 foreach ( $all_class_directives as $attribute_name ) { 1015 list( , $class_name ) = $this->extract_prefix_and_suffix( $attribute_name ); 1074 $entries = $this->get_directive_entries( $p, 'class' ); 1075 foreach ( $entries as $entry ) { 1076 if ( empty( $entry['suffix'] ) ) { 1077 continue; 1078 } 1079 $class_name = isset( $entry['unique_id'] ) && $entry['unique_id'] 1080 ? "{$entry['suffix']}---{$entry['unique_id']}" 1081 : $entry['suffix']; 1082 1016 1083 if ( empty( $class_name ) ) { 1017 1084 return; 1018 1085 } 1019 1086 1020 $attribute_value = $p->get_attribute( $attribute_name ); 1021 $result = $this->evaluate( $attribute_value ); 1087 $result = $this->evaluate( $entry ); 1022 1088 1023 1089 if ( $result ) { … … 1043 1109 private function data_wp_style_processor( WP_Interactivity_API_Directives_Processor $p, string $mode ) { 1044 1110 if ( 'enter' === $mode ) { 1045 $all_style_attributes = $p->get_attribute_names_with_prefix( 'data-wp-style--' ); 1046 1047 foreach ( $all_style_attributes as $attribute_name ) { 1048 list( , $style_property ) = $this->extract_prefix_and_suffix( $attribute_name ); 1049 if ( empty( $style_property ) ) { 1111 $entries = $this->get_directive_entries( $p, 'style' ); 1112 foreach ( $entries as $entry ) { 1113 $style_property = $entry['suffix']; 1114 if ( empty( $style_property ) || null !== $entry['unique_id'] ) { 1050 1115 continue; 1051 1116 } 1052 1117 1053 $directive_attribute_value = $p->get_attribute( $attribute_name ); 1054 $style_property_value = $this->evaluate( $directive_attribute_value ); 1055 $style_attribute_value = $p->get_attribute( 'style' ); 1056 $style_attribute_value = ( $style_attribute_value && ! is_bool( $style_attribute_value ) ) ? $style_attribute_value : ''; 1118 $style_property_value = $this->evaluate( $entry ); 1119 $style_attribute_value = $p->get_attribute( 'style' ); 1120 $style_attribute_value = ( $style_attribute_value && ! is_bool( $style_attribute_value ) ) ? $style_attribute_value : ''; 1057 1121 1058 1122 /* … … 1134 1198 private function data_wp_text_processor( WP_Interactivity_API_Directives_Processor $p, string $mode ) { 1135 1199 if ( 'enter' === $mode ) { 1136 $attribute_value = $p->get_attribute( 'data-wp-text' ); 1137 $result = $this->evaluate( $attribute_value ); 1200 $entries = $this->get_directive_entries( $p, 'text' ); 1201 $valid_entry = null; 1202 // Get the first valid `data-wp-text` entry without suffix or unique ID. 1203 foreach ( $entries as $entry ) { 1204 if ( null === $entry['suffix'] && null === $entry['unique_id'] && ! empty( $entry['value'] ) ) { 1205 $valid_entry = $entry; 1206 break; 1207 } 1208 } 1209 if ( null === $valid_entry ) { 1210 return; 1211 } 1212 $result = $this->evaluate( $valid_entry ); 1138 1213 1139 1214 /* … … 1264 1339 private function data_wp_each_processor( WP_Interactivity_API_Directives_Processor $p, string $mode, array &$tag_stack ) { 1265 1340 if ( 'enter' === $mode && 'TEMPLATE' === $p->get_tag() ) { 1266 $attribute_name = $p->get_attribute_names_with_prefix( 'data-wp-each' )[0]; 1267 $extracted_suffix = $this->extract_prefix_and_suffix( $attribute_name ); 1268 $item_name = isset( $extracted_suffix[1] ) ? $this->kebab_to_camel_case( $extracted_suffix[1] ) : 'item'; 1269 $attribute_value = $p->get_attribute( $attribute_name ); 1270 $result = $this->evaluate( $attribute_value ); 1341 $entries = $this->get_directive_entries( $p, 'each' ); 1342 if ( count( $entries ) > 1 || empty( $entries ) ) { 1343 // There should be only one `data-wp-each` directive per template tag. 1344 return; 1345 } 1346 $entry = $entries[0]; 1347 if ( null !== $entry['unique_id'] ) { 1348 return; 1349 } 1350 $item_name = isset( $entry['suffix'] ) ? $this->kebab_to_camel_case( $entry['suffix'] ) : 'item'; 1351 $result = $this->evaluate( $entry ); 1271 1352 1272 1353 // Gets the content between the template tags and leaves the cursor in the closer tag. … … 1301 1382 } 1302 1383 1303 // Extracts the namespace from the directive attribute value.1304 $namespace_value = end( $this->namespace_stack );1305 list( $namespace_value, $path ) = is_string( $attribute_value ) && ! empty( $attribute_value )1306 ? $this->extract_directive_value( $attribute_value, $namespace_value )1307 : array( $namespace_value, null );1308 1309 1384 // Processes the inner content for each item of the array. 1310 1385 $processed_content = ''; … … 1313 1388 $this->context_stack[] = array_replace_recursive( 1314 1389 end( $this->context_stack ) !== false ? end( $this->context_stack ) : array(), 1315 array( $ namespace_value=> array( $item_name => $item ) )1390 array( $entry['namespace'] => array( $item_name => $item ) ) 1316 1391 ); 1317 1392 … … 1338 1413 $i = new WP_Interactivity_API_Directives_Processor( $processed_item ); 1339 1414 while ( $i->next_tag() ) { 1340 $i->set_attribute( 'data-wp-each-child', $ namespace_value . '::' . $path);1415 $i->set_attribute( 'data-wp-each-child', $entry['namespace'] . '::' . $entry['value'] ); 1341 1416 $i->next_balanced_tag_closer_tag(); 1342 1417 } -
trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-bind.php
r58321 r61020 399 399 $this->assertSame( true, $p->get_attribute( 'id' ) ); 400 400 } 401 402 /** 403 * Tests ignores unique IDs in bind directive. 404 * 405 * @ticket 64106 406 * 407 * @covers ::process_directives 408 */ 409 public function test_wp_bind_ignores_unique_ids() { 410 $html = '<div data-wp-bind--id="myPlugin::state.trueValue"></div>'; 411 list($p) = $this->process_directives( $html ); 412 $this->assertSame( true, $p->get_attribute( 'id' ) ); 413 414 $html = '<div data-wp-bind--id---unique-id="myPlugin::state.trueValue"></div>'; 415 list($p) = $this->process_directives( $html ); 416 $this->assertNull( $p->get_attribute( 'id' ) ); 417 $this->assertNull( $p->get_attribute( 'id---unique-id' ) ); 418 } 401 419 } -
trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-class.php
r58594 r61020 77 77 >Text</div>'; 78 78 list($p) = $this->process_directives( $html ); 79 $this->assertSame( ' some-class other-class', $p->get_attribute( 'class' ) );79 $this->assertSame( 'other-class some-class', $p->get_attribute( 'class' ) ); 80 80 } 81 81 … … 329 329 $this->assertNull( $p->get_attribute( 'class' ) ); 330 330 } 331 332 /** 333 * Tests that classes with several dashes can be used. 334 * 335 * @ticket 64106 336 * 337 * @covers ::process_directives 338 */ 339 public function test_wp_class_can_use_several_dashes() { 340 $html = '<div data-wp-class--main-bg--color="myPlugin::state.true">Text</div>'; 341 list($p) = $this->process_directives( $html ); 342 $this->assertSame( 'main-bg--color', $p->get_attribute( 'class' ) ); 343 344 $html = '<div data-wp-class--main-bg---color="myPlugin::state.true">Text</div>'; 345 list($p) = $this->process_directives( $html ); 346 $this->assertSame( 'main-bg---color', $p->get_attribute( 'class' ) ); 347 348 $html = '<div data-wp-class--main-bg----color="myPlugin::state.true">Text</div>'; 349 list($p) = $this->process_directives( $html ); 350 $this->assertSame( 'main-bg----color', $p->get_attribute( 'class' ) ); 351 } 331 352 } -
trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-context.php
r58594 r61020 523 523 $this->assertSame( 'some-id-1', $p->get_attribute( 'id' ) ); 524 524 } 525 526 /** 527 * Tests supports multiple context directives in the same element. 528 * 529 * @ticket 64106 530 * 531 * @covers ::process_directives 532 */ 533 public function test_wp_context_supports_multiple_directives_in_the_same_element() { 534 $html = ' 535 <div 536 data-wp-interactive="directive-context/multiple" 537 data-wp-context=\'{ "prop": "parent", "parent": true }\' 538 > 539 <div 540 data-wp-context---id2=\'other-namespace::{ "prop": true }\' 541 data-wp-context=\'{ "prop": "default", "default": true }\' 542 data-wp-context---id1=\'{ "prop": "id1", "id1": true }\' 543 > 544 <span 545 class="test" 546 data-wp-bind--data-test-prop="context.prop" 547 data-wp-bind--data-test-parent="context.parent" 548 data-wp-bind--data-test-default="context.default" 549 data-wp-bind--data-test-id1="context.id1" 550 data-wp-bind--data-test-other="other-namespace::context.prop" 551 ></span> 552 </div> 553 </div> 554 '; 555 list($p) = $this->process_directives( $html ); 556 $this->assertSame( 'id1', $p->get_attribute( 'data-test-prop' ) ); 557 foreach ( array( 'parent', 'default', 'id1', 'other' ) as $attribute ) { 558 $attr_name = "data-test-$attribute"; 559 $this->assertSame( 560 'true', 561 $p->get_attribute( $attr_name ), 562 "Failed asserting that $attr_name equals 'true'" 563 ); 564 } 565 } 525 566 } -
trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-each.php
r60953 r61020 581 581 * 582 582 * @covers ::process_directives 583 *584 * @expectedIncorrectUsage WP_Interactivity_API::_process_directives585 583 */ 586 584 public function test_wp_each_unbalanced_tags() { … … 601 599 * 602 600 * @covers ::process_directives 603 *604 * @expectedIncorrectUsage WP_Interactivity_API::_process_directives605 601 */ 606 602 public function test_wp_each_unbalanced_tags_in_nested_template_tags() { … … 685 681 $this->assertSame( $expected, $new ); 686 682 } 683 684 /** 685 * Tests it doesn't support multiple directives. 686 * 687 * @ticket 64106 688 * 689 * @covers ::process_directives 690 */ 691 public function test_wp_each_doesnt_support_multiple_directives() { 692 $original = '' . 693 '<div data-wp-interactive="directive-each">' . 694 '<template data-wp-each="myPlugin::state.list" data-wp-each--item="myPlugin::state.list">' . 695 '<span data-wp-text="myPlugin::context.item"></span>' . 696 '</template>' . 697 '<template data-wp-each---unique-id="myPlugin::state.list">' . 698 '<span data-wp-text="myPlugin::context.item"></span>' . 699 '</template>' . 700 '<div data-wp-bind--id="myPlugin::state.after">Text</div>' . 701 '</div>'; 702 $expected = '' . 703 '<div data-wp-interactive="directive-each">' . 704 '<template data-wp-each="myPlugin::state.list" data-wp-each--item="myPlugin::state.list">' . 705 '<span data-wp-text="myPlugin::context.item"></span>' . 706 '</template>' . 707 '<template data-wp-each---unique-id="myPlugin::state.list">' . 708 '<span data-wp-text="myPlugin::context.item"></span>' . 709 '</template>' . 710 '<div id="after-wp-each" data-wp-bind--id="myPlugin::state.after">Text</div>' . 711 '</div>'; 712 $new = $this->interactivity->process_directives( $original ); 713 $this->assertSame( $expected, $new ); 714 } 687 715 } -
trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-style.php
r60729 r61020 191 191 >Text</div>'; 192 192 list($p) = $this->process_directives( $html ); 193 $this->assertSame( ' color:green;background:green;', $p->get_attribute( 'style' ) );193 $this->assertSame( 'background:green;color:green;', $p->get_attribute( 'style' ) ); 194 194 } 195 195 … … 449 449 $this->assertNull( $p->get_attribute( 'style' ) ); 450 450 } 451 452 /** 453 * Tests it can use CSS variables. 454 * 455 * @ticket 64106 456 * 457 * @covers ::process_directives 458 */ 459 public function test_wp_style_can_use_CSS_variables() { 460 $html = '<div data-wp-style----text-color="myPlugin::state.green">Text</div>'; 461 list($p) = $this->process_directives( $html ); 462 $this->assertSame( '--text-color:green;', $p->get_attribute( 'style' ) ); 463 } 464 465 /** 466 * Tests it ignores unique IDs. 467 * 468 * @ticket 64106 469 * 470 * @covers ::process_directives 471 */ 472 public function test_wp_style_ignores_unique_ids() { 473 $html = '<div data-wp-style--color---unique-id="myPlugin::state.green">Text</div>'; 474 list($p) = $this->process_directives( $html ); 475 $this->assertNull( $p->get_attribute( 'style' ) ); 476 } 451 477 } -
trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-text.php
r58594 r61020 13 13 * @group interactivity-api 14 14 */ 15 class Tests_ Interactivity_API_WpInteractivityAPIWPText extends WP_UnitTestCase {15 class Tests_WP_Interactivity_API_WP_Text extends WP_UnitTestCase { 16 16 /** 17 17 * Instance of WP_Interactivity_API. … … 132 132 * 133 133 * @covers ::process_directives 134 *135 * @expectedIncorrectUsage WP_Interactivity_API::_process_directives136 134 */ 137 135 public function test_wp_text_fails_with_unbalanced_and_same_tags_inside_content() { … … 155 153 $this->assertSame( '<div data-wp-text="myPlugin::state.text"><span>Updated</span></div>', $new_html ); 156 154 } 155 156 /** 157 * Tests it ignores suffixes and unique-ids. 158 * 159 * @ticket 64106 160 * 161 * @covers ::process_directives 162 */ 163 public function test_wp_text_ignores_suffixes_and_unique_ids() { 164 $html = '<span data-wp-text--suffix="myPlugin::state.text">Text</span>'; 165 $new_html = $this->interactivity->process_directives( $html ); 166 $this->assertSame( $html, $new_html ); 167 168 $html = '<span data-wp-text---unique-id="myPlugin::state.text">Text</span>'; 169 $new_html = $this->interactivity->process_directives( $html ); 170 $this->assertSame( $html, $new_html ); 171 } 172 173 /** 174 * Tests first `data-wp-text` works even when suffixes and unique-ids are included. 175 * 176 * @ticket 64106 177 * 178 * @covers ::process_directives 179 */ 180 public function test_wp_text_works_even_when_suffixes_and_unique_ids_are_included() { 181 $original = '<span data-wp-text--suffix="myPlugin::state.text" data-wp-text---unique-id="myPlugin::state.text" data-wp-text="myPlugin::state.text">Text</span>'; 182 $expected = '<span data-wp-text--suffix="myPlugin::state.text" data-wp-text---unique-id="myPlugin::state.text" data-wp-text="myPlugin::state.text">Updated</span>'; 183 $new_html = $this->interactivity->process_directives( $original ); 184 $this->assertSame( $expected, $new_html ); 185 } 157 186 } -
trunk/tests/phpunit/tests/interactivity-api/wpInteractivityAPI.php
r61019 r61020 379 379 // Multiple evaluations should be serialized only once. 380 380 $this->set_internal_namespace_stack( 'pluginWithInvokedDerivedState' ); 381 $this->evaluate( 'state.derivedProp' ); 382 $this->evaluate( 'state.derivedProp' ); 383 $this->evaluate( 'state.nested.derivedProp' ); 384 $this->evaluate( 'state.nested.derivedProp' ); 381 $this->evaluate( 382 array( 383 'namespace' => 'pluginWithInvokedDerivedState', 384 'value' => 'state.derivedProp', 385 ) 386 ); 387 $this->evaluate( 388 array( 389 'namespace' => 'pluginWithInvokedDerivedState', 390 'value' => 'state.derivedProp', 391 ) 392 ); 393 $this->evaluate( 394 array( 395 'namespace' => 'pluginWithInvokedDerivedState', 396 'value' => 'state.nested.derivedProp', 397 ) 398 ); 399 $this->evaluate( 400 array( 401 'namespace' => 'pluginWithInvokedDerivedState', 402 'value' => 'state.nested.derivedProp', 403 ) 404 ); 385 405 386 406 // Only the path part that points to a derived state prop should be serialized. 387 407 $this->set_internal_namespace_stack( 'pluginWithInvokedDerivedStateReturningArray' ); 388 $this->evaluate( 'state.nested.derivedProp.prop' ); 408 $this->evaluate( 409 array( 410 'namespace' => 'pluginWithInvokedDerivedStateReturningArray', 411 'value' => 'state.nested.derivedProp', 412 ) 413 ); 389 414 } 390 415 ); … … 820 845 * name. 821 846 * 822 * @ticket 6 0356823 * 824 * @covers :: extract_prefix_and_suffix825 */ 826 public function test_ extract_prefix_and_suffix() {827 $ extract_prefix_and_suffix = new ReflectionMethod( $this->interactivity, 'extract_prefix_and_suffix' );847 * @ticket 64106 848 * 849 * @covers ::parse_directive_name 850 */ 851 public function test_parse_directive_name() { 852 $parse_directive_name = new ReflectionMethod( $this->interactivity, 'parse_directive_name' ); 828 853 if ( PHP_VERSION_ID < 80100 ) { 829 $ extract_prefix_and_suffix->setAccessible( true );854 $parse_directive_name->setAccessible( true ); 830 855 } 831 856 832 $result = $extract_prefix_and_suffix->invoke( $this->interactivity, 'data-wp-interactive' ); 833 $this->assertSame( array( 'data-wp-interactive' ), $result ); 834 835 $result = $extract_prefix_and_suffix->invoke( $this->interactivity, 'data-wp-bind--src' ); 836 $this->assertSame( array( 'data-wp-bind', 'src' ), $result ); 837 838 $result = $extract_prefix_and_suffix->invoke( $this->interactivity, 'data-wp-foo--and--bar' ); 839 $this->assertSame( array( 'data-wp-foo', 'and--bar' ), $result ); 857 // Should parse directives without suffix or unique ID. 858 $result = $parse_directive_name->invoke( $this->interactivity, 'data-wp-test' ); 859 $this->assertSame( 'test', $result['prefix'] ); 860 $this->assertNull( $result['suffix'] ); 861 $this->assertNull( $result['unique_id'] ); 862 863 // Should parse directives with suffix only. 864 $result = $parse_directive_name->invoke( $this->interactivity, 'data-wp-test--one' ); 865 $this->assertSame( 'test', $result['prefix'] ); 866 $this->assertSame( 'one', $result['suffix'] ); 867 $this->assertNull( $result['unique_id'] ); 868 869 // Should parse directives with unique ID only. 870 $result = $parse_directive_name->invoke( $this->interactivity, 'data-wp-test---unique-id' ); 871 $this->assertSame( 'test', $result['prefix'] ); 872 $this->assertNull( $result['suffix'] ); 873 $this->assertSame( 'unique-id', $result['unique_id'] ); 874 875 // Should parse directives with suffix and unique ID. 876 $result = $parse_directive_name->invoke( $this->interactivity, 'data-wp-test--suffix---unique-id' ); 877 $this->assertSame( 'test', $result['prefix'] ); 878 $this->assertSame( 'suffix', $result['suffix'] ); 879 $this->assertSame( 'unique-id', $result['unique_id'] ); 880 881 // Should handle empty suffix (just two dashes). 882 $result = $parse_directive_name->invoke( $this->interactivity, 'data-wp-test--' ); 883 $this->assertSame( 'test', $result['prefix'] ); 884 $this->assertNull( $result['suffix'] ); 885 $this->assertNull( $result['unique_id'] ); 886 887 // Should handle empty unique ID (just three dashes). 888 $result = $parse_directive_name->invoke( $this->interactivity, 'data-wp-test---' ); 889 $this->assertSame( 'test', $result['prefix'] ); 890 $this->assertNull( $result['suffix'] ); 891 $this->assertNull( $result['unique_id'] ); 892 893 // Should handle only dashes (4 or more dashes). 894 $result = $parse_directive_name->invoke( $this->interactivity, 'data-wp-test----' ); 895 $this->assertSame( 'test', $result['prefix'] ); 896 $this->assertSame( '--', $result['suffix'] ); 897 $this->assertNull( $result['unique_id'] ); 898 899 // Should handle suffix starting with 4 or more dashes but containing valid characters. 900 $result = $parse_directive_name->invoke( $this->interactivity, 'data-wp-test------custom-suffix' ); 901 $this->assertSame( 'test', $result['prefix'] ); 902 $this->assertSame( '----custom-suffix', $result['suffix'] ); 903 $this->assertNull( $result['unique_id'] ); 904 905 // Should handle complex pattern with multiple dashes. 906 $result = $parse_directive_name->invoke( $this->interactivity, 'data-wp-test--complex--suffix---complex--unique---id' ); 907 $this->assertSame( 'test', $result['prefix'] ); 908 $this->assertSame( 'complex--suffix', $result['suffix'] ); 909 $this->assertSame( 'complex--unique---id', $result['unique_id'] ); 910 911 // Should handle suffix with dashes followed by unique ID. 912 $result = $parse_directive_name->invoke( $this->interactivity, 'data-wp-test----suffix---unique-id' ); 913 $this->assertSame( 'test', $result['prefix'] ); 914 $this->assertSame( '--suffix', $result['suffix'] ); 915 $this->assertSame( 'unique-id', $result['unique_id'] ); 916 917 // Should handle unique IDs followed by suffix in wrong order. 918 $result = $parse_directive_name->invoke( $this->interactivity, 'data-wp-test---unique-id--wrong-suffix' ); 919 $this->assertSame( 'test', $result['prefix'] ); 920 $this->assertNull( $result['suffix'] ); 921 $this->assertSame( 'unique-id--wrong-suffix', $result['unique_id'] ); 922 } 923 924 /** 925 * Tests the ability to get the valid entries of a specific directive in an HTML element. 926 * 927 * @ticket 64106 928 * 929 * @covers ::get_directive_entries 930 */ 931 public function test_get_directive_entries() { 932 $get_directive_entries = new ReflectionMethod( $this->interactivity, 'get_directive_entries' ); 933 if ( PHP_VERSION_ID < 80100 ) { 934 $get_directive_entries->setAccessible( true ); 935 } 936 $this->set_internal_namespace_stack( 'myPlugin' ); 937 938 // Should process simple directives. 939 $html = '<div data-wp-test="test value"></div>'; 940 $p = new WP_Interactivity_API_Directives_Processor( $html ); 941 $p->next_tag(); 942 $results = $get_directive_entries->invoke( $this->interactivity, $p, 'test' ); 943 $this->assertCount( 1, $results ); 944 $result = $results[0]; 945 $this->assertSame( 'myPlugin', $result['namespace'] ); 946 $this->assertSame( 'test value', $result['value'] ); 947 $this->assertNull( $result['suffix'] ); 948 $this->assertNull( $result['unique_id'] ); 949 950 // Should process directives without value. 951 $html = '<div data-wp-test></div>'; 952 $p = new WP_Interactivity_API_Directives_Processor( $html ); 953 $p->next_tag(); 954 $results = $get_directive_entries->invoke( $this->interactivity, $p, 'test' ); 955 $this->assertNull( $results[0]['value'] ); 956 957 // Should parse JSON values in directives. 958 $html = '<div data-wp-test=\'{"key": "value"}\'></div>'; 959 $p = new WP_Interactivity_API_Directives_Processor( $html ); 960 $p->next_tag(); 961 $results = $get_directive_entries->invoke( $this->interactivity, $p, 'test' ); 962 $this->assertSame( array( 'key' => 'value' ), $results[0]['value'] ); 963 964 // Should handle malformed JSON and keep as string. 965 $html = '<div data-wp-test="{malformed: json}"></div>'; 966 $p = new WP_Interactivity_API_Directives_Processor( $html ); 967 $p->next_tag(); 968 $results = $get_directive_entries->invoke( $this->interactivity, $p, 'test' ); 969 $this->assertSame( '{malformed: json}', $results[0]['value'] ); 970 971 // Should process directives with a custom namespace. 972 $html = '<div data-wp-test="my-namespace::test value"></div>'; 973 $p = new WP_Interactivity_API_Directives_Processor( $html ); 974 $p->next_tag(); 975 $results = $get_directive_entries->invoke( $this->interactivity, $p, 'test' ); 976 $this->assertSame( 'my-namespace', $results[0]['namespace'] ); 977 $this->assertSame( 'test value', $results[0]['value'] ); 978 979 // Should parse JSON values with a custom namespace. 980 $html = '<div data-wp-test=\'my-namespace::{"key": "value"}\'></div>'; 981 $p = new WP_Interactivity_API_Directives_Processor( $html ); 982 $p->next_tag(); 983 $results = $get_directive_entries->invoke( $this->interactivity, $p, 'test' ); 984 $this->assertSame( 'my-namespace', $results[0]['namespace'] ); 985 $this->assertSame( array( 'key' => 'value' ), $results[0]['value'] ); 986 987 // Should handle multiple directives with different unique IDs. 988 $html = ' 989 <div 990 data-wp-test---plugin-a="value-a" 991 data-wp-test---plugin-b="value-b" 992 data-wp-test---plugin-c="value-c" 993 ></div>'; 994 $p = new WP_Interactivity_API_Directives_Processor( $html ); 995 $p->next_tag(); 996 $results = $get_directive_entries->invoke( $this->interactivity, $p, 'test' ); 997 $this->assertCount( 3, $results ); 998 $this->assertSame( 999 array( 1000 'namespace' => 'myPlugin', 1001 'value' => 'value-a', 1002 'suffix' => null, 1003 'unique_id' => 'plugin-a', 1004 ), 1005 $results[0] 1006 ); 1007 $this->assertSame( 1008 array( 1009 'namespace' => 'myPlugin', 1010 'value' => 'value-b', 1011 'suffix' => null, 1012 'unique_id' => 'plugin-b', 1013 ), 1014 $results[1] 1015 ); 1016 $this->assertSame( 1017 array( 1018 'namespace' => 'myPlugin', 1019 'value' => 'value-c', 1020 'suffix' => null, 1021 'unique_id' => 'plugin-c', 1022 ), 1023 $results[2] 1024 ); 1025 1026 // Should handle mix of different suffixes and unique IDs. 1027 $html = ' 1028 <div 1029 data-wp-test--suffix-a---id-1="value1" 1030 data-wp-test--suffix-a---id-2="value2" 1031 data-wp-test--suffix-b---id-1="value3" 1032 data-wp-test--suffix-c---id-1="value4" 1033 ></div>'; 1034 $p = new WP_Interactivity_API_Directives_Processor( $html ); 1035 $p->next_tag(); 1036 $results = $get_directive_entries->invoke( $this->interactivity, $p, 'test' ); 1037 $this->assertCount( 4, $results ); 1038 $this->assertSame( 1039 array( 1040 'namespace' => 'myPlugin', 1041 'value' => 'value1', 1042 'suffix' => 'suffix-a', 1043 'unique_id' => 'id-1', 1044 ), 1045 $results[0] 1046 ); 1047 $this->assertSame( 1048 array( 1049 'namespace' => 'myPlugin', 1050 'value' => 'value2', 1051 'suffix' => 'suffix-a', 1052 'unique_id' => 'id-2', 1053 ), 1054 $results[1] 1055 ); 1056 $this->assertSame( 1057 array( 1058 'namespace' => 'myPlugin', 1059 'value' => 'value3', 1060 'suffix' => 'suffix-b', 1061 'unique_id' => 'id-1', 1062 ), 1063 $results[2] 1064 ); 1065 $this->assertSame( 1066 array( 1067 'namespace' => 'myPlugin', 1068 'value' => 'value4', 1069 'suffix' => 'suffix-c', 1070 'unique_id' => 'id-1', 1071 ), 1072 $results[3] 1073 ); 1074 1075 // Should handle unique ID with namespace. 1076 $html = '<div data-wp-test---unique-id="my-namespace::test value"></div>'; 1077 $p = new WP_Interactivity_API_Directives_Processor( $html ); 1078 $p->next_tag(); 1079 $results = $get_directive_entries->invoke( $this->interactivity, $p, 'test' ); 1080 $this->assertSame( 'my-namespace', $results[0]['namespace'] ); 1081 $this->assertSame( 'test value', $results[0]['value'] ); 1082 $this->assertSame( 'unique-id', $results[0]['unique_id'] ); 1083 1084 // Should handle multiple directives with different namespaces and unique IDs. 1085 $html = ' 1086 <div 1087 data-wp-test---id-a="namespace-a::value1" 1088 data-wp-test---id-b="namespace-b::value2" 1089 ></div>'; 1090 $p = new WP_Interactivity_API_Directives_Processor( $html ); 1091 $p->next_tag(); 1092 $results = $get_directive_entries->invoke( $this->interactivity, $p, 'test' ); 1093 $this->assertCount( 2, $results ); 1094 $this->assertSame( 1095 array( 1096 'namespace' => 'namespace-a', 1097 'value' => 'value1', 1098 'suffix' => null, 1099 'unique_id' => 'id-a', 1100 ), 1101 $results[0] 1102 ); 1103 $this->assertSame( 1104 array( 1105 'namespace' => 'namespace-b', 1106 'value' => 'value2', 1107 'suffix' => null, 1108 'unique_id' => 'id-b', 1109 ), 1110 $results[1] 1111 ); 1112 // Should sort directives by suffix and uniqueId for stable ordering. 1113 $html = ' 1114 <div 1115 data-wp-test---z 1116 data-wp-test---a 1117 data-wp-test--b---z 1118 data-wp-test--b---a 1119 data-wp-test--a 1120 data-wp-test 1121 ></div>'; 1122 $p = new WP_Interactivity_API_Directives_Processor( $html ); 1123 $p->next_tag(); 1124 $results = $get_directive_entries->invoke( $this->interactivity, $p, 'test' ); 1125 $this->assertCount( 6, $results ); 1126 $this->assertEquals( 1127 array( 1128 array( null, null ), 1129 array( null, 'a' ), 1130 array( null, 'z' ), 1131 array( 'a', null ), 1132 array( 'b', 'a' ), 1133 array( 'b', 'z' ), 1134 ), 1135 array_map( 1136 function ( $d ) { 1137 return array( $d['suffix'], $d['unique_id'] ); 1138 }, 1139 $results 1140 ) 1141 ); 840 1142 } 841 1143 … … 925 1227 * @dataProvider data_html_with_unbalanced_tags 926 1228 * 927 * @expectedIncorrectUsage WP_Interactivity_API::_process_directives928 *929 1229 * @param string $html HTML containing unbalanced tags and also a directive. 930 1230 */ … … 1088 1388 * Invokes the private `evaluate` method of WP_Interactivity_API class. 1089 1389 * 1090 * @param string $ directive_value The directive attribute value to evaluate.1390 * @param string $entry The entry array containing namespace, value, suffix, and unique ID. 1091 1391 * @return mixed The result of the evaluate method. 1092 1392 */ 1093 private function evaluate( $ directive_value) {1393 private function evaluate( $entry ) { 1094 1394 /* 1095 1395 * The global WP_Interactivity_API instance is momentarily replaced to … … 1106 1406 } 1107 1407 1108 $result = $evaluate->invokeArgs( $this->interactivity, array( $ directive_value) );1408 $result = $evaluate->invokeArgs( $this->interactivity, array( $entry ) ); 1109 1409 1110 1410 // Restore the original WP_Interactivity_API instance. … … 1152 1452 ) 1153 1453 ); 1154 $this->set_internal_namespace_stack( 'myPlugin' ); 1155 1156 $result = $this->evaluate( 'state.key' ); 1454 $default_ns = 'myPlugin'; 1455 $this->set_internal_namespace_stack( $default_ns ); 1456 1457 $result = $this->evaluate( 1458 array( 1459 'namespace' => $default_ns, 1460 'value' => 'state.key', 1461 ) 1462 ); 1157 1463 $this->assertSame( 'myPlugin-state', $result ); 1158 1464 1159 $result = $this->evaluate( 'context.key' ); 1465 $result = $this->evaluate( 1466 array( 1467 'namespace' => $default_ns, 1468 'value' => 'context.key', 1469 ) 1470 ); 1160 1471 $this->assertSame( 'myPlugin-context', $result ); 1161 1472 1162 $result = $this->evaluate( 'otherPlugin::state.key' ); 1473 $result = $this->evaluate( 1474 array( 1475 'namespace' => 'otherPlugin', 1476 'value' => 'state.key', 1477 ) 1478 ); 1163 1479 $this->assertSame( 'otherPlugin-state', $result ); 1164 1480 1165 $result = $this->evaluate( 'otherPlugin::context.key' ); 1481 $result = $this->evaluate( 1482 array( 1483 'namespace' => 'otherPlugin', 1484 'value' => 'context.key', 1485 ) 1486 ); 1166 1487 $this->assertSame( 'otherPlugin-context', $result ); 1167 1488 1168 $result = $this->evaluate( 'state.obj.prop' ); 1489 $result = $this->evaluate( 1490 array( 1491 'namespace' => $default_ns, 1492 'value' => 'state.obj.prop', 1493 ) 1494 ); 1169 1495 $this->assertSame( 'object property', $result ); 1170 1496 1171 $result = $this->evaluate( 'state.arrAccess.1' ); 1497 $result = $this->evaluate( 1498 array( 1499 'namespace' => $default_ns, 1500 'value' => 'state.arrAccess.1', 1501 ) 1502 ); 1172 1503 $this->assertSame( '1', $result ); 1173 1504 } … … 1190 1521 ) 1191 1522 ); 1192 $this->set_internal_namespace_stack( 'myPlugin' ); 1193 1194 $result = $this->evaluate( '!state.key' ); 1523 $default_ns = 'myPlugin'; 1524 $this->set_internal_namespace_stack( $default_ns ); 1525 1526 $result = $this->evaluate( 1527 array( 1528 'namespace' => $default_ns, 1529 'value' => '!state.key', 1530 ) 1531 ); 1195 1532 $this->assertFalse( $result ); 1196 1533 1197 $result = $this->evaluate( '!context.key' ); 1534 $result = $this->evaluate( 1535 array( 1536 'namespace' => $default_ns, 1537 'value' => '!context.key', 1538 ) 1539 ); 1198 1540 $this->assertFalse( $result ); 1199 1541 1200 $result = $this->evaluate( 'otherPlugin::!state.key' ); 1542 $result = $this->evaluate( 1543 array( 1544 'namespace' => 'otherPlugin', 1545 'value' => '!state.key', 1546 ) 1547 ); 1201 1548 $this->assertFalse( $result ); 1202 1549 1203 $result = $this->evaluate( 'otherPlugin::!context.key' ); 1550 $result = $this->evaluate( 1551 array( 1552 'namespace' => 'otherPlugin', 1553 'value' => '!context.key', 1554 ) 1555 ); 1204 1556 $this->assertFalse( $result ); 1205 1557 } … … 1222 1574 ) 1223 1575 ); 1224 $this->set_internal_namespace_stack( 'myPlugin' ); 1225 1226 $result = $this->evaluate( '!state.missing' ); 1576 $default_ns = 'myPlugin'; 1577 $this->set_internal_namespace_stack( $default_ns ); 1578 1579 $result = $this->evaluate( 1580 array( 1581 'namespace' => $default_ns, 1582 'value' => '!state.missing', 1583 ) 1584 ); 1227 1585 $this->assertTrue( $result ); 1228 1586 1229 $result = $this->evaluate( '!context.missing' ); 1587 $result = $this->evaluate( 1588 array( 1589 'namespace' => $default_ns, 1590 'value' => '!context.missing', 1591 ) 1592 ); 1230 1593 $this->assertTrue( $result ); 1231 1594 1232 $result = $this->evaluate( 'otherPlugin::!state.deeply.nested.missing' ); 1595 $result = $this->evaluate( 1596 array( 1597 'namespace' => 'otherPlugin', 1598 'value' => '!state.deeply.nested.missing', 1599 ) 1600 ); 1233 1601 $this->assertTrue( $result ); 1234 1602 1235 $result = $this->evaluate( 'otherPlugin::!context.deeply.nested.missing' ); 1603 $result = $this->evaluate( 1604 array( 1605 'namespace' => 'otherPlugin', 1606 'value' => '!context.deeply.nested.missing', 1607 ) 1608 ); 1236 1609 $this->assertTrue( $result ); 1237 1610 } … … 1253 1626 ) 1254 1627 ); 1255 $this->set_internal_namespace_stack( 'myPlugin' ); 1256 1257 $result = $this->evaluate( 'state.nonExistentKey' ); 1628 $default_ns = 'myPlugin'; 1629 $this->set_internal_namespace_stack( $default_ns ); 1630 1631 $result = $this->evaluate( 1632 array( 1633 'namespace' => $default_ns, 1634 'value' => 'state.nonExistentKey', 1635 ) 1636 ); 1258 1637 $this->assertNull( $result ); 1259 1638 1260 $result = $this->evaluate( 'context.nonExistentKey' ); 1639 $result = $this->evaluate( 1640 array( 1641 'namespace' => $default_ns, 1642 'value' => 'context.nonExistentKey', 1643 ) 1644 ); 1261 1645 $this->assertNull( $result ); 1262 1646 1263 $result = $this->evaluate( 'otherPlugin::state.nonExistentKey' ); 1647 $result = $this->evaluate( 1648 array( 1649 'namespace' => 'otherPlugin', 1650 'value' => 'state.nonExistentKey', 1651 ) 1652 ); 1264 1653 $this->assertNull( $result ); 1265 1654 1266 $result = $this->evaluate( 'otherPlugin::context.nonExistentKey' ); 1655 $result = $this->evaluate( 1656 array( 1657 'namespace' => 'otherPlugin', 1658 'value' => 'context.nonExistentKey', 1659 ) 1660 ); 1267 1661 $this->assertNull( $result ); 1268 1662 1269 $result = $this->evaluate( ' state.key' ); // Extra space. 1663 $result = $this->evaluate( 1664 array( 1665 'namespace' => $default_ns, 1666 'value' => ' state.key', // Extra space. 1667 ) 1668 ); 1270 1669 $this->assertNull( $result ); 1271 1670 1272 $result = $this->evaluate( 'otherPlugin:: state.key' ); // Extra space. 1671 $result = $this->evaluate( 1672 array( 1673 'namespace' => 'otherPlugin', 1674 'value' => ' state.key', // Extra space. 1675 ) 1676 ); 1273 1677 $this->assertNull( $result ); 1274 1678 } … … 1304 1708 ) 1305 1709 ); 1306 $this->set_internal_namespace_stack( 'myPlugin' ); 1307 1308 $result = $this->evaluate( 'state.nested.key' ); 1710 $default_ns = 'myPlugin'; 1711 $this->set_internal_namespace_stack( $default_ns ); 1712 1713 $result = $this->evaluate( 1714 array( 1715 'namespace' => $default_ns, 1716 'value' => 'state.nested.key', 1717 ) 1718 ); 1309 1719 $this->assertSame( 'myPlugin-state-nested', $result ); 1310 1720 1311 $result = $this->evaluate( 'context.nested.key' ); 1721 $result = $this->evaluate( 1722 array( 1723 'namespace' => $default_ns, 1724 'value' => 'context.nested.key', 1725 ) 1726 ); 1312 1727 $this->assertSame( 'myPlugin-context-nested', $result ); 1313 1728 1314 $result = $this->evaluate( 'otherPlugin::state.nested.key' ); 1729 $result = $this->evaluate( 1730 array( 1731 'namespace' => 'otherPlugin', 1732 'value' => 'state.nested.key', 1733 ) 1734 ); 1315 1735 $this->assertSame( 'otherPlugin-state-nested', $result ); 1316 1736 1317 $result = $this->evaluate( 'otherPlugin::context.nested.key' ); 1737 $result = $this->evaluate( 1738 array( 1739 'namespace' => 'otherPlugin', 1740 'value' => 'context.nested.key', 1741 ) 1742 ); 1318 1743 $this->assertSame( 'otherPlugin-context-nested', $result ); 1319 1744 } … … 1331 1756 $this->set_internal_namespace_stack(); 1332 1757 1333 $result = $this->evaluate( 'path', 'null' ); 1758 $result = $this->evaluate( 1759 array( 1760 'namespace' => 'null', 1761 'value' => 'path', 1762 ) 1763 ); 1334 1764 $this->assertNull( $result ); 1335 1765 1336 $result = $this->evaluate( 'path', '' ); 1766 $result = $this->evaluate( 1767 array( 1768 'namespace' => '', 1769 'value' => 'path', 1770 ) 1771 ); 1337 1772 $this->assertNull( $result ); 1338 1773 1339 $result = $this->evaluate( 'path', '{}' ); 1774 $result = $this->evaluate( 1775 array( 1776 'namespace' => '{}', 1777 'value' => 'path', 1778 ) 1779 ); 1340 1780 $this->assertNull( $result ); 1341 1781 } … … 1375 1815 $this->set_internal_namespace_stack( 'myPlugin' ); 1376 1816 1377 $result = $this->evaluate( 'state.derived' ); 1817 $result = $this->evaluate( 1818 array( 1819 'namespace' => 'myPlugin', 1820 'value' => 'state.derived', 1821 ) 1822 ); 1378 1823 $this->assertSame( "Derived state: myPlugin-state\nDerived context: myPlugin-context", $result ); 1379 1824 } … … 1418 1863 $this->set_internal_namespace_stack( 'myPlugin' ); 1419 1864 1420 $result = $this->evaluate( 'state.derived' ); 1865 $result = $this->evaluate( 1866 array( 1867 'namespace' => 'myPlugin', 1868 'value' => 'state.derived', 1869 ) 1870 ); 1421 1871 $this->assertSame( "Derived state: otherPlugin-state\nDerived context: otherPlugin-context", $result ); 1422 1872 } … … 1461 1911 $this->set_internal_namespace_stack( 'myPlugin' ); 1462 1912 1463 $result = $this->evaluate( 'otherPlugin::state.derived' ); 1913 $result = $this->evaluate( 1914 array( 1915 'namespace' => 'otherPlugin', 1916 'value' => 'state.derived', 1917 ) 1918 ); 1464 1919 $this->assertSame( "Derived state: otherPlugin-state\nDerived context: otherPlugin-context", $result ); 1465 1920 } … … 1485 1940 $this->set_internal_namespace_stack( 'myPlugin' ); 1486 1941 1487 $result = $this->evaluate( 'state.derivedThatThrows' ); 1942 $result = $this->evaluate( 1943 array( 1944 'namespace' => 'myPlugin', 1945 'value' => 'state.derivedThatThrows', 1946 ) 1947 ); 1488 1948 $this->assertNull( $result ); 1489 1949 } … … 1508 1968 $this->set_internal_namespace_stack( 'myPlugin' ); 1509 1969 1510 $result = $this->evaluate( 'state.derivedState.property' ); 1970 $result = $this->evaluate( 1971 array( 1972 'namespace' => 'myPlugin', 1973 'value' => 'state.derivedState.property', 1974 ) 1975 ); 1511 1976 $this->assertSame( 'value', $result ); 1512 1977 }
Note: See TracChangeset
for help on using the changeset viewer.