268 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			268 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?php
 | 
						|
namespace Ratchet\Tests\Component\WebSocket\Version\RFC6455;
 | 
						|
use Ratchet\Component\WebSocket\Version\RFC6455\Frame;
 | 
						|
 | 
						|
/**
 | 
						|
 * @covers Ratchet\Component\WebSocket\Version\RFC6455\Frame
 | 
						|
 * @todo getMaskingKey, getPayloadStartingByte don't have tests yet
 | 
						|
 * @todo Could use some clean up in general, I had to rush to fix a bug for a deadline, sorry.
 | 
						|
 */
 | 
						|
class FrameTest extends \PHPUnit_Framework_TestCase {
 | 
						|
    protected $_firstByteFinText    = '10000001';
 | 
						|
    protected $_secondByteMaskedSPL = '11111101';
 | 
						|
 | 
						|
    protected $_frame;
 | 
						|
 | 
						|
    protected $_packer;
 | 
						|
 | 
						|
    public function setUp() {
 | 
						|
        $this->_frame = new Frame;
 | 
						|
    }
 | 
						|
 | 
						|
    protected static function convert($in) {
 | 
						|
        if (strlen($in) > 8) {
 | 
						|
            $out = '';
 | 
						|
 | 
						|
            while (strlen($in) > 8) {
 | 
						|
                $out .= static::convert(substr($in, 0, 8));
 | 
						|
                $in   = substr($in, 8); 
 | 
						|
            }
 | 
						|
 | 
						|
            return $out;
 | 
						|
        }
 | 
						|
 | 
						|
        return pack('C', bindec($in));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * This is a data provider
 | 
						|
     * @param string The UTF8 message
 | 
						|
     * @param string The WebSocket framed message, then base64_encoded
 | 
						|
     */
 | 
						|
    public static function UnframeMessageProvider() {
 | 
						|
        return array(
 | 
						|
            array('Hello World!',                'gYydAIfa1WXrtvIg0LXvbOP7')
 | 
						|
          , array('!@#$%^&*()-=_+[]{}\|/.,<>`~', 'gZv+h96r38f9j9vZ+IHWrvOWoayF9oX6gtfRqfKXwOeg')
 | 
						|
          , array('ಠ_ಠ',                         'gYfnSpu5B/g75gf4Ow==')
 | 
						|
          , array("The quick brown fox jumps over the lazy dog.  All work and no play makes Chris a dull boy.  I'm trying to get past 128 characters for a unit test here...", 'gf4Amahb14P8M7Kj2S6+4MN7tfHHLLmjzjSvo8IuuvPbe7j1zSn398A+9+/JIa6jzDSwrYh7lu/Ee6Ds2jD34sY/9+3He6fvySL37skwsvCIGL/xwSj34og/ou/Ee7Xs0XX3o+F8uqPcKa7qxjz398d7sObce6fi2y/3sppj9+DAOqXiyy+y8dt7sezae7aj3TW+94gvsvDce7/m2j75rYY=')
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    public static function underflowProvider() {
 | 
						|
        return array(
 | 
						|
            array('isFinal', '')
 | 
						|
          , array('getOpcode', '')
 | 
						|
          , array('isMasked', '10000001')
 | 
						|
          , array('getPayloadLength', '10000001')
 | 
						|
          , array('getPayloadLength', '1000000111111110')
 | 
						|
          , array('getMaskingKey', '1000000110000111')
 | 
						|
          , array('getPayload', '100000011000000100011100101010101001100111110100')
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @dataProvider underflowProvider
 | 
						|
     */
 | 
						|
    public function testUnderflowExceptionFromAllTheMethodsMimickingBuffering($method, $bin) {
 | 
						|
        $this->setExpectedException('\UnderflowException');
 | 
						|
 | 
						|
        if (!empty($bin)) {
 | 
						|
            $this->_frame->addBuffer(static::convert($bin));
 | 
						|
        }
 | 
						|
 | 
						|
        call_user_func(array($this->_frame, $method));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * A data provider for testing the first byte of a WebSocket frame
 | 
						|
     * @param bool Given, is the byte indicate this is the final frame
 | 
						|
     * @param int Given, what is the expected opcode
 | 
						|
     * @param string of 0|1 Each character represents a bit in the byte
 | 
						|
     */
 | 
						|
    public static function firstByteProvider() {
 | 
						|
        return array(
 | 
						|
            array(false, 8,  '00001000')
 | 
						|
          , array(true,  10, '10001010')
 | 
						|
          , array(false, 15, '00001111')
 | 
						|
          , array(true,   1, '10000001')
 | 
						|
          , array(true,  15, '11111111')
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @dataProvider firstByteProvider
 | 
						|
     */
 | 
						|
    public function testFinCodeFromBits($fin, $opcode, $bin) {
 | 
						|
        $this->_frame->addBuffer(static::convert($bin));
 | 
						|
        $this->assertEquals($fin, $this->_frame->isFinal());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @dataProvider UnframeMessageProvider
 | 
						|
     */
 | 
						|
    public function testFinCodeFromFullMessage($msg, $encoded) {
 | 
						|
        $this->_frame->addBuffer(base64_decode($encoded));
 | 
						|
        $this->assertTrue($this->_frame->isFinal());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @dataProvider firstByteProvider
 | 
						|
     */
 | 
						|
    public function testOpcodeFromBits($fin, $opcode, $bin) {
 | 
						|
        $this->_frame->addBuffer(static::convert($bin));
 | 
						|
        $this->assertEquals($opcode, $this->_frame->getOpcode());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @dataProvider UnframeMessageProvider
 | 
						|
     */
 | 
						|
    public function testOpcodeFromFullMessage($msg, $encoded) {
 | 
						|
        $this->_frame->addBuffer(base64_decode($encoded));
 | 
						|
        $this->assertEquals(1, $this->_frame->getOpcode());
 | 
						|
    }
 | 
						|
 | 
						|
    public static function payloadLengthDescriptionProvider() {
 | 
						|
        return array(
 | 
						|
            array(7,  '01110101')
 | 
						|
          , array(7,  '01111101')
 | 
						|
          , array(23, '01111110')
 | 
						|
          , array(71, '01111111')
 | 
						|
          , array(7,  '00000000') // Should this throw an exception?  Can a payload be empty?
 | 
						|
          , array(7,  '00000001')
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @dataProvider payloadLengthDescriptionProvider
 | 
						|
     */
 | 
						|
    public function testFirstPayloadDesignationValue($bits, $bin) {
 | 
						|
        $this->_frame->addBuffer(static::convert($this->_firstByteFinText));
 | 
						|
        $this->_frame->addBuffer(static::convert($bin));
 | 
						|
 | 
						|
        $ref = new \ReflectionClass($this->_frame);
 | 
						|
        $cb  = $ref->getMethod('getFirstPayloadVal');
 | 
						|
        $cb->setAccessible(true);
 | 
						|
 | 
						|
        $this->assertEquals(bindec($bin), $cb->invoke($this->_frame));
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @dataProvider payloadLengthDescriptionProvider
 | 
						|
     */
 | 
						|
    public function testDetermineHowManyBitsAreUsedToDescribePayload($expected_bits, $bin) {
 | 
						|
        $this->_frame->addBuffer(static::convert($this->_firstByteFinText));
 | 
						|
        $this->_frame->addBuffer(static::convert($bin));
 | 
						|
 | 
						|
        $ref = new \ReflectionClass($this->_frame);
 | 
						|
        $cb  = $ref->getMethod('getNumPayloadBits');
 | 
						|
        $cb->setAccessible(true);
 | 
						|
 | 
						|
        $this->assertEquals($expected_bits, $cb->invoke($this->_frame));
 | 
						|
    }
 | 
						|
 | 
						|
    public function secondByteProvider() {
 | 
						|
        return array(
 | 
						|
            array(true,   1, '10000001')
 | 
						|
          , array(false,  1, '00000001')
 | 
						|
          , array(true, 125, $this->_secondByteMaskedSPL)
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @dataProvider secondByteProvider
 | 
						|
     */
 | 
						|
    public function testIsMaskedReturnsExpectedValue($masked, $payload_length, $bin) {
 | 
						|
        $this->_frame->addBuffer(static::convert($this->_firstByteFinText));
 | 
						|
        $this->_frame->addBuffer(static::convert($bin));
 | 
						|
 | 
						|
        $this->assertEquals($masked, $this->_frame->isMasked());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @dataProvider UnframeMessageProvider
 | 
						|
     */
 | 
						|
    public function testIsMaskedFromFullMessage($msg, $encoded) {
 | 
						|
        $this->_frame->addBuffer(base64_decode($encoded));
 | 
						|
        $this->assertTrue($this->_frame->isMasked());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @dataProvider secondByteProvider
 | 
						|
     */
 | 
						|
    public function testGetPayloadLengthWhenOnlyFirstFrameIsUsed($masked, $payload_length, $bin) {
 | 
						|
        $this->_frame->addBuffer(static::convert($this->_firstByteFinText));
 | 
						|
        $this->_frame->addBuffer(static::convert($bin));
 | 
						|
 | 
						|
        $this->assertEquals($payload_length, $this->_frame->getPayloadLength());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @dataProvider UnframeMessageProvider
 | 
						|
     * @todo Not yet testing when second additional payload length descriptor
 | 
						|
     */
 | 
						|
    public function testGetPayloadLengthFromFullMessage($msg, $encoded) {
 | 
						|
        $this->_frame->addBuffer(base64_decode($encoded));
 | 
						|
        $this->assertEquals(strlen($msg), $this->_frame->getPayloadLength());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @todo Use a masking key generator when one is coded later
 | 
						|
     */
 | 
						|
    protected function generateMask() {
 | 
						|
        $mask = '';
 | 
						|
        for($i = 0; $i < 4; $i++) {
 | 
						|
            $mask .= chr(rand(0, 255));
 | 
						|
        }
 | 
						|
 | 
						|
        return $mask;
 | 
						|
    }
 | 
						|
 | 
						|
    public function maskingKeyProvider() {
 | 
						|
        return array(
 | 
						|
            array($this->generateMask())
 | 
						|
          , array($this->generateMask())
 | 
						|
          , array($this->generateMask())
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @dataProvider maskingKeyProvider
 | 
						|
     * @todo I I wrote the dataProvider incorrectly, skpping for now
 | 
						|
     */
 | 
						|
    public function testGetMaskingKey($mask) {
 | 
						|
        $this->_frame->addBuffer(static::convert($this->_firstByteFinText));
 | 
						|
        $this->_frame->addBuffer(static::convert($this->_secondByteMaskedSPL));
 | 
						|
        $this->_frame->addBuffer($mask);
 | 
						|
 | 
						|
        $this->assertEquals($mask, $this->_frame->getMaskingKey());
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @dataProvider UnframeMessageProvider
 | 
						|
     * @todo Move this test to bottom as it requires all methods of the class
 | 
						|
     */
 | 
						|
    public function testUnframeFullMessage($unframed, $base_framed) {
 | 
						|
        $this->_frame->addBuffer(base64_decode($base_framed));
 | 
						|
        $this->assertEquals($unframed, $this->_frame->getPayload());
 | 
						|
    }
 | 
						|
 | 
						|
    public static function messageFragmentProvider() {
 | 
						|
        return array(
 | 
						|
            array(false, '', '', '', '', '')
 | 
						|
        );
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * @dataProvider UnframeMessageProvider
 | 
						|
     */
 | 
						|
    public function testCheckPiecingTogetherMessage($msg, $encoded) {
 | 
						|
//        return $this->markTestIncomplete('Ran out of time, had to attend to something else, come finish me!');
 | 
						|
 | 
						|
        $framed = base64_decode($encoded);
 | 
						|
        for ($i = 0, $len = strlen($framed);$i < $len; $i++) {
 | 
						|
            $this->_frame->addBuffer(substr($framed, $i, 1));
 | 
						|
        }
 | 
						|
 | 
						|
        $this->assertEquals($msg, $this->_frame->getPayload());
 | 
						|
    }
 | 
						|
} |