code:
<?php

require_once 'TestUtil.php';

require_once 'Auth/OpenID.php';
require_once 'Auth/OpenID/Discover.php';
require_once 'Auth/Yadis/Manager.php';
require_once 'Auth/Yadis/Misc.php';
require_once 'Auth/Yadis/XRI.php';

/**
 * Tests for the core of the PHP Yadis library discovery logic.
 */

class _SimpleMockFetcher {
    function _SimpleMockFetcher($responses)
    {
        $this->responses = $responses;
    }

    function get($url)
    {
        $response = array_pop($this->responses);
        assert($response[1] == $url);
        return $response;
    }
}

class Tests_Auth_OpenID_ServiceEndpoint extends PHPUnit_Framework_TestCase {
    function setUp() {
        $this->endpoint = new Auth_OpenID_ServiceEndpoint();
    }

    function test_getDisplayIdentifier_noFragment() {
        $urls = array("http://foo.bar.com/something",
                      "http://foo.bar.com/something?else=what&nothing=0",
                      "https://smoker.myopenid.com/"
                      );

        foreach ($urls as $url) {
            $this->endpoint->claimed_id = $url;
            $this->assertEquals($url, $this->endpoint->getDisplayIdentifier());
        }
    }

    function test_getDisplayIdentifier_withFragment() {
        $urls = array("http://foo.bar.com/something#fragged",
                      "http://foo.bar.com/something?else=what&nothing=0#ow",
                      "https://smoker.myopenid.com/#myentirelife"
                      );

        foreach ($urls as $url) {
            $this->endpoint->claimed_id = $url;
            $split = explode('#', $url);
            $this->assertEquals($split[0],
                                $this->endpoint->getDisplayIdentifier());
        }
    }
}

class Tests_Auth_OpenID_DiscoveryFailure extends PHPUnit_Framework_TestCase {

    function Tests_Auth_OpenID_DiscoveryFailure($responses)
    {
        // Response is ($code, $url, $body).
        $this->cases = array(
                             array(null, 'http://network.error/', ''),
                             array(404, 'http://not.found/', ''),
                             array(400, 'http://bad.request/', ''),
                             array(500, 'http://server.error/', ''),
                             array(200, 'http://header.found/', 200,
                                   array('x-xrds-location' => 'http://xrds.missing/')),
                             array(404, 'http://xrds.missing/', ''));

        $this->url = $responses[0]->final_url;
        $this->responses = $responses;
        $this->fetcher = new _SimpleMockFetcher($this->responses);
    }

    function runTest()
    {
        foreach ($this->cases as $case) {
            list($status, $url, $body) = $case;
            $expected_status = $status;

            $result = Auth_OpenID_discover($this->url, $this->fetcher);
            list($id_url, $svclist) = $result;

            $this->assertEquals($svclist, array());
        }
    }
}

### Tests for raising/catching exceptions from the fetcher through the
### discover function

class _ErrorRaisingFetcher {
    // Just raise an exception when fetch is called

    function _ErrorRaisingFetcher($thing_to_raise)
    {
        $this->thing_to_raise = $thing_to_raise;
    }

    function post($body = null)
    {
        __raiseError($this->thing_to_raise);
    }

    function get($url)
    {
        __raiseError($this->thing_to_raise);
    }
}

define('E_AUTH_OPENID_EXCEPTION', 'e_exception');
define('E_AUTH_OPENID_DIDFETCH', 'e_didfetch');
define('E_AUTH_OPENID_VALUE_ERROR', 'e_valueerror');
define('E_AUTH_OPENID_RUNTIME_ERROR', 'e_runtimeerror');
define('E_AUTH_OPENID_OI', 'e_oi');

class Tests_Auth_OpenID_Discover_FetchException extends PHPUnit_Framework_TestCase {
    // Make sure exceptions get passed through discover function from
    // fetcher.

    function Tests_Auth_OpenID_Discover_FetchException($exc)
    {
        $this->cases = array(E_AUTH_OPENID_EXCEPTION,
                             E_AUTH_OPENID_DIDFETCH,
                             E_AUTH_OPENID_VALUE_ERROR,
                             E_AUTH_OPENID_RUNTIME_ERROR,
                             E_AUTH_OPENID_OI);
    }

    function runTest()
    {
        foreach ($this->cases as $thing_to_raise) {
            $fetcher = ErrorRaisingFetcher($thing_to_raise);
            Auth_OpenID_discover('http://doesnt.matter/', $fetcher);
            $exc = __getError();

            if ($exc !== $thing_to_raise) {
                $this->fail('FetchException expected %s to be raised',
                            $thing_to_raise);
            }
        }
    }
}

// Tests for openid.consumer.discover.discover

class _DiscoveryMockFetcher extends Auth_Yadis_HTTPFetcher {
    function _DiscoveryMockFetcher($documents)
    {
        $this->redirect = null;
        $this->documents = $documents;
        $this->fetchlog = array();
    }

    function supportsSSL()
    {
        return true;
    }

    function post($url, $body = null, $headers = null)
    {
        return $this->get($url, $headers, $body);
    }

    function get($url, $headers = null, $body = null)
    {
        $this->fetchlog[] = array($url, $body, $headers);

        if ($this->redirect) {
            $final_url = $this->redirect;
        } else {
            $final_url = $url;
        }

        if (array_key_exists($url, $this->documents)) {
            list($ctype, $body) = $this->documents[$url];
            $status = 200;
        } else {
            $status = 404;
            $ctype = 'text/plain';
            $body = '';
        }

        return new Auth_Yadis_HTTPResponse($final_url, $status,
                                           array('content-type' => $ctype), $body);
    }
}

class _DiscoveryBase extends PHPUnit_Framework_TestCase {
    var $id_url = "http://someuser.unittest/";
    var $fetcherClass = '_DiscoveryMockFetcher';

    function _checkService($s,
                           $server_url,
                           $claimed_id=null,
                           $local_id=null,
                           $canonical_id=null,
                           $types=null,
                           $used_yadis=false,
			   $display_identifier=null)
    {
        $this->assertEquals($server_url, $s->server_url);
        if ($types == array('2.0 OP')) {
            $this->assertFalse($claimed_id);
            $this->assertFalse($local_id);
            $this->assertFalse($s->claimed_id);
            $this->assertFalse($s->local_id);
            $this->assertFalse($s->getLocalID());
            $this->assertFalse($s->compatibilityMode());
            $this->assertTrue($s->isOPIdentifier());
            $this->assertEquals($s->preferredNamespace(),
                                Auth_OpenID_OPENID2_NS);
        } else {
            $this->assertEquals($claimed_id, $s->claimed_id);
            $this->assertEquals($local_id, $s->getLocalID());
        }

        if ($used_yadis) {
            $this->assertTrue($s->used_yadis, "Expected to use Yadis");
        } else {
            $this->assertFalse($s->used_yadis,
                               "Expected to use old-style discovery");
        }

        $openid_types = array(
                              '1.1' => Auth_OpenID_TYPE_1_1,
                              '1.0' => Auth_OpenID_TYPE_1_0,
                              '2.0' => Auth_OpenID_TYPE_2_0,
                              '2.0 OP' => Auth_OpenID_TYPE_2_0_IDP);

        $type_uris = array();
        foreach ($types as $t) {
            $type_uris[] = $openid_types[$t];
        }

        $this->assertEquals($type_uris, $s->type_uris);
        $this->assertEquals($canonical_id, $s->canonicalID);

        if ($s->canonicalID) {
	  $this->assertTrue($s->getDisplayIdentifier() != $claimed_id);
	  $this->assertTrue($s->getDisplayIdentifier() !== null);
	  $this->assertEquals($display_identifier, $s->getDisplayIdentifier());
	  $this->assertEquals($s->claimed_id, $s->canonicalID);
	}

        $this->assertEquals($s->display_identifier ? $s->display_identifier : $s->claimed_id,
			    $s->getDisplayIdentifier());
    }

    function setUp()
    {
        $cls = $this->fetcherClass;
        // D is for Dumb.
        $d = array();
        $this->fetcher = new $cls($d);
    }
}

class Tests_Auth_OpenID_Discover_OpenID extends _DiscoveryBase {
    function _discover($content_type, $data,
                       $expected_services, $expected_id=null)
    {
        if ($expected_id === null) {
            $expected_id = $this->id_url;
        }

        $this->fetcher->documents[$this->id_url] = array($content_type, $data);
        list($id_url, $services) = Auth_OpenID_discover($this->id_url,
                                                        $this->fetcher);
        $this->assertEquals($expected_services, count($services));
        $this->assertEquals($expected_id, $id_url);
        return $services;
    }

    function test_404()
    {
        list($url, $services) = Auth_OpenID_discover($this->id_url . '/404',
                                                     $this->fetcher);
        $this->assertTrue($services == array());
    }

    function test_noOpenID()
    {
        $services = $this->_discover('text/plain',
                                     "junk",
                                     0);

        $services = $this->_discover(
                                     'text/html',
                                     Tests_Auth_OpenID_readdata('test_discover_openid_no_delegate.html'),
                                     1);

        $this->_checkService($services[0],
                             "http://www.myopenid.com/server",
                             $this->id_url,
                             $this->id_url,
                             null,
                             array('1.1'),
                             false);
    }

    function test_html1()
    {
        $services = $this->_discover('text/html',
                                     Tests_Auth_OpenID_readdata('test_discover_openid.html'),
                                     1);

        $this->_checkService($services[0],
                             "http://www.myopenid.com/server",
                             $this->id_url,
                             'http://smoker.myopenid.com/',
                             null,
                             array('1.1'),
                             false,
			     $this->id_url);
    }

    /*
     * Ensure that the Claimed Identifier does not have a fragment if
     * one is supplied in the User Input.
     */
    function test_html1Fragment()
    {
        $data = Tests_Auth_OpenID_readdata('openid.html');
        $content_type = 'text/html';
        $expected_services = 1;

        $this->fetcher->documents[$this->id_url] = array($content_type, $data);
        $expected_id = $this->id_url;
        $this->id_url = $this->id_url . '#fragment';
        list($id_url, $services) = Auth_OpenID_discover($this->id_url, $this->fetcher);
        $this->assertEquals($expected_services, count($services));
        $this->assertEquals($expected_id, $id_url);

        $this->_checkService(
            $services[0],
            "http://www.myopenid.com/server",
            $expected_id,
            'http://smoker.myopenid.com/',
            null,
            array('1.1'),
            false,
	    $this->id_url);
    }

    function test_html2()
    {
        $services = $this->_discover('text/html',
                                     Tests_Auth_OpenID_readdata('test_discover_openid2.html'),
                                     1);

        $this->_checkService($services[0],
                             "http://www.myopenid.com/server",
                             $this->id_url,
                             'http://smoker.myopenid.com/',
                             null,
                             array('2.0'),
                             false,
			     $this->id_url);
    }

    function test_html1And2()
    {
        $services = $this->_discover('text/html',
                                     Tests_Auth_OpenID_readdata('test_discover_openid_1_and_2.html'),
                                     2);

        $types = array('2.0', '1.1');

        for ($i = 0; $i < count($types); $i++) {
            $t = $types[$i];
            $s = $services[$i];

            $this->_checkService(
                $s,
                "http://www.myopenid.com/server",
                $this->id_url,
                'http://smoker.myopenid.com/',
                null,
                array($t),
                false,
		$this->id_url);
        }
    }

    function test_yadisEmpty()
    {
        $services = $this->_discover('application/xrds+xml',
                                     Tests_Auth_OpenID_readdata('test_discover_yadis_0entries.xml'),
                                     0);
    }

    function test_htmlEmptyYadis()
    {
        // HTML document has discovery information, but points to an
        // empty Yadis document.

        // The XRDS document pointed to by "openid_and_yadis.html"
        $this->fetcher->documents[$this->id_url . 'xrds'] =
            array('application/xrds+xml',
                  Tests_Auth_OpenID_readdata('test_discover_yadis_0entries.xml'));

        $services = $this->_discover('text/html',
                                     Tests_Auth_OpenID_readdata('test_discover_openid_and_yadis.html'),
                                     1);

        $this->_checkService($services[0],
                             "http://www.myopenid.com/server",
                             $this->id_url,
                             'http://smoker.myopenid.com/',
                             null,
                             array('1.1'),
                             false,
			     $this->id_url);
    }

    function test_yadis1NoDelegate()
    {
        $services = $this->_discover('application/xrds+xml',
                                     Tests_Auth_OpenID_readdata('test_discover_yadis_no_delegate.xml'),
                                     1);

        $this->_checkService(
                             $services[0],
                             "http://www.myopenid.com/server",
                             $this->id_url,
                             $this->id_url,
                             null,
                             array('1.0'),
                             true,
			     $this->id_url);
    }

    function test_yadis2NoLocalID()
    {
        $services = $this->_discover('application/xrds+xml',
                                     Tests_Auth_OpenID_readdata('test_discover_openid2_xrds_no_local_id.xml'),
                                     1);

        $this->_checkService(
                             $services[0],
                             "http://www.myopenid.com/server",
                             $this->id_url,
                             $this->id_url,
                             null,
                             array('2.0'),
                             true,
			     $this->id_url);
    }

    function test_yadis2()
    {
        $services = $this->_discover('application/xrds+xml',
                                     Tests_Auth_OpenID_readdata('test_discover_openid2_xrds.xml'),
                                     1);

        $this->_checkService($services[0],
                             "http://www.myopenid.com/server",
                             $this->id_url,
                             'http://smoker.myopenid.com/',
                             null,
                             array('2.0'),
                             true,
			     $this->id_url);
    }

    function test_yadis2OP()
    {
        $services = $this->_discover('application/xrds+xml',
                                     Tests_Auth_OpenID_readdata('test_discover_yadis_idp.xml'),
                                     1);

        $this->_checkService($services[0],
                             "http://www.myopenid.com/server",
                             null,
                             null,
                             null,
                             array('2.0 OP'),
                             true,
			     $this->id_url);
    }

    function test_yadis2OPDelegate()
    {
        // The delegate tag isn't meaningful for OP entries.
        $services = $this->_discover('application/xrds+xml',
                                     Tests_Auth_OpenID_readdata('test_discover_yadis_idp_delegate.xml'),
                                     1);

        $this->_checkService(
                             $services[0],
                             "http://www.myopenid.com/server",
                             null, null, null,
                             array('2.0 OP'),
                             true,
			     $this->id_url);
    }

    function test_yadis2BadLocalID()
    {
        $services = $this->_discover('application/xrds+xml',
                                     Tests_Auth_OpenID_readdata('test_discover_yadis_2_bad_local_id.xml'),
                                     0);
    }

    function test_yadis1And2()
    {
        $services = $this->_discover('application/xrds+xml',
                                     Tests_Auth_OpenID_readdata('test_discover_openid_1_and_2_xrds.xml'),
                                     1);

        $this->_checkService(
            $services[0],
            "http://www.myopenid.com/server",
            $this->id_url,
            'http://smoker.myopenid.com/',
            null,
            array('2.0', '1.1'),
            true);
    }

    function test_yadis1And2BadLocalID()
    {
        $services = $this->_discover('application/xrds+xml',
                                     Tests_Auth_OpenID_readdata('test_discover_openid_1_and_2_xrds_bad_delegate.xml'),
                                     0);
    }
}

class _MockFetcherForXRIProxy extends Auth_Yadis_HTTPFetcher {

    function _MockFetcherForXRIProxy($documents)
    {
        $this->documents = $documents;
        $this->fetchlog = array();
    }

    function get($url, $headers=null)
    {
        return $this->fetch($url, $headers);
    }

    function post($url, $body)
    {
        return $this->fetch($url, $body);
    }

    function fetch($url, $body=null, $headers=null)
    {
        $this->fetchlog[] = array($url, $body, $headers);

        $u = parse_url($url);
        $proxy_host = $u['host'];
        $xri = $u['path'];
        $query = Auth_OpenID::arrayGet($u, 'query');

        if ((!$headers) && (!$query)) {
            trigger_error('Error in mock XRI fetcher: no headers or query');
        }

        if (Auth_Yadis_startswith($xri, '/')) {
            $xri = substr($xri, 1);
        }

        if (array_key_exists($xri, $this->documents)) {
            list($ctype, $body) = $this->documents[$xri];
            $status = 200;
        } else {
            $status = 404;
            $ctype = 'text/plain';
            $body = '';
        }

        return new Auth_Yadis_HTTPResponse($url, $status,
                                               array('content-type' => $ctype),
                                               $body);
    }
}

class TestXRIDiscovery extends _DiscoveryBase {
    var $fetcherClass = '_MockFetcherForXRIProxy';

    function setUp() {
        parent::setUp();

	$this->fetcher->documents = array('=smoker' => array('application/xrds+xml',
							     Tests_Auth_OpenID_readdata('yadis_2entries_delegate.xml')),
					  '=smoker*bad' => array('application/xrds+xml',
								 Tests_Auth_OpenID_readdata('yadis_another_delegate.xml')));
    }

    function test_xri() {
        list($user_xri, $services) = Auth_OpenID_discoverXRI('=smoker');

	$this->_checkService(
			     $services[0],
			     "http://www.myopenid.com/server",
			     Auth_Yadis_XRI("=!1000"),
			     'http://smoker.myopenid.com/',
			     Auth_Yadis_XRI("=!1000"),
			     array('1.0'),
			     true,
			     '=smoker');

	$this->_checkService(
			     $services[1],
			     "http://www.livejournal.com/openid/server.bml",
			     Auth_Yadis_XRI("=!1000"),
			     'http://frank.livejournal.com/',
			     Auth_Yadis_XRI("=!1000"),
			     array('1.0'),
			     true,
			     '=smoker');
    }

    function test_xriNoCanonicalID() {
        list($user_xri, $services) = Auth_OpenID_discoverXRI('=smoker*bad');
	$this->assertFalse($services);
    }

    function test_useCanonicalID() {
        $endpoint = new Auth_OpenID_ServiceEndpoint();
	$endpoint->claimed_id = Auth_Yadis_XRI("=!1000");
	$endpoint->canonicalID = Auth_Yadis_XRI("=!1000");
	$htis->assertEquals($endpoint->getLocalID(), Auth_Yadis_XRI("=!1000"));
    }
}

class Tests_Auth_OpenID_DiscoverSession {
    function Tests_Auth_OpenID_DiscoverSession()
    {
        $this->data = array();
    }

    function set($name, $value)
    {
        $this->data[$name] = $value;
    }

    function get($name, $default=null)
    {
        if (array_key_exists($name, $this->data)) {
            return $this->data[$name];
        } else {
            return $default;
        }
    }

    function del($name)
    {
        unset($this->data[$name]);
    }
}

global $__Tests_BOGUS_SERVICE;
$__Tests_BOGUS_SERVICE = new Auth_OpenID_ServiceEndpoint();
$__Tests_BOGUS_SERVICE->claimed_id = "=really.bogus.endpoint";

function __serviceCheck_discover_cb($url, $fetcher)
{
    global $__Tests_BOGUS_SERVICE;
    return array($url, array($__Tests_BOGUS_SERVICE));
}

class _FetcherWithSSL extends _DiscoveryMockFetcher {
    function supportsSSL()
    {
        return true;
    }
}

class _FetcherWithoutSSL extends _DiscoveryMockFetcher {
    function supportsSSL()
    {
        return false;
    }
}

class _NonFetcher extends _DiscoveryMockFetcher {
    var $used = false;

    function _NonFetcher()
    {
        $a = array();
        parent::_DiscoveryMockFetcher($a);
    }

    function supportsSSL()
    {
        return false;
    }

    function get($url, $headers)
    {
        $this->used = true;
    }
}

class Tests_Auth_OpenID_SSLSupport extends PHPUnit_Framework_TestCase {
    function test_discoverDropSSL()
    {
        // In the absence of SSL support, the discovery process should
        // drop endpoints whose server URLs are HTTPS.
        $id_url = 'http://bogus/';

        $d = array(
                   $id_url => array('application/xrds+xml',
                                    Tests_Auth_OpenID_readdata('test_discover_openid_ssl.xml'))
                   );

        $f = new _FetcherWithoutSSL($d);

        $result = Auth_OpenID_discover($id_url, $f);

        list($url, $services) = $result;

        $this->assertTrue($url == $id_url);
        $this->assertTrue(count($services) == 1);

        $e = $services[0];
        $this->assertTrue($e->server_url == 'http://nossl.vroom.unittest/server');
    }

    function test_discoverRetainSSL()
    {
        // In the presence of SSL support, the discovery process
        // should NOT drop endpoints whose server URLs are HTTPS.

        // In the absence of SSL support, the discovery process should
        // drop endpoints whose server URLs are HTTPS.
        $id_url = 'http://bogus/';

        $d = array(
                   $id_url => array('application/xrds+xml',
                                    Tests_Auth_OpenID_readdata('test_discover_openid_ssl.xml'))
                   );

        $f = new _FetcherWithSSL($d);

        $result = Auth_OpenID_discover($id_url, $f);

        list($url, $services) = $result;

        $this->assertTrue($url == $id_url);
        $this->assertTrue(count($services) == 2);

        $e = $services[0];
        $this->assertTrue($e->server_url == 'http://nossl.vroom.unittest/server');

        $e = $services[1];
        $this->assertTrue($e->server_url == 'https://ssl.vroom.unittest/server');
    }

    function test_discoverSSL()
    {
        // The consumer code should not attempt to perform discovery
        // on an HTTPS identity URL in the absence of SSL support.

        $id_url = 'https://unsupported/';

        $f = new _NonFetcher();

        $result = Auth_OpenID_discover($id_url, $f);

        $this->assertTrue($result == array($id_url, array()));
        $this->assertFalse($f->used);
    }
}

global $Tests_Auth_OpenID_Discover_OpenID_other;
$Tests_Auth_OpenID_Discover_OpenID_other = array(
                                                 new Tests_Auth_OpenID_SSLSupport()
                                                 );


code:
<?php

require_once 'Auth/OpenID/Message.php';
require_once 'Auth/OpenID/Extension.php';

class _ExtensionTest_DummyExtension extends Auth_OpenID_Extension {
    var $ns_uri = 'http://an.extension/';
    var $ns_alias = 'dummy';

    function getExtensionArgs()
    {
        return array();
    }
}

class Tests_Auth_OpenID_Extension extends PHPUnit_Framework_TestCase {
    function test_OpenID1()
    {
        $oid1_msg = new Auth_OpenID_Message(Auth_OpenID_OPENID1_NS);
        $ext = new _ExtensionTest_DummyExtension();
        $ext->toMessage($oid1_msg);
        $namespaces = $oid1_msg->namespaces;

        $this->assertTrue($namespaces->isImplicit($ext->ns_uri));
        $this->assertEquals($ext->ns_uri,
                            $namespaces->getNamespaceURI($ext->ns_alias));
        $this->assertEquals($ext->ns_alias,
                            $namespaces->getAlias($ext->ns_uri));
    }

    function test_OpenID2()
    {
        $oid2_msg = new Auth_OpenID_Message(Auth_OpenID_OPENID2_NS);
        $ext = new _ExtensionTest_DummyExtension();
        $ext->toMessage($oid2_msg);
        $namespaces = $oid2_msg->namespaces;
        $this->assertFalse($namespaces->isImplicit($ext->ns_uri));
        $this->assertEquals($ext->ns_uri,
                            $namespaces->getNamespaceURI($ext->ns_alias));
        $this->assertEquals($ext->ns_alias,
                            $namespaces->getAlias($ext->ns_uri));
    }
}

repo_name: spookie/gnu

license: mit


code:
<?php

/**
 * Tests for the HMAC-SHA1 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/HMAC.php';
require_once 'Tests/Auth/OpenID/TestUtil.php';

class Tests_Auth_OpenID_HMAC_TestCase extends PHPUnit_Framework_TestCase {
    function Tests_Auth_OpenID_HMAC_TestCase(
        $name, $key, $data, $expected, $hmac_func)
    {

        $this->setName($name);
        $this->key = $key;
        $this->data = $data;
        $this->expected = $expected;
        $this->hmac_func = $hmac_func;
    }

    function runTest()
    {
        $actual = call_user_func($this->hmac_func, $this->key, $this->data);
        $this->assertEquals(bin2hex($this->expected), bin2hex($actual));
    }
}

class Tests_Auth_OpenID_HMAC extends PHPUnit_Framework_TestSuite {
    function _strConvert($s)
    {
        $repeat_pat = '/^0x([a-f0-9]{2}) repeated (\d+) times$/';
        if (preg_match($repeat_pat, $s, $match)) {
            $c = chr(hexdec($match[1]));
            $n = $match[2];
            $data = '';
            for ($i = 0; $i < $n; $i++) {
                $data .= $c;
            }
        } elseif (substr($s, 0, 2) == "0x") {
            $data = pack('H*', substr($s, 2, strlen($s) - 1));
        } elseif (preg_match('/^"(.*)"$/', $s, $match)) {
            $data = $match[1];
        } else {
            trigger_error("Bad data format: $s", E_USER_ERROR);
        }
        return $data;
    }

    function _readTestCases($test_file_name, $digest_len)
    {
        $lines = Tests_Auth_OpenID_readlines($test_file_name);
        $cases = array();
        $case = array();
        foreach ($lines as $line) {
            if ($line{0} == "#") {
                continue;
            }

            // Blank line separates test cases
            if ($line == "\n") {
                $cases[] = $case;
                $case = array();
            } else {
                $match = array();
                $pat = '/^([a-z0-9_-]+) =\s+(.*?)\n$/';
                if (!preg_match($pat, $line, $match)) {
                    trigger_error("Bad test input: $line", E_USER_ERROR);
                }

                $c = count($match);
                if ($c != 3) {
                    trigger_error(
                        "Wrong number of elements in parsed case: $c",
                        E_USER_ERROR);
                    return false;
                }

                $key = $match[1];
                $value = $match[2];
                $case[$key] = $value;
            }
        }

        if (count($case)) {
            $cases[] = $case;
        }

        $final = array();

        // Normalize strings and check data integrity
        foreach ($cases as $case) {
            $clean = array();
            $clean["key"] =
                Tests_Auth_OpenID_HMAC::_strConvert($case["key"]);
            if (defined(@$case["key_len"])) {
                if (Auth_OpenID::bytes($clean["key"]) != $case["key_len"]) {
                    trigger_error("Bad key length", E_USER_ERROR);
                }
            }

            $clean["data"] =
                Tests_Auth_OpenID_HMAC::_strConvert($case["data"]);
            if (defined(@$case["data_len"])) {
                if (Auth_OpenID::bytes($clean["data"]) != $case["data_len"]) {
                    trigger_error("Bad data length", E_USER_ERROR);
                }
            }

            $clean["digest"] =
                Tests_Auth_OpenID_HMAC::_strConvert($case["digest"]);
            if (Auth_OpenID::bytes($clean["digest"]) != $digest_len) {
                $l = Auth_OpenID::bytes($clean["digest"]);
                trigger_error("Bad digest length: $l", E_USER_ERROR);
            }

            $clean['test_case'] = $case['test_case'];

            $final[] = $clean;
        }
        return $final;
    }

    function Tests_Auth_OpenID_HMAC($name)
    {
        $this->setName($name);
        $hash_test_defs = array(array(
            'Auth_OpenID_HMACSHA1', 'hmac-sha1.txt', 20));
        if (Auth_OpenID_HMACSHA256_SUPPORTED) {
            $hash_test_defs[] =
                array('Auth_OpenID_HMACSHA256', 'hmac-sha256.txt', 32);
        }
        foreach ($hash_test_defs as $params) {
            list($hash_func, $filename, $hash_len) = $params;
            $cases = $this->_readTestCases($filename, $hash_len);
            foreach ($cases as $case) {
                $test = new Tests_Auth_OpenID_HMAC_TestCase(
                    $case['test_case'],
                    $case['key'],
                    $case['data'],
                    $case['digest'],
                    $hash_func);

                $digest = $case['digest'];
                $this->_addTestByValue($test);
            }
        }
    }

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


code:
<?php

/**
 * Tests for the KVForm module.
 *
 * 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/KVForm.php';

global $_Tests_Auth_OpenID_kverrors;
$_Tests_Auth_OpenID_kverrors = null;

/**
 * Keep a list of the logged errors
 */
function Tests_Auth_OpenID_kvHandleError($errno, $errmsg)
{
    global $_Tests_Auth_OpenID_kverrors;
    $_Tests_Auth_OpenID_kverrors[] = $errmsg;
}

class Tests_Auth_OpenID_KVForm_TestCase extends PHPUnit_Framework_TestCase {
    var $errs;

    function runTest()
    {
        // Re-set the number of logged errors
        global $_Tests_Auth_OpenID_kverrors;
        $_Tests_Auth_OpenID_kverrors = array();

        set_error_handler("Tests_Auth_OpenID_kvHandleError");

        $this->_runTest();

        // Check to make sure we have the expected number of logged errors
        //$this->assertEquals($this->errs, count($_Tests_Auth_OpenID_kverrors));

        restore_error_handler();
    }

    function _runTest()
    {
        trigger_error('Must be overridden', E_USER_ERROR);
    }
}

class Tests_Auth_OpenID_KVForm_TestCase_Parse
extends Tests_Auth_OpenID_KVForm_TestCase {
    function Tests_Auth_OpenID_KVForm_TestCase_Parse(
        $arr, $str, $lossy, $errs)
    {

        $this->arr = $arr;
        $this->str = $str;
        $this->lossy = $lossy;
        $this->errs = $errs;
    }

    function _runTest()
    {
        // Do one parse, after which arrayToKV and kvToArray should be
        // inverses.
        $parsed1 = Auth_OpenID_KVForm::toArray($this->str);
        $serial1 = Auth_OpenID_KVForm::fromArray($this->arr);

        if ($this->lossy == "neither" || $this->lossy == "str") {
            $this->assertEquals($this->arr, $parsed1, "str was lossy");
        }

        if ($this->lossy == "neither" || $this->lossy == "arr") {
            $this->assertEquals($this->str, $serial1, "array was lossy");
        }

        $parsed2 = Auth_OpenID_KVForm::toArray($serial1);
        $serial2 = Auth_OpenID_KVForm::fromArray($parsed1);

        // Round-trip both
        $parsed3 = Auth_OpenID_KVForm::toArray($serial2);
        $serial3 = Auth_OpenID_KVForm::fromArray($parsed2);

        $this->assertEquals($serial2, $serial3, "serialized forms differ");

        // Check to make sure that they're inverses.
        $this->assertEquals($parsed2, $parsed3, "parsed forms differ");

    }
}

class Tests_Auth_OpenID_KVForm_TestCase_Null
extends Tests_Auth_OpenID_KVForm_TestCase {
    function Tests_Auth_OpenID_KVForm_TestCase_Null($arr, $errs)
    {
        $this->arr = $arr;
        $this->errs = $errs;
    }

    function _runTest()
    {
        $serialized = Auth_OpenID_KVForm::fromArray($this->arr);
        $this->assertTrue($serialized === null,
                          'serialization unexpectedly succeeded');
    }
}

class Tests_Auth_OpenID_KVForm extends PHPUnit_Framework_TestSuite {
    function Tests_Auth_OpenID_KVForm($name)
    {
        $this->setName($name);
        $testdata_list = array(
            array("name" => "simple",
                  "str" => "college:harvey mudd\n",
                  "arr" => array("college" => "harvey mudd"),
                  ),
            array("name" => "empty",
                  "str" => "",
                  "arr" => array(),
                  ),
            array("name" => "empty (just newline)",
                  "str" => "\n",
                  "arr" => array(),
                  "lossy" => "str",
                  "errors" => 1,
                  ),
            array("name" => "empty (double newline)",
                  "str" => "\n\n",
                  "arr" => array(),
                  "lossy" => "str",
                  "errors" => 2,
                  ),
            array("name" => "empty (no colon)",
                  "str" => "East is least\n",
                  "arr" => array(),
                  "lossy" => "str",
                  "errors" => 1,
                  ),
            array("name" => "two keys",
                  "str" => "city:claremont\nstate:CA\n",
                  "arr" => array('city' => 'claremont',
                                 'state' => 'CA'),
                  ),
            array("name" => "real life",
                  "str" => "is_valid:true\ninvalidate_handle:" .
                  "{HMAC-SHA1:2398410938412093}\n",
                  "arr" => array('is_valid' => 'true',
                                 'invalidate_handle' =>
                                 '{HMAC-SHA1:2398410938412093}'),
                  ),
            array("name" => "empty key and value",
                  "str" => ":\n",
                  "arr" => array(''=>''),
                  ),
            array("name" => "empty key, not value",
                  "str" => ":missing key\n",
                  "arr" => array(''=>'missing key'),
                  ),
            array("name" => "whitespace at front of key",
                  "str" => " street:foothill blvd\n",
                  "arr" => array('street'=>'foothill blvd'),
                  "lossy" => "str",
                  "errors" => 1,
                  ),
            array("name" => "whitespace at front of value",
                  "str" => "major: computer science\n",
                  "arr" => array('major'=>'computer science'),
                  "lossy" => "str",
                  "errors" => 1,
                  ),
            array("name" => "whitespace around key and value",
                  "str" => " dorm : east \n",
                  "arr" => array('dorm'=>'east'),
                  "lossy" => "str",
                  "errors" => 2,
                  ),
            array("name" => "missing trailing newline",
                  "str" => "e^(i*pi)+1:0",
                  "arr" => array('e^(i*pi)+1'=>'0'),
                  "lossy" => "str",
                  "errors" => 1,
                  ),
            array("name" => "missing trailing newline (two key)",
                  "str" => "east:west\nnorth:south",
                  "arr" => array('east'=>'west',
                                 'north'=>'south'),
                  "lossy" => "str",
                  "errors" => 1,
                  ),
            array("name" => "colon in key",
                  "arr" => array("k:k" => 'v'),
                  "errors" => 1,
                  ),
            array("name" => "newline in key",
                  "arr" => array("k\nk" => 'v'),
                  "errors" => 1,
                  ),
            array("name" => "newline in value",
                  "arr" => array('k' => "v\nv"),
                  "errors" => 1,
                  ),
            array("name" => "array whitespace",
                  "arr" => array(" k " => "v"),
                  "lossy" => "both",
                  "str" => " k :v\n",
                  "errors" => 2,
                  ),
            array("name" => "array ordering 1",
                  "arr" => array("a" => "x",
                                 "b" => "x",
                                 "c" => "x"),
                  "str" => "a:x\nb:x\nc:x\n",
                  ),
            array("name" => "array ordering 2",
                  "arr" => array("a" => "x",
                                 "c" => "x",
                                 "b" => "x"),
                  "str" => "a:x\nc:x\nb:x\n",
                  ),
            );

        foreach ($testdata_list as $testdata) {
            if (isset($testdata['str'])) {
                $str = $testdata['str'];
            } else {
                $str = null;
            }

            $arr = $testdata["arr"];

            if (isset($testdata['errors'])) {
                $errs = $testdata["errors"];
            } else {
                $errs = 0;
            }

            if (is_null($str)) {
                $test = new Tests_Auth_OpenID_KVForm_TestCase_Null($arr, $errs);
            } else {
                if (isset($testdata['lossy'])) {
                    $lossy = $testdata["lossy"];
                } else {
                    $lossy = 'neither';
                }
                $test = new Tests_Auth_OpenID_KVForm_TestCase_Parse(
                    $arr, $str, $lossy, $errs);
            }
            $test->setName($testdata["name"]);
            $this->addTest($test);
        }
    }
}


code:
<?php

/**
 * In-memory OpenID store implementation for testing only
 */
require_once "Auth/OpenID/Interface.php";
require_once 'Auth/OpenID/Nonce.php';

class ServerAssocs {
    function ServerAssocs()
    {
        $this->assocs = array();
    }

    function set($assoc)
    {
        $this->assocs[$assoc->handle] = $assoc;
    }

    function get($handle)
    {
        return Auth_OpenID::arrayGet($this->assocs, $handle);
    }

    function remove($handle)
    {
        if (array_key_exists($handle, $this->assocs)) {
            unset($this->assocs[$handle]);
            return true;
        } else {
            return false;
        }
    }

    /*
     * Returns association with the oldest issued date.
     *
     * or null if there are no associations.
     */
    function best()
    {
        $best = null;
        foreach ($this->assocs as $handle => $assoc) {
            if (($best === null) || ($best->issued < $assoc->issued)) {
                $best = $assoc;
            }
        }
        return $best;
    }

    /*
     * Remove expired associations.
     *
     * @return (removed associations, remaining associations)
     */
    function cleanup()
    {
        $remove = array();
        foreach ($this->assocs as $handle => $assoc) {
            if ($assoc->getExpiresIn() == 0) {
                $remove[] = $handle;
            }
        }

        foreach ($remove as $handle) {
            unset($this->assocs[$handle]);
        }

        return array(count($remove), count($this->assocs));
    }
}

/*
 * In-process memory store.
 *
 * Use for single long-running processes.  No persistence supplied.
 */
class Tests_Auth_OpenID_MemStore extends Auth_OpenID_OpenIDStore {
    function Tests_Auth_OpenID_MemStore()
    {
        $this->server_assocs = array();
        $this->nonces = array();
    }

    function &_getServerAssocs($server_url)
    {
        if (!array_key_exists($server_url, $this->server_assocs)) {
            $this->server_assocs[$server_url] = new ServerAssocs();
        }

        return $this->server_assocs[$server_url];
    }

    function storeAssociation($server_url, $assoc)
    {
        $assocs =& $this->_getServerAssocs($server_url);
        $assocs->set($assoc);
    }

    function getAssociation($server_url, $handle=null)
    {
        $assocs =& $this->_getServerAssocs($server_url);
        if ($handle === null) {
            return $assocs->best();
        } else {
            return $assocs->get($handle);
        }
    }

    function removeAssociation($server_url, $handle)
    {
        $assocs =& $this->_getServerAssocs($server_url);
        return $assocs->remove($handle);
    }

    function useNonce($server_url, $timestamp, $salt)
    {
        global $Auth_OpenID_SKEW;

        if (abs($timestamp - time()) > $Auth_OpenID_SKEW) {
            return false;
        }

        $anonce = array($server_url, intval($timestamp), $salt);

        if (in_array($anonce, $this->nonces)) {
            return false;
        } else {
            array_push($this->nonces, $anonce);
            return true;
        }
    }

    function cleanupNonces()
    {
        global $Auth_OpenID_SKEW;

        $now = time();
        $expired = array();
        foreach ($this->nonces as $anonce) {
            if (abs($anonce[1] - $now) > $Auth_OpenID_SKEW) {
                // removing items while iterating over the set could
                // be bad.
                $expired[] = $anonce;
            }
        }

        foreach ($expired as $anonce) {
            unset($this->nonces[array_search($anonce, $this->nonces)]);
        }

        return count($expired);
    }

    function cleanupAssociations()
    {
        $remove_urls = array();
        $removed_assocs = 0;
        foreach ($this->server_assocs as $server_url => $assocs) {
            list($removed, $remaining) = $assocs->cleanup();
            $removed_assocs += $removed;
            if (!$remaining) {
                $remove_urls[] = $server_url;
            }
        }

        // Remove entries from server_assocs that had none remaining.
        foreach ($remove_urls as $server_url) {
            unset($this->server_assocs[$server_url]);
        }

        return $removed_assocs;
    }
}


code:
<?php

/**
 * Unit tests for the Auth_OpenID_Message implementation.
 */

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

class MessageTest extends PHPUnit_Framework_TestCase {
    function _argTest($ns, $key, $expected = null)
    {
        $a_default = 'a bogus default value';

        $this->assertEquals($this->msg->getArg($ns, $key), $expected);
        if ($expected === null) {
            $this->assertEquals(
                $this->msg->getArg($ns, $key, $a_default), $a_default);
            $result = $this->msg->getArg($ns, $key, Auth_OpenID_NO_DEFAULT);
            $this->assertTrue(Auth_OpenID::isFailure($result));
        } else {
            $this->assertEquals(
                $this->msg->getArg($ns, $key, $a_default), $expected);
            $this->assertEquals(
                $this->msg->getArg($ns, $key, Auth_OpenID_NO_DEFAULT),
                $expected);
        }
    }
}

class Tests_Auth_OpenID_EmptyMessage extends MessageTest {
    function setUp()
    {
        $this->msg = new Auth_OpenID_Message();
    }

    function test_toPostArgs()
    {
        $this->assertEquals($this->msg->toPostArgs(), array());
    }

    function test_toArgs()
    {
        $this->assertEquals($this->msg->toArgs(), array());
    }

    function test_toKVForm()
    {
        $this->assertEquals($this->msg->toKVForm(), '');
    }

    function test_toURLEncoded()
    {
        $this->assertEquals($this->msg->toURLEncoded(), '');
    }

    function test_toURL()
    {
        $base_url = 'http://base.url/';
        $this->assertEquals($this->msg->toURL($base_url), $base_url);
    }

    function test_getOpenID()
    {
        $this->assertEquals($this->msg->getOpenIDNamespace(), null);
    }

    function test_getKeyOpenID()
    {
        $key = $this->msg->getKey(Auth_OpenID_OPENID_NS, 'foo');
        $this->assertTrue(Auth_OpenID::isFailure($key));

        $this->msg->setOpenIDNamespace(Auth_OpenID_OPENID1_NS, false);
        $key = $this->msg->getKey(Auth_OpenID_OPENID_NS, 'foo');
        $this->assertEquals('openid.foo', $key);
    }

    function test_getKeyBARE()
    {
        $this->assertEquals($this->msg->getKey(Auth_OpenID_BARE_NS, 'foo'), 'foo');
    }

    function test_getKeyNS1()
    {
        $this->assertEquals($this->msg->getKey(Auth_OpenID_OPENID1_NS, 'foo'), null);
    }

    function test_getKeyNS2()
    {
        $this->assertEquals($this->msg->getKey(Auth_OpenID_OPENID2_NS, 'foo'), null);
    }

    function test_getKeyNS3()
    {
        $this->assertEquals($this->msg->getKey('urn:nothing-significant', 'foo'),
                               null);
    }

    function test_hasKey()
    {
        $this->assertEquals($this->msg->hasKey(Auth_OpenID_OPENID_NS, 'foo'), false);
    }

    function test_hasKeyBARE()
    {
        $this->assertEquals($this->msg->hasKey(Auth_OpenID_BARE_NS, 'foo'), false);
    }

    function test_hasKeyNS1()
    {
        $this->assertEquals($this->msg->hasKey(Auth_OpenID_OPENID1_NS, 'foo'), false);
    }

    function test_hasKeyNS2()
    {
        $this->assertEquals($this->msg->hasKey(Auth_OpenID_OPENID2_NS, 'foo'), false);
    }

    function test_hasKeyNS3()
    {
        $this->assertEquals($this->msg->hasKey('urn:nothing-significant', 'foo'),
                               false);
    }

    function test_getArg()
    {
        $result = $this->msg->getArg(Auth_OpenID_OPENID_NS, 'foo');
        $this->assertTrue(Auth_OpenID::isFailure($result));
    }

    function test_getArgs()
    {
        $result = $this->msg->getArgs(Auth_OpenID_OPENID_NS);
        $this->assertTrue(Auth_OpenID::isFailure($result));
    }

    function test_getArgsBARE()
    {
        $this->assertEquals($this->msg->getArgs(Auth_OpenID_BARE_NS), array());
    }

    function test_getArgsNS1()
    {
        $this->assertEquals($this->msg->getArgs(Auth_OpenID_OPENID1_NS), array());
    }

    function test_getArgsNS2()
    {
        $this->assertEquals($this->msg->getArgs(Auth_OpenID_OPENID2_NS), array());
    }

    function test_getArgsNS3()
    {
        $this->assertEquals($this->msg->getArgs('urn:nothing-significant'), array());
    }

    function test_updateArgs()
    {
        $result= $this->msg->updateArgs(Auth_OpenID_OPENID_NS,
                                        array('does not' => 'matter'));
        $this->assertTrue(Auth_OpenID::isFailure($result));
    }

    function _test_updateArgsNS($ns)
    {
        $update_args = array(
            'Camper van Beethoven' => 'David Lowery',
            'Magnolia Electric Co.' => 'Jason Molina');

        $this->assertEquals($this->msg->getArgs($ns), array());
        $this->msg->updateArgs($ns, $update_args);
        $this->assertEquals($this->msg->getArgs($ns), $update_args);
    }

    function test_updateArgsBARE()
    {
        $this->_test_updateArgsNS(Auth_OpenID_BARE_NS);
    }

    function test_updateArgsNS1()
    {
        $this->_test_updateArgsNS(Auth_OpenID_OPENID1_NS);
    }

    function test_updateArgsNS2()
    {
        $this->_test_updateArgsNS(Auth_OpenID_OPENID2_NS);
    }

    function test_updateArgsNS3()
    {
        $this->_test_updateArgsNS('urn:nothing-significant');
    }

    function test_setArg()
    {
        $result = $this->msg->setArg(Auth_OpenID_OPENID_NS,
                                     'does not', 'matter');
        $this->assertTrue(Auth_OpenID::isFailure($result));
    }

    function _test_setArgNS($ns)
    {
        $key = 'Camper van Beethoven';
        $value = 'David Lowery';
        $this->assertEquals($this->msg->getArg($ns, $key), null);
        $this->msg->setArg($ns, $key, $value);
        $this->assertEquals($this->msg->getArg($ns, $key), $value);
    }

    function test_setArgBARE()
    {
        $this->_test_setArgNS(Auth_OpenID_BARE_NS);
    }

    function test_setArgNS1()
    {
        $this->_test_setArgNS(Auth_OpenID_OPENID1_NS);
    }

    function test_setArgNS2()
    {
        $this->_test_setArgNS(Auth_OpenID_OPENID2_NS);
    }

    function test_setArgNS3()
    {
        $this->_test_setArgNS('urn:nothing-significant');
    }

    function test_delArg()
    {
        $result = $this->msg->delArg(Auth_OpenID_OPENID_NS, 'does not');
        $this->assertTrue(Auth_OpenID::isFailure($result));
    }

    function _test_delArgNS($ns)
    {
        $key = 'Camper van Beethoven';
        $this->assertEquals($this->msg->delArg($ns, $key), false);
    }

    function test_delArgBARE()
    {
        $this->_test_delArgNS(Auth_OpenID_BARE_NS);
    }

    function test_delArgNS1()
    {
        $this->_test_delArgNS(Auth_OpenID_OPENID1_NS);
    }

    function test_delArgNS2()
    {
        $this->_test_delArgNS(Auth_OpenID_OPENID2_NS);
    }

    function test_delArgNS3()
    {
        $this->_test_delArgNS('urn:nothing-significant');
    }

    function test_isOpenID1()
    {
        $this->assertFalse($this->msg->isOpenID1());
    }

    function test_isOpenID2()
    {
        $this->assertFalse($this->msg->isOpenID2());
    }

    function test_args()
    {
        $this->_argTest(Auth_OpenID_BARE_NS, 'foo');
        $this->_argTest(Auth_OpenID_OPENID1_NS, 'foo');
        $this->_argTest(Auth_OpenID_OPENID2_NS, 'foo');
        $this->_argTest('urn:nothing-significant', 'foo');
    }
}

class Tests_Auth_OpenID_OpenID1Message extends MessageTest {
    function setUp()
    {
        $this->msg = Auth_OpenID_Message::fromPostArgs(array('openid.mode' => 'error',
                                                             'openid.error' => 'unit test'));
    }

    function test_toPostArgs()
    {
        $this->assertEquals($this->msg->toPostArgs(),
                               array('openid.mode' => 'error',
                                     'openid.error' => 'unit test'));
    }

    function test_toArgs()
    {
        $this->assertEquals($this->msg->toArgs(),
                               array('mode' => 'error',
                                     'error' => 'unit test'));
    }

    function test_toKVForm()
    {
        $this->assertEquals($this->msg->toKVForm(),
                            "error:unit test\nmode:error\n");
    }

    function test_toURLEncoded()
    {
        $this->assertEquals($this->msg->toURLEncoded(),
                               'openid.error=unit+test&openid.mode=error');
    }

    function test_toURL()
    {
        $base_url = 'http://base.url/';
        $actual = $this->msg->toURL($base_url);
        $actual_base = substr($actual, 0, strlen($base_url));
        $this->assertEquals($actual_base, $base_url);
        $this->assertEquals($actual[strlen($base_url)], '?');
        $query = substr($actual, strlen($base_url) + 1);

        $parsed = Auth_OpenID::parse_str($query);

        $this->assertEquals($parsed, array('openid.mode' => 'error',
                                           'openid.error' => 'unit test'));
    }

    function test_getOpenID()
    {
        $this->assertEquals($this->msg->getOpenIDNamespace(),
                               Auth_OpenID_OPENID1_NS);
        $this->assertTrue($this->msg->namespaces->isImplicit(Auth_OpenID_OPENID1_NS));
    }

    function test_getKeyOpenID()
    {
        $this->assertEquals($this->msg->getKey(Auth_OpenID_OPENID_NS, 'mode'),
                               'openid.mode');
    }

    function test_getKeyBARE()
    {
        $this->assertEquals($this->msg->getKey(Auth_OpenID_BARE_NS, 'mode'), 'mode');
    }

    function test_getKeyNS1()
    {
        $this->assertEquals(
                               $this->msg->getKey(Auth_OpenID_OPENID1_NS, 'mode'), 'openid.mode');
    }

    function test_getKeyNS2()
    {
        $this->assertEquals($this->msg->getKey(Auth_OpenID_OPENID2_NS, 'mode'), null);
    }

    function test_getKeyNS3()
    {
        $this->assertEquals(
                               $this->msg->getKey('urn:nothing-significant', 'mode'), null);
    }

    function test_hasKey()
    {
        $this->assertEquals($this->msg->hasKey(Auth_OpenID_OPENID_NS, 'mode'), true);
    }

    function test_hasKeyBARE()
    {
        $this->assertEquals($this->msg->hasKey(Auth_OpenID_BARE_NS, 'mode'), false);
    }

    function test_hasKeyNS1()
    {
        $this->assertEquals($this->msg->hasKey(Auth_OpenID_OPENID1_NS, 'mode'), true);
    }

    function test_hasKeyNS2()
    {
        $this->assertEquals(
                               $this->msg->hasKey(Auth_OpenID_OPENID2_NS, 'mode'), false);
    }

    function test_hasKeyNS3()
    {
        $this->assertEquals(
                               $this->msg->hasKey('urn:nothing-significant', 'mode'), false);
    }

    function test_getArgs()
    {
        $this->assertEquals($this->msg->getArgs(Auth_OpenID_OPENID_NS),
                               array('mode' => 'error',
                                     'error' => 'unit test'));
    }

    function test_getArgsBARE()
    {
        $this->assertEquals($this->msg->getArgs(Auth_OpenID_BARE_NS), array());
    }

    function test_getArgsNS1()
    {
        $this->assertEquals($this->msg->getArgs(Auth_OpenID_OPENID1_NS),
                               array('mode' => 'error',
                                     'error' => 'unit test'));
    }

    function test_getArgsNS2()
    {
        $this->assertEquals($this->msg->getArgs(Auth_OpenID_OPENID2_NS), array());
    }

    function test_getArgsNS3()
    {
        $this->assertEquals($this->msg->getArgs('urn:nothing-significant'), array());
    }

    function _test_updateArgsNS($ns, $before=null)
    {
        if ($before === null) {
            $before = array();
        }

        $update_args = array(
                             'Camper van Beethoven' => 'David Lowery',
                             'Magnolia Electric Co.' => 'Jason Molina');

        $this->assertEquals($this->msg->getArgs($ns), $before);
        $this->msg->updateArgs($ns, $update_args);
        $after = $before;
        $after = array_merge($after, $update_args);
        $this->assertEquals($this->msg->getArgs($ns), $after);
    }

    function test_updateArgs()
    {
        $this->_test_updateArgsNS(Auth_OpenID_OPENID_NS,
                                  array('mode' => 'error', 'error' => 'unit test'));
    }

    function test_updateArgsBARE()
    {
        $this->_test_updateArgsNS(Auth_OpenID_BARE_NS);
    }

    function test_updateArgsNS1()
    {
        $this->_test_updateArgsNS(Auth_OpenID_OPENID1_NS,
                                  array('mode' => 'error', 'error' => 'unit test'));
    }

    function test_updateArgsNS2()
    {
        $this->_test_updateArgsNS(Auth_OpenID_OPENID2_NS);
    }

    function test_updateArgsNS3()
    {
        $this->_test_updateArgsNS('urn:nothing-significant');
    }

    function _test_setArgNS($ns)
    {
        $key = 'Camper van Beethoven';
        $value = 'David Lowery';
        $this->assertEquals($this->msg->getArg($ns, $key), null);
        $this->msg->setArg($ns, $key, $value);
        $this->assertEquals($this->msg->getArg($ns, $key), $value);
    }

    function test_setArg()
    {
        $this->_test_setArgNS(Auth_OpenID_OPENID_NS);
    }

    function test_setArgBARE()
    {
        $this->_test_setArgNS(Auth_OpenID_BARE_NS);
    }

    function test_setArgNS1()
    {
        $this->_test_setArgNS(Auth_OpenID_OPENID1_NS);
    }

    function test_setArgNS2()
    {
        $this->_test_setArgNS(Auth_OpenID_OPENID2_NS);
    }

    function test_setArgNS3()
    {
        $this->_test_setArgNS('urn:nothing-significant');
    }

    function _test_delArgNS($ns)
    {
        $key = 'Camper van Beethoven';
        $value = 'David Lowery';

        $this->assertEquals($this->msg->delArg($ns, $key), false);
        $this->msg->setArg($ns, $key, $value);
        $this->assertEquals($this->msg->getArg($ns, $key), $value);
        $this->msg->delArg($ns, $key);
        $this->assertEquals($this->msg->getArg($ns, $key), null);
    }

    function test_delArg()
    {
        $this->_test_delArgNS(Auth_OpenID_OPENID_NS);
    }

    function test_delArgBARE()
    {
        $this->_test_delArgNS(Auth_OpenID_BARE_NS);
    }

    function test_delArgNS1()
    {
        $this->_test_delArgNS(Auth_OpenID_OPENID1_NS);
    }

    function test_delArgNS2()
    {
        $this->_test_delArgNS(Auth_OpenID_OPENID2_NS);
    }

    function test_delArgNS3()
    {
        $this->_test_delArgNS('urn:nothing-significant');
    }

    function test_isOpenID1()
    {
        $this->assertTrue($this->msg->isOpenID1());
    }

    function test_isOpenID2()
    {
        $this->assertFalse($this->msg->isOpenID2());
    }

    function test_args()
    {
        $this->_argTest(Auth_OpenID_BARE_NS, 'mode');
        $this->_argTest(Auth_OpenID_OPENID_NS, 'mode', 'error');
        $this->_argTest(Auth_OpenID_OPENID1_NS, 'mode', 'error');
        $this->_argTest(Auth_OpenID_OPENID2_NS, 'mode');
        $this->_argTest('urn:nothing-significant', 'mode');
    }
}

class Tests_Auth_OpenID_OpenID1ExplicitMessage extends PHPUnit_Framework_TestCase {
    function setUp()
    {
        $this->msg = Auth_OpenID_Message::fromPostArgs(array('openid.mode' => 'error',
                                                             'openid.error' => 'unit test',
                                                             'openid.ns' => Auth_OpenID_OPENID1_NS));
    }

    function test_isOpenID1()
    {
        $this->assertTrue($this->msg->isOpenID1());
        $this->assertFalse(
            $this->msg->namespaces->isImplicit(Auth_OpenID_OPENID1_NS));
    }

    function test_isOpenID2()
    {
        $this->assertFalse($this->msg->isOpenID2());
    }

    function test_toPostArgs()
    {
        $this->assertEquals($this->msg->toPostArgs(),
                               array('openid.mode' => 'error',
                                     'openid.error' => 'unit test',
                                     'openid.ns' => Auth_OpenID_OPENID1_NS));
    }

    function test_toArgs()
    {
        $this->assertEquals($this->msg->toArgs(),
                               array('mode' => 'error',
                                     'error' => 'unit test',
                                     'ns' => Auth_OpenID_OPENID1_NS));
    }

    function test_toKVForm()
    {
        $this->assertEquals($this->msg->toKVForm(),
                            "error:unit test\nmode:error\nns:".
                            Auth_OpenID_OPENID1_NS."\n");
    }

    function test_toURLEncoded()
    {
        $this->assertEquals($this->msg->toURLEncoded(),
                               'openid.error=unit+test&openid.mode=error&openid.ns=http%3A%2F%2Fopenid.net%2Fsignon%2F1.0');
    }

    function test_toURL()
    {
        $base_url = 'http://base.url/';
        $actual = $this->msg->toURL($base_url);
        $actual_base = substr($actual, 0, strlen($base_url));
        $this->assertEquals($actual_base, $base_url);
        $this->assertEquals($actual[strlen($base_url)], '?');
        $query = substr($actual, strlen($base_url) + 1);

        $parsed = Auth_OpenID::parse_str($query);

        $this->assertEquals($parsed, array('openid.mode' => 'error',
                                           'openid.error' => 'unit test',
                                           'openid.ns' => Auth_OpenID_OPENID1_NS));
    }
}

class Tests_Auth_OpenID_OpenID2Message extends MessageTest {
    function setUp()
    {
        $this->msg = Auth_OpenID_Message::fromPostArgs(array('openid.mode' => 'error',
                                                             'openid.error' => 'unit test',
                                                             'openid.ns' => Auth_OpenID_OPENID2_NS));
        $this->msg->setArg(Auth_OpenID_BARE_NS, "xey", "value");
    }

    function test_toPostArgs()
    {
        $this->assertEquals($this->msg->toPostArgs(),
                            array('openid.mode' => 'error',
                                  'openid.error' => 'unit test',
                                  'openid.ns' => Auth_OpenID_OPENID2_NS,
                                  'xey' => 'value'));
    }

    function test_toArgs()
    {
        // This method can't tolerate BARE_NS.
        $this->msg->delArg(Auth_OpenID_BARE_NS, "xey");
        $this->assertEquals($this->msg->toArgs(),
                               array('mode' => 'error',
                                     'error' => 'unit test',
                                     'ns' => Auth_OpenID_OPENID2_NS));
    }

    function test_toKVForm()
    {
        // Can't tolerate BARE_NS in kvform
        $this->msg->delArg(Auth_OpenID_BARE_NS, "xey");
        $this->assertEquals($this->msg->toKVForm(),
                               sprintf("error:unit test\nmode:error\nns:%s\n",
                                       Auth_OpenID_OPENID2_NS));
    }

    function _test_urlencoded($s)
    {
        $expected = 'openid.error=unit+test&openid.mode=error&' .
            'openid.ns=%s&xey=value';

        $expected = sprintf($expected, urlencode(Auth_OpenID_OPENID2_NS));
        $this->assertEquals($s, $expected);
    }

    function test_toURLEncoded()
    {
        $this->_test_urlencoded($this->msg->toURLEncoded());
    }

    function test_toURL()
    {
        $base_url = 'http://base.url/';
        $actual = $this->msg->toURL($base_url);
        $actual_base = substr($actual, 0, strlen($base_url));

        $this->assertEquals($actual_base, $base_url);
        $this->assertEquals($actual[strlen($base_url)], '?');
        $query = substr($actual, strlen($base_url) + 1);
        $this->_test_urlencoded($query);
    }

    function test_getOpenID()
    {
        $this->assertEquals($this->msg->getOpenIDNamespace(),
                               Auth_OpenID_OPENID2_NS);
    }

    function test_getKeyOpenID()
    {
        $this->assertEquals($this->msg->getKey(Auth_OpenID_OPENID_NS, 'mode'),
                               'openid.mode');
    }

    function test_getKeyBARE()
    {
        $this->assertEquals($this->msg->getKey(Auth_OpenID_BARE_NS, 'mode'), 'mode');
    }

    function test_getKeyNS1()
    {
        $this->assertEquals(
                               $this->msg->getKey(Auth_OpenID_OPENID1_NS, 'mode'), null);
    }

    function test_getKeyNS2()
    {
        $this->assertEquals(
                               $this->msg->getKey(Auth_OpenID_OPENID2_NS, 'mode'), 'openid.mode');
    }

    function test_getKeyNS3()
    {
        $this->assertEquals(
                               $this->msg->getKey('urn:nothing-significant', 'mode'), null);
    }

    function test_hasKeyOpenID()
    {
        $this->assertEquals($this->msg->hasKey(Auth_OpenID_OPENID_NS, 'mode'), true);
    }

    function test_hasKeyBARE()
    {
        $this->assertEquals($this->msg->hasKey(Auth_OpenID_BARE_NS, 'mode'), false);
    }

    function test_hasKeyNS1()
    {
        $this->assertEquals(
                               $this->msg->hasKey(Auth_OpenID_OPENID1_NS, 'mode'), false);
    }

    function test_hasKeyNS2()
    {
        $this->assertEquals(
                               $this->msg->hasKey(Auth_OpenID_OPENID2_NS, 'mode'), true);
    }

    function test_hasKeyNS3()
    {
        $this->assertEquals(
                               $this->msg->hasKey('urn:nothing-significant', 'mode'), false);
    }

    function test_getArgsOpenID()
    {
        $this->assertEquals($this->msg->getArgs(Auth_OpenID_OPENID_NS),
                               array('mode' => 'error',
                                     'error' => 'unit test'));
    }

    function test_getArgsBARE()
    {
        $this->assertEquals($this->msg->getArgs(Auth_OpenID_BARE_NS),
                               array('xey' =>  'value'));
    }

    function test_getArgsNS1()
    {
        $this->assertEquals($this->msg->getArgs(Auth_OpenID_OPENID1_NS), array());
    }

    function test_getArgsNS2()
    {
        $this->assertEquals($this->msg->getArgs(Auth_OpenID_OPENID2_NS),
                               array('mode' => 'error',
                                     'error' => 'unit test'));
    }

    function test_getArgsNS3()
    {
        $this->assertEquals($this->msg->getArgs('urn:nothing-significant'), array());
    }

    function _test_updateArgsNS($ns, $before=null)
    {
        if ($before === null) {
            $before = array();
        }

        $update_args = array(
            'Camper van Beethoven' => 'David Lowery',
            'Magnolia Electric Co.' => 'Jason Molina');

        $this->assertEquals($this->msg->getArgs($ns), $before);
        $this->msg->updateArgs($ns, $update_args);
        $after = $before;
        $after = array_merge($after, $update_args);
        $this->assertEquals($this->msg->getArgs($ns), $after);
    }

    function test_updateArgsOpenID()
    {
        $this->_test_updateArgsNS(Auth_OpenID_OPENID_NS,
                                  array('mode' => 'error', 'error' => 'unit test'));
    }

    function test_updateArgsBARE()
    {
        $this->_test_updateArgsNS(Auth_OpenID_BARE_NS,
                                  array('xey' => 'value'));
    }

    function test_updateArgsNS1()
    {
        $this->_test_updateArgsNS(Auth_OpenID_OPENID1_NS);
    }

    function test_updateArgsNS2()
    {
        $this->_test_updateArgsNS(Auth_OpenID_OPENID2_NS,
                                  array('mode' => 'error', 'error' => 'unit test'));
    }

    function test_updateArgsNS3()
    {
        $this->_test_updateArgsNS('urn:nothing-significant');
    }

    function _test_setArgNS($ns)
    {
        $key = 'Camper van Beethoven';
        $value = 'David Lowery';
        $this->assertEquals($this->msg->getArg($ns, $key), null);
        $this->msg->setArg($ns, $key, $value);
        $this->assertEquals($this->msg->getArg($ns, $key), $value);
    }

    function test_setArgOpenID()
    {
        $this->_test_setArgNS(Auth_OpenID_OPENID_NS);
    }

    function test_setArgBARE()
    {
        $this->_test_setArgNS(Auth_OpenID_BARE_NS);
    }

    function test_setArgNS1()
    {
        $this->_test_setArgNS(Auth_OpenID_OPENID1_NS);
    }

    function test_setArgNS2()
    {
        $this->_test_setArgNS(Auth_OpenID_OPENID2_NS);
    }

    function test_setArgNS3()
    {
        $this->_test_setArgNS('urn:nothing-significant');
    }

    function test_badAlias()
    {
        // Make sure dotted aliases and OpenID protocol fields are not
        // allowed as namespace aliases.

        global $Auth_OpenID_OPENID_PROTOCOL_FIELDS;

        $all = array_merge($Auth_OpenID_OPENID_PROTOCOL_FIELDS, array('dotted.alias'));

        foreach ($all as $f) {
            $args = array(sprintf('openid.ns.%s', $f) => 'blah',
                          sprintf('openid.%s.foo', $f) =>  'test');

            // .fromPostArgs covers .fromPostArgs, .fromOpenIDArgs,
            // ._fromOpenIDArgs, and .fromOpenIDArgs (since it calls
            // .fromPostArgs).  Python code raises AssertionError, but
            // we usually return null for bad things in PHP.
            $this->assertEquals($this->msg->fromPostArgs($args), null);
        }
    }

    function _test_delArgNS($ns)
    {
        $key = 'Camper van Beethoven';
        $value = 'David Lowery';

        $this->assertEquals($this->msg->delArg($ns, $key), false);
        $this->msg->setArg($ns, $key, $value);
        $this->assertEquals($this->msg->getArg($ns, $key), $value);
        $this->msg->delArg($ns, $key);
        $this->assertEquals($this->msg->getArg($ns, $key), null);
    }

    function test_delArgOpenID()
    {
        $this->_test_delArgNS(Auth_OpenID_OPENID_NS);
    }

    function test_delArgBARE()
    {
        $this->_test_delArgNS(Auth_OpenID_BARE_NS);
    }

    function test_delArgNS1()
    {
        $this->_test_delArgNS(Auth_OpenID_OPENID1_NS);
    }

    function test_delArgNS2()
    {
        $this->_test_delArgNS(Auth_OpenID_OPENID2_NS);
    }

    function test_delArgNS3()
    {
        $this->_test_delArgNS('urn:nothing-significant');
    }

    function test_overwriteExtensionArg()
    {
        $ns = 'urn:unittest_extension';
        $key = 'mykey';
        $value_1 = 'value_1';
        $value_2 = 'value_2';

        $this->msg->setArg($ns, $key, $value_1);
        $this->assertTrue($this->msg->getArg($ns, $key) == $value_1);
        $this->msg->setArg($ns, $key, $value_2);
        $this->assertTrue($this->msg->getArg($ns, $key) == $value_2);
    }

    function test_argList()
    {
        $this->assertEquals($this->msg->fromPostArgs(array('arg' => array(1, 2, 3))),
                            null);
    }

    function test_isOpenID1()
    {
        $this->assertFalse($this->msg->isOpenID1());
    }

    function test_isOpenID2()
    {
        $this->assertTrue($this->msg->isOpenID2());
    }

    function test_args()
    {
        $this->_argTest(Auth_OpenID_BARE_NS, 'mode');
        $this->_argTest(Auth_OpenID_OPENID_NS, 'mode', 'error');
        $this->_argTest(Auth_OpenID_OPENID1_NS, 'mode');
        $this->_argTest(Auth_OpenID_OPENID2_NS, 'mode', 'error');
        $this->_argTest('urn:nothing-significant', 'mode');
    }
}

class Tests_Auth_OpenID_GeneralMessageTest extends PHPUnit_Framework_TestCase {
    function setUp()
    {
        $this->postargs = array(
            'openid.ns' => Auth_OpenID_OPENID2_NS,
            'openid.mode' => 'checkid_setup',
            'openid.identity' => 'http://bogus.example.invalid:port/',
            'openid.assoc_handle' => 'FLUB',
            'openid.return_to' => 'Neverland');

        $this->action_url = 'scheme://host:port/path?query';

        $this->form_tag_attrs = array(
            'company' => 'janrain',
            'class' => 'fancyCSS');

        $this->submit_text = 'GO!';

        // Expected data regardless of input

        $this->required_form_attrs = array(
            'accept-charset' => 'UTF-8',
            'enctype' => 'application/x-www-form-urlencoded',
            'method' => 'post');
    }

    function _checkForm($html, $message_, $action_url,
                        $form_tag_attrs, $submit_text)
    {
        $parser = Auth_Yadis_getXMLParser();

        // Parse HTML source
        $this->assertTrue($parser->init($html, array()));

        // Get root element
        $form = $parser->evalXPath('/form[1]');
        $this->assertTrue(count($form) == 1);
        $form = $form[0];

        // Check required form attributes
        $form_attrs = $parser->attributes($form);
        foreach ($this->required_form_attrs as $k => $v) {
            $this->assertTrue($form_attrs[$k] == $v);
        }

        // Check extra form attributes
        foreach ($form_tag_attrs as $k => $v) {
            // Skip attributes that already passed the required
            // attribute check, since they should be ignored by the
            // form generation code.
            if (in_array($k, array_keys($this->required_form_attrs))) {
                continue;
            }

            $this->assertTrue($form_attrs[$k] == $v,
                              "Form attr $k is ".$form_attrs[$k]." (expected $v)");
        }

        // Check hidden fields against post args
        $hiddens = array();
        $input_elements = $parser->evalXPath('input', $form);
        foreach ($input_elements as $e) {
            $attrs = $parser->attributes($e);
            if (strtoupper($attrs['type']) == 'HIDDEN') {
                $hiddens[] = $e;
            }
        }

        // For each post arg, make sure there is a hidden with that
        // value.  Make sure there are no other hiddens.
        $postargs = $message_->toPostArgs();
        foreach ($postargs as $name => $value) {
            $found = false;

            foreach ($hiddens as $e) {
                $attrs = $parser->attributes($e);
                if ($attrs['name'] == $name) {
                    $this->assertTrue($attrs['value'] == $value);
                    $found = true;
                    break;
                }
            }

            if (!$found) {
                $this->fail("Post arg $name not found in form");
            }
        }

        $keys = array_keys($postargs);
        foreach ($hiddens as $e) {
            $attrs = $parser->attributes($e);
            $this->assertTrue(in_array($attrs['name'], $keys));
        }

        // Check action URL
        $this->assertTrue($form_attrs['action'] == $action_url);

        // Check submit text
        $submits = array();
        foreach ($input_elements as $e) {
            $attrs = $parser->attributes($e);
            if (strtoupper($attrs['type']) == 'SUBMIT') {
                $submits[] = $e;
            }
        }

        $this->assertTrue(count($submits) == 1);

        $attrs = $parser->attributes($submits[0]);
        $this->assertTrue($attrs['value'] == $submit_text);
    }

    function test_toFormMarkup()
    {
        $m = Auth_OpenID_Message::fromPostArgs($this->postargs);
        $html = $m->toFormMarkup($this->action_url, $this->form_tag_attrs,
                                 $this->submit_text);
        $this->_checkForm($html, $m, $this->action_url,
                          $this->form_tag_attrs, $this->submit_text);
    }

    function test_overrideMethod()
    {
        // Be sure that caller cannot change form method to GET.
        $m = Auth_OpenID_Message::fromPostArgs($this->postargs);

        $tag_attrs = $this->form_tag_attrs;
        $tag_attrs['method'] = 'GET';

        $html = $m->toFormMarkup($this->action_url, $this->form_tag_attrs,
                                 $this->submit_text);
        $this->_checkForm($html, $m, $this->action_url,
                          $this->form_tag_attrs, $this->submit_text);
    }

    function test_overrideRequired()
    {
        // Be sure that caller CANNOT change the form charset for
        // encoding type.
        $m = Auth_OpenID_Message::fromPostArgs($this->postargs);

        $tag_attrs = $this->form_tag_attrs;
        $tag_attrs['accept-charset'] = 'UCS4';
        $tag_attrs['enctype'] = 'invalid/x-broken';

        $html = $m->toFormMarkup($this->action_url, $tag_attrs,
                                 $this->submit_text);
        $this->_checkForm($html, $m, $this->action_url,
                          $tag_attrs, $this->submit_text);
    }

    function test_setOpenIDNamespace_invalid()
    {
        $m = new Auth_OpenID_Message();
        $invalid_things = array(
            // Empty string is not okay here.
            '',
            // Good guess!  But wrong.
            'http://openid.net/signon/2.0',
            // What?
            'http://specs%\\\r2Eopenid.net/auth/2.0',
            // Too much escapings!
            'http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0',
            // This is a Type URI, not a openid.ns value.
            'http://specs.openid.net/auth/2.0/signon',
            );

        foreach ($invalid_things as $x) {
            $this->assertTrue($m->setOpenIDNamespace($x, true) === false);
        }
    }

    function test_isOpenID1()
    {
        $v1_namespaces = array(
            // Yes, there are two of them.
            'http://openid.net/signon/1.1',
            'http://openid.net/signon/1.0',
                               );

        foreach ($v1_namespaces as $ns) {
            $m = new Auth_OpenID_Message($ns);
            $this->assertTrue($m->isOpenID1(),
                              "$ns not recognized as OpenID 1");
            $this->assertEquals($ns, $m->getOpenIDNamespace());
            $this->assertTrue($m->namespaces->isImplicit($ns));
        }
    }

    function test_isOpenID2()
    {
        $ns = 'http://specs.openid.net/auth/2.0';
        $m = new Auth_OpenID_Message($ns);
        $this->assertTrue($m->isOpenID2());
        $this->assertFalse(
            $m->namespaces->isImplicit(Auth_OpenID_NULL_NAMESPACE));
        $this->assertEquals($ns, $m->getOpenIDNamespace());
    }

    function test_setOpenIDNamespace_explicit()
    {
        $m = new Auth_OpenID_Message();
        $m->setOpenIDNamespace(Auth_OpenID_THE_OTHER_OPENID1_NS, false);
        $this->assertFalse($m->namespaces->isImplicit(
            Auth_OpenID_THE_OTHER_OPENID1_NS));
    }

    function test_setOpenIDNamespace_implicit()
    {
        $m = new Auth_OpenID_Message();
        $m->setOpenIDNamespace(Auth_OpenID_THE_OTHER_OPENID1_NS, true);
        $this->assertTrue(
            $m->namespaces->isImplicit(Auth_OpenID_THE_OTHER_OPENID1_NS));
    }

    function test_explicitOpenID11NSSerialzation()
    {
        $m = new Auth_OpenID_Message();
        $m->setOpenIDNamespace(Auth_OpenID_THE_OTHER_OPENID1_NS, false);

        $post_args = $m->toPostArgs();
        $this->assertEquals($post_args,
                            array('openid.ns' =>
                                  Auth_OpenID_THE_OTHER_OPENID1_NS));
    }

    function test_fromPostArgs_ns11()
    {
        // An example of the stuff that some Drupal installations send us,
        // which includes openid.ns but is 1.1.
        $query = array(
            'openid.assoc_handle' => '',
            'openid.claimed_id' => 'http://foobar.invalid/',
            'openid.identity' => 'http://foobar.myopenid.com',
            'openid.mode' => 'checkid_setup',
            'openid.ns' => 'http://openid.net/signon/1.1',
            'openid.ns.sreg' => 'http://openid.net/extensions/sreg/1.1',
            'openid.return_to' => 'http://drupal.invalid/return_to',
            'openid.sreg.required' => 'nickname,email',
            'openid.trust_root' => 'http://drupal.invalid',
            );
        $m = Auth_OpenID_Message::fromPostArgs($query);
        $this->assertTrue($m->isOpenID1());
    }
}

class Tests_Auth_OpenID_NamespaceMap extends PHPUnit_Framework_TestCase {
    function test_onealias()
    {
        $nsm = new Auth_OpenID_NamespaceMap();
        $uri = 'http://example.com/foo';
        $alias = "foo";
        $nsm->addAlias($uri, $alias);
        $this->assertTrue($nsm->getNamespaceURI($alias) == $uri);
        $this->assertTrue($nsm->getAlias($uri) == $alias);
    }

    function test_iteration()
    {
        $nsm = new Auth_OpenID_NamespaceMap();
        $uripat = 'http://example.com/foo%d';

        $nsm->add(sprintf($uripat, 0));

        for ($n = 1; $n < 23; $n++) {
            $this->assertTrue($nsm->contains(sprintf($uripat, $n - 1)));
            $this->assertTrue($nsm->isDefined(sprintf($uripat, $n - 1)));
            $nsm->add(sprintf($uripat, $n));
        }

        foreach ($nsm->iteritems() as $pair) {
            list($uri, $alias) = $pair;
            $this->assertTrue('ext'.substr($uri, 22) == $alias);
        }

        $it = $nsm->iterAliases();
        $this->assertTrue(count($it) == 23);

        $it = $nsm->iterNamespaceURIs();
        $this->assertTrue(count($it) == 23);
    }
}

class Tests_Auth_OpenID_Message extends PHPUnit_Framework_TestCase {
}

global $Tests_Auth_OpenID_Message_other;
$Tests_Auth_OpenID_Message_other = array(
                                         new Tests_Auth_OpenID_EmptyMessage(),
                                         new Tests_Auth_OpenID_OpenID1Message(),
                                         new Tests_Auth_OpenID_OpenID2Message(),
                                         new Tests_Auth_OpenID_NamespaceMap(),
                                         new Tests_Auth_OpenID_OpenID1ExplicitMessage(),
                                         new Tests_Auth_OpenID_GeneralMessageTest()
                                         );


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";

/**
 * A consumer whose _requestAssocation will return predefined results
 * instead of trying to actually perform association requests.
 */
class ErrorRaisingConsumer extends Auth_OpenID_GenericConsumer {
    // The list of objects to be returned by successive calls to
    // _requestAssocation.  Each call will pop the first element from
    // this list and return it to _negotiateAssociation.  If the
    // element is a Message object, it will be wrapped in a
    // ServerErrorContainer exception.  Otherwise it will be returned
    // as-is.
    var $return_messages = array();

    function _requestAssociation($endpoint, $assoc_type, $session_type)
    {
        $m = array_pop($this->return_messages);
        if (is_a($m, 'Auth_OpenID_Message')) {
            return Auth_OpenID_ServerErrorContainer::fromMessage($m);
        } else if (Auth_OpenID::isFailure($m)) {
            return $m;
        } else {
            return $m;
        }
    }
}

/**
 * Test the session type negotiation behavior of an OpenID 2 consumer.
 */
class TestOpenID2SessionNegotiation extends PHPUnit_Framework_TestCase {
    function setUp()
    {
        $dumb = null;
        $this->consumer = new ErrorRaisingConsumer($dumb);
        $this->endpoint = new Auth_OpenID_ServiceEndpoint();
        $this->endpoint->type_uris = array(Auth_OpenID_TYPE_2_0);
        $this->endpoint->server_url = 'bogus';
    }

    /**
     * Test the case where the response to an associate request is a
     * server error or is otherwise undecipherable.
     */
    function testBadResponse()
    {
        $this->consumer->return_messages = array(
           new Auth_OpenID_Message($this->endpoint->preferredNamespace()));
        $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);
        // $this->failUnlessLogMatches('Server error when requesting an association')
    }

    /**
     * Test the case where the response to an associate request is a
     * a failure response object.
     */
    function testBadResponseWithFailure()
    {
        $this->consumer->return_messages = array(
             new Auth_OpenID_FailureResponse($this->endpoint));
        $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);
        // $this->failUnlessLogMatches('Server error when requesting an association')
    }

    /**
     * Test the case where the association type (assoc_type) returned
     * in an unsupported-type response is absent.
     */
    function testEmptyAssocType()
    {
        $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', null);
        $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', 'new-session-type');

        $this->consumer->return_messages = array($msg);
        $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);

        // $this->failUnlessLogMatches('Unsupported association type',
        //                           'Server responded with unsupported association ' +
        //                           'session but did not supply a fallback.')
    }

    /**
     * Test the case where the session type (session_type) returned in
     * an unsupported-type response is absent.
     */
    function testEmptySessionType()
    {
        $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', 'new-assoc-type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', null);

        $this->consumer->return_messages = array($msg);
        $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);

        // $this->failUnlessLogMatches('Unsupported association type',
        //                           'Server responded with unsupported association ' +
        //                           'session but did not supply a fallback.')
    }

    /**
     * Test the case where an unsupported-type response specifies a
     * preferred (assoc_type, session_type) combination that is not
     * allowed by the consumer's SessionNegotiator.
     */
    function testNotAllowed()
    {
        $allowed_types = array();

        $negotiator = new Auth_OpenID_SessionNegotiator($allowed_types);
        $this->consumer->negotiator = $negotiator;

        $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', 'not-allowed');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', 'not-allowed');

        $this->consumer->return_messages = array($msg);
        $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);

        // $this->failUnlessLogMatches('Unsupported association type',
        //                       'Server sent unsupported session/association type:')
    }

    /**
     * Test the case where an unsupported-type response triggers a
     * retry to get an association with the new preferred type.
     */
    function testUnsupportedWithRetry()
    {
        $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', 'HMAC-SHA1');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', 'DH-SHA1');

        $assoc = new Auth_OpenID_Association(
                   'handle', 'secret', 'issued', 10000, 'HMAC-SHA1');

        $this->consumer->return_messages = array($msg, $assoc);
        $this->assertTrue($this->consumer->_negotiateAssociation($this->endpoint) === $assoc);

        // $this->failUnlessLogMatches('Unsupported association type');
    }

    /**
     * Test the case where an unsupported-typ response triggers a
     * retry, but the retry fails and None is returned instead.
     */
    function testUnsupportedWithRetryAndFail()
    {
        $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', 'HMAC-SHA1');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', 'DH-SHA1');

        $this->consumer->return_messages = array($msg,
           new Auth_OpenID_Message($this->endpoint->preferredNamespace()));

        $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);

        // $this->failUnlessLogMatches('Unsupported association type',
        //                           'Server %s refused' % ($this->endpoint.server_url))
    }

    /**
     * Test the valid case, wherein an association is returned on the
     * first attempt to get one.
     */
    function testValid()
    {
        $assoc = new Auth_OpenID_Association(
                   'handle', 'secret', 'issued', 10000, 'HMAC-SHA1');

        $this->consumer->return_messages = array($assoc);
        $this->assertTrue($this->consumer->_negotiateAssociation($this->endpoint) === $assoc);
        // $this->failUnlessLogEmpty()
    }
}

/**
 * Tests for the OpenID 1 consumer association session behavior.  See
 * the docs for TestOpenID2SessionNegotiation.  Notice that this class
 * is not a subclass of the OpenID 2 tests.  Instead, it uses many of
 * the same inputs but inspects the log messages logged with
 * oidutil.log.  See the calls to $this->failUnlessLogMatches.  Some
 * of these tests pass openid2-style messages to the openid 1
 * association processing logic to be sure it ignores the extra data.
 */
class TestOpenID1SessionNegotiation extends PHPUnit_Framework_TestCase {
    function setUp()
    {
        $dumb = null;
        $this->consumer = new ErrorRaisingConsumer($dumb);

        $this->endpoint = new Auth_OpenID_ServiceEndpoint();
        $this->endpoint->type_uris = array(Auth_OpenID_OPENID1_NS);
        $this->endpoint->server_url = 'bogus';
    }

    function testBadResponse()
    {
        $this->consumer->return_messages =
            array(new Auth_OpenID_Message($this->endpoint->preferredNamespace()));
        $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);
        // $this->failUnlessLogMatches('Server error when requesting an association')
    }

    function testEmptyAssocType()
    {
        $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', null);
        $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', 'new-session-type');

        $this->consumer->return_messages = array($msg);
        $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);

        // $this->failUnlessLogMatches('Server error when requesting an association')
    }

    function testEmptySessionType()
    {
        $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', 'new-assoc-type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', null);

        $this->consumer->return_messages = array($msg);
        $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);

        // $this->failUnlessLogMatches('Server error when requesting an association');
    }

    function testNotAllowed()
    {
        $allowed_types = array();

        $negotiator = new Auth_OpenID_SessionNegotiator($allowed_types);
        $this->consumer->negotiator = $negotiator;

        $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', 'not-allowed');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', 'not-allowed');

        $this->consumer->return_messages = array($msg);
        $this->assertEquals($this->consumer->_negotiateAssociation($this->endpoint), null);

        // $this->failUnlessLogMatches('Server error when requesting an association')
    }

    function testUnsupportedWithRetry()
    {
        $msg = new Auth_OpenID_Message($this->endpoint->preferredNamespace());
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error', 'Unsupported type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'error_code', 'unsupported-type');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'assoc_type', 'HMAC-SHA1');
        $msg->setArg(Auth_OpenID_OPENID_NS, 'session_type', 'DH-SHA1');

        $assoc = new Auth_OpenID_Association(
                   'handle', 'secretxx', 'issued', 10000, 'HMAC-SHA1');

        $this->consumer->return_messages = array($assoc, $msg);

        $result = $this->consumer->_negotiateAssociation($this->endpoint);
        $this->assertTrue($result === null);

        // $this->failUnlessLogMatches('Server error when requesting an association')
    }

    function testValid()
    {
        $assoc = new Auth_OpenID_Association(
                   'handle', 'secret', 'issued', 10000, 'HMAC-SHA1');

        $this->consumer->return_messages = array($assoc);
        $this->assertTrue($this->consumer->_negotiateAssociation($this->endpoint) === $assoc);
        // $this->failUnlessLogEmpty()
    }
}

class TestNegotiatorBehaviors extends PHPUnit_Framework_TestCase {
    function setUp()
    {
        $this->allowed_types = array(
                                     array('HMAC-SHA1', 'no-encryption'),
                                     array('HMAC-SHA256', 'no-encryption')
                                     );

        $this->n = new Auth_OpenID_SessionNegotiator($this->allowed_types);
    }

    function testAddAllowedTypeNoSessionTypes()
    {
        $this->assertFalse($this->n->addAllowedType('invalid'));
    }

    function testAddAllowedTypeBadSessionType()
    {
        $this->assertFalse($this->n->addAllowedType('assoc1', 'invalid'));
    }

    function testAddAllowedTypeContents()
    {
        $assoc_type = 'HMAC-SHA1';
        $this->assertTrue($this->n->addAllowedType($assoc_type));

        foreach (Auth_OpenID_getSessionTypes($assoc_type) as $typ) {
            $this->assertTrue(in_array(array($assoc_type, $typ),
                                       $this->n->allowed_types));
        }
    }
}

class Tests_Auth_OpenID_Negotiation extends PHPUnit_Framework_TestSuite {

    function getName()
    {
        return 'Tests_Auth_OpenID_Negotiation';
    }

    function Tests_Auth_OpenID_Negotiation()
    {
        $this->addTestSuite('TestNegotiatorBehaviors');
        $this->addTestSuite('TestOpenID1SessionNegotiation');
        $this->addTestSuite('TestOpenID2SessionNegotiation');
    }
}