<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[32602] trunk: Add support for `WP_Widget::get_settings()` returning `ArrayIterator`/`ArrayObject` instances.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="https://core.trac.wordpress.org/changeset/32602">32602</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"https://core.trac.wordpress.org/changeset/32602","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>westonruter</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2015-05-26 16:50:03 +0000 (Tue, 26 May 2015)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>Add support for `WP_Widget::get_settings()` returning `ArrayIterator`/`ArrayObject` instances.

Plugins can use `pre_option_widget_{$id_base}` filters to return `ArrayIterator`/`ArrayObject` instances instead of primitive arrays. This makes possible for widget instance data to be drawn from somewhere else than `wp_options`, such as a custom post type.

Add unit tests for widgets.

Fixes <a href="https://core.trac.wordpress.org/ticket/32474">#32474</a>.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunksrcwpincludeswidgetsphp">trunk/src/wp-includes/widgets.php</a></li>
<li><a href="#trunktestsphpunittestswidgetsphp">trunk/tests/phpunit/tests/widgets.php</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunksrcwpincludeswidgetsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/src/wp-includes/widgets.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/src/wp-includes/widgets.php 2015-05-25 22:08:08 UTC (rev 32601)
+++ trunk/src/wp-includes/widgets.php   2015-05-26 16:50:03 UTC (rev 32602)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -214,20 +214,24 @@
</span><span class="cx" style="display: block; padding: 0 10px">                $settings = $this->get_settings();
</span><span class="cx" style="display: block; padding: 0 10px">                $empty = true;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( is_array($settings) ) {
-                       foreach ( array_keys($settings) as $number ) {
-                               if ( is_numeric($number) ) {
-                                       $this->_set($number);
-                                       $this->_register_one($number);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // When $settings is an array-like object, get an intrinsic array for use with array_keys().
+               if ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) {
+                       $settings = $settings->getArrayCopy();
+               }
+
+               if ( is_array( $settings ) ) {
+                       foreach ( array_keys( $settings ) as $number ) {
+                               if ( is_numeric( $number ) ) {
+                                       $this->_set( $number );
+                                       $this->_register_one( $number );
</ins><span class="cx" style="display: block; padding: 0 10px">                                         $empty = false;
</span><span class="cx" style="display: block; padding: 0 10px">                                }
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                if ( $empty ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // If there are none, we register the widget's existence with a
-                       // generic template
-                       $this->_set(1);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // If there are none, we register the widget's existence with a generic template.
+                       $this->_set( 1 );
</ins><span class="cx" style="display: block; padding: 0 10px">                         $this->_register_one();
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -294,15 +298,16 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * }
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function display_callback( $args, $widget_args = 1 ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( is_numeric($widget_args) )
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( is_numeric( $widget_args ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         $widget_args = array( 'number' => $widget_args );
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $widget_args = wp_parse_args( $widget_args, array( 'number' => -1 ) );
</span><span class="cx" style="display: block; padding: 0 10px">                $this->_set( $widget_args['number'] );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $instance = $this->get_settings();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $instances = $this->get_settings();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( array_key_exists( $this->number, $instance ) ) {
-                       $instance = $instance[$this->number];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( isset( $instances[ $this->number ] ) ) {
+                       $instance = $instances[ $this->number ];
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        /**
</span><span class="cx" style="display: block; padding: 0 10px">                         * Filter the settings for a particular widget instance.
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -424,6 +429,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">         * @access public
</span><span class="cx" style="display: block; padding: 0 10px">         *
</span><span class="cx" style="display: block; padding: 0 10px">         * @param int|array $widget_args Widget instance number or array of widget arguments.
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         * @return string|null
</ins><span class="cx" style="display: block; padding: 0 10px">          */
</span><span class="cx" style="display: block; padding: 0 10px">        public function form_callback( $widget_args = 1 ) {
</span><span class="cx" style="display: block; padding: 0 10px">                if ( is_numeric($widget_args) )
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -516,20 +522,22 @@
</span><span class="cx" style="display: block; padding: 0 10px">         */
</span><span class="cx" style="display: block; padding: 0 10px">        public function get_settings() {
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $settings = get_option($this->option_name);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $settings = get_option( $this->option_name );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( false === $settings && isset($this->alt_option_name) )
-                       $settings = get_option($this->alt_option_name);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( false === $settings && isset( $this->alt_option_name ) ) {
+                       $settings = get_option( $this->alt_option_name );
+               }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( !is_array($settings) )
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( ! is_array( $settings ) && ! ( $settings instanceof ArrayObject || $settings instanceof ArrayIterator ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                         $settings = array();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                if ( !empty($settings) && !array_key_exists('_multiwidget', $settings) ) {
-                       // old format, convert if single widget
-                       $settings = wp_convert_widget_settings($this->id_base, $this->option_name, $settings);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         if ( ! empty( $settings ) && ! isset( $settings['_multiwidget'] ) ) {
+                       // Old format, convert if single widget.
+                       $settings = wp_convert_widget_settings( $this->id_base, $this->option_name, $settings );
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                unset($settings['_multiwidget'], $settings['__i__']);
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         unset( $settings['_multiwidget'], $settings['__i__'] );
</ins><span class="cx" style="display: block; padding: 0 10px">                 return $settings;
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre></div>
<a id="trunktestsphpunittestswidgetsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: trunk/tests/phpunit/tests/widgets.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- trunk/tests/phpunit/tests/widgets.php     2015-05-25 22:08:08 UTC (rev 32601)
+++ trunk/tests/phpunit/tests/widgets.php       2015-05-26 16:50:03 UTC (rev 32602)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,33 +1,48 @@
</span><span class="cx" style="display: block; padding: 0 10px"> <?php
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px"> /**
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">- * Test widget template tags
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ * Test functions and classes for widgets and sidebars.
</ins><span class="cx" style="display: block; padding: 0 10px">  *
</span><span class="cx" style="display: block; padding: 0 10px">  * @group widgets
</span><span class="cx" style="display: block; padding: 0 10px">  */
</span><span class="cx" style="display: block; padding: 0 10px"> class Tests_Widgets extends WP_UnitTestCase {
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function test_register_widget_core_widget() {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ function clean_up_global_scope() {
+               global $wp_widget_factory, $wp_registered_sidebars, $wp_registered_widgets, $wp_registered_widget_controls, $wp_registered_widget_updates;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                global $wp_widget_factory;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $wp_registered_sidebars = array();
+               $wp_registered_widgets = array();
+               $wp_registered_widget_controls = array();
+               $wp_registered_widget_updates = array();
+               $wp_widget_factory->widgets = array();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                unregister_widget( 'WP_Widget_Search' );
-               register_widget( 'WP_Widget_Search' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         parent::clean_up_global_scope();
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->assertTrue( isset( $wp_widget_factory->widgets['WP_Widget_Search'] ) );
-
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ function tearDown() {
+               global $wp_customize;
+               $wp_customize = null;
+               parent::tearDown();
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function test_unregister_widget_core_widget() {
-
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ /**
+        * @see register_widget()
+        * @see unregister_widget()
+        */
+       function test_register_and_unregister_widget_core_widget() {
</ins><span class="cx" style="display: block; padding: 0 10px">                 global $wp_widget_factory;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                unregister_widget( 'WP_Widget_Search' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $widget_class = 'WP_Widget_Search';
+               register_widget( $widget_class );
+               $this->assertArrayHasKey( $widget_class, $wp_widget_factory->widgets );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->assertFalse( isset( $wp_widget_factory->widgets['WP_Widget_Search'] ) );
-
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         unregister_widget( $widget_class );
+               $this->assertArrayNotHasKey( $widget_class, $wp_widget_factory->widgets );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+        * @see register_sidebars()
+        */
</ins><span class="cx" style="display: block; padding: 0 10px">         function test_register_sidebars_single() {
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                global $wp_registered_sidebars;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -38,41 +53,244 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+        * @see register_sidebars()
+        */
</ins><span class="cx" style="display: block; padding: 0 10px">         function test_register_sidebars_multiple() {
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                global $wp_registered_sidebars;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                $result = array();
</ins><span class="cx" style="display: block; padding: 0 10px">                 $num = 3;
</span><span class="cx" style="display: block; padding: 0 10px">                $id_base = 'WP Unit Test';
</span><span class="cx" style="display: block; padding: 0 10px">                register_sidebars( $num, array( 'name' => $id_base . ' %d' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $names = wp_list_pluck( $wp_registered_sidebars, 'name' );
</span><span class="cx" style="display: block; padding: 0 10px">                for ( $i = 1; $i <= $num; $i++ ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        if ( in_array( "$id_base $i", $names ) )
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 if ( in_array( "$id_base $i", $names ) ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                                 $result[] = true;
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        }
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                $this->assertEquals( $num, count( $result ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function test_register_sidebar() {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ /**
+        * @see register_sidebar
+        * @see unregister_sidebar
+        */
+       function test_register_and_unregister_sidebar() {
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                global $wp_registered_sidebars;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                register_sidebar( array( 'id' => 'wp-unit-test' ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $sidebar_id = 'wp-unit-test';
+               register_sidebar( array( 'id' => $sidebar_id ) );
+               $this->assertArrayHasKey( $sidebar_id, $wp_registered_sidebars );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->assertTrue( isset( $wp_registered_sidebars['wp-unit-test'] ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         unregister_sidebar( $sidebar_id );
+               $this->assertArrayNotHasKey( 'wp-unit-test', $wp_registered_sidebars );
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+        * @see WP_Widget_Search::form()
+        */
+       function test_wp_widget_search_form() {
+               $widget = new WP_Widget_Search( 'foo', 'Foo' );
+               ob_start();
+               $args = array(
+                       'before_widget' => '<section>',
+                       'after_widget' => "</section>\n",
+                       'before_title' => '<h2>',
+                       'after_title' => "</h2>\n",
+               );
+               $instance = array( 'title' => 'Buscar' );
+               $widget->_set( 2 );
+               $widget->widget( $args, $instance );
+               $output = ob_get_clean();
+               $this->assertNotContains( 'no-options-widget', $output );
+               $this->assertContains( '<h2>Buscar</h2>', $output );
+               $this->assertContains( '<section>', $output );
+               $this->assertContains( '</section>', $output );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        function test_unregister_sidebar() {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ /**
+        * @see WP_Widget::form()
+        */
+       function test_wp_widget_form() {
+               $widget = new WP_Widget( 'foo', 'Foo' );
+               ob_start();
+               $retval = $widget->form( array() );
+               $output = ob_get_clean();
+               $this->assertEquals( 'noform', $retval );
+               $this->assertContains( 'no-options-widget', $output );
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                global $wp_registered_sidebars;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ /**
+        * @see WP_Widget::__construct()
+        */
+       function test_wp_widget_constructor() {
+               $id_base = 'foo';
+               $name = 'Foo';
+               $foo_widget = new WP_Widget( $id_base, $name );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                unregister_sidebar( 'sidebar-1' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $this->assertEquals( $id_base, $foo_widget->id_base );
+               $this->assertEquals( $name, $foo_widget->name );
+               $this->assertEquals( "widget_{$id_base}", $foo_widget->option_name );
+               $this->assertArrayHasKey( 'classname', $foo_widget->widget_options );
+               $this->assertEquals( "widget_{$id_base}", $foo_widget->widget_options['classname'] );
+               $this->assertArrayHasKey( 'id_base', $foo_widget->control_options );
+               $this->assertEquals( $id_base, $foo_widget->control_options['id_base'] );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                $this->assertFalse( isset( $wp_registered_sidebars['sidebar-1'] ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         $id_base = 'bar';
+               $name = 'Bar';
+               $widget_options = array(
+                       'classname' => 'bar_classname',
+               );
+               $control_options = array(
+                       'id_base' => 'bar_id_base',
+               );
+               $bar_widget = new WP_Widget( $id_base, $name, $widget_options, $control_options );
+               $this->assertEquals( $widget_options['classname'], $bar_widget->widget_options['classname'] );
+               $this->assertEquals( $control_options['id_base'], $bar_widget->control_options['id_base'] );
+       }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+        /**
+        * @see WP_Widget::get_field_name()
+        */
+       function test_wp_widget_get_field_name() {
+               $widget = new WP_Widget( 'foo', 'Foo' );
+               $widget->_set( 2 );
+               $this->assertEquals( 'widget-foo[2][title]', $widget->get_field_name( 'title' ) );
</ins><span class="cx" style="display: block; padding: 0 10px">         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       /**
+        * @see WP_Widget::get_field_id()
+        */
+       function test_wp_widget_get_field_id() {
+               $widget = new WP_Widget( 'foo', 'Foo' );
+               $widget->_set( 2 );
+               $this->assertEquals( 'widget-foo-2-title', $widget->get_field_id( 'title' ) );
+       }
+
+       /**
+        * @see WP_Widget::_register()
+        */
+       function test_wp_widget__register() {
+               global $wp_registered_widgets;
+
+               $settings = get_option( 'widget_search' );
+               unset( $settings['_multiwidget'] );
+               $this->assertArrayHasKey( 2, $settings );
+
+               $this->assertEmpty( $wp_registered_widgets );
+               wp_widgets_init();
+
+               // Note: We cannot use array_keys() here because $settings could be an ArrayIterator
+               foreach ( $settings as $widget_number => $instance ) {
+                       $widget_id = "search-$widget_number";
+                       $this->assertArrayHasKey( $widget_id, $wp_registered_widgets );
+               }
+       }
+
+       // @todo test WP_Widget::display_callback()
+
+       /**
+        * @see WP_Widget::is_preview()
+        */
+       function test_wp_widget_is_preview() {
+               global $wp_customize;
+
+               $widget = new WP_Widget( 'foo', 'Foo' );
+
+               $this->assertEmpty( $wp_customize );
+               $this->assertFalse( $widget->is_preview() );
+
+               wp_set_current_user( $this->factory->user->create( array( 'role' => 'administrator' ) ) );
+               require_once ABSPATH . WPINC . '/class-wp-customize-manager.php';
+               $wp_customize = new WP_Customize_Manager();
+               $wp_customize->start_previewing_theme();
+
+               $this->assertTrue( $widget->is_preview() );
+       }
+
+       // @todo test WP_Widget::update_callback()
+       // @todo test WP_Widget::form_callback()
+       // @todo test WP_Widget::_register_one()
+
+       /**
+        * @see WP_Widget::get_settings()
+        */
+       function test_wp_widget_get_settings() {
+               global $wp_registered_widgets;
+
+               $option_value = get_option( 'widget_search' );
+               $this->assertArrayHasKey( '_multiwidget', $option_value );
+               $this->assertEquals( 1, $option_value['_multiwidget'] );
+               $this->assertArrayHasKey( 2, $option_value );
+               $instance = $option_value[2];
+               $this->assertInternalType( 'array', $instance );
+               $this->assertArrayHasKey( 'title', $instance );
+               unset( $option_value['_multiwidget'] );
+
+               wp_widgets_init();
+               $wp_widget_search = $wp_registered_widgets['search-2']['callback'][0];
+
+               $settings = $wp_widget_search->get_settings();
+               // @todo $this->assertArrayNotHasKey( '_multiwidget', $settings ); ?
+               $this->assertArrayHasKey( 2, $settings );
+
+               foreach ( $option_value as $widget_number => $instance ) {
+                       $this->assertEquals( $settings[ $widget_number ], $option_value[ $widget_number ] );
+               }
+       }
+
+       /**
+        * @see WP_Widget::save_settings()
+        */
+       function test_wp_widget_save_settings() {
+               global $wp_registered_widgets;
+
+               wp_widgets_init();
+               $wp_widget_search = $wp_registered_widgets['search-2']['callback'][0];
+
+               $settings = $wp_widget_search->get_settings();
+               $overridden_title = 'Unit Tested';
+
+               /*
+                * Note that if a plugin is filtering $settings to be an ArrayIterator,
+                * then doing this:
+                *     $settings[2]['title'] = $overridden_title;
+                * Will fail with this:
+                * > Indirect modification of overloaded element of X has no effect.
+                * So this is why the value must be obtained.
+                */
+               $instance = $settings[2];
+               $instance['title'] = $overridden_title;
+               $settings[2] = $instance;
+
+               $wp_widget_search->save_settings( $settings );
+
+               $option_value = get_option( $wp_widget_search->option_name );
+               $this->assertArrayHasKey( '_multiwidget', $option_value );
+               $this->assertEquals( $overridden_title, $option_value[2]['title'] );
+       }
+
+       /**
+        * @see WP_Widget::save_settings()
+        */
+       function test_wp_widget_save_settings_delete() {
+               global $wp_registered_widgets;
+
+               wp_widgets_init();
+               $wp_widget_search = $wp_registered_widgets['search-2']['callback'][0];
+
+               $settings = $wp_widget_search->get_settings();
+               $this->assertArrayHasKey( 2, $settings );
+               unset( $settings[2] );
+               $wp_widget_search->save_settings( $settings );
+               $option_value = get_option( $wp_widget_search->option_name );
+               $this->assertArrayNotHasKey( 2, $option_value );
+       }
+
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span></span></pre>
</div>
</div>

</body>
</html>