diff --git a/.gitattributes b/.gitattributes index 64ab6e0..f658344 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,6 @@ /.gitattributes export-ignore +/.github/ export-ignore /.gitignore export-ignore -/.travis.yml export-ignore /examples export-ignore /phpunit.xml.dist export-ignore /phpunit.xml.legacy export-ignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d321f38 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,45 @@ +name: CI + +on: + push: + pull_request: + +jobs: + PHPUnit: + name: PHPUnit (PHP ${{ matrix.php }}) + runs-on: ubuntu-20.04 + strategy: + matrix: + php: + - 7.4 + - 7.3 + - 7.2 + - 7.1 + - 7.0 + - 5.6 + - 5.5 + - 5.4 + - 5.3 + steps: + - uses: actions/checkout@v2 + - uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + coverage: xdebug + - run: composer install + - run: vendor/bin/phpunit --coverage-text + if: ${{ matrix.php >= 7.3 }} + - run: vendor/bin/phpunit --coverage-text -c phpunit.xml.legacy + if: ${{ matrix.php < 7.3 }} + + PHPUnit-hhvm: + name: PHPUnit (HHVM) + runs-on: ubuntu-18.04 + continue-on-error: true + steps: + - uses: actions/checkout@v2 + - uses: azjezz/setup-hhvm@v1 + with: + version: lts-3.30 + - run: hhvm $(which composer) install + - run: hhvm vendor/bin/phpunit diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 5623330..0000000 --- a/.travis.yml +++ /dev/null @@ -1,27 +0,0 @@ -language: php - -# lock distro so new future defaults will not break the build -dist: trusty - -jobs: - include: - - php: 5.3 - dist: precise - - php: 5.4 - - php: 5.5 - - php: 5.6 - - php: 7.0 - - php: 7.1 - - php: 7.2 - - php: 7.3 - - php: 7.4 - - php: hhvm-3.18 - allow_failures: - - php: hhvm-3.18 - -install: - - composer install - -script: - - if [[ "$TRAVIS_PHP_VERSION" > "7.2" ]]; then vendor/bin/phpunit --coverage-text; fi - - if [[ "$TRAVIS_PHP_VERSION" < "7.3" ]]; then vendor/bin/phpunit --coverage-text -c phpunit.xml.legacy; fi diff --git a/README.md b/README.md index 837bed0..159459d 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Datagram -[![Build Status](https://travis-ci.org/reactphp/datagram.svg?branch=master)](https://travis-ci.org/reactphp/datagram) +[![CI status](https://github.com/reactphp/datagram/workflows/CI/badge.svg)](https://github.com/reactphp/datagram/actions) Event-driven UDP datagram socket client and server for [ReactPHP](https://reactphp.org). diff --git a/src/Buffer.php b/src/Buffer.php index dc02953..e5aa2f6 100644 --- a/src/Buffer.php +++ b/src/Buffer.php @@ -79,10 +79,6 @@ public function close() public function end() { - if ($this->writable === false) { - return; - } - $this->writable = false; if (!$this->outgoing) { diff --git a/src/Socket.php b/src/Socket.php index 1315d8c..8a1d294 100644 --- a/src/Socket.php +++ b/src/Socket.php @@ -102,11 +102,10 @@ private function sanitizeAddress($address) return null; } - // this is an IPv6 address which includes colons but no square brackets + // check if this is an IPv6 address which includes multiple colons but no square brackets (PHP < 7.3) $pos = \strrpos($address, ':'); if ($pos !== false && \strpos($address, ':') < $pos && \substr($address, 0, 1) !== '[') { - $port = \substr($address, $pos + 1); - $address = '[' . \substr($address, 0, $pos) . ']:' . $port; + $address = '[' . \substr($address, 0, $pos) . ']:' . \substr($address, $pos + 1); // @codeCoverageIgnore } return $address; } diff --git a/tests/BufferTest.php b/tests/BufferTest.php new file mode 100644 index 0000000..2149ce4 --- /dev/null +++ b/tests/BufferTest.php @@ -0,0 +1,72 @@ +getMockBuilder('React\EventLoop\LoopInterface')->getMock(); + $loop->expects($this->once())->method('addWriteStream')->with($socket); + + $client = new Buffer($loop, $socket); + + $client->send('foo'); + } + + public function testSendAfterCloseIsNoop() + { + $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock(); + $loop->expects($this->never())->method('addWriteStream'); + + $socket = stream_socket_client('udp://127.0.0.1:8000'); + + $client = new Buffer($loop, $socket); + + $client->close(); + $client->send('foo'); + } + + public function testCloseAfterSendAddsSocketToLoopRemovesSocketFromLoopAgain() + { + $socket = stream_socket_client('udp://127.0.0.1:8000'); + + $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock(); + $loop->expects($this->once())->method('addWriteStream')->with($socket); + $loop->expects($this->once())->method('removeWriteStream')->with($socket); + + $client = new Buffer($loop, $socket); + + $client->send('foo'); + $client->close(); + } + + public function testCloseTwiceEmitsCloseEventOnce() + { + $loop = $this->getMockBuilder('React\EventLoop\LoopInterface')->getMock(); + + $socket = stream_socket_client('udp://127.0.0.1:8000'); + + $client = new Buffer($loop, $socket); + + $closed = 0; + $client->on('close', function () use (&$closed) { + ++$closed; + }); + + $this->assertEquals(0, $closed); + + $client->close(); + + $this->assertEquals(1, $closed); + + $client->close(); + + $this->assertEquals(1, $closed); + } +}