<?php

/**
 * @file
 * Unit tests for Mollom class.
 *
 * @todo After final Mollom class commit, move all low-level tests from
 *   mollom.test into this file.
 */

/**
 * Tests Mollom class functionality.
 */
class MollomClassUnitTestCase extends DrupalUnitTestCase {
  public static function getInfo() {
    return array(
      'name' => 'Mollom class',
      'description' => 'Tests Mollom class functionality.',
      'group' => 'Mollom',
    );
  }

  function setUp() {
    parent::setUp();
    // DrupalUnitTestCase does not autoload classes for whatever reason.
    module_load_include('inc', 'mollom', 'includes/mollom.class');
  }

  /**
   * Asserts that two values belonging to the same variable are equal.
   *
   * Checks to see whether two values, which belong to the same variable name or
   * identifier, are equal and logs a readable assertion message.
   *
   * @param $name
   *   A name or identifier to use in the assertion message.
   * @param $first
   *   The first value to check.
   * @param $second
   *   The second value to check.
   *
   * @return
   *   TRUE if the assertion succeeded, FALSE otherwise.
   *
   * @see MollomWebTestCase::assertNotSame()
   *
   * @todo D8: Move into core. This improved assertEqual() did not get into D7,
   *   since the function signature differs and it's plenty of work to manually
   *   update all assertEqual() invocations throughout all tests.
   */
  protected function assertSame($name, $first, $second) {
    $message = t("@name: @first is equal to @second.", array(
      '@name' => $name,
      '@first' => var_export($first, TRUE),
      '@second' => var_export($second, TRUE),
    ));
    $this->assertEqual($first, $second, $message);
  }

  /**
   * Asserts that two values belonging to the same variable are not equal.
   *
   * Checks to see whether two values, which belong to the same variable name or
   * identifier, are not equal and logs a readable assertion message.
   *
   * @param $name
   *   A name or identifier to use in the assertion message.
   * @param $first
   *   The first value to check.
   * @param $second
   *   The second value to check.
   *
   * @return
   *   TRUE if the assertion succeeded, FALSE otherwise.
   *
   * @see MollomWebTestCase::assertSame()
   */
  protected function assertNotSame($name, $first, $second) {
    $message = t("@name: @first is not equal to @second.", array(
      '@name' => $name,
      '@first' => var_export($first, TRUE),
      '@second' => var_export($second, TRUE),
    ));
    $this->assertNotEqual($first, $second, $message);
  }

  /**
   * Tests Mollom::httpBuildQuery().
   */
  function testHttpBuildQuery() {
    // Single parameter.
    $input = array('checks' => 'spam');
    $expected = 'checks=spam';
    $this->assertSame(var_export($input, TRUE), Mollom::httpBuildQuery($input), $expected);

    // Multiple parameters, numbers.
    $input = array('foo' => 1, 'bar' => 2);
    $expected = 'bar=2&foo=1';
    $this->assertSame(var_export($input, TRUE), Mollom::httpBuildQuery($input), $expected);

    // Parameter with multiple values.
    $input = array('checks' => array('spam', 'profanity'));
    $expected = 'checks=profanity&checks=spam';
    $this->assertSame(var_export($input, TRUE), Mollom::httpBuildQuery($input), $expected);

    // Parameter with multiple values, empty.
    $input = array('checks' => array('spam', ''));
    $expected = 'checks=&checks=spam';
    $this->assertSame(var_export($input, TRUE), Mollom::httpBuildQuery($input), $expected);

    // Parameter with multiple values, NULL.
    $input = array('checks' => array('spam', NULL));
    $expected = 'checks=&checks=spam';
    $this->assertSame(var_export($input, TRUE), Mollom::httpBuildQuery($input), $expected);

    // Multiple parameters with NULL value.
    $input = array('foo' => 1, 'checks' => NULL);
    $expected = 'checks=&foo=1';
    $this->assertSame(var_export($input, TRUE), Mollom::httpBuildQuery($input), $expected);

    // Multiple parameters with multiple values.
    // (official OAuth protocol example)
    // @see RFC 5849 3.4.1.3.1
    $input = array(
      'b5' => '=%3D',
      'a3' => array('a', '2 q'),
      'c@' => '',
      'a2' => 'r b',
      'oauth_consumer_key' => '9djdj82h48djs9d2',
      'oauth_token' => 'kkk9d7dh3k39sjv7',
      'oauth_signature_method' => 'HMAC-SHA1',
      'oauth_timestamp' => '137131201',
      'oauth_nonce' => '7d8f3e4a',
      'c2' => '',
    );
    $expected = 'a2=r%20b&a3=2%20q&a3=a&b5=%3D%253D&c%40=&c2=&oauth_consumer_key=9djdj82h48djs9d2&oauth_nonce=7d8f3e4a&oauth_signature_method=HMAC-SHA1&oauth_timestamp=137131201&oauth_token=kkk9d7dh3k39sjv7';
    $this->assertSame(var_export($input, TRUE), Mollom::httpBuildQuery($input), $expected);

    // Parameter with recursive multiple values.
    $input = array('checks' => array(array('spam'), array('profanity')));
    $expected = 'checks=profanity&checks=spam';
    $this->assertSame(var_export($input, TRUE), Mollom::httpBuildQuery($input), $expected);

    // Parameter with multiple named values.
    // @todo Drop support for this?
    $input = array('checks' => array('foo' => 'spam', 'bar' => 'profanity'));
    $expected = 'checks[bar]=profanity&checks[foo]=spam';
    $this->assertSame(var_export($input, TRUE), Mollom::httpBuildQuery($input), $expected);

    // Prior to PHP 5.3.0, rawurlencode() encoded tildes (~) as per RFC 1738.
    $input = array(
      'reserved' => ':/?#[]@!$&\'()*+,;=',
      'unreserved' => '-._~',
    );
    $expected = 'reserved=%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D&unreserved=-._~';
    $this->assertSame(var_export($input, TRUE), Mollom::httpBuildQuery($input), $expected);
  }

  /**
   * Tests Mollom::httpParseQuery().
   */
  function testHttpParseQuery() {
    $input = 'foo=1&bar=2';
    $expected = array('foo' => 1, 'bar' => 2);
    $this->assertSame($input, Mollom::httpParseQuery($input), $expected);

    $input = 'checks=spam&checks=profanity';
    $expected = array('checks' => array('spam', 'profanity'));
    $this->assertSame($input, Mollom::httpParseQuery($input), $expected);

    // Mollom::httpParseQuery() does not attempt to work transparently. Thus,
    // multiple parameter names containing brackets itself (regular PHP syntax)
    // will lead to an "unexpected" result. Although it wouldn't be hard to add
    // support for this, there's currently no need for it.
    $input = 'checks[]=spam&checks[]=profanity';
    $expected = array('checks' => array(array('spam'), array('profanity')));
    $this->assertSame($input, Mollom::httpParseQuery($input), $expected);

    $input = 'checks=spam&checks=';
    $expected = array('checks' => array('spam', ''));
    $this->assertSame($input, Mollom::httpParseQuery($input), $expected);

    $input = 'checks=spam&checks';
    $expected = array('checks' => array('spam', ''));
    $this->assertSame($input, Mollom::httpParseQuery($input), $expected);

    $input = 'checks=spam&';
    $expected = array('checks' => 'spam');
    $this->assertSame($input, Mollom::httpParseQuery($input), $expected);

    $input = 'checks=spam';
    $expected = array('checks' => 'spam');
    $this->assertSame($input, Mollom::httpParseQuery($input), $expected);
  }

  /**
   * Tests Mollom::parseXML().
   */
  function testParseXML() {
    $header = '<?xml version="1.0"?>';

    $input = $header . <<<EOF
<response>
  <code>0</code>
  <message>Foo.</message>
  <content>
    <contentId>321</contentId>
    <languages>
      <language>
        <languageCode>en</languageCode>
        <languageScore>1.0</languageScore>
      </language>
      <language>
        <languageCode>de</languageCode>
        <languageScore>0.5</languageScore>
      </language>
    </languages>
  </content>
</response>
EOF;
    $expected = array(
      'code' => 0,
      'message' => 'Foo.',
      'content' => array(
        'contentId' => 321,
        'languages' => array(
          array('languageCode' => 'en', 'languageScore' => 1.0),
          array('languageCode' => 'de', 'languageScore' => 0.5),
        ),
      ),
    );
    $this->assertSame($input, Mollom::parseXML(new SimpleXmlIterator($input)), $expected);

    $input = $header . <<<EOF
<response>
  <code>0</code>
  <message></message>
  <site>
    <publicKey>321</publicKey>
    <servers>
      <server>http://foo</server>
      <server>http://bar</server>
    </servers>
  </site>
</response>
EOF;
    $expected = array(
      'code' => 0,
      'message' => '',
      'site' => array(
        'publicKey' => 321,
        'servers' => array(
          'http://foo',
          'http://bar',
        ),
      ),
    );
    $this->assertSame($input, Mollom::parseXML(new SimpleXmlIterator($input)), $expected);
  }

  /**
   * Test Mollom::addAuthentication().
   *
   * @todo Requires class instance for unit testing.
   *
   * - Reserved characters (such as '%') have to be double-encoded in signature base string.
   * - Compare signature base string with PECL OAuth result, if available?
   */
}

