<?php

if ( is_multisite() ) :

/**
 * Test site status views in multisite.
 *
 * @group admin
 * @group network-admin
 * @ticket 38071
 *
 * @todo integrate into wpMSSitesListTable.php after 38071 is accepted
 */
class Tests_WP_MS_Sites_List_Table_38071 extends WP_UnitTestCase {
	protected static $site_ids;
	protected $public;
	protected $archived;
	protected $spam;
	protected $mature;
	protected $deleted;

	/**
	 * @var WP_MS_Sites_List_Table
	 */
	var $table = false;

	function setUp() {
		parent::setUp();
		$this->table = _get_list_table( 'WP_MS_Sites_List_Table', array( 'screen' => 'ms-sites' ) );
	}

	public static function wpSetUpBeforeClass( $factory ) {
		self::$site_ids = array(
			'wordpress.org/'          => array( 'domain' => 'wordpress.org',      'path' => '/',
												'meta' => array( 'public' => 1, 'archived' => 0, 'mature' => 0, 'spam' => 0, 'deleted' => 0 ) ),
			'wordpress.org/foo/'      => array( 'domain' => 'wordpress.org',      'path' => '/foo/',
												'meta' => array( 'public' => 1, 'archived' => 1, 'mature' => 0, 'spam' => 0, 'deleted' => 0 ) ),
			'wordpress.org/foo/bar/'  => array( 'domain' => 'wordpress.org',      'path' => '/foo/bar/',
												'meta' => array( 'public' => 0, 'archived' => 1, 'mature' => 1, 'spam' => 0, 'deleted' => 0 ) ),
			'wordpress.org/afoo/'     => array( 'domain' => 'wordpress.org',      'path' => '/afoo/',
												'meta' => array( 'public' => 1, 'archived' => 0, 'mature' => 1, 'spam' => 0, 'deleted' => 0 ) ),
			'make.wordpress.org/'     => array( 'domain' => 'make.wordpress.org', 'path' => '/',
												'meta' => array( 'public' => 0, 'archived' => 0, 'mature' => 0, 'spam' => 1, 'deleted' => 0 ) ),
			'make.wordpress.org/foo/' => array( 'domain' => 'make.wordpress.org', 'path' => '/foo/',
												'meta' => array( 'public' => 0, 'archived' => 0, 'mature' => 0, 'spam' => 1, 'deleted' => 1 ) ),
			'www.w.org/'              => array( 'domain' => 'www.w.org',          'path' => '/',
												'meta' => array( 'public' => 1, 'archived' => 0, 'mature' => 0, 'spam' => 0, 'deleted' => 0 ) ),
			'www.w.org/foo/'          => array( 'domain' => 'www.w.org',          'path' => '/foo/',
												'meta' => array( 'public' => 1, 'archived' => 0, 'mature' => 0, 'spam' => 0, 'deleted' => 1 ) ),
			'www.w.org/foo/bar/'      => array( 'domain' => 'www.w.org',          'path' => '/foo/bar/',
												'meta' => array( 'public' => 1, 'archived' => 1, 'mature' => 1, 'spam' => 0, 'deleted' => 0 ) ),
			'test.example.org/'       => array( 'domain' => 'test.example.org',   'path' => '/',
												'meta' => array( 'public' => 0, 'archived' => 0, 'mature' => 0, 'spam' => 0, 'deleted' => 1 ) ),
			'test2.example.org/'      => array( 'domain' => 'test2.example.org',  'path' => '/',
												'meta' => array( 'public' => 1, 'archived' => 0, 'mature' => 1, 'spam' => 0, 'deleted' => 1 ) ),
			'test3.example.org/zig/'  => array( 'domain' => 'test3.example.org',  'path' => '/zig/',
												'meta' => array( 'public' => 1, 'archived' => 0, 'mature' => 0, 'spam' => 0, 'deleted' => 0 ) ),
			'atest.example.org/'      => array( 'domain' => 'atest.example.org',  'path' => '/',
												'meta' => array( 'public' => 1, 'archived' => 1, 'mature' => 1, 'spam' => 0, 'deleted' => 0 ) ),
		);

		foreach ( self::$site_ids as &$id ) {
			$id = $factory->blog->create( $id );
		}
		unset( $id );
	}

	public static function wpTearDownAfterClass() {
		foreach ( self::$site_ids as $site_id ) {
			wpmu_delete_blog( $site_id, true );
		}
	}

	public function test_ms_sites_list_table_site_status_views() {
		// status public
		$_REQUEST['site_status'] = 'public';

		$this->table->prepare_items();

		$items = wp_list_pluck( $this->table->items, 'blog_id' );
		$items = array_map( 'intval', $items );

		$this->assertEqualSetsWithMessage( get_sites( array ( 'public' => 1, 'fields' => 'ids', 'number' => 0 ) ), $items, 'site_status=public' );

		// status archived
		$_REQUEST['site_status'] = 'archived';

		$this->table->prepare_items();

		$items = wp_list_pluck( $this->table->items, 'blog_id' );
		$items = array_map( 'intval', $items );

		$this->assertEqualSetsWithMessage( get_sites( array ( 'archived' => 1, 'fields' => 'ids', 'number' => 0 ) ), $items, 'site_status=archived' );

		// status mature
		$_REQUEST['site_status'] = 'mature';

		$this->table->prepare_items();

		$items = wp_list_pluck( $this->table->items, 'blog_id' );
		$items = array_map( 'intval', $items );

		$this->assertEqualSetsWithMessage( get_sites( array ( 'mature' => 1, 'fields' => 'ids', 'number' => 0 ) ), $items, 'site_status=mature' );

		// status spam
		$_REQUEST['site_status'] = 'spam';

		$this->table->prepare_items();

		$items = wp_list_pluck( $this->table->items, 'blog_id' );
		$items = array_map( 'intval', $items );

		$this->assertEqualSetsWithMessage( get_sites( array ( 'spam' => 1, 'fields' => 'ids', 'number' => 0 ) ), $items, 'site_status=spam' );

		// status deleted
		$_REQUEST['site_status'] = 'deleted';

		$this->table->prepare_items();

		$items = wp_list_pluck( $this->table->items, 'blog_id' );
		$items = array_map( 'intval', $items );

		$this->assertEqualSetsWithMessage( get_sites( array ( 'deleted' => 1, 'fields' => 'ids', 'number' => 0 ) ), $items, 'site_status=deleted' );

		// negative test: status deleted, but checked against all sites (i.e., should fail assertEqualSets())
		$_REQUEST['site_status'] = 'deleted';

		$this->table->prepare_items();

		$items = wp_list_pluck( $this->table->items, 'blog_id' );
		$items = array_map( 'intval', $items );

		$this->assertNotEmpty( array_diff( get_sites( array( 'fields' => 'ids', 'number' => 0 ) ), $items), 'site_status=deleted, check against all sites' );
	}

	/**
	 * Test WP_MS_Sites_List_Table::is_base_request(), which is used to the "All" view should
	 * be considered as 'current'
	 *
	 * As of the writing of this test, there is inconsistency between the various
	 * WP_List_Table subclasses that display views in this regard.  For instance,
	 * WP_(Posts|Plugins)_List_Table show no view as current when a search has been performed,
	 * wherea WP_Users_List_Table shows "All" as current IF the search was performed
	 * while the user is on the "All" view.  The patch in 30871 that adds site_status
	 * views aligns with WP_Users_List_Table.
	 *
	 * @todo open a trac ticket to make ALL subclasses act this way
	 */
	public function test_ms_sites_list_table_is_base_request() {
		// tests that should be true
		$_GET = array();
		$is_base_request = self::callMethod( $this->table, 'is_base_request');

		$this->assertTrue( $is_base_request, '$_GET=array()' );

		$_GET = array ('site_status' => 'all' );
		$is_base_request = self::callMethod( $this->table, 'is_base_request');

		$this->assertTrue( $is_base_request, '$_GET=array(site_status=all)' );

		$_GET = array ('s' => 'wordpress');
		$is_base_request = self::callMethod( $this->table, 'is_base_request');

		$this->assertTrue( $is_base_request, '$_GET=array(s=wordpress)' );

		$_GET = array ('s' => 'wordpress', 'site_status' => 'all' );
		$is_base_request = self::callMethod( $this->table, 'is_base_request');

		$this->assertTrue( $is_base_request, '$_GET=array(s=wordpress,site_status=all)' );

		// in case a plugin adds query_args core is unware of
		$_GET = array ('foo' => 'bar');
		$is_base_request = self::callMethod( $this->table, 'is_base_request');

		$this->assertTrue( $is_base_request, '$_GET=array(foo=bar)' );

		// tests that should be false
		$_GET = array('site_status' => 'public');
		$is_base_request = self::callMethod( $this->table, 'is_base_request');

		$this->assertFalse( $is_base_request, '$_GET=array(site_status=public)' );

		$_GET = array('site_status' => 'public', 'foo' => 'bar');
		$is_base_request = self::callMethod( $this->table, 'is_base_request');

		$this->assertFalse( $is_base_request, '$_GET=array(site_status=public, foo=bar)' );
	}

	/**
	 * call a protected/private method so that method can be tested...when doing so is
	 * less error prone than testing the output of a public method that relies on it.
	 *
	 * @param class $obj
	 * @param string $method Protected/private method name of $obj
	 * @param array $args
	 *
	 * @return mixed Return value of $method
	 *
	 * @link http://stackoverflow.com/questions/249664/best-practices-to-test-protected-methods-with-phpunit#answer-8702347
	 */
	public static function callMethod( $obj, $method, $args = array() ) {
		$class = new \ReflectionClass( $obj );
		$method = $class->getMethod( $method );
		$method->setAccessible( true );
		
		return $method->invokeArgs( $obj, $args );
    }

	/**
	 * same as assertEqualSets() in phpunit/includes/testcase.php but passes
	 * $message thru to assertEquals() so that when multiple asserts are included
	 * in a single test the assert that failed can be more easily identified
	 *
	 * @todo open meta.trac (is that the right place?) ticket suggesting that all
	 * of the "custom" asserts in testcase.php accept $message
	 */
	public function assertEqualSetsWithMessage( $expected, $actual, $message = '' ) {
		sort( $expected );
		sort( $actual );

		$this->assertEquals( $expected, $actual, $message );
	}
}

endif;
