<?php
/*
 * Copyright (c) 2012, webvariants GbR, http://www.webvariants.de
 *
 * This file is released under the terms of the MIT license. You can find the
 * complete text in the attached LICENSE file or online at:
 *
 * http://www.opensource.org/licenses/mit-license.php
 */

class RealURL2_UtilTest extends sly_StatelessTest {
	protected function getRequiredComponents() {
		return array('developer_utils', 'global_settings', 'realurl2');
	}

	/**
	 * @dataProvider makeURLFriendlyProvider
	 */
	public function testMakeURLFriendly($in, $cleanup, $lowercase, $expected) {
		$this->assertEquals($expected, WV24_Util::makeURLFriendly($in, $cleanup, $lowercase));
	}

	public function makeURLFriendlyProvider() {
		return array(
			array('', false, false, ''),

			// basic combos
			array('Hallo Welt!', false, false, 'Hallo+Welt'),
			array('Hallo Welt', true, false, 'Hallo-Welt'),
			array('Hallo Welt', false, true, 'hallo+welt'),
			array('Hallo Welt', true, true, 'hallo-welt'),

			// lowercasing
			array('AbCdEFg', false, true, 'abcdefg'),
			array('Höhle', false, true, urlencode('höhle')),
			array('Änieß', false, true, urlencode('änieß')),
			array('€uro', false, true, urlencode('€uro')), // euro char

			// cleanup
			array('Höhle', true, false, 'Hoehle'),
			array('Änieß', true, false, 'Aeniess'),
			array('€uro', true, false, 'uro'), // euro char

			// both
			array('häHÄß', true, true, 'haehaess'),
			array('€uRo', true, true, 'uro'), // euro char

			// whitespace
			array('! hallo !', false, false, 'hallo'),
			array('-hallo-', false, false, 'hallo'),
			array('test  word', false, false, 'test+word'),
			array('test  word', true, false, 'test-word'),
			array('(test)', false, false, 'test'),
			array('foo (test)', false, false, 'foo+test'),
			array('foo (test)', true, false, 'foo-test'),
			array(' foo ? $ bar', false, false, 'foo+%24+bar'),
			array(' foo ? $ bar', true, false, 'foo-bar'),
			array('test...', false, false, 'test'),

			// and the grand finale...
			array('franz, der mal jagte, wohl nach Wöhl, und einen Geißbock besaß...', true, true, 'franz-der-mal-jagte-wohl-nach-woehl-und-einen-geissbock-besass')
		);
	}

	/**
	 * @dataProvider isAbsoluteFragmentProvider
	 */
	public function testIsAbsoluteFragment($str, $expected) {
		$this->assertEquals($expected, WV24_Util::isAbsoluteFragment($str));
	}

	public function isAbsoluteFragmentProvider() {
		return array(
			array('//', true),
			array('/foo', true),
			array('/foo/', true),
			array('', false),
			array('foo/bar', false),
			array('foo/', false)
		);
	}

	/**
	 * @dataProvider isDomainFragmentProvider
	 */
	public function testIsDomainFragment($str, $expected) {
		$this->assertEquals($expected, WV24_Util::isDomainFragment($str));
	}

	public function isDomainFragmentProvider() {
		return array(
			array('//', true),
			array('//foo', true),
			array('//foo//', true),
			array('/', false),
			array('', false),
			array('foo//bar', false),
			array('foo//', false)
		);
	}

	/**
	 * @dataProvider decodePathProvider
	 */
	public function testDecodePath($path, $expected) {
		$this->assertEquals($expected, WV24_Util::decodePath($path));
	}

	public function decodePathProvider() {
		return array(
			// valid
			array('', array()),
			array('|', array()),
			array('|1|', array(1)),
			array('|1|1|', array(1,1)),
			array('|123|456|', array(123,456)),
			array(array(), array()),
			array(array('a1', '2b'), array(2)),

			// invalid
			array('|1|1', array(1,1)),
			array('1|2', array(1,2)),
			array('1|2|', array(1,2)),
			array('1', array(1)),
			array('', array()),
			array('1a|b|b3|foo||', array(1)),
			array('||foo||5||', array(5))
		);
	}

	/**
	 * @dataProvider getDomainFromFragmentProvider
	 */
	public function testGetDomainFromFragment($fragment, $expected) {
		$this->assertEquals($expected, WV24_Util::getDomainFromFragment($fragment));
	}

	public function getDomainFromFragmentProvider() {
		return array(
			// valid
			array('//foo', 'foo'),
			array('//foo/bar', 'foo'),
			array('//foo.bar', 'foo.bar'),
			array('//foo.bar/bar', 'foo.bar'),
			array('//foo.bar:80/bar', 'foo.bar'),
			array('//user@foo.bar:80/bar', 'foo.bar'),
			array('//1.2.3.4/bar', '1.2.3.4'),
			array('///bar', '')
		);
	}

	/**
	 * @dataProvider shortenUrlProvider
	 */
	public function testShortenUrl($url, $forceDomain, $expected, $ssl = false) {
		if ($ssl) {
			$_SERVER['HTTPS'] = 'on';
			$_SERVER['HTTP_X_FORWARDED_PROTO'] = 'https';
		}
		else {
			unset($_SERVER['HTTPS'], $_SERVER['HTTP_X_FORWARDED_PROTO']);
		}

		$this->assertEquals($expected, WV24_Util::shortenUrl($url, $forceDomain));
	}

	public function shortenUrlProvider() {
		// in CLI the base URI is 'http://cli'
		return array(
			array('http://www.example.com/', false, 'http://www.example.com/'),
			array('http://www.example.com/my/path', false, 'http://www.example.com/my/path'),
			array('http://cli/sally/my/path', false, 'my/path'),
			array('http://cli/sally/', false, './'),
			array('http://cli/sally/', true, 'http://cli/sally/'),
			array('http://cli/sally/foo', true, 'http://cli/sally/foo'),

			// URLs pointing outside the installation should always be absolute
			array('http://cli/', true, 'http://cli/'),
			array('http://cli/', false, 'http://cli/'),
			array('http://cli/anothingthing', false, 'http://cli/anothingthing'),

			// assume we're on SSL: since the base URI already contains the 'https://',
			// the base URI should be stripped as well
			array('http://cli/sally/foo', false, 'foo', true),
			array('http://cli/sally/', false, './', true),

			// make sure that even when we leave the current domain, we stay in the same protocol
			array('http://foo.com/', false, 'https://foo.com/', true)
		);
	}

	public function testGetStorage() {
		$this->assertInstanceOf('_WV24_Storage', WV24_Util::getStorage());
	}

	/**
	 * @dataProvider storageWhereProvider
	 */
	public function testStorageWhere($expected, $namespace = null, $ident = null, $identIsLike = null, $path = null, $pathIsLike = null, $article = null, $clang = null) {
		$storage = new _WV24_Storage(sly_DB_Persistence::getInstance(), sly_Core::cache());
		$this->assertEquals($expected, $storage->where($namespace, $ident, $identIsLike, $path, $pathIsLike, $article, $clang));
	}

	public function storageWhereProvider() {
		return array(
			// array syntax
			array('1' /* no arguments for where() */),
			array(array('namespace' => 'test'),                                  'test'),
			array(array('ident' => 'test'),                                      null, 'test'),
			array(array('namespace' => 'foo', 'ident' => 'test'),                'foo', 'test'),
			array(array('namespace' => 'test', 'article_id' => 1),               'test', null, null, null, null, 1),
			array(array('namespace' => 'test', 'article_id' => 1, 'clang' => 2), 'test', null, null, null, null, 1, 2),

			// handcrafted SQL
			array("ident LIKE 'test'",                                           null, 'test', true),
			array("ident LIKE 'test' AND path = 'blub'",                         null, 'test', true, 'blub'),
			array("ident LIKE 'test' AND path LIKE 'blub'",                      null, 'test', true, 'blub', true),
			array("ident LIKE 'test' AND path LIKE 'blub' AND article_id = '1'", null, 'test', true, 'blub', true, 1),

			// quoting
			array("ident LIKE 'te\\'st'", null, 'te\'st', true),
			array("ident LIKE 'te\\\"st'", null, 'te"st', true),
			array("ident LIKE 'te\\\\\\\"st'", null, 'te\\"st', true),
		);
	}

	/**
	 * @dataProvider cleanUrlProvider
	 */
	public function testCleanUrl($url, $expected) {
		$this->assertEquals($expected, WV24_Util::cleanUrl($url));
	}

	public function cleanUrlProvider() {
		return array(
			array('http://www.foo.com/', 'http://www.foo.com/'),
			array('https://bla/', 'http://bla/'),
			array('gopher:/invalid/', 'http:/invalid/'),
			array('http://h/foo.html', 'http://h/foo.html'),
			array('http://h/foo.html?', 'http://h/foo.html'),
			array('http://h/foo.html&', 'http://h/foo.html'),
			array('http://h/foo.html&?', 'http://h/foo.html'),
			array('http://h/foo.html&?&', 'http://h/foo.html'),
			array('http://h/foo.html?arg1=arg2', 'http://h/foo.html'),
			array('http://h/foo.html?arg1=arg2&foo=bar', 'http://h/foo.html'),
			array('http://h/foo.html&arg1=arg2&foo=bar', 'http://h/foo.html'),
			array('http://h/foo.html&arg1=arg2?f%20 arg+-=bar', 'http://h/foo.html'),
			array('http://h/foo.html&arg1=arg2?foo=bar&', 'http://h/foo.html'),
			array('http://h/foo.html&arg1=arg2?foo=bar&x', 'http://h/foo.html'),
			array('http://h/foo.html&amp;x=?', 'http://h/foo.html'),
			array('http://h/foo.html&amp;x=?', 'http://h/foo.html'),
		);
	}

	/**
	 * @dataProvider buildQueryProvider
	 */
	public function testBuildQuery($params, $divider, $expected) {
		$this->assertEquals($expected, WV24_Util::buildQuery($params, $divider));
	}

	public function buildQueryProvider() {
		return array(
			array('',                     '',      ''),
			array('a=b',                  '',      '?a=b'),
			array('a=b',                  '&',     '?a=b'),
			array('&a=b&foo=bar',         '&',     '?a=b&foo=bar'),
			array('&a=b&foo=bar',         'A',     '?&a=b&foo=bar'),
			array('&amp;a=b&amp;foo=bar', '&amp;', '?a=b&amp;foo=bar'),
			array('?a=b',                 '&amp;', '?a=b'),
			array('?a=b&amp;c',           '&amp;', '?a=b&amp;c'),

			array(array(),                             '',      ''),
			array(array('a'),                          '',      '?0=a'),
			array(array('a' => 'möp'),                 '',      '?a='.urlencode('möp')),
			array(array('a' => 'möp', 'foo' => 'bar'), '&amp;', '?a='.urlencode('möp').'&amp;foo=bar'),
			array(array('a' => 'möp', 'foo' => 'bar'), '&',     '?a='.urlencode('möp').'&foo=bar')
		);
	}
}
