<?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_ExtensionsTest extends RealURL2_BaseTest {
	const NUM_ARTICLES = 24;

	protected function prepareDatabase(array $preparations) {
		$db    = sly_DB_Persistence::getInstance();
		$_POST = array();

		foreach ($preparations as $id => $fragment) {
			if (strpos($fragment, '|') !== false) {
				$parts = explode('|', $fragment);
				$what  = array('wv24_fragment' => $parts[0], 'wv24_skip' => $parts[1]);
			}
			else {
				$what = array('wv24_fragment' => $fragment);
			}

			if ($id === 'form') {
				$_POST['realurl2_fragment'] = $what['wv24_fragment'];
				$_POST['realurl2_skip']     = isset($what['wv24_skip']) ? $what['wv24_skip'] : false;
			}
			else {
				$db->update('article', $what, array('id' => $id, 'clang' => 5));
			}
		}
	}

	protected function assertURL($id, $clang, $url, _WV24_Storage $storage) {
		$urls = $storage->findByIdent(WV24_RealURL2::URL_NAMESPACE, $id.'_'.$clang, false, true);
		$this->assertCount(1, $urls);

		$urlInstance = reset($urls);
		$this->assertEquals($url, $urlInstance->getRawURL());
	}

	protected function assertURLCount($count = null, _WV24_Storage $storage = null) {
		$storage = $storage ?: WV24_Util::getStorage();
		$count   = $count === null ? (2*self::NUM_ARTICLES) : $count;

		$this->assertCount($count, $storage->findAll());
	}

	/**
	 * @dataProvider articleProvider
	 */
	public function testAddArticle($parentID, $name, array $preparations, array $expectations) {
		// prepare the database
		$this->prepareDatabase($preparations);

		// and now add the article
		$service = sly_Service_Factory::getArticleService();
		$article = $service->add($parentID, $name, 1, -1);
		$storage = WV24_Util::getStorage();

		// test if all expectations are met
		foreach ($expectations as $clang => $url) {
			$this->assertURL($article, $clang, $url, $storage);
		}

		$this->assertURLCount(2, $storage);
	}

	public function articleProvider() {
		return array(
			array(0,  'Testseite mit Ümlauten', array(), array(5 => 'http://cli/testseite-mit-uemlauten.html', 8 => 'http://cli/en/Testseite+mit+'.urlencode('Ü').'mlauten.html')),
			array(48, 'Testseite',              array(), array(5 => 'http://cli/c64/testseite.html')),
			array(2,  'Testseite',              array(), array(5 => 'http://cli/c64/hardware/testseite.html')),

			// check if fragments are OK
			array(48, 'Testseite', array(48 => '/foo'),                    array(5 => 'http://cli/foo/testseite.html')),
			array(48, 'Testseite', array(48 => '//c64.com'),               array(5 => 'http://c64.com/testseite.html')),
			array(2,  'Testseite', array(48 => '//c64.com', 2 => '/hart'), array(5 => 'http://c64.com/hart/testseite.html')),
		);
	}

	/**
	 * @dataProvider categoryProvider
	 */
	public function testAddCategory($parentID, $name, array $preparations, array $expectations) {
		// prepare the database
		$this->prepareDatabase($preparations);

		// and now add the category
		$service  = sly_Service_Factory::getCategoryService();
		$category = $service->add($parentID, $name, 1, -1);
		$storage  = WV24_Util::getStorage();

		// test if all expectations are met
		foreach ($expectations as $clang => $url) {
			$this->assertURL($category, $clang, $url, $storage);
		}

		$this->assertURLCount(2, $storage);
	}

	public function categoryProvider() {
		return array(
			array(0,  'Test mit Ümlauten', array(), array(5 => 'http://cli/test-mit-uemlauten/', 8 => 'http://cli/en/Test+mit+'.urlencode('Ü').'mlauten/')),
			array(48, 'Test',              array(), array(5 => 'http://cli/c64/test/')),
			array(2,  'Test',              array(), array(5 => 'http://cli/c64/hardware/test/')),

			// check if fragments are OK
			array(48, 'Test', array(48 => '/foo'),                    array(5 => 'http://cli/foo/test/')),
			array(48, 'Test', array(48 => '//c64.com'),               array(5 => 'http://c64.com/test/')),
			array(2,  'Test', array(48 => '//c64.com', 2 => '/hart'), array(5 => 'http://c64.com/hart/test/')),
		);
	}

	/**
	 * @dataProvider updateArticleProvider
	 */
	public function testUpdateArticle($id, $clang, $name, array $preparations, $url, $startArticle = null) {
		if ($startArticle !== null) {
			sly_Core::config()->set('START_ARTICLE_ID', $startArticle);
			sly_Core::cache()->flush('realurl2', true);
			sly_Core::cache()->flush('globalsettings', true);
		}

		// prepare the database
		$this->prepareDatabase($preparations);

		// rebuild all URLs
		self::rebuildAll();

		// and now update the article
		$service = sly_Service_Factory::getArticleService();
		$storage = WV24_Util::getStorage();

		$service->edit($id, $clang, $name);

		// test if URL is okay
		$this->assertURL($id, $clang, $url, $storage);
		$this->assertURLCount(2*self::NUM_ARTICLES, $storage);
	}

	public function updateArticleProvider() {
		return array(
			array(90, 5,  'Testseite mit Ümlauten', array(), 'http://cli/testseite-mit-uemlauten.html'),
			array(90, 8,  'Testseite mit Ümlauten', array(), 'http://cli/en/Testseite+mit+'.urlencode('Ü').'mlauten.html'),
			array(101, 5, 'Hallo Welt',             array(), 'http://cli/c64/hardware/hallo-welt.html'),
			array(101, 5, '',                       array(), 'http://cli/c64/hardware/unbenannter-artikel.html'),

			// the name of the site start article doesn't matter
			array(98, 5, '(egal)', array(), 'http://cli/'),
			array(90, 5, '(egal)', array(), 'http://cli/', 90),

			// the artname of categories doesn't matter
			array(48, 5, 'C64-Artikel', array(), 'http://cli/c64/'),

			// check if fragments on the article itself take precedence
			array(90, 5, 'Testseite', array(90 => 'foo'),      'http://cli/foo'),
			array(90, 5, 'Testseite', array(90 => '/'),        'http://cli/'),
			array(90, 5, 'Testseite', array(90 => '/foo/bar'), 'http://cli/foo/bar'),
			array(90, 5, 'Testseite', array(90 => '//domain'), 'http://domain/'),

			// check if fragments are OK
			array(101, 5, 'Testseite', array(48 => '//c64.com'),       'http://c64.com/hardware/testseite.html'),
			array(101, 5, 'Testseite', array(2  => '/'),               'http://cli/testseite.html'),
			array(101, 5, 'Testseite', array(2  => '/', 101 => 'foo'), 'http://cli/foo'),
		);
	}

	/**
	 * @dataProvider updateCategoryProvider
	 */
	public function testUpdateCategory($id, $clang, $name, array $preparations, array $expectations, $startArticle = null) {
		if ($startArticle !== null) {
			sly_Core::config()->set('START_ARTICLE_ID', $startArticle);
		}

		// prepare the database
		$this->prepareDatabase($preparations);

		// rebuild all URLs
		self::rebuildAll();

		// and now update the category
		$service = sly_Service_Factory::getCategoryService();
		$storage = WV24_Util::getStorage();

		$service->edit($id, $clang, $name);

		// test if all expectations are met
		foreach ($expectations as $catID => $url) {
			$this->assertURL($catID, $clang, $url, $storage);
		}

		$this->assertURLCount(2*self::NUM_ARTICLES, $storage);
	}

	public function updateCategoryProvider() {
		return array(
			array(48, 5, 'C65', array(),                     array(48 => 'http://cli/c65/', 1 => 'http://cli/c65/entwicklung/', 16 => 'http://cli/c65/hardware/ram/', 102 => 'http://cli/c65/hardware/prozessor/x86-ftw.html')),
			array(48, 5, 'C65', array('form' => 'foo'),      array(48 => 'http://cli/foo', 1 => 'http://cli/foo/entwicklung/')),
			array(48, 5, 'C65', array('form' => '//domain'), array(48 => 'http://domain/', 1 => 'http://domain/entwicklung/', 90 => 'http://cli/ackermannfunktion.html', 49 => 'http://cli/computervirus/')),
			array(48, 5, 'C65', array('form' => '|1'),       array(48 => 'http://cli/c65/', 1 => 'http://cli/entwicklung/', 90 => 'http://cli/ackermannfunktion.html', 49 => 'http://cli/computervirus/')),
			array(48, 5, 'C65', array('form' => 'foo|1'),    array(48 => 'http://cli/foo', 1 => 'http://cli/entwicklung/')),
			array(48, 5, 'C65', array('form' => '//foo|1'),  array(48 => 'http://foo/', 1 => 'http://foo/entwicklung/')),

			array(1,  5, 'Wickeln', array('form' => 'foo|1'),   array(48 => 'http://cli/c64/', 1 => 'http://cli/c64/foo', 99 => 'http://cli/c64/test-foo.html')),
			array(1,  5, 'Wickeln', array('form' => '/foo'),    array(48 => 'http://cli/c64/', 1 => 'http://cli/foo', 99 => 'http://cli/foo/test-foo.html')),
			array(1,  5, 'Wickeln', array('form' => '/foo|1'),  array(48 => 'http://cli/c64/', 1 => 'http://cli/foo', 99 => 'http://cli/c64/test-foo.html')),
			array(1,  5, 'Wickeln', array('form' => '//foo|1'), array(48 => 'http://cli/c64/', 1 => 'http://foo/', 99 => 'http://foo/test-foo.html')),

			array(1,  5, 'Wickeln', array(48 => '/foo|1'),  array(48 => 'http://cli/foo', 1 => 'http://cli/wickeln/')),
			array(1,  5, 'Wickeln', array(48 => '//foo|1'), array(48 => 'http://foo/', 1 => 'http://foo/wickeln/')),
			array(1,  5, 'Wickeln', array(99 => '//foo'),   array(48 => 'http://cli/c64/', 1 => 'http://cli/c64/wickeln/', 99 => 'http://foo/')),

			// make sure realURL2 does nothing if there was no submitted form
			array(48, 5, 'C65', array(48 => 'foo'), array(48 => 'http://cli/foo')),
		);
	}

	public function testDeleteArticle() {
		// rebuild all URLs
		_WV24_Extensions::cacheCleared(array('subject' => true));

		// and now delete the article
		$service = sly_Service_Factory::getArticleService();
		$storage = WV24_Util::getStorage();

		$urls = $storage->findByArticle(90);
		$this->assertCount(2, $urls);

		$service->delete(90);

		$urls = $storage->findByArticle(90);
		$this->assertCount(0, $urls);

		$this->assertURLCount(2*self::NUM_ARTICLES-2, $storage);
	}

	public function testDeleteCategory() {
		// rebuild all URLs
		_WV24_Extensions::cacheCleared(array('subject' => true));

		// and now delete the category
		$service = sly_Service_Factory::getCategoryService();
		$storage = WV24_Util::getStorage();

		$urls = $storage->findByArticle(18);
		$this->assertCount(2, $urls);

		$service->delete(18);

		$urls = $storage->findByArticle(18);
		$this->assertCount(0, $urls);

		$this->assertURLCount(2*self::NUM_ARTICLES-2, $storage);
	}

	public function testArticleMetaForm() {
		$fragment = 'test';
		$this->prepareDatabase(array(90 => $fragment));

		// rebuild all URLs
		self::rebuildAll();

		$form   = new sly_Form('index.php', 'POST', 'Test');
		$params = array('subject' => $form, 'id' => 90);
		$result = _WV24_Extensions::artMetaFormSection($params);

		$this->assertInstanceof('sly_Form', $result);

		$element = $result->findElementByName('realurl2_fragment');
		$this->assertInstanceof('sly_Form_Input_Text', $element);
		$this->assertEquals($fragment, $element->getValue());

		// check that the form for the homepage does not contain an input field
		$form   = new sly_Form('index.php', 'POST', 'Test');
		$params = array('subject' => $form, 'id' => 98);
		$result = _WV24_Extensions::artMetaFormSection($params);

		$this->assertInstanceof('sly_Form', $result);
		$this->assertNull($result->findElementByName('realurl2_fragment'));
	}

	public function testUpdatingArticleFragmentOnHomepage() {
		$_POST['realurl2_fragment'] = 'test';

		// rebuild all URLs
		self::rebuildAll();

		$storage = WV24_Util::getStorage();
		$params  = array('id' => 98, 'clang' => 5, 'subject' => '');
		$result  = _WV24_Extensions::artMetaUpdated($params);

		$this->assertEquals('', $result);
		$this->assertURL(98, 5, 'http://cli/', $storage);
		$this->assertURLCount(2*self::NUM_ARTICLES, $storage);
	}

	public function testUpdatingArticleFragmentOnArticles() {
		$_POST['realurl2_fragment'] = 'test';

		// rebuild all URLs
		self::rebuildAll();

		$_POST['realurl2_fragment'] = 'test'; // just in case

		$params  = array('id' => 101, 'clang' => 5, 'subject' => 'foo');
		$result  = _WV24_Extensions::artMetaUpdated($params);
		$storage = WV24_Util::getStorage();

		$this->assertNotEquals('foo', $result);
		$this->assertFalse(strpos($result, 'translate:'));
		$this->assertURL(101, 5, 'http://cli/c64/hardware/test', $storage);
		$this->assertURLCount(2*self::NUM_ARTICLES, $storage);
	}

	public function testUpdatingArticleFragmentOnCategories() {
		$_POST['realurl2_fragment'] = 'test'; // just in case

		$params  = array('id' => 2, 'clang' => 5, 'subject' => 'foo');
		$result  = _WV24_Extensions::artMetaUpdated($params);
		$storage = WV24_Util::getStorage();

		$this->assertNotEquals('foo', $result);
		$this->assertFalse(strpos($result, 'translate:'));
		$this->assertURL(2, 5, 'http://cli/c64/test', $storage);
		$this->assertURL(15, 5, 'http://cli/c64/test/prozessor/', $storage);
		$this->assertURL(101, 5, 'http://cli/c64/test/deutsch-ist-auch-mal-toll.html', $storage);
		$this->assertURLCount(6, $storage);
	}

	public function testIfMetaFormLeavesSkipAlone() {
		// prepare the database
		$this->prepareDatabase(array(48 => '|1'));

		// rebuild all URLs
		self::rebuildAll();

		// check pre-conditions
		$storage = WV24_Util::getStorage();
		$this->assertURL(48, 5, 'http://cli/c64/', $storage);
		$this->assertURL(1, 5, 'http://cli/entwicklung/', $storage);

		// test if the skip status is not changed
		$params = array('id' => 48, 'clang' => 5, 'subject' => '');
		$result = _WV24_Extensions::artMetaUpdated($params); // with no fragment

		$this->assertURL(48, 5, 'http://cli/c64/', $storage);
		$this->assertURL(1, 5, 'http://cli/entwicklung/', $storage);
		$this->assertURLCount(2*self::NUM_ARTICLES, $storage);
	}

	public function testUpdatingHomepageCategory() {
		$_POST['realurl2_fragment'] = 'test';
		sly_Core::config()->set('START_ARTICLE_ID', 48);

		// make sure the DB is empty
		$storage = WV24_Util::getStorage();
		$this->assertURLCount(0, $storage);

		$params = array('subject' => sly_Util_Category::findById(48, 5));
		_WV24_Extensions::catUpdated($params);

		// nothing should have happened
		$this->assertURLCount(0, $storage);
	}

	public function testAddingLanguage() {
		// rebuild all URLs
		self::rebuildAll();

		// check pre-conditions
		$storage = WV24_Util::getStorage();
		$this->assertURLCount(2*self::NUM_ARTICLES, $storage);

		// add the language
		$service  = sly_Service_Factory::getLanguageService();
		$language = $service->create(array('name' => 'testsprache', 'locale' => 'xx-XX'));
		$clang    = $language->getId();

		// all URLs available?
		$this->assertURLCount(3*self::NUM_ARTICLES, $storage);

		// global settings updated
		$this->assertEquals('//cli/sally/xx-xx', WV8_Settings::getValue('realurl2', 'default_fragment', null, $clang));
		$this->assertTrue(WV8_Settings::getValue('realurl2', 'lowercase', null, $clang));
		$this->assertTrue(WV8_Settings::getValue('realurl2', 'cleanup', null, $clang));

		// correct base URI?
		$this->assertURL(98, $clang, 'http://cli/sally/xx-xx/', $storage);
		$this->assertURL(48, $clang, 'http://cli/sally/xx-xx/c64/', $storage);
		$this->assertURL(101, $clang, 'http://cli/sally/xx-xx/c64/hardware/deutsch-ist-auch-mal-toll.html', $storage);
	}

	public function testUpdatingLanguage() {
		// prepare the database
		$this->prepareDatabase(array(48 => '|1'));

		// rebuild all URLs
		self::rebuildAll();

		// check pre-conditions
		$storage = WV24_Util::getStorage();
		$this->assertURL(48, 5, 'http://cli/c64/', $storage);
		$this->assertURL(1, 5, 'http://cli/entwicklung/', $storage);

		// revert database
		$this->prepareDatabase(array(48 => '|0'));

		// find and update language
		$service  = sly_Service_Factory::getLanguageService();
		$language = $service->findById(5);

		$language->setName('foo');
		$language->setLocale('xx-xx');
		$service->save($language);

		// nothing changed?
		$this->assertURL(48, 5, 'http://cli/c64/', $storage);
		$this->assertURL(1, 5, 'http://cli/entwicklung/', $storage);
		$this->assertURLCount(2*self::NUM_ARTICLES, $storage);
	}

	public function testDeletingLanguage() {
		// rebuild all URLs
		self::rebuildAll();

		// check pre-conditions
		$storage = WV24_Util::getStorage();
		$this->assertURLCount(2*self::NUM_ARTICLES, $storage);

		// delete the language
		$service = sly_Service_Factory::getLanguageService();
		$service->delete(array('id' => 8));

		// URLs removed?
		$this->assertURLCount(self::NUM_ARTICLES, $storage);
		$this->assertCount(0, $storage->findByClang(8));
	}

	public function testClearCache() {
		// set some data
		sly_Core::cache()->set('realurl2', 'foo', 'foo');
		sly_Core::cache()->set('realurl2.foo', 'foo', 'foo');

		// check pre-conditions
		$storage = WV24_Util::getStorage();
		$this->assertURLCount(0, $storage);

		// clear cache
		$result = _WV24_Extensions::cacheCleared(array('subject' => 'foo'));
		$this->assertEquals('foo', $result);

		// URLs generated?
		$this->assertURLCount(2*self::NUM_ARTICLES, $storage);

		// Data removed?
		$this->assertNull(sly_Core::cache()->get('realurl2', 'foo'));
		$this->assertNull(sly_Core::cache()->get('realurl2.foo', 'foo'));
	}

	public function testCatchBadHomepage() {
		// set some data
		sly_Core::cache()->set('realurl2', 'foo', 'foo');
		sly_Core::cache()->set('realurl2.foo', 'foo', 'foo');

		// check pre-conditions
		$storage = WV24_Util::getStorage();
		$this->assertURLCount(0, $storage);

		// set bad homepage
		sly_Core::config()->set('START_ARTICLE_ID', 0);

		// clear cache
		$result = _WV24_Extensions::cacheCleared(array('subject' => 'foo'));
		$this->assertEquals('foo', $result);

		// URLs generated?
		$this->assertURLCount(0, $storage);

		// Data should be removed anyway.
		$this->assertNull(sly_Core::cache()->get('realurl2', 'foo'));
		$this->assertNull(sly_Core::cache()->get('realurl2.foo', 'foo'));
	}

	public function testClearCacheByEvent() {
		// set some data
		sly_Core::cache()->set('realurl2', 'foo', 'foo');
		sly_Core::cache()->set('realurl2.foo', 'foo', 'foo');

		// check pre-conditions
		$storage = WV24_Util::getStorage();
		$this->assertURLCount(0, $storage);

		// clear cache
		sly_Core::clearCache();

		// URLs generated?
		$this->assertURLCount(2*self::NUM_ARTICLES, $storage);

		// Data removed?
		$this->assertNull(sly_Core::cache()->get('realurl2', 'foo'));
		$this->assertNull(sly_Core::cache()->get('realurl2.foo', 'foo'));
	}

	public function testArticleToStartpage() {
		// rebuild all URLs
		self::rebuildAll();

		// make the article the startpage
		$service = sly_Service_Factory::getArticleService();
		$service->convertToStartArticle(101);

		// URLs generated?
		$storage = WV24_Util::getStorage();
		$this->assertURL(101, 5, 'http://cli/c64/hardware/', $storage);
		$this->assertURL(2,   5, 'http://cli/c64/hardware/hardware.html', $storage);
		$this->assertURL(101, 8, 'http://cli/en/C64/'.urlencode('硬件').'+hardware/', $storage);
		$this->assertURL(2,   8, 'http://cli/en/C64/'.urlencode('硬件').'+hardware/'.urlencode('硬件').'+hardware.html', $storage);
		$this->assertURL(3,   8, 'http://cli/en/C64/Schnittstellen/', $storage);

		$this->assertURLCount(2*self::NUM_ARTICLES, $storage);
	}

	public function testMoveArticle() {
		// rebuild all URLs
		self::rebuildAll();

		// move the article
		$service = sly_Service_Factory::getArticleService();
		$service->move(101, 48);

		// URLs generated?
		$storage = WV24_Util::getStorage();
		$this->assertURL(101, 5, 'http://cli/c64/deutsch-ist-auch-mal-toll.html', $storage);
		$this->assertURL(101, 8, 'http://cli/en/C64/Deutsch+ist+auch+mal+toll.html', $storage);

		$this->assertURLCount(2*self::NUM_ARTICLES, $storage);
	}

	public function testMoveCategory() {
		// rebuild all URLs
		self::rebuildAll();

		// move the category
		$service = sly_Service_Factory::getCategoryService();
		$service->move(2, 3);

		// URLs generated?
		$storage = WV24_Util::getStorage();
		$this->assertURL(2, 5,   'http://cli/c64/schnittstellen/hardware/', $storage);
		$this->assertURL(2, 8,   'http://cli/en/C64/Schnittstellen/'.urlencode('硬件').'+hardware/', $storage);
		$this->assertURL(15, 5,  'http://cli/c64/schnittstellen/hardware/prozessor/', $storage);
		$this->assertURL(102, 8, 'http://cli/en/C64/Schnittstellen/'.urlencode('硬件').'+hardware/Prozessor/x86+FTW.html', $storage);

		$this->assertURLCount(2*self::NUM_ARTICLES, $storage);
	}

	public function testCopyArticle() {
		// rebuild all URLs
		self::rebuildAll();

		// move the article
		$service = sly_Service_Factory::getArticleService();
		$newID   = $service->copy(90, 0);

		// URLs generated?
		$storage = WV24_Util::getStorage();
		$this->assertURL($newID, 5, 'http://cli/ackermannfunktion.html', $storage);
		$this->assertURL($newID, 8, 'http://cli/en/Ackermann+function.html', $storage);

		$this->assertURLCount(2*self::NUM_ARTICLES+2, $storage);
	}

	public function testCopyStartArticle() {
		// rebuild all URLs
		self::rebuildAll();

		// move the article
		$service = sly_Service_Factory::getArticleService();
		$newID   = $service->copy(48, 49);

		// URLs generated?
		$storage = WV24_Util::getStorage();
		$this->assertURL($newID, 5, 'http://cli/computervirus/c64.html', $storage);
		$this->assertURL($newID, 8, 'http://cli/en/Computer+virus/C64.html', $storage);

		$this->assertURLCount(2*self::NUM_ARTICLES+2, $storage);
	}

	public function testModelExtensions() {
		$this->prepareDatabase(array(48 => 'c64', 98 => '|1', 2 => '/foo|1'));

		$article = sly_Util_Article::findById(48, 5);
		$this->assertEquals('c64', $article->getFragment());
		$this->assertFalse($article->isSkipped());

		$article = sly_Util_Article::findById(98, 5);
		$this->assertEquals('', $article->getFragment());
		$this->assertTrue($article->isSkipped());

		$article = sly_Util_Article::findById(2, 5);
		$this->assertEquals('/foo', $article->getFragment());
		$this->assertTrue($article->isSkipped());

		// and nothing in other languages
		$article = sly_Util_Article::findById(2, 8);
		$this->assertEquals('', $article->getFragment());
		$this->assertFalse($article->isSkipped());
	}

	/**
	 * @dataProvider  outputFilterProvider
	 */
	public function testOutputFilter($baseTag, $html, $expected, $rebuild = false) {
		if ($baseTag) {
			WV24_RealURL2::enableAutoBaseTag();
		}
		else {
			WV24_RealURL2::disableAutoBaseTag();
		}

		if ($rebuild) {
			// for the replacements to work, we have to be inside '//cli/sally',
			// the baseUrl with script path
			sly_Core::config()->set('START_ARTICLE_ID', 98);
			sly_Core::config()->set('NOTFOUND_ARTICLE_ID', 3);

			$this->setConfigValue('default_fragment', '//cli/sally', 5);
			$this->setConfigValue('default_fragment', '//cli/sally/en', 8);

			// rebuild all URLs
			self::rebuildAll();
		}

		$params['subject'] = $html;
		$result = _WV24_Extensions::outputFilter($params);
		$this->assertEquals($expected, $result);
	}

	public function outputFilterProvider() {
		$baseTag = WV24_RealURL2::getBaseTag(true, false);

		return array(
			array(true,  '', ''),
			array(false, '', ''),

			// adding the <base>...
			array(true,  '<html><head></head>i\'m invalid, but you should not care.', '<html><head>'."\n\t".$baseTag.'</head>i\'m invalid, but you should not care.'),
			array(true,  '<head lang="foo"></head>foo', '<head lang="foo">'."\n\t".$baseTag.'</head>foo'),
			array(false, '<head lang="foo"></head>foo', '<head lang="foo"></head>foo'),
			array(true,  '<header lang="foo"></header>foo', '<header lang="foo"></header>foo'),
			array(true,  '<header lang="foo"></head>foo', '<header lang="foo"></head>foo'),
			array(true,  '<head lang="foo"><script></script></head>foo', '<head lang="foo">'."\n\t".$baseTag.'<script></script></head>foo'),

			// adjusting the <base>...
			array(true,  '<head><base href="">', '<head>'.$baseTag),
			array(true,  '<head><base href="" />', '<head>'.$baseTag),
			array(true,  '<head><base>', '<head>'.$baseTag),
			array(true,  '<head><base />', '<head>'.$baseTag),

			// test URL placeholders
			array(true, 'href="%%realurl2://98-5/%%"', 'href="./"', true),
			array(true, 'href="%%realurl2://90-5/%%"', 'href="ackermannfunktion.html"', true),
			array(true, 'href="%%realurl2://48-5/%%"', 'href="c64/"', true),
			array(true, 'href="%%realurl2://49-8/%%"', 'href="en/Computer+virus/"', true),

			// test URL placeholders with params
			array(true, 'href="%%realurl2://98-5/?foo=bar%%"', 'href="./?foo=bar"', true),
			array(true, 'href="%%realurl2://90-5/?foo=bar&amp;bar=1%%"', 'href="ackermannfunktion.html?foo=bar&amp;bar=1"', true),

			// be nice and remove useless anchors
			array(true, 'href="%%realurl2://49-8/#%%"', 'href="en/Computer+virus/"', true),

			// keep good anchors
			array(true, 'href="%%realurl2://49-8/#foo%%"', 'href="en/Computer+virus/#foo"', true),
			array(true, 'href="%%realurl2://49-8/%%#foo"', 'href="en/Computer+virus/#foo"', true),

			// bad placeholders (=> URL to 404 article)
			array(true, 'href="%%realurl2://49-7/%%"',   'href="computervirus/"', true), // rescued the 49
			array(true, 'href="%%realurl2://1000-8/%%"', 'href="en/C64/Schnittstellen/"', true), // rescued the 8
			array(true, 'href="%%realurl2://1000-5/%%"', 'href="c64/schnittstellen/"', true), // rescued the 5

			// remove broken tags
			array(true, 'href="%%realurl2://"', 'href="#"'),
			array(true, 'href=%%realurl2://%%', 'href=#'),
			array(true, 'href="%%realurl2://%%"', 'href="#"'),
			array(true, 'href=%%realurl2://-%', 'href=#'),
			array(true, 'href="%%realurl2:/%%"', 'href="#"'),
			array(true, 'href="%%realurl2:/5%%"', 'href="#"'),
			array(true, 'href="%%realurl2:/5-5%%"', 'href="#"'),
		);
	}

	/**
	 * @dataProvider  rewriteProvider
	 */
	public function testUrlRewrite($articleID, $clang, $params, $divider, $expected) {
		self::rebuildAll();

		$article = sly_Util_Article::findById($articleID, $clang);
		$url     = $article->getUrl($params, $divider);

		$this->assertEquals($expected, $url);
	}

	public function rewriteProvider() {
		$bear = urlencode('bär');

		return array(
			// vanilla cases
			array(98, 5, '', '', 'http://cli/'),
			array(98, 8, '', '', 'http://cli/en/'),
			array(90, 8, '', '', 'http://cli/en/Ackermann+function.html'),

			// string params
			array(98, 5, 'foo=bar', '', 'http://cli/?foo=bar'),
			array(98, 5, '?foo=bar', '', 'http://cli/?foo=bar'),
			array(98, 5, '?foo=bar&a=b', '', 'http://cli/?foo=bar&a=b'),
			array(98, 5, '?foo=bar&a=b', 'amp;', 'http://cli/?foo=bar&a=b'),

			// array params
			array(98, 5, array(),                           '&amp;', 'http://cli/'),
			array(98, 5, array('foo' => 'bär'),             '&amp;', 'http://cli/?foo='.$bear),
			array(98, 5, array('foo' => 'bär', 'a' => 'b'), '&amp;', 'http://cli/?foo='.$bear.'&amp;a=b'),
			array(98, 5, array('foo' => 'bär', 'a' => 'b'), '&',     'http://cli/?foo='.$bear.'&a=b'),
		);
	}
}
