code:
<?php

/**
 * A test script for the OpenIDStore classes.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

/**
 * Require classes and functions to run the Store tests.
 */
require_once 'Auth/OpenID/Association.php';
require_once 'Auth/OpenID/CryptUtil.php';
require_once 'Auth/OpenID/Nonce.php';
require_once 'Auth/OpenID.php';

function _Auth_OpenID_mkdtemp()
{
    if (function_exists('sys_get_temp_dir')) {
        $dir = sys_get_temp_dir();
    }
    else {
        if (strpos(PHP_OS, 'WIN') === 0) {
            $dir = $_ENV['TMP'];
            if (!isset($dir)) {
                $dir = 'C:\Windows\Temp';
            }
        } else {
            $dir = @$_ENV['TMPDIR'];
            if (!isset($dir)) {
                $dir = '/tmp';
            }
        }
    }

    return Auth_OpenID_FileStore::_mkdtemp($dir);
}

/**
 * This is the host where the SQL stores' databases should be created
 * and destroyed.
 */
global $_Auth_OpenID_db_test_host;
$_Auth_OpenID_db_test_host = 'dbtest';

/**
 * Generate a sufficently unique database name so many hosts can run
 * SQL store tests on the server at the same time and not step on each
 * other.
 */
function _Auth_OpenID_getTmpDbName()
{
    $hostname = php_uname('n');
    $hostname = str_replace('.', '_', $hostname);
    $hostname = str_replace('-', '_', $hostname);
    $hostname = strtolower($hostname);

    return sprintf("%s_%d_%s_openid_test",
                   $hostname,
                   getmypid(),
                   strval(rand(1, time())));
}

/**
 * Superclass that has methods for testing OpenID stores. Subclass this to
 * test your own store implementation.
 *
 * @package OpenID
 */
class Tests_Auth_OpenID_Store extends PHPUnit_Framework_TestCase {

  function pass() {}

    /**
     * Prepares for the SQL store tests.
     */
    function setUp()
    {
        $this->letters = Auth_OpenID_letters;
        $this->digits = Auth_OpenID_digits;
        $this->punct = Auth_OpenID_punct;
        $this->allowed_nonce = $this->letters . $this->digits;
        $this->allowed_handle = $this->letters . $this->digits . $this->punct;
    }

    /**
     * Generates an association with the specified parameters.
     */
    function genAssoc($now, $issued = 0, $lifetime = 600)
    {
        $sec = Auth_OpenID_CryptUtil::randomString(20);
        $hdl = Auth_OpenID_CryptUtil::randomString(128, $this->allowed_handle);
        return new Auth_OpenID_Association($hdl, $sec, $now + $issued,
                                          $lifetime, 'HMAC-SHA1');
    }

    /**
     * @access private
     */
    function _checkRetrieve($store, $url, $handle, $expected, $name = null)
    {
        $retrieved_assoc = $store->getAssociation($url, $handle);
        if ($expected === null) {
            $this->assertTrue($retrieved_assoc === null);
        } else {
            $this->assertTrue($expected->equal($retrieved_assoc), $name);
        }
    }

    function _checkRemove($store, $url, $handle, $expected, $name = null)
    {
        $present = $store->removeAssociation($url, $handle);
        $this->assertTrue((!$expected && !$present) ||
                          ($expected && $present),
                          $name);
    }

    /**
     * Make sure a given store has a minimum of API compliance. Call
     * this function with an empty store.
     *
     * Raises AssertionError if the store does not work as expected.
     *
     * OpenIDStore -> NoneType
     */
    function _testStore($store)
    {
        // Association functions
        $now = time();

        $server_url = 'http://www.myopenid.com/openid';

        $assoc = $this->genAssoc($now);

        $this->_checkRetrieve($store, $server_url, null, null,
            'Make sure that a missing association returns no result');

        $store->storeAssociation($server_url, $assoc);
        $this->_checkRetrieve($store, $server_url, null, $assoc,
            'Check that after storage, getting returns the same result');

        $this->_checkRetrieve($store, $server_url, null, $assoc,
            'more than once');

        $store->storeAssociation($server_url, $assoc);
        $this->_checkRetrieve($store, $server_url, null, $assoc,
            'Storing more than once has no ill effect');

        // Removing an association that does not exist returns not present
        $this->_checkRemove($store, $server_url, $assoc->handle . 'x', false,
                            "Remove nonexistent association (1)");

        // Removing an association that does not exist returns not present
        $this->_checkRemove($store, $server_url . 'x', $assoc->handle, false,
                            "Remove nonexistent association (2)");

        // Removing an association that is present returns present
        $this->_checkRemove($store, $server_url, $assoc->handle, true,
                            "Remove existent association");

        // but not present on subsequent calls
        $this->_checkRemove($store, $server_url, $assoc->handle, false,
                            "Remove nonexistent association after removal");

        // Put assoc back in the store
        $store->storeAssociation($server_url, $assoc);

        // More recent and expires after assoc
        $assoc2 = $this->genAssoc($now, $issued = 1);
        $store->storeAssociation($server_url, $assoc2);

        $this->_checkRetrieve($store, $server_url, null, $assoc2,
            'After storing an association with a different handle, but the
same $server_url, the handle with the later expiration is
returned.');

        $this->_checkRetrieve($store, $server_url, $assoc->handle, $assoc,
            'We can still retrieve the older association');

        $this->_checkRetrieve($store, $server_url, $assoc2->handle, $assoc2,
            'Plus we can retrieve the association with the later expiration
explicitly');

        $assoc3 = $this->genAssoc($now, $issued = 2, $lifetime = 100);
        $store->storeAssociation($server_url, $assoc3);

        // More recent issued time, so assoc3 is expected.
        $this->_checkRetrieve($store, $server_url, null, $assoc3, "(1)");

        $this->_checkRetrieve($store, $server_url, $assoc->handle,
                              $assoc, "(2)");

        $this->_checkRetrieve($store, $server_url, $assoc2->handle,
                              $assoc2, "(3)");

        $this->_checkRetrieve($store, $server_url, $assoc3->handle,
                              $assoc3, "(4)");

        $this->_checkRemove($store, $server_url, $assoc2->handle, true, "(5)");

        $this->_checkRetrieve($store, $server_url, null, $assoc3, "(6)");

        $this->_checkRetrieve($store, $server_url, $assoc->handle,
                              $assoc, "(7)");

        $this->_checkRetrieve($store, $server_url, $assoc2->handle,
                              null, "(8)");

        $this->_checkRetrieve($store, $server_url, $assoc3->handle,
                              $assoc3, "(9)");

        $this->_checkRemove($store, $server_url, $assoc2->handle,
                            false, "(10)");

        $this->_checkRemove($store, $server_url, $assoc3->handle,
                            true, "(11)");

        $this->_checkRetrieve($store, $server_url, null, $assoc, "(12)");

        $this->_checkRetrieve($store, $server_url, $assoc->handle,
                              $assoc, "(13)");

        $this->_checkRetrieve($store, $server_url, $assoc2->handle,
                              null, "(14)");

        $this->_checkRetrieve($store, $server_url, $assoc3->handle,
                              null, "(15)");

        $this->_checkRemove($store, $server_url, $assoc2->handle,
                            false, "(16)");

        $this->_checkRemove($store, $server_url, $assoc->handle,
                            true, "(17)");

        $this->_checkRemove($store, $server_url, $assoc3->handle,
                            false, "(18)");

        $this->_checkRetrieve($store, $server_url, null, null, "(19)");

        $this->_checkRetrieve($store, $server_url, $assoc->handle,
                              null, "(20)");

        $this->_checkRetrieve($store, $server_url, $assoc2->handle,
                              null, "(21)");

        $this->_checkRetrieve($store, $server_url,$assoc3->handle,
                              null, "(22)");

        $this->_checkRemove($store, $server_url, $assoc2->handle,
                            false, "(23)");

        $this->_checkRemove($store, $server_url, $assoc->handle,
                            false, "(24)");

        $this->_checkRemove($store, $server_url, $assoc3->handle,
                            false, "(25)");

        // Put associations into store, for two different server URLs
        $assoc1 = $this->genAssoc($now);
        $assoc2 = $this->genAssoc($now + 2);
        $server_url1 = "http://one.example.com/one";
        $server_url2 = "http://two.localhost.localdomain/two";

        $store->storeAssociation($server_url1, $assoc1);
        $store->storeAssociation($server_url2, $assoc2);

        // Ask for each one, make sure we get it
        $this->_checkRetrieve($store, $server_url1, $assoc1->handle,
                              $assoc1, "(26)");

        $this->_checkRetrieve($store, $server_url2, $assoc2->handle,
                              $assoc2, "(27)");

        $store->storeAssociation($server_url1, $assoc1);
        $store->storeAssociation($server_url2, $assoc2);

        // Ask for each one, make sure we get it
        $this->_checkRetrieve($store, $server_url1, null,
                              $assoc1, "(28)");

        $this->_checkRetrieve($store, $server_url2, null,
                              $assoc2, "(29)");

        // test expired associations
        // assoc 1: server 1, valid
        // assoc 2: server 1, expired
        // assoc 3: server 2, expired
        // assoc 4: server 3, valid
        $assocValid1 = $this->genAssoc($now, -3600, 7200);
        $assocValid2 = $this->genAssoc($now, -5);
        $assocExpired1 = $this->genAssoc($now, -7200, 3600);
        $assocExpired2 = $this->genAssoc($now, -7200, 3600);

        if (!$store->supportsCleanup()) {
            return;
        }

        $store->cleanupAssociations();
        $store->storeAssociation($server_url . '1', $assocValid1);
        $store->storeAssociation($server_url . '1', $assocExpired1);
        $store->storeAssociation($server_url . '2', $assocExpired2);
        $store->storeAssociation($server_url . '3', $assocValid2);

        $cleaned = $store->cleanupAssociations();
        $this->assertEquals(2, $cleaned);
    }

    function _checkUseNonce($store, $nonce, $expected, $server_url, $msg=null)
    {
        list($stamp, $salt) = Auth_OpenID_splitNonce($nonce);
        $actual = $store->useNonce($server_url, $stamp, $salt);
        $this->assertEquals(intval($expected), intval($actual), "_checkUseNonce failed: $server_url, $msg");
    }

    function _testNonce($store)
    {
        // Nonce functions

        $server_url = 'http://www.myopenid.com/openid';

        foreach (array($server_url, '') as $url) {
            // Random nonce (not in store)
            $nonce1 = Auth_OpenID_mkNonce();

            // A nonce is not by default
            $this->_checkUseNonce($store, $nonce1, true, $url, "blergx");

            // Once stored, cannot be stored again
            $this->_checkUseNonce($store, $nonce1, false, $url, 2);

            // And using again has the same effect
            $this->_checkUseNonce($store, $nonce1, false, $url, 3);

            // Nonces from when the universe was an hour old should
            // not pass these days.
            $old_nonce = Auth_OpenID_mkNonce(3600);
            $this->_checkUseNonce($store, $old_nonce, false, $url,
                                  "Old nonce ($old_nonce) passed.");

        }
    }

    function _testNonceCleanup($store) {
        if (!$store->supportsCleanup()) {
        	return;
        }

        $server_url = 'http://www.myopenid.com/openid';

        $now = time();

        $old_nonce1 = Auth_OpenID_mkNonce($now - 20000);
        $old_nonce2 = Auth_OpenID_mkNonce($now - 10000);
        $recent_nonce = Auth_OpenID_mkNonce($now - 600);

        global $Auth_OpenID_SKEW;
        $orig_skew = $Auth_OpenID_SKEW;

        $Auth_OpenID_SKEW = 0;
        $store->cleanupNonces();
        // Set SKEW high so stores will keep our nonces.
        $Auth_OpenID_SKEW = 100000;

        $params = Auth_OpenID_splitNonce($old_nonce1);
        array_unshift($params, $server_url);
        $this->assertTrue(call_user_func_array(array($store, 'useNonce'), $params));

        $params = Auth_OpenID_splitNonce($old_nonce2);
        array_unshift($params, $server_url);
        $this->assertTrue(call_user_func_array(array($store, 'useNonce'), $params));

        $params = Auth_OpenID_splitNonce($recent_nonce);
        array_unshift($params, $server_url);
        $this->assertTrue(call_user_func_array(array($store, 'useNonce'), $params));

        $Auth_OpenID_SKEW = 3600;
        $cleaned = $store->cleanupNonces();
        $this->assertEquals(2, $cleaned); // , "Cleaned %r nonces." % (cleaned,)

        $Auth_OpenID_SKEW = 100000;
        // A roundabout method of checking that the old nonces were
        // cleaned is to see if we're allowed to add them again.

        $params = Auth_OpenID_splitNonce($old_nonce1);
        array_unshift($params, $server_url);
        $this->assertTrue(call_user_func_array(array($store, 'useNonce'), $params));
        $params = Auth_OpenID_splitNonce($old_nonce2);
        array_unshift($params, $server_url);
        $this->assertTrue(call_user_func_array(array($store, 'useNonce'), $params));

        // The recent nonce wasn't cleaned, so it should still fail.
        $params = Auth_OpenID_splitNonce($recent_nonce);
        array_unshift($params, $server_url);
        $this->assertFalse(call_user_func_array(array($store, 'useNonce'), $params));

        $Auth_OpenID_SKEW = $orig_skew;
    }

}
/**
 * Class that tests all of the stores included with the OpenID library
 *
 * @package OpenID
 */
class Tests_Auth_OpenID_Included_StoreTest extends Tests_Auth_OpenID_Store {
    function test_memstore()
    {
        require_once 'Tests/Auth/OpenID/MemStore.php';
        $store = new Tests_Auth_OpenID_MemStore();
        $this->_testStore($store);
        $this->_testNonce($store);
        $this->_testNonceCleanup($store);
    }

    function test_filestore()
    {
        require_once 'Auth/OpenID/FileStore.php';

        $temp_dir = _Auth_OpenID_mkdtemp();

        if (!$temp_dir) {
            trigger_error('Could not create temporary directory ' .
                          'with Auth_OpenID_FileStore::_mkdtemp',
                          E_USER_WARNING);
            return null;
        }

        $store = new Auth_OpenID_FileStore($temp_dir);
        $this->_testStore($store);
        $this->_testNonce($store);
        $this->_testNonceCleanup($store);
        $store->destroy();
    }

    function test_postgresqlstore()
    {
        // If the postgres extension isn't loaded or loadable, succeed
        // because we can't run the test.
        if (!(extension_loaded('pgsql')) ||
            !(@include_once 'DB.php')) {
            print "(not testing PostGreSQL store)";
            $this->pass();
            return;
        }

        require_once 'Auth/OpenID/PostgreSQLStore.php';

        global $_Auth_OpenID_db_test_host;

        $temp_db_name = _Auth_OpenID_getTmpDbName();

        $connect_db_name = 'test_master';

        $dsn = array(
                     'phptype'  => 'pgsql',
                     'username' => 'openid_test',
                     'password' => '',
                     'hostspec' => $_Auth_OpenID_db_test_host,
                     'database' => $connect_db_name
                     );

        $allowed_failures = 5;
        $result = null;
        $sleep_time = 1.0;
        $sql = sprintf("CREATE DATABASE %s", $temp_db_name);

        for ($failures = 0; $failures < $allowed_failures; $failures++) {
            $template_db =& DB::connect($dsn);

            if (PEAR::isError($template_db)) {
                $result =& $template_db;
            } else {
                // Try to create the test database.
                $result = $template_db->query($sql);

                $template_db->disconnect();
                unset($template_db);

                if (!PEAR::isError($result)) {
                    break;
                }
            }

            $sleep_time *= ((mt_rand(1, 100) / 100.0) + 1.5);
            print "Failed to create database $temp_db_name.\n".
                "Waiting $sleep_time before trying again\n";

            $int_sleep = floor($sleep_time);
            $frac_sleep = $sleep_time - $int_sleep;
            sleep($int_sleep);
            usleep($frac_sleep * 1000000.0);
        }

        if ($failures == $allowed_failures) {
            $this->pass("Temporary database creation failed after $failures ".
                        " tries ('$temp_db_name'): " . $result->getMessage());
            return;
        }

        // Disconnect from template1 and reconnect to the temporary
        // testing database.
        $dsn['database'] = $temp_db_name;
        $db =& DB::connect($dsn);

        if (PEAR::isError($db)) {
            $this->fail("Temporary database connection failed " .
                        " ('$temp_db_name'): " . $db->getMessage());
            return;
        }

        $store = new Auth_OpenID_PostgreSQLStore($db);

        $this->assertFalse($store->tableExists($store->nonces_table_name));
        $this->assertFalse($store->tableExists($store->associations_table_name));

        $store->createTables();

        $this->assertTrue($store->tableExists($store->nonces_table_name));
        $this->assertTrue($store->tableExists($store->associations_table_name));

        $this->_testStore($store);
        $this->_testNonce($store);
        $this->_testNonceCleanup($store);

        $db->disconnect();
        unset($db);

        // Connect to template1 again so we can drop the temporary
        // database.
        $dsn['database'] = $connect_db_name;
        $template_db =& DB::connect($dsn);

        if (PEAR::isError($template_db)) {
            $this->fail("Template database connection (to drop " .
                        "temporary database) failed: " .
                        $template_db->getMessage());
            return;
        }

        $result = $template_db->query(sprintf("DROP DATABASE %s",
                                              $temp_db_name));

        if (PEAR::isError($result)) {
            $this->fail("Dropping temporary database failed: " .
                        $result->getMessage());
            return;
        }

        $template_db->disconnect();
        unset($template_db);
    }

    function test_sqlitestore()
    {
        // If the sqlite extension isn't loaded or loadable, succeed
        // because we can't run the test.
        if (!(extension_loaded('sqlite')) ||
            !(@include_once 'DB.php')) {
            print "(not testing SQLite store)";
            $this->pass();
            return;
        }

        require_once 'Auth/OpenID/SQLiteStore.php';

        $temp_dir = _Auth_OpenID_mkdtemp();

        if (!$temp_dir) {
            trigger_error('Could not create temporary directory ' .
                          'with Auth_OpenID_FileStore::_mkdtemp',
                          E_USER_WARNING);
            return null;
        }

        $dsn = 'sqlite:///' . urlencode($temp_dir) . '/php_openid_storetest.db';
        $db =& DB::connect($dsn);

        if (PEAR::isError($db)) {
            $this->pass("SQLite database connection failed: " .
                        $db->getMessage());
        } else {
            $store = new Auth_OpenID_SQLiteStore($db);
            $this->assertTrue($store->createTables(), "Table creation failed");
            $this->_testStore($store);
            $this->_testNonce($store);
            $this->_testNonceCleanup($store);
        }

        $db->disconnect();
        unset($db);
        unset($store);
        unlink($temp_dir . '/php_openid_storetest.db');
        rmdir($temp_dir);
    }

    function test_mysqlstore()
    {
        // If the mysql extension isn't loaded or loadable, succeed
        // because we can't run the test.
        if (!(extension_loaded('mysql')) ||
            !(@include_once 'DB.php')) {
            print "(not testing MySQL store)";
            $this->pass();
            return;
        }

        require_once 'Auth/OpenID/MySQLStore.php';

        global $_Auth_OpenID_db_test_host;

        $dsn = array(
                     'phptype'  => 'mysql',
                     'username' => 'openid_test',
                     'password' => '',
                     'hostspec' => $_Auth_OpenID_db_test_host
                     );

        $db =& DB::connect($dsn);

        if (PEAR::isError($db)) {
            print "MySQL database connection failed: " .
                $db->getMessage();
            $this->pass();
            return;
        }

        $temp_db_name = _Auth_OpenID_getTmpDbName();

        $result = $db->query("CREATE DATABASE $temp_db_name");

        if (PEAR::isError($result)) {
            $this->pass("Error creating MySQL temporary database: " .
                        $result->getMessage());
            return;
        }

        $db->query("USE $temp_db_name");

        $store = new Auth_OpenID_MySQLStore($db);
        $store->createTables();
        $this->_testStore($store);
        $this->_testNonce($store);
        $this->_testNonceCleanup($store);

        $db->query("DROP DATABASE $temp_db_name");
    }

    function test_mdb2store()
    {
        // The MDB2 test can use any database engine. MySQL is chosen
        // arbitrarily.
        if (!(extension_loaded('mysql') ||
            (function_exists('dl') && @dl('mysql.' . PHP_SHLIB_SUFFIX))) ||
            !(@include_once 'MDB2.php')) {
            print "(not testing MDB2 store)";
            $this->pass();
            return;
        }

        require_once 'Auth/OpenID/MDB2Store.php';

        global $_Auth_OpenID_db_test_host;

        $dsn = array(
                     'phptype'  => 'mysql',
                     'username' => 'openid_test',
                     'password' => '',
                     'hostspec' => $_Auth_OpenID_db_test_host
                     );

        $db =& MDB2::connect($dsn);

        if (PEAR::isError($db)) {
            print "MySQL database connection failed: " .
                $db->getMessage();
            $this->pass();
            return;
        }

        $temp_db_name = _Auth_OpenID_getTmpDbName();

        $result = $db->query("CREATE DATABASE $temp_db_name");

        if (PEAR::isError($result)) {
            $this->pass("Error creating MySQL temporary database: " .
                        $result->getMessage());
            return;
        }

        $db->query("USE $temp_db_name");

        $store =& new Auth_OpenID_MDB2Store($db);
        if (!$store->createTables()) {
            $this->fail("Failed to create tables");
            return;
        }
        $this->_testStore($store);
        $this->_testNonce($store);
        $this->_testNonceCleanup($store);

        $db->query("DROP DATABASE $temp_db_name");
    }
}

/**
 * This is the host that the store test will use
 */
global $_Auth_OpenID_memcache_test_host;
$_Auth_OpenID_memcache_test_host = 'localhost';

class Tests_Auth_OpenID_MemcachedStore_Test extends Tests_Auth_OpenID_Store {
    function test_memcache()
    {
        // If the memcache extension isn't loaded or loadable, succeed
        // because we can't run the test.
        if (!extension_loaded('memcache')) {
            print "(skipping memcache store tests)";
            $this->pass();
            return;
        }
        require_once 'Auth/OpenID/MemcachedStore.php';

        global $_Auth_OpenID_memcache_test_host;

        $memcached = new Memcache();
        if (!$memcached->connect($_Auth_OpenID_memcache_test_host)) {
            print "(skipping memcache store tests - couldn't connect)";
            $this->pass();
        } else {
            $store = new Auth_OpenID_MemcachedStore($memcached);

            $this->_testStore($store);
            $this->_testNonce($store);
            $this->_testNonceCleanup($store);

            $memcached->close();
        }
    }
}

class Tests_Auth_OpenID_StoreTest extends PHPUnit_Framework_TestSuite {
    function getName()
    {
        return "Tests_Auth_OpenID_StoreTest";
    }

      function Tests_Auth_OpenID_StoreTest()
    {
        $this->addTestSuite('Tests_Auth_OpenID_Included_StoreTest');
        $this->addTestSuite('Tests_Auth_OpenID_MemcachedStore_Test');
    }
}

repo_name: andremichelle/gnu

license: mit


code:
<?php

/**
 * Utilites for test functions
 */

function Tests_Auth_OpenID_datafile($name, $reader)
{
    $path = dirname(realpath(__FILE__));
    $sep = DIRECTORY_SEPARATOR;
    $filename = $path . $sep . 'data' . $sep . $name;
    $data = $reader($filename);
    if ($data === false) {
        $msg = "Failed to open data file: $name";
        trigger_error($msg, E_USER_ERROR);
    }
    return $data;
}

function Tests_Auth_OpenID_readdata($name)
{
    return Tests_Auth_OpenID_datafile($name, 'file_get_contents');
}

function Tests_Auth_OpenID_readlines($name)
{
    return Tests_Auth_OpenID_datafile($name, 'file');
}

class OpenIDTestMixin extends PHPUnit_Framework_TestCase {
    function failUnlessOpenIDValueEquals($msg, $key, $expected, $ns=null)
    {
        if ($ns === null) {
            $ns = Auth_OpenID_OPENID_NS;
        }

        $actual = $msg->getArg($ns, $key);
        $error_format = 'Wrong value for openid.%s: expected=%s, actual=%s';
        $error_message = sprintf($error_format,
                                 $key, $expected, $actual);

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

    function failIfOpenIDKeyExists($msg, $key, $ns=null)
    {
        if ($ns === null) {
            $ns = Auth_OpenID_OPENID_NS;
        }

        $actual = $msg->getArg($ns, $key);
        $error_message = sprintf('openid.%s unexpectedly present: %s',
                                 $key, $actual);

        $this->assertFalse($msg->hasKey($ns, $key),
                           $error_message);
    }
}


code:
<?php

/**
 * Tests for the TrustRoot module
 */

require_once "Auth/OpenID/TrustRoot.php";
require_once "Tests/Auth/OpenID/TestUtil.php";

class Tests_Auth_OpenID_TRParseCase extends PHPUnit_Framework_TestCase {
    function Tests_Auth_OpenID_TRParseCase($desc, $case, $expected)
    {
        $this->setName($desc);
        $this->case = $case;
        $this->expected = $expected;
    }

    function runTest()
    {
        $is_sane = Auth_OpenID_TrustRoot::isSane($this->case);
        $parsed = (bool)Auth_OpenID_TrustRoot::_parse($this->case);
        switch ($this->expected) {
        case 'sane':
            $this->assertTrue($parsed, "Did not parse");
            $this->assertTrue($is_sane, "Is not sane");
            break;
        case 'insane':
            $this->assertTrue($parsed, "Did not parse");
            $this->assertFalse($is_sane, "Is sane");
            break;
        default:
            $this->assertFalse($parsed, "Did parse");
            $this->assertFalse($is_sane, "Is sane");
        }
    }
}

class Tests_Auth_OpenID_TRMatchCase extends PHPUnit_Framework_TestCase {
    function Tests_Auth_OpenID_TRMatchCase($desc, $tr, $rt, $matches)
    {
        $this->setName($desc);
        $this->tr = $tr;
        $this->rt = $rt;
        $this->matches = $matches;
    }

    function runTest()
    {
        $matches = Auth_OpenID_TrustRoot::match($this->tr, $this->rt);
        $this->assertEquals((bool)$this->matches, (bool)$matches);
    }
}

function Tests_Auth_OpenID_parseHeadings($data, $c)
{
    $heading_pat = '/(^|\n)' . $c . '{40}\n([^\n]+)\n' . $c . '{40}\n()/';
    $offset = 0;
    $headings = array();
    while (true) {
        preg_match($heading_pat, substr($data, $offset), $matches,
                   PREG_OFFSET_CAPTURE);
        if (!$matches) {
            break;
        }
        $start = $matches[0][1];
        $heading = $matches[2][0];
        $end = $matches[3][1];
        $headings[] = array('heading' => $heading,
                            'start' => $offset + $start,
                            'end' => $offset + $end,
                            );
        $offset += $end;
    }
    return $headings;
}

function Tests_Auth_OpenID_getSections($data)
{
    $headings = Tests_Auth_OpenID_parseHeadings($data, '-');
    $sections = array();
    $n = count($headings);
    for ($i = 0; $i < $n; ) {
        $secdata = $headings[$i];
        list($numtests, $desc) = explode(': ', $secdata['heading']);
        $start = $secdata['end'];
        $i += 1;
        if ($i < $n) {
            $blob = substr($data, $start, $headings[$i]['start'] - $start);
        } else {
            $blob = substr($data, $start);
        }
        $lines = explode("\n", trim($blob));
        if (count($lines) != $numtests) {
            trigger_error('Parse failure: ' . var_export($secdata, true),
                          E_USER_ERROR);
        }
        $sections[] = array('desc' => $desc, 'lines' => $lines,);
    }
    return $sections;
}

function Tests_Auth_OpenID_trParseTests($head, $tests)
{
    $tests = array('fail' => $tests[0],
                   'insane' => $tests[1],
                   'sane' => $tests[2]);
    $testobjs = array();
    foreach ($tests as $expected => $testdata) {
        $lines = $testdata['lines'];
        foreach ($lines as $line) {
            $desc = sprintf("%s - %s: %s", $head,
                            $testdata['desc'], var_export($line, true));
            $testobjs[] = new Tests_Auth_OpenID_TRParseCase(
                $desc, $line, $expected);
        }
    }
    return $testobjs;
}

function Tests_Auth_OpenID_trMatchTests($head, $tests)
{
    $tests = array(true => $tests[0], false => $tests[1]);
    $testobjs = array();
    foreach ($tests as $expected => $testdata) {
        $lines = $testdata['lines'];
        foreach ($lines as $line) {
            $pat = '/^([^ ]+) +([^ ]+)$/';
            preg_match($pat, $line, $matches);
            list($_, $tr, $rt) = $matches;
            $desc = sprintf("%s - %s: %s %s", $head, $testdata['desc'],
                            var_export($tr, true), var_export($rt, true));
            $testobjs[] = new Tests_Auth_OpenID_TRMatchCase(
                $desc, $tr, $rt, $expected);
        }
    }
    return $testobjs;
}

function Tests_Auth_OpenID_trustRootTests()
{
    $data = Tests_Auth_OpenID_readdata('trustroot.txt');
    list($parsehead, $matchhead) = Tests_Auth_OpenID_parseHeadings($data, '=');
    $pe = $parsehead['end'];
    $parsedata = substr($data, $pe, $matchhead['start'] - $pe);
    $parsetests = Tests_Auth_OpenID_getSections($parsedata);
    $parsecases = Tests_Auth_OpenID_trParseTests($parsehead['heading'],
                                                 $parsetests);

    $matchdata = substr($data, $matchhead['end']);
    $matchtests = Tests_Auth_OpenID_getSections($matchdata);
    $matchcases = Tests_Auth_OpenID_trMatchTests($matchhead['heading'],
                                                 $matchtests);

    return array_merge($parsecases, $matchcases);
}

class Tests_Auth_OpenID_TrustRoot extends PHPUnit_Framework_TestSuite {
    function Tests_Auth_OpenID_TrustRoot($name)
    {
        $this->setName($name);

        foreach (Tests_Auth_OpenID_trustRootTests() as $test) {
            $this->_addTestByValue($test);
        }
    }

    function _addTestByValue($test) {
        $this->addTest($test);
    }
}


code:
<?php

/**
 * Tests for the URI normalization routines used by the OpenID
 * library.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

require_once 'Auth/OpenID/URINorm.php';
require_once 'Tests/Auth/OpenID/TestUtil.php';

class Tests_Auth_OpenID_URINorm_TestCase extends PHPUnit_Framework_TestCase {
    function Tests_Auth_OpenID_URINorm_TestCase(
                               $name, $uri, $expected)
    {

        $this->setName($name);
        $this->uri = $uri;
        $this->expected = $expected;
    }

    function runTest()
    {
        $actual = Auth_OpenID_urinorm($this->uri);
        $this->assertEquals($this->expected, $actual);
    }
}

class Tests_Auth_OpenID_URINorm extends PHPUnit_Framework_TestSuite {
    function _readTestCases()
    {
        $lines = Tests_Auth_OpenID_readlines('urinorm.txt');
        $cases = array();
        $case = array();
        for ($i = 0; $i < count($lines) && ($i + 3 <= count($lines)); $i += 4) {
            $name = trim($lines[$i]);
            $uri = trim($lines[$i + 1]);
            $expected = trim($lines[$i + 2]);
            if ($expected == 'fail') {
                $expected = null;
            }
            $cases[] = array($name, $uri, $expected);
        }

        return $cases;
    }

    function Tests_Auth_OpenID_URINorm($name)
    {
        $this->setName($name);
        $cases = $this->_readTestCases();
        foreach ($cases as $case) {
            list($name, $uri, $expected) = $case;
            $this->addTest(new Tests_Auth_OpenID_URINorm_TestCase($name, $uri, $expected));
        }
    }
}


code:
<?php

/**
 * Tests for utility functions used by the OpenID library.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

require_once 'Auth/OpenID.php';

class Tests_Auth_OpenID_Util extends PHPUnit_Framework_TestCase {
    function test_base64()
    {
        // This is not good for international use, but PHP doesn't
        // appear to provide access to the local alphabet.
        $letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        $digits = "0123456789";
        $extra = "+/=";
        $allowed_s = $letters . $digits . $extra;
        $allowed_d = array();

        for ($i = 0; $i < strlen($allowed_s); $i++) {
            $c = $allowed_s[$i];
            $allowed_d[$c] = null;
        }

        function checkEncoded($obj, $str, $allowed_array)
            {
                for ($i = 0; $i < strlen($str); $i++) {
                    $obj->assertTrue(array_key_exists($str[$i],
                                                      $allowed_array));
                }
            }

        $cases = array(
                       "",
                       "x",
                       "\x00",
                       "\x01",
                       str_repeat("\x00", 100),
                       implode("", array_map('chr', range(0, 255)))
                       );

        foreach ($cases as $s) {
            $b64 = base64_encode($s);
            checkEncoded($this, $b64, $allowed_d);
            $s_prime = base64_decode($b64);
            $this->assertEquals($s_prime, $s);
        }

        function random_ordinal($unused)
            {
                return rand(0, 255);
            }

        // Randomized test
        foreach (range(0, 49) as $i) {
            $n = rand(0, 2048);
            $s = implode("", array_map('chr',
                                       array_map('random_ordinal',
                                                 range(0, $n))));
            $b64 = base64_encode($s);
            checkEncoded($this, $b64, $allowed_d);
            $s_prime = base64_decode($b64);
            $this->assertEquals($s_prime, $s);
        }
    }

    function test_urldefrag()
    {
        $cases = array(
                       array('http://foo.com', 'http://foo.com'),
                       array('http://foo.com/', 'http://foo.com/'),
                       array('http://foo.com/path', 'http://foo.com/path'),
                       array('http://foo.com/path?query', 'http://foo.com/path?query'),
                       array('http://foo.com/path?query=v', 'http://foo.com/path?query=v'),
                       array('http://foo.com/?query=v', 'http://foo.com/?query=v'),
                       );

        foreach ($cases as $pair) {
            list($orig, $after) = $pair;
            list($base, $frag) = Auth_OpenID::urldefrag($orig);
            $this->assertEquals($after, $base);
            $this->assertEquals($frag, '');

            list($base, $frag) = Auth_OpenID::urldefrag($orig . "#fragment");
            $this->assertEquals($after, $base);
            $this->assertEquals('fragment', $frag);
        }
    }

    function test_normalizeUrl()
    {
        $this->assertEquals("http://foo.com/",
                            Auth_OpenID::normalizeUrl("foo.com"));

        $this->assertEquals("http://foo.com/",
                            Auth_OpenID::normalizeUrl("http://foo.com"));

        $this->assertEquals("https://foo.com/",
                            Auth_OpenID::normalizeUrl("https://foo.com"));

        $this->assertEquals("http://foo.com/bar",
                            Auth_OpenID::normalizeUrl("foo.com/bar"));

        $this->assertEquals("http://foo.com/bar",
                            Auth_OpenID::normalizeUrl("http://foo.com/bar"));

        $this->assertEquals("http://foo.com/",
                            Auth_OpenID::normalizeUrl("http://foo.com/"));

        $this->assertEquals("https://foo.com/",
                            Auth_OpenID::normalizeUrl("https://foo.com/"));

        $this->assertEquals("https://foo.com/bar" ,
                            Auth_OpenID::normalizeUrl("https://foo.com/bar"));

        $this->assertEquals("http://foo.com/bar" ,
                            Auth_OpenID::normalizeUrl("HTtp://foo.com/bar"));

        $this->assertEquals("http://foo.com/bar" ,
             Auth_OpenID::normalizeUrl("HTtp://foo.com/bar#fraggle"));

        $this->assertEquals("http://foo.com/bAr/" ,
             Auth_OpenID::normalizeUrl("HTtp://fOo.com/bAr/.#fraggle"));

        if (0) {
            $this->assertEquals("http://foo.com/%E8%8D%89",
                           Auth_OpenID::normalizeUrl("foo.com/\u8349"));

            $this->assertEquals("http://foo.com/%E8%8D%89",
                           Auth_OpenID::normalizeUrl("http://foo.com/\u8349"));
        }

        $non_ascii_domain_cases = array(
                                        array("http://xn--vl1a.com/",
                                              "\u8349.com"),

                                        array("http://xn--vl1a.com/",
                                              "http://\u8349.com"),

                                        array("http://xn--vl1a.com/",
                                              "\u8349.com/"),

                                        array("http://xn--vl1a.com/",
                                              "http://\u8349.com/"),

                                        array("http://xn--vl1a.com/%E8%8D%89",
                                              "\u8349.com/\u8349"),

                                        array("http://xn--vl1a.com/%E8%8D%89",
                                              "http://\u8349.com/\u8349"),
                                        );

        // XXX
        /*
        codecs.getencoder('idna')
         except LookupError:
        # If there is no idna codec, these cases with
        # non-ascii-representable domain names should fail.
        should_raise = True
    else:
        should_raise = False

    for expected, case in non_ascii_domain_cases:
try:
actual = Auth_OpenID::normalizeUrl(case)
         except UnicodeError:
            assert should_raise
    else:
assert not should_raise and actual == expected, case
        */

        $this->assertNull(Auth_OpenID::normalizeUrl(null));
        $this->assertNull(Auth_OpenID::normalizeUrl(''));
        $this->assertNull(Auth_OpenID::normalizeUrl('http://'));
    }

    function test_appendArgs()
    {

        $simple = 'http://www.example.com/';

        $cases = array(
                       array('empty list',
                             array($simple, array()),
                             $simple),

                       array('empty dict',
                             array($simple, array()),
                             $simple),

                       array('one list',
                             array($simple, array(array('a', 'b'))),
                             $simple . '?a=b'),

                       array('one dict',
                             array($simple, array('a' => 'b')),
                             $simple . '?a=b'),

                       array('two list (same)',
                             array($simple, array(array('a', 'b'),
                                                  array('a', 'c'))),
                             $simple . '?a=b&a=c'),

                       array('two list',
                             array($simple, array(array('a', 'b'),
                                                  array('b', 'c'))),
                             $simple . '?a=b&b=c'),

                       array('two list (order)',
                             array($simple, array(array('b', 'c'),
                                                  array('a', 'b'))),
                             $simple . '?b=c&a=b'),

                       array('two dict (order)',
                             array($simple, array('b' => 'c',
                                                  'a' => 'b')),
                             $simple . '?a=b&b=c'),

                       array('escape',
                             array($simple, array(array('=', '='))),
                             $simple . '?%3D=%3D'),

                       array('escape (URL)',
                             array($simple, array(array('this_url',
                                                        $simple))),
                             $simple .
                             '?this_url=http%3A%2F%2Fwww.example.com%2F'),

                       array('use dots',
                             array($simple, array(array('openid.stuff',
                                                        'bother'))),
                             $simple . '?openid.stuff=bother'),

                       array('args exist (empty)',
                             array($simple . '?stuff=bother', array()),
                             $simple . '?stuff=bother'),

                       array('args exist',
                             array($simple . '?stuff=bother',
                                   array(array('ack', 'ack'))),
                             $simple . '?stuff=bother&ack=ack'),

                       array('args exist',
                             array($simple . '?stuff=bother',
                                   array(array('ack', 'ack'))),
                             $simple . '?stuff=bother&ack=ack'),

                       array('args exist (dict)',
                             array($simple . '?stuff=bother',
                                   array('ack' => 'ack')),
                             $simple . '?stuff=bother&ack=ack'),

                       array('args exist (dict 2)',
                             array($simple . '?stuff=bother',
                                   array('ack' => 'ack', 'zebra' => 'lion')),
                             $simple . '?stuff=bother&ack=ack&zebra=lion'),

                       array('three args (dict)',
                             array($simple, array('stuff' => 'bother',
                                                  'ack' => 'ack',
                                                  'zebra' => 'lion')),
                             $simple . '?ack=ack&stuff=bother&zebra=lion'),

                       array('three args (list)',
                             array($simple, array(
                                                  array('stuff', 'bother'),
                                                  array('ack', 'ack'),
                                                  array('zebra', 'lion'))),
                             $simple . '?stuff=bother&ack=ack&zebra=lion'),
                       );

        // Tests.
        foreach ($cases as $case) {
            list($desc, $data, $expected) = $case;
            list($url, $query) = $data;
            $this->assertEquals($expected,
                    Auth_OpenID::appendArgs($url, $query));
        }
    }

    function test_getQuery()
    {
        $queries = array(
                         '' => array(),
                         'single' => array(),
                         'no&pairs' => array(),
                         'x%3Dy' => array(),
                         'single&real=value' => array('real' => 'value'),
                         'x=y&m=x%3Dn' => array('x' => 'y', 'm' => 'x=n'),
                         '&m=x%20y' => array('m' => 'x y'),
                         'single&&m=x%20y&bogus' => array('m' => 'x y'),
                         // Even with invalid encoding.  But don't do that.
                         'too=many=equals&' => array('too' => 'many=equals')
                         );

        foreach ($queries as $s => $data) {
            $query = Auth_OpenID::getQuery($s);

            foreach ($data as $key => $value) {
                $this->assertTrue($query[$key] === $value);
            }

            foreach ($query as $key => $value) {
                $this->assertTrue($data[$key] === $value);
            }
        }
    }
}


code:
<?php

require_once "Tests/Auth/OpenID/TestUtil.php";
require_once "Tests/Auth/OpenID/MemStore.php";

require_once "Auth/OpenID/Message.php";
require_once "Auth/OpenID/Consumer.php";

class Tests_Auth_OpenID_VerifyDisco_1 extends Auth_OpenID_GenericConsumer {
    function _discoverAndVerify($claimed_id, $to_match_endpoints)
    {
        $this->test_case->assertEquals($this->endpoint->claimed_id, $claimed_id);
        return new Auth_OpenID_FailureResponse(null, $this->text);
    }
}

class __VerifiedError extends Auth_OpenID_FailureResponse {
}

class VerifyDisco_Consumer_verifiedError extends Auth_OpenID_GenericConsumer {
    function _discoverAndVerify($to_match)
    {
        return new __VerifiedError(null, 'verified error');
    }
}

class _DiscoverAndVerify extends OpenIDTestMixin {
    var $consumer_class = 'Auth_OpenID_GenericConsumer';

    function setUp()
    {
        $this->store = new Tests_Auth_OpenID_MemStore();
        $cl = $this->consumer_class;
        $this->consumer = new $cl($this->store);
        $this->return_to = "http://some.host/path";
        $this->endpoint = new Auth_OpenID_ServiceEndpoint();

        $this->server_id = "sirod";
        $this->server_url = "serlie";
        $this->consumer_id = "consu";

        $this->endpoint->claimed_id = $this->consumer_id;
        $this->endpoint->server_url = $this->server_url;
        $this->endpoint->local_id = $this->server_id;
        $this->endpoint->type_uris = array(Auth_OpenID_TYPE_1_1);
    }

    function failUnlessProtocolError($thing)
    {
        $this->assertTrue(Auth_OpenID::isFailure($thing));
    }
}

class _Tests_discoveryOverride {
    function _Tests_discoveryOverride($endpoint)
    {
        $this->endpoint = $endpoint;
    }

    function discover($unused_url)
    {
        return array($this->endpoint->claimed_id, array($this->endpoint));
    }
}
class Tests_openID1Fallback1_0 extends _DiscoverAndVerify {
    function test_openID1Fallback1_0()
    {
        $claimed_id = 'http://claimed.id/';
        $resp_msg = Auth_OpenID_Message::fromOpenIDArgs(
            array('ns' => Auth_OpenID_OPENID1_NS,
                  'identity' => $claimed_id));
        $resp_msg->setArg(Auth_OpenID_BARE_NS, 'openid1_claimed_id',
                          $claimed_id);
        $expected_endpoint = new Auth_OpenID_ServiceEndpoint();
        $expected_endpoint->type_uris = array(Auth_OpenID_TYPE_1_0);
        $expected_endpoint->local_id = null;
        $expected_endpoint->claimed_id = $claimed_id;

        $discovery_override = new _Tests_discoveryOverride($expected_endpoint);
        $this->consumer->discoverMethod = array($discovery_override, 'discover');

        $actual_endpoint = $this->consumer->_verifyDiscoveryResults(
            $resp_msg, null);

        $this->assertTrue(is_a($actual_endpoint, "Auth_OpenID_ServiceEndpoint"));

        $this->assertEquals($expected_endpoint->local_id,
                            $actual_endpoint->local_id);
        $this->assertEquals($expected_endpoint->server_url,
                            $actual_endpoint->server_url);

        $this->assertEquals($expected_endpoint->type_uris,
                            $actual_endpoint->type_uris);

        $this->assertEquals($expected_endpoint->claimed_id,
                            $actual_endpoint->claimed_id);

    }
}

class Tests_Auth_OpenID_VerifyDisco extends _DiscoverAndVerify {
    function test_openID1NoLocalID()
    {
        $endpoint = new Auth_OpenID_ServiceEndpoint();
        $endpoint->claimed_id = 'bogus';

        $msg = Auth_OpenID_Message::fromOpenIDArgs(array());
        // 'Missing required field openid.identity'
        $this->failUnlessProtocolError($this->consumer->_verifyDiscoveryResults($msg, $endpoint));
    }

    function test_openID1NoEndpoint()
    {
        $msg = Auth_OpenID_Message::fromOpenIDArgs(array('identity' => 'snakes on a plane'));
        $this->failUnlessProtocolError($this->consumer->_verifyDiscoveryResults($msg));
    }

    function test_openID2NoOPEndpointArg()
    {
        $msg = Auth_OpenID_Message::fromOpenIDArgs(array('ns' => Auth_OpenID_OPENID2_NS));
        $this->failUnlessProtocolError($this->consumer->_verifyDiscoveryResults($msg, null));
    }

    function test_openID2LocalIDNoClaimed()
    {
        $msg = Auth_OpenID_Message::fromOpenIDArgs(array('ns' => Auth_OpenID_OPENID2_NS,
                                                         'op_endpoint' => 'Phone Home',
                                                         'identity' => 'Jose Lius Borges'));
        // 'openid.identity is present without',
        $this->failUnlessProtocolError($this->consumer->_verifyDiscoveryResults($msg));
    }

    function test_openID2NoLocalIDClaimed()
    {
        $msg = Auth_OpenID_Message::fromOpenIDArgs(array('ns' => Auth_OpenID_OPENID2_NS,
                                                         'op_endpoint' => 'Phone Home',
                                                         'claimed_id' => 'Manuel Noriega'));
        // 'openid.claimed_id is present without',
        $this->failUnlessProtocolError(
           $this->consumer->_verifyDiscoveryResults($msg));
    }

    function test_openID2NoIdentifiers()
    {
        $op_endpoint = 'Phone Home';
        $msg = Auth_OpenID_Message::fromOpenIDArgs(array('ns' => Auth_OpenID_OPENID2_NS,
                                                         'op_endpoint' => $op_endpoint));
        $result_endpoint = $this->consumer->_verifyDiscoveryResults($msg);
        $this->assertTrue($result_endpoint->isOPIdentifier());
        $this->assertEquals($op_endpoint, $result_endpoint->server_url);
        $this->assertEquals(null, $result_endpoint->claimed_id);
    }

    function test_openid2UsePreDiscovered()
    {
        $endpoint = new Auth_OpenID_ServiceEndpoint();
        $endpoint->local_id = 'my identity';
        $endpoint->claimed_id = 'i am sam';
        $endpoint->server_url = 'Phone Home';
        $endpoint->type_uris = array(Auth_OpenID_TYPE_2_0);

        $msg = Auth_OpenID_Message::fromOpenIDArgs(
                    array('ns' => Auth_OpenID_OPENID2_NS,
                          'identity' => $endpoint->local_id,
                          'claimed_id' => $endpoint->claimed_id,
                          'op_endpoint' => $endpoint->server_url));

        $result = $this->consumer->_verifyDiscoveryResults($msg, $endpoint);
        $this->assertTrue($result === $endpoint);
    }

    function test_openid2UsePreDiscoveredWrongType()
    {
        $this->consumer = new Tests_Auth_OpenID_VerifyDisco_1($this->store);
        $this->consumer->test_case =& $this;
        $this->consumer->text = "verify failed";

        $endpoint = new Auth_OpenID_ServiceEndpoint();
        $endpoint->local_id = 'my identity';
        $endpoint->claimed_id = 'i am sam';
        $endpoint->server_url = 'Phone Home';
        $endpoint->type_uris = array(Auth_OpenID_TYPE_1_1);

        $this->consumer->endpoint =& $endpoint;

        $msg = Auth_OpenID_Message::fromOpenIDArgs(
              array('ns' => Auth_OpenID_OPENID2_NS,
                    'identity' => $endpoint->local_id,
                    'claimed_id' => $endpoint->claimed_id,
                    'op_endpoint' => $endpoint->server_url));

        $result = $this->consumer->_verifyDiscoveryResults($msg, $endpoint);
        $this->failUnlessProtocolError($result);
        $this->assertTrue($result->message == "verify failed");
    }

    function test_openid1UsePreDiscovered()
    {
        $endpoint = new Auth_OpenID_ServiceEndpoint();
        $endpoint->local_id = 'my identity';
        $endpoint->claimed_id = 'i am sam';
        $endpoint->server_url = 'Phone Home';
        $endpoint->type_uris = array(Auth_OpenID_TYPE_1_1);

        $msg = Auth_OpenID_Message::fromOpenIDArgs(
            array('ns' => Auth_OpenID_OPENID1_NS,
                  'identity' => $endpoint->local_id));
        $result = $this->consumer->_verifyDiscoveryResults($msg, $endpoint);
        $this->assertTrue($result == $endpoint);
    }

    function test_openid2Fragment()
    {
        $claimed_id = "http://unittest.invalid/";
        $claimed_id_frag = $claimed_id . "#fragment";

        $endpoint = new Auth_OpenID_ServiceEndpoint();
        $endpoint->local_id = 'my identity';
        $endpoint->claimed_id = $claimed_id;
        $endpoint->server_url = 'Phone Home';
        $endpoint->type_uris = array(Auth_OpenID_TYPE_2_0);

        $msg = Auth_OpenID_Message::fromOpenIDArgs(
                    array('ns' => Auth_OpenID_OPENID2_NS,
                          'identity' => $endpoint->local_id,
                          'claimed_id' => $claimed_id_frag,
                          'op_endpoint' => $endpoint->server_url));
        $result = $this->consumer->_verifyDiscoveryResults($msg, $endpoint);

        $this->assertEquals($result->local_id, $endpoint->local_id);
        $this->assertEquals($result->server_url, $endpoint->server_url);

        $this->assertEquals($result->type_uris, $endpoint->type_uris);

        $this->assertEquals($result->claimed_id, $claimed_id_frag);
    }

}

class Tests_openid1UsePreDiscoveredWrongType extends _DiscoverAndVerify {
    var $consumer_class = 'VerifyDisco_Consumer_verifiedError';

    function test_openid1UsePreDiscoveredWrongType()
    {
        $endpoint = new Auth_OpenID_ServiceEndpoint();
        $endpoint->local_id = 'my identity';
        $endpoint->claimed_id = 'i am sam';
        $endpoint->server_url = 'Phone Home';
        $endpoint->type_uris = array(Auth_OpenID_TYPE_2_0);

        $msg = Auth_OpenID_Message::fromOpenIDArgs(
            array('ns' => Auth_OpenID_OPENID1_NS,
                  'identity' => $endpoint->local_id));

        $result = $this->consumer->_verifyDiscoveryResults($msg, $endpoint);
        $this->failUnlessProtocolError($result);
        $this->assertTrue(is_a($result, '__VerifiedError'));
    }
}

// XXX: test the implementation of _discoverAndVerify

class Tests_openID2NoEndpointDoesDisco_sentinel extends Auth_OpenID_GenericConsumer {
    var $sentinel = 'blah';

    function _discoverAndVerify($to_match)
    {
        return $this->sentinel;
    }
}

class Tests_openID2NoEndpointDoesDisco_failure extends Auth_OpenID_GenericConsumer {
    var $failure_message = 'A fake failure response message';

    function _verifyDiscoverySingle($to_match)
    {
        return new Auth_OpenID_FailureResponse(null, $this->failure_message);
    }
}

class Tests_openID2NoEndpointDoesDisco extends Tests_Auth_OpenID_VerifyDisco {
    var $consumer_class = 'Tests_openID2NoEndpointDoesDisco_sentinel';

    function test_openID2NoEndpointDoesDisco()
    {
        $op_endpoint = 'Phone Home';
        $this->consumer->sentinel = new Auth_OpenID_ServiceEndpoint();
        $this->consumer->sentinel->claimed_id = 'monkeysoft';

        $msg = Auth_OpenID_Message::fromOpenIDArgs(
            array('ns' => Auth_OpenID_OPENID2_NS,
                  'identity' => 'sour grapes',
                  'claimed_id' => 'monkeysoft',
                  'op_endpoint' => $op_endpoint));

        $result = $this->consumer->_verifyDiscoveryResults($msg);
        $this->assertEquals($this->consumer->sentinel, $result);
    }
}

class Tests_openID2MismatchedDoesDisco extends Tests_Auth_OpenID_VerifyDisco {
    var $consumer_class = 'Tests_openID2NoEndpointDoesDisco_sentinel';

    function test_openID2MismatchedDoesDisco()
    {
        $mismatched = new Auth_OpenID_ServiceEndpoint();
        $mismatched->identity = 'nothing special, but different';
        $mismatched->local_id = 'green cheese';

        $sentinel = new Auth_OpenID_ServiceEndpoint();
        $sentinel->claimed_id = 'monkeysoft';
        $this->consumer->sentinel = $sentinel;

        $op_endpoint = 'Phone Home';

        $msg = Auth_OpenID_Message::fromOpenIDArgs(
            array('ns' => Auth_OpenID_OPENID2_NS,
                  'identity' => 'sour grapes',
                  'claimed_id' => 'monkeysoft',
                  'op_endpoint' => $op_endpoint));

        $result = $this->consumer->_verifyDiscoveryResults($msg, $mismatched);
        $this->assertEquals($this->consumer->sentinel, $result);
    }
}

class Tests_openID2MismatchedDoesDisco_failure extends PHPUnit_Framework_TestCase {
    var $consumer_class = 'Tests_openID2NoEndpointDoesDisco_failure';

    function setUp()
    {
        $this->store = new Tests_Auth_OpenID_MemStore();
        $cl = $this->consumer_class;
        $this->consumer = new $cl($this->store);
        $this->return_to = "http://some.host/path";
        $this->endpoint = new Auth_OpenID_ServiceEndpoint();

        $this->consumer->discoverMethod = array($this, "_getServices");

        $this->server_id = "sirod";
        $this->server_url = "serlie";
        $this->consumer_id = "consu";

        $this->endpoint->claimed_id = $this->consumer_id;
        $this->endpoint->server_url = $this->server_url;
        $this->endpoint->local_id = $this->server_id;
        $this->endpoint->type_uris = array(Auth_OpenID_TYPE_1_1);
    }

    function _getServices($claimed_id, $fetcher=null) {
        return array(null, array($this->endpoint));
    }

    function test_openID2MismatchedDoesDisco_failure()
    {
        $mismatched = new Auth_OpenID_ServiceEndpoint();
        $mismatched->identity = 'nothing special, but different';
        $mismatched->local_id = 'green cheese';

        $op_endpoint = 'Phone Home';

        $msg = Auth_OpenID_Message::fromOpenIDArgs(
            array('ns' => Auth_OpenID_OPENID2_NS,
                  'identity' => 'sour grapes',
                  'claimed_id' => 'monkeysoft',
                  'op_endpoint' => $op_endpoint));

        $result = $this->consumer->_verifyDiscoveryResults($msg, $mismatched);
        $this->assertTrue(Auth_OpenID::isFailure($result));
    }
}

class TestVerifyDiscoverySingle extends OpenIDTestMixin {
    var $consumer_class = 'Auth_OpenID_GenericConsumer';

    function setUp()
    {
        $this->store = new Tests_Auth_OpenID_MemStore();
        $cl = $this->consumer_class;
        $this->consumer = new $cl($this->store);
        $this->return_to = "http://some.host/path";
        $this->endpoint = new Auth_OpenID_ServiceEndpoint();

        $this->server_id = "sirod";
        $this->server_url = "serlie";
        $this->consumer_id = "consu";

        $this->endpoint->claimed_id = $this->consumer_id;
        $this->endpoint->server_url = $this->server_url;
        $this->endpoint->local_id = $this->server_id;
        $this->endpoint->type_uris = array(Auth_OpenID_TYPE_1_1);
    }

    function test_endpointWithoutLocalID()
    {
        // An endpoint like this with no local_id is generated as a
        // result of e.g. Yadis discovery with no LocalID tag.
        $endpoint = new Auth_OpenID_ServiceEndpoint();
        $endpoint->server_url = "http://localhost:8000/openidserver";
        $endpoint->claimed_id = "http://localhost:8000/id/id-jo";

        $to_match = new Auth_OpenID_ServiceEndpoint();
        $to_match->server_url = "http://localhost:8000/openidserver";
        $to_match->claimed_id = "http://localhost:8000/id/id-jo";
        $to_match->local_id = "http://localhost:8000/id/id-jo";

        $result = $this->consumer->_verifyDiscoverySingle($endpoint, $to_match);

        // result should always be None, raises exception on failure.
        $this->assertEquals($result, null);
    }
}

global $Tests_Auth_OpenID_VerifyDisco_other;
$Tests_Auth_OpenID_VerifyDisco_other = array(
                                             new Tests_openID2MismatchedDoesDisco(),
                                             new Tests_openID2NoEndpointDoesDisco(),
                                             new Tests_openID2MismatchedDoesDisco_failure(),
                                             new Tests_openid1UsePreDiscoveredWrongType(),
                                             new Tests_openID1Fallback1_0(),
                                             );


code:
test_case =     1
key =           0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
key_len =       20
data =          "Hi There"
data_len =      8
digest =        0xb617318655057264e28bc0b6fb378c8ef146be00

test_case =     2
key =           "Jefe"
key_len =       4
data =          "what do ya want for nothing?"
data_len =      28
digest =        0xeffcdf6ae5eb2fa2d27416d5f184df9c259a7c79

test_case =     3
key =           0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
key_len =       20
data =          0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
data_len =      50
digest =        0x125d7342b9ac11cd91a39af48aa17b4f63f175d3

test_case =     4
key =           0x0102030405060708090a0b0c0d0e0f10111213141516171819
key_len =       25
data =          0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd
data_len =      50
digest =        0x4c9007f4026250c6bc8414f9bf50c86c2d7235da

test_case =     5
key =           0x0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c
key_len =       20
data =          "Test With Truncation"
data_len =      20
digest =        0x4c1a03424b55e07fe7f27be1d58bb9324a9a5a04
digest-96 =     0x4c1a03424b55e07fe7f27be1

test_case =     6
key =           0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
key_len =       80
data =          "Test Using Larger Than Block-Size Key - Hash Key First"
data_len =      54
digest =        0xaa4ae5e15272d00e95705637ce8a3b55ed402112

test_case =     7
key =           0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
key_len =       80
data =          "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data"
data_len =      73
digest =        0xe8e99d0f45237d786d6bbaa7965c7808bbff1a91


code:
test_case = 1
key = 0x0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b
data = 0x4869205468657265
digest = 0xb0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7

test_case = 2
key = 0x4a656665
data = 0x7768617420646f2079612077616e7420666f72206e6f7468696e673f
digest = 0x5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843

test_case = 3
key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
data = 0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd
digest = 0x773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe

test_case = 4
key = 0x0102030405060708090a0b0c0d0e0f10111213141516171819
data = 0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd
digest = 0x82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b

test_case = 6
key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
data = 0x54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a65204b6579202d2048617368204b6579204669727374
digest = 0x60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54

test_case = 7
key = 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
data = 0x5468697320697320612074657374207573696e672061206c6172676572207468616e20626c6f636b2d73697a65206b657920616e642061206c6172676572207468616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565647320746f20626520686173686564206265666f7265206265696e6720757365642062792074686520484d414320616c676f726974686d2e
digest = 0x9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2


code:
Num Tests: 73

OpenID link parsing test cases
Copyright (C) 2005-2008, JanRain, Inc.
See COPYING for license information.

File format
-----------

All text before the first triple-newline (this chunk) should be ignored.

This file may be interpreted as Latin-1 or UTF-8.

Test cases separated by three line separators (`\n\n\n'). The test
cases consist of a headers section followed by a data block. These are
separated by a double newline. The headers consist of the header name,
followed by a colon, a space, the value, and a newline. There must be
one, and only one, `Name' header for a test case. There may be zero or
more link headers. The `Link' header consists of whitespace-separated
attribute pairs. A link header with an empty string as a value
indicates an empty but present link tag. The attribute pairs are `='
separated and not quoted.

Optional Links and attributes have a trailing `*'. A compilant
implementation may produce this as output or may not. A compliant
implementation will not produce any output that is absent from this
file.

Name: Well-formed link rel (in CAPS)
Link: rel=openid.server href=http://www.myopenid.com/server

<HTML>
  <HEAD>
    <LINK REL="openid.server"
          HREF="http://www.myopenid.com/server" />
  </HEAD>
</HTML>

Name: No link tag at all

<html>
<head>
</head>
</html>

Name: Link element first

<link>

Name: Link inside HTML, not head

<html>
<link>

Name: Link inside head, not html

<head>
<link>

Name: Link inside html, after head

<html>
<head>
</head>
<link>

Name: Link inside html, before head

<html>
<link>
<head>

Name: Link before html and head

<link>
<html>
<head>

Name: Link after html document with head

<html>
<head>
</head>
</html>
<link>

Name: Link inside html inside head, inside another html

<html>
<head>
<html>
<link>

Name: Link inside html inside head

<head>
<html>
<link>

Name: link inside body inside head inside html

<html>
<head>
<body>
<link>

Name: Link inside head inside head inside html

<html>
<head>
<head>
<link>

Name: Link inside script inside head inside html

<html>
<head>
<script>
<link>
</script>

Name: Link inside comment inside head inside html

<html>
<head/>
<link>

Name: Link inside of head after short head

<html>
<head/>
<head>
<link>

Name: Plain vanilla
Link:

<html>
<head>
<link>

Name: Ignore tags in the <script:... > namespace
Link*:

<html>
<head>
<script:paddypan>
<link>
</script:paddypan>

Name: Short link tag
Link:

<html>
<head>
<link/>

Name: Spaces in the HTML tag
Link:

<html >
<head>
<link>

Name: Spaces in the head tag
Link:

<html>
<head >
<link>

Name: Spaces in the link tag
Link:

<html>
<head>
<link >

Name: No whitespace
Link:

<html><head><link>

Name: Closed head tag
Link:

<html>
<head>
<link>
</head>

Name: One good, one bad (after close head)
Link:

<html>
<head>
<link>
</head>
<link>

Name: One good, one bad (after open body)
Link:

<html>
<head>
<link>
<body>
<link>

Name: ill formed (missing close head)
Link:

<html>
<head>
<link>
</html>

Name: Ill formed (no close head, link after </html>)
Link:

<html>
<head>
<link>
</html>
<link>

Name: Ignore random tags inside of html
Link:

<html>
<delicata>
<head>
<title>
<link>

Name: case-folding
Link*:

<HtMl>
<hEaD>
<LiNk>

Name: unexpected tags
Link:

<butternut>
<html>
<summer>
<head>
<turban>
<link>

Name: un-closed script tags
Link*:

<html>
<head>
<script>
<link>

Name: un-closed script tags (no whitespace)
Link*:

<html><head><script><link>

Name: un-closed comment
Link*:

<html>
<head>
<!--
<link>

Name: un-closed CDATA
Link*:

<html>
<head>
<![CDATA[
<link>

Name: cdata-like
Link*:

<html>
<head>
<![ACORN[
<link>
]]>

Name: comment close only
Link:

<html>
<head>
<link>
-->

Name: Vanilla, two links
Link:
Link:

<html>
<head>
<link>
<link>

Name: extra tag, two links
Link:
Link:

<html>
<gold nugget>
<head>
<link>
<link>

Name: case-fold, body ends, two links
Link:
Link*:

<html>
<head>
<link>
<LiNk>
<body>
<link>

Name: simple, non-quoted rel
Link: rel=openid.server

<html><head><link rel=openid.server>

Name: short tag has rel
Link: rel=openid.server

<html><head><link rel=openid.server/>

Name: short tag w/space has rel
Link: rel=openid.server

<html><head><link rel=openid.server />

Name: extra non-attribute, has rel
Link: rel=openid.server

<html><head><link hubbard rel=openid.server>

Name: non-attr, has rel, short
Link: rel=openid.server

<html><head><link hubbard rel=openid.server/>

Name: non-attr, has rel, short, space
Link: rel=openid.server

<html><head><link hubbard rel=openid.server />

Name: misplaced slash has rel
Link: rel=openid.server

<html><head><link / rel=openid.server>

Name: quoted rel
Link: rel=openid.server

<html><head><link rel="openid.server">

Name: single-quoted rel
Link: rel=openid.server

<html><head><link rel='openid.server'>

Name: two links w/ rel
Link: x=y
Link: a=b

<html><head><link x=y><link a=b>

Name: non-entity
Link: x=&y

<html><head><link x=&y>

Name: quoted non-entity
Link: x=&y

<html><head><link x="&y">

Name: quoted entity
Link: x=&

<html><head><link x="&">

Name: entity not processed
Link: x=

<html><head><link x="">

Name: <
Link: x=<

<html><head><link x="<">

Name: >
Link: x=>

<html><head><link x=">">

Name: "
Link: x="

<html><head><link x=""">

Name: &"
Link: x=&"

<html><head><link x="&"">

Name: mixed entity and non-entity
Link: x=&"…>

<html><head><link x="&"…>">

Name: mixed entity and non-entity (w/normal chars)
Link: x=x&"…>x

<html><head><link x="x&"…>x">

Name: broken tags
Link*: x=y

<html><head><link x=y<>

Name: missing close pointy
Link: z=y

<html><head><link x=y<link z=y />

Name: missing attribute value
Link: x=y y*=
Link: x=y

<html><head><link x=y y=><link x=y />

Name: Missing close pointy (no following)
Link*: x=y

<html><head><link x=y

Name: Should be quoted
Link: x*=<

<html><head><link x="<">

Name: Should be quoted (2)
Link: x*=>

<html><head><link x=">">

Name: Repeated attribute
Link: x=y

<html><head><link x=z x=y>

Name: Repeated attribute (2)
Link: x=y

<html><head><link x=y x=y>

Name: Two attributes
Link: x=y y=z

<html><head><link x=y y=z>

Name: Well-formed link rel="openid.server"
Link: rel=openid.server href=http://www.myopenid.com/server

<html>
  <head>
    <link rel="openid.server"
          href="http://www.myopenid.com/server" />
  </head>
</html>

Name: Well-formed link rel="openid.server" and "openid.delegate"
Link: rel=openid.server href=http://www.myopenid.com/server
Link: rel=openid.delegate href=http://example.myopenid.com/

<html><head><link rel="openid.server"
                  href="http://www.myopenid.com/server" />
            <link rel="openid.delegate" href="http://example.myopenid.com/" />
</head></html>

Name: from brian's livejournal page
Link: rel=stylesheet href=http://www.livejournal.com/~serotta/res/319998/stylesheet?1130478711 type=text/css
Link: rel=openid.server href=http://www.livejournal.com/openid/server.bml

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
          "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <link rel="stylesheet"
          href="http://www.livejournal.com/~serotta/res/319998/stylesheet?1130478711"
          type="text/css" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    <meta name="foaf:maker"
          content="foaf:mbox_sha1sum '12f8abdacb5b1a806711e23249da592c0d316260'" />
    <meta name="robots" content="noindex, nofollow, noarchive" />
    <meta name="googlebot" content="nosnippet" />
    <link rel="openid.server"
          href="http://www.livejournal.com/openid/server.bml" />
    <title>Brian</title>
  </head>

Name: non-ascii (Latin-1 or UTF8)
Link: x=®

<html><head><link x="®">


code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <title>Identity Page for Smoker</title>
    <link rel="openid.server" href="http://www.myopenid.com/server" />
    <link rel="openid.delegate" href="http://smoker.myopenid.com/" />

foo


code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <title>Identity Page for Smoker</title>
    <link rel="openid2.provider" href="http://www.myopenid.com/server" />
    <link rel="openid2.local_id" href="http://smoker.myopenid.com/" />

foo


code:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds"
           xmlns="xri://$xrd*($v*2.0)"
           >
  <XRD>
    <Service priority="10">
      <Type>http://specs.openid.net/auth/2.0/signon</Type>
      <URI>http://www.myopenid.com/server</URI>
      <LocalID>http://smoker.myopenid.com/</LocalID>
    </Service>
  </XRD>
</xrds:XRDS>


code:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds"
           xmlns="xri://$xrd*($v*2.0)"
           >
  <XRD>
    <Service priority="10">
      <Type>http://specs.openid.net/auth/2.0/signon</Type>
      <URI>http://www.myopenid.com/server</URI>
    </Service>
  </XRD>
</xrds:XRDS>


code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <title>Identity Page for Smoker</title>
    <link rel="openid2.provider openid.server" href="http://www.myopenid.com/server" />
    <link rel="openid2.local_id openid.delegate" href="http://smoker.myopenid.com/" />

foo


code:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds"
           xmlns="xri://$xrd*($v*2.0)"
           xmlns:openid="http://openid.net/xmlns/1.0"
           >
  <XRD>

    <Service priority="10">
      <Type>http://specs.openid.net/auth/2.0/signon</Type>
      <Type>http://openid.net/signon/1.1</Type>
      <URI>http://www.myopenid.com/server</URI>
      <LocalID>http://smoker.myopenid.com/</LocalID>
      <openid:Delegate>http://smoker.myopenid.com/</openid:Delegate>
    </Service>
  </XRD>
</xrds:XRDS>


code:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds"
           xmlns="xri://$xrd*($v*2.0)"
           xmlns:openid="http://openid.net/xmlns/1.0"
           >
  <XRD>

    <Service priority="10">
      <Type>http://specs.openid.net/auth/2.0/signon</Type>
      <Type>http://openid.net/signon/1.0</Type>
      <Type>http://openid.net/signon/1.1</Type>
      <URI>http://www.myopenid.com/server</URI>
      <LocalID>http://smoker.myopenid.com/</LocalID>
      <openid:Delegate>http://localid.mismatch.invalid/</openid:Delegate>
    </Service>
  </XRD>
</xrds:XRDS>


code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <title>Identity Page for Smoker</title>
    <meta http-equiv="X-XRDS-Location" content="http://someuser.unittest/xrds" />
    <link rel="openid.server" href="http://www.myopenid.com/server" />
    <link rel="openid.delegate" href="http://smoker.myopenid.com/" />

foo


code:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

    <title>Identity Page for Smoker</title>
    <link rel="openid.server" href="http://www.myopenid.com/server" />

foo


code:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds"
           xmlns="xri://$xrd*($v*2.0)"
           xmlns:openid="http://openid.net/xmlns/1.0"
           >
  <XRD>

    <Service priority="10">
      <Type>http://openid.net/signon/1.0</Type>
      <URI>http://nossl.vroom.unittest/server</URI>
      <openid:Delegate>http://smoker.myopenid.com/</openid:Delegate>
    </Service>
    <Service priority="11">
      <Type>http://openid.net/signon/1.0</Type>
      <URI>https://ssl.vroom.unittest/server</URI>
      <openid:Delegate>http://smoker.myopenid.com/</openid:Delegate>
    </Service>
  </XRD>
</xrds:XRDS>


code:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds"
           xmlns="xri://$xrd*($v*2.0)"
           xmlns:openid="http://openid.net/xmlns/1.0"
           >
  <XRD>
    <Service >
      <Type>http://is-not-openid.unittest/</Type>
      <URI>http://noffing.unittest./</URI>
    </Service>
  </XRD>
</xrds:XRDS>


code:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds"
           xmlns="xri://$xrd*($v*2.0)"
           xmlns:openid="http://openid.net/xmlns/1.0"
           >
  <XRD>

    <Service priority="10">
      <Type>http://specs.openid.net/auth/2.0/signon</Type>
      <URI>http://www.myopenid.com/server</URI>
      <LocalID>http://smoker.myopenid.com/</LocalID>
      <LocalID>http://localid.mismatch.invalid/</LocalID>
    </Service>
  </XRD>
</xrds:XRDS>


code:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds"
           xmlns="xri://$xrd*($v*2.0)"
           xmlns:openid="http://openid.net/xmlns/1.0"
           >
  <XRD>
    <CanonicalID>=!1000</CanonicalID>

    <Service priority="10">
      <Type>http://openid.net/signon/1.0</Type>
      <URI>http://www.myopenid.com/server</URI>
      <openid:Delegate>http://smoker.myopenid.com/</openid:Delegate>
    </Service>

    <Service priority="20">
      <Type>http://openid.net/signon/1.0</Type>
      <URI>http://www.livejournal.com/openid/server.bml</URI>
      <openid:Delegate>http://frank.livejournal.com/</openid:Delegate>
    </Service>

  </XRD>
</xrds:XRDS>


code:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds"
           xmlns="xri://$xrd*($v*2.0)"
           xmlns:openid="http://openid.net/xmlns/1.0"
           >
  <XRD>
    <CanonicalID>=!1000</CanonicalID>

    <Service priority="10">
      <Type>http://specs.openid.net/auth/2.0/signon</Type>
      <URI>http://www.myopenid.com/server</URI>
      <openid:LocalID>http://smoker.myopenid.com/</openid:LocalID>
    </Service>

    <Service priority="20">
      <Type>http://specs.openid.net/auth/2.0/server</Type>
      <URI>http://www.livejournal.com/openid/server.bml</URI>
    </Service>

  </XRD>
</xrds:XRDS>


code:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds"
           xmlns="xri://$xrd*($v*2.0)"
           xmlns:openid="http://openid.net/xmlns/1.0"
           >
  <XRD>

    <Service priority="10">
      <Type>http://openid.net/signon/1.0</Type>
      <URI>http://vroom.unittest/server</URI>
      <openid:Delegate>http://smoker.myopenid.com/</openid:Delegate>
    </Service>
  </XRD>
</xrds:XRDS>


code:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds"
           xmlns="xri://$xrd*($v*2.0)"
           xmlns:openid="http://openid.net/xmlns/1.0"
           >
  <XRD>
    <Service priority="10">
      <Type>http://specs.openid.net/auth/2.0/server</Type>
      <URI>http://www.myopenid.com/server</URI>
    </Service>
  </XRD>
</xrds:XRDS>


code:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds"
           xmlns="xri://$xrd*($v*2.0)"
           xmlns:openid="http://openid.net/xmlns/1.0"
           >
  <XRD>
    <Service>
      <Type>http://specs.openid.net/auth/2.0/server</Type>
      <URI>http://www.myopenid.com/server</URI>
      <openid:Delegate>http://smoker.myopenid.com/</openid:Delegate>
    </Service>
  </XRD>
</xrds:XRDS>


code:
<?xml version="1.0" encoding="UTF-8"?>
<xrds:XRDS xmlns:xrds="xri://$xrds"
           xmlns="xri://$xrd*($v*2.0)"
           >
  <XRD>
    <Service priority="10">
      <Type>http://openid.net/signon/1.0</Type>
      <URI>http://www.myopenid.com/server</URI>
    </Service>
  </XRD>
</xrds:XRDS>


code:
Already normal form
http://example.com/
http://example.com/

Add a trailing slash
http://example.com
http://example.com/

Remove an empty port segment
http://example.com:/
http://example.com/

Remove a default port segment
http://example.com:80/
http://example.com/

Capitalization in host names
http://wWw.exaMPLE.COm/
http://www.example.com/

Capitalization in scheme names
htTP://example.com/
http://example.com/

Capitalization in percent-escaped reserved characters
http://example.com/foo%2cbar
http://example.com/foo%2Cbar

Unescape percent-encoded unreserved characters
http://example.com/foo%2Dbar%2dbaz
http://example.com/foo-bar-baz

remove_dot_segments example 1
http://example.com/a/b/c/./../../g
http://example.com/a/g

remove_dot_segments example 2
http://example.com/mid/content=5/../6
http://example.com/mid/6

remove_dot_segments: single-dot
http://example.com/a/./b
http://example.com/a/b

remove_dot_segments: double-dot
http://example.com/a/../b
http://example.com/b

remove_dot_segments: leading double-dot
http://example.com/../b
http://example.com/b

remove_dot_segments: trailing single-dot
http://example.com/a/.
http://example.com/a/

remove_dot_segments: trailing double-dot
http://example.com/a/..
http://example.com/

remove_dot_segments: trailing single-dot-slash
http://example.com/a/./
http://example.com/a/

remove_dot_segments: trailing double-dot-slash
http://example.com/a/../
http://example.com/

Test of all kinds of syntax-based normalization
hTTPS://a/./b/../b/%63/%7bfoo%7d
https://a/b/c/%7Bfoo%7D

Unsupported scheme
ftp://example.com/
fail

Non-absolute URI
http:/foo
fail

Illegal character in URI
http://<illegal>.com/
fail

Non-ascii character in URI
http://foo.com/
fail


code:
<?php

require_once "Auth/Yadis/Yadis.php";
require_once "Tests/Auth/Yadis/TestUtil.php";

global $testlist;
$testlist = array(
                  // success,  input_name,          id_name,            result_name
                  array(true,  "equiv",             "equiv",            "xrds"),
                  array(true,  "header",            "header",           "xrds"),
                  array(true,  "lowercase_header",  "lowercase_header", "xrds"),
                  array(true,  "xrds",              "xrds",             "xrds"),
                  array(true,  "xrds_ctparam",      "xrds_ctparam",     "xrds_ctparam"),
                  array(true,  "xrds_ctcase",       "xrds_ctcase",      "xrds_ctcase"),
                  array(false, "xrds_html",         "xrds_html",        "xrds_html"),
                  array(true,  "redir_equiv",       "equiv",            "xrds"),
                  array(true,  "redir_header",      "header",           "xrds"),
                  array(true,  "redir_xrds",        "xrds",             "xrds"),
                  array(false, "redir_xrds_html",   "xrds_html",        "xrds_html"),
                  array(true,  "redir_redir_equiv", "equiv",            "xrds"),
                  array(false, "404_server_response", null,             null),
                  array(false, "404_with_header",     null,             null),
                  array(false, "404_with_meta",       null,             null),
                  array(false, "201_server_response", null,             null),
                  array(false, "500_server_response", null,             null)
                  );

function getExampleXRDS()
{
    return Tests_Auth_Yadis_readdata('example-xrds.xml');
}

global $example_xrds;
$example_xrds = getExampleXRDS();

global $default_test_file;
$default_test_file = 'test1-discover.txt';

global $discover_tests;
$discover_tests = array();

function readTests($filename)
{
    $data = Tests_Auth_Yadis_readdata($filename);

    if ($data === null) {
        return null;
    }

    $tests = array();
    foreach (preg_split("/\f\n/", $data) as $case) {
        list($name, $content) = explode("\n", $case, 2);
        $tests[$name] = $content;
    }
    return $tests;
}

function getData($filename, $name)
{
    global $discover_tests;
    if (!array_key_exists($filename, $discover_tests)) {
        $data = readTests($filename);
        if ($data === null) {
            return null;
        }
        $discover_tests[$filename] = $data;
    }

    $file_tests = $discover_tests[$filename];

    if (array_key_exists($name, $file_tests)) {
        return $file_tests[$name];
    } else {
        return null;
    }
}

function fillTemplate($test_name, $template, $base_url, $example_xrds)
{
    $mapping = array(
                     array('URL_BASE/', $base_url),
                     array('<XRDS Content>', $example_xrds),
                     array('YADIS_HEADER', 'X-XRDS-Location'),
                     array('NAME', $test_name));

    foreach ($mapping as $pair) {
        list($k, $v) = $pair;
        $template = str_replace($k, $v, $template);
    }

    return $template;
}

function generateSample($test_name, $base_url,
                        $_example_xrds = null, $filename = null)
{
    global $example_xrds, $default_test_file;

    if ($_example_xrds === null) {
        $_example_xrds = $example_xrds;
    }

    if ($filename === null) {
        $filename = $default_test_file;
    }

    $template = getData($filename, $test_name);

    if ($template === null) {
        return null;
    }

    return fillTemplate($test_name, $template, $base_url, $_example_xrds);
}

function generateResult($base_url, $input_name, $id_name, $result_name, $success)
{
    $input_url = $base_url . $input_name; // urlparse.urljoin(base_url, input_name)

    // If the name is null then we expect the protocol to fail, which
    // we represent by null
    if ($id_name === null) {
        // assert result_name is null
        return array($input_url, null); // DiscoveryFailure
    }

    $result = generateSample($result_name, $base_url);
    list($headers, $content) = explode("\n\n", $result, 2);
    $header_lines = explode("\n", $headers);
    $ctype = null;
    foreach ($header_lines as $header_line) {
        if (strpos($header_line, 'Content-Type:') === 0) {
            list($temp, $ctype) = explode(":", $header_line, 2);
            $ctype = trim($ctype);
            break;
        }
    }

    $id_url = $base_url . $id_name;

    $result = new Auth_Yadis_Yadis();
    $result->uri = $id_url;
    if ($success) {
        $result->xrds_uri = $base_url . $result_name;
    } else {
        $result->xrds_uri = null;
    }
    $result->content_type = $ctype;
    $result->body = $content;
    return array($input_url, $result);
}


code:
<?php

require_once "Tests/Auth/Yadis/DiscoverData.php";
require_once "Auth/Yadis/Yadis.php";
require_once "Auth/Yadis/HTTPFetcher.php";

global $__status_header_re;
$__status_header_re = '/Status: (\d+) .*?$/m';

function mkResponse($data)
{
    global $__status_header_re;

    $matches = array();
    $status_mo = preg_match($__status_header_re, $data, $matches);
    list($headers_str, $body) = explode("\n\n", $data, 2);
    $headers = array();
    foreach (explode("\n", $headers_str) as $line) {
        list($k, $v) = explode(":", $line, 2);
        $k = strtolower(trim($k));
        $v = trim($v);
        $headers[$k] = $v;
    }
    $status = intval($matches[1]);
    $r = new Auth_Yadis_HTTPResponse(null, $status, $headers, $body);
    return $r;
}
class TestFetcher {
    function TestFetcher($base_url)
    {
        $this->base_url = $base_url;
    }

    function get($url, $headers = null)
    {
        $current_url = $url;
        while (true) {
            $parsed = parse_url($current_url);
            $path = substr($parsed['path'], 1);
            $data = generateSample($path, $this->base_url);

            if ($data === null) {
                return new Auth_Yadis_HTTPResponse($current_url,
                                                       404,
                                                       array(),
                                                       '');
            }

            $response = mkResponse($data);
            if (in_array($response->status, array(301, 302, 303, 307))) {
                $current_url = $response->headers['location'];
            } else {
                $response->final_url = $current_url;
                return $response;
            }
        }
    }
}

class BlankContentTypeFetcher {
    function get($url, $headers=null)
    {
        return new Auth_Yadis_HTTPResponse(
            $url, 200, array("Content-Type" => ""), '');
    }
}

class NoContentTypeFetcher {
    function get($url, $headers=null)
    {
        return new Auth_Yadis_HTTPResponse($url, 200, array(), '');
    }
}

class MockFetcher {
    function MockFetcher() {
        $this->count = 0;
    }

    function get($uri, $headers = null, $body = null)
    {
        $this->count++;
        if ($this->count == 1) {
            $headers = array(strtolower('X-XRDS-Location') . ': http://unittest/404');
            return new Auth_Yadis_HTTPResponse($uri, 200, $headers, '');
        } else {
            return new Auth_Yadis_HTTPResponse($uri, 404);
        }
    }
}

class TestSecondGet extends PHPUnit_Framework_TestCase {
    function test_404()
    {
        $uri = "http://something.unittest/";
        $response = null;
        $fetcher = new MockFetcher();
        $this->assertTrue(
               Auth_Yadis_Yadis::discover($uri, $response, $fetcher) === null);
    }
}

class _TestCase extends PHPUnit_Framework_TestCase {
    var $base_url = 'http://invalid.unittest/';

    function _TestCase($input_name, $id_name, $result_name, $success)
    {
      parent::__construct();
        $this->input_name = $input_name;
        $this->id_name = $id_name;
        $this->result_name = $result_name;
        $this->success = $success;
        $this->fetcher = new TestFetcher($this->base_url);
    }

    function setUp()
    {
        list($this->input_url, $this->expected) = generateResult($this->base_url,
                                                                 $this->input_name,
                                                                 $this->id_name,
                                                                 $this->result_name,
                                                                 $this->success);
    }

    function runTest()
    {
        if ($this->expected === null) {
            $result = Auth_Yadis_Yadis::discover($this->input_url,
                                                     $this->fetcher);
            $this->assertTrue($result->isFailure());
        } else {
            $result = Auth_Yadis_Yadis::discover($this->input_url,
                                                     $this->fetcher);

            if ($result === null) {
                $this->fail("Discovery result was null");
                return;
            }

            $this->assertEquals($this->input_url, $result->request_uri);

            $msg = 'Identity URL mismatch: actual = %s, expected = %s';
            $msg = sprintf($msg, $result->normalized_uri, $this->expected->uri);
            $this->assertEquals($this->expected->uri, $result->normalized_uri, $msg);

            $msg = 'Content mismatch: actual = %s, expected = %s';
            $msg = sprintf($msg, $result->response_text, $this->expected->body);
            $this->assertEquals($this->expected->body, $result->response_text, $msg);

            $this->assertEquals($this->expected->xrds_uri, $result->xrds_uri);
            $this->assertEquals($this->expected->content_type, $result->content_type);
        }
    }

    function getName()
    {
        if ($this->input_url) {
            return $this->input_url;
        } else {
            return $this->input_name;
        }
    }
}

class Tests_Auth_Yadis_Discover_Yadis extends PHPUnit_Framework_TestSuite {

    function getName()
    {
        return "Tests_Auth_Yadis_Discover_Yadis";
    }

    function Tests_Auth_Yadis_Discover_Yadis()
    {
        global $testlist;

        foreach ($testlist as $test) {
            list($success, $input_name, $id_name, $result_name) = $test;
            $this->addTest(new _TestCase($input_name, $id_name, $result_name, $success));
        }
    }
}

class Tests_Auth_Yadis_Discover_Yadis_ContentTypes extends PHPUnit_Framework_TestCase {
    function test_is_xrds_yadis_location()
    {
        $result = new Auth_Yadis_DiscoveryResult('http://request.uri/');
        $result->normalized_uri = "http://normalized/";
        $result->xrds_uri = "http://normalized/xrds";

        $this->assertTrue($result->isXRDS());
    }

    function test_is_xrds_content_type()
    {
        $result = new Auth_Yadis_DiscoveryResult('http://request.uri/');
        $result->normalized_uri = $result->xrds_uri = "http://normalized/";
        $result->content_type = Auth_Yadis_CONTENT_TYPE;

        $this->assertTrue($result->isXRDS());
      }

    function test_is_xrds_neither()
    {
        $result = new Auth_Yadis_DiscoveryResult('http://request.uri/');
        $result->normalized_uri = $result->xrds_uri = "http://normalized/";
        $result->content_type = "another/content-type";

        $this->assertTrue(!$result->isXRDS());
      }

    function test_no_content_type()
    {
        $fetcher = new NoContentTypeFetcher();
        $result = Auth_Yadis_Yadis::discover("http://bogus", $fetcher);
        $this->assertEquals(null, $result->content_type);
    }

    function test_blank_content_type()
    {
        $fetcher = new BlankContentTypeFetcher();
        $result = Auth_Yadis_Yadis::discover("http://bogus", $fetcher);
        $this->assertEquals("", $result->content_type);
    }
}

global $Tests_Auth_Yadis_Discover_Yadis_other;
$Tests_Auth_Yadis_Discover_Yadis_other = array(
      new Tests_Auth_Yadis_Discover_Yadis_ContentTypes()
      );


code:
<?php

/**
 * Tests for the Yadis HTML parsing functionality.
 *
 * PHP versions 4 and 5
 *
 * LICENSE: See the COPYING file included in this distribution.
 *
 * @package OpenID
 * @author JanRain, Inc. <openid@janrain.com>
 * @copyright 2005-2008 Janrain, Inc.
 * @license http://www.apache.org/licenses/LICENSE-2.0 Apache
 */

require_once 'Tests/Auth/Yadis/TestUtil.php';
require_once 'Auth/Yadis/ParseHTML.php';

class Tests_Auth_Yadis_ParseTest extends PHPUnit_Framework_TestCase {
    function Tests_Auth_Yadis_ParseTest($case)
    {
        list($result, $comment, $html) = $case;

        $this->result = $result;
        $this->comment = $comment;
        $this->html_string = $html;
        $this->parser = new Auth_Yadis_ParseHTML();
    }

    function getName()
    {
        return $this->comment;
    }

    function runTest()
    {
        $value = $this->parser->getHTTPEquiv($this->html_string);

        if ($this->result == "EOF") {
            $this->assertTrue($value === null);
        } else if ($this->result == "None") {
            $this->assertTrue($value === null);
        } else {
            $this->assertEquals($this->result, $value);
        }
    }
}

class Tests_Auth_Yadis_ParseHTML extends PHPUnit_Framework_TestSuite {

    function getName()
    {
        return "Tests_Auth_Yadis_Parse";
    }

    function parseTests($s)
    {
        $tests = array();

        $cases = preg_split("/\f\n/", $s);

        foreach ($cases as $case) {
            // Split the case text on newline, and keep the first two
            // lines and re-join the rest (those are the HTML).
            $parts = explode("\n", $case);
            $result = $parts[0];
            $html_comment = $parts[1];
            $html_string = implode("\n", array_slice($parts, 2));
            $tests[] = array($result, $html_comment, $html_string);
        }

        return $tests;
    }

    function Tests_Auth_Yadis_ParseHTML()
    {
        $test_data = Tests_Auth_Yadis_readdata('test1-parsehtml.txt');

        $test_cases = $this->parseTests($test_data);

        foreach ($test_cases as $case) {
            $this->addTest(new Tests_Auth_Yadis_ParseTest($case));
        }
    }
}


code:
<?php

/**
 * Utilites for test functions
 */

function Tests_Auth_Yadis_datafile($name, $reader)
{
    $path = dirname(realpath(__FILE__));
    $sep = DIRECTORY_SEPARATOR;
    $filename = $path . $sep . 'data' . $sep . $name;
    $data = $reader($filename);
    if ($data === false) {
        $msg = "Failed to open data file: $name";
        trigger_error($msg, E_USER_ERROR);
    }
    return $data;
}

function Tests_Auth_Yadis_readdata($name)
{
    return Tests_Auth_Yadis_datafile($name, 'file_get_contents');
}

function Tests_Auth_Yadis_readlines($name)
{
    return Tests_Auth_Yadis_datafile($name, 'file');
}