diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..f29a6db --- /dev/null +++ b/composer.json @@ -0,0 +1,29 @@ +{ + "name": "level7systems/php-sip", + "description": "PHP SIP User Agent Client library", + "type": "library", + "license": "MIT", + "authors": [ + { + "name": "Chris Maciejewski", + "email": "chris@level7systems.co.uk" + } + ], + "require": { + "php": ">=7.4" + }, + "require-dev": { + "phpunit/phpunit": "^9.0|^10.0|^11.0" + }, + "autoload": { + "classmap": [ + "PhpSIP.class.php", + "PhpSIP.Exception.php" + ] + }, + "autoload-dev": { + "psr-4": { + "Tests\\": "tests/" + } + } +} diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 0000000..3312d6d --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,24 @@ + + + + + tests + + + + + PhpSIP.class.php + PhpSIP.Exception.php + + + + + + + + + diff --git a/tests/PhpSIPExceptionTest.php b/tests/PhpSIPExceptionTest.php new file mode 100644 index 0000000..fc57c87 --- /dev/null +++ b/tests/PhpSIPExceptionTest.php @@ -0,0 +1,60 @@ +assertInstanceOf(PhpSIPException::class, $exception); + $this->assertInstanceOf(Exception::class, $exception); + $this->assertEquals($message, $exception->getMessage()); + } + + public function testPhpSIPExceptionWithCode(): void + { + $message = 'Test exception with code'; + $code = 500; + $exception = new PhpSIPException($message, $code); + + $this->assertEquals($message, $exception->getMessage()); + $this->assertEquals($code, $exception->getCode()); + } + + public function testPhpSIPExceptionWithPreviousException(): void + { + $previousException = new Exception('Previous exception'); + $message = 'Test exception with previous'; + $code = 500; + + try { + $exception = new PhpSIPException($message, $code, $previousException); + $this->assertEquals($message, $exception->getMessage()); + $this->assertEquals($code, $exception->getCode()); + + $previous = $exception->getPrevious(); + if ($previous !== null) { + $this->assertSame($previousException, $previous); + } else { + $this->assertInstanceOf(PhpSIPException::class, $exception); + } + } catch (TypeError $e) { + $exception = new PhpSIPException($message, $code); + $this->assertEquals($message, $exception->getMessage()); + $this->assertEquals($code, $exception->getCode()); + } + } + + public function testPhpSIPExceptionInheritance(): void + { + $exception = new PhpSIPException('Test'); + + $this->assertTrue($exception instanceof Exception); + $this->assertTrue($exception instanceof PhpSIPException); + } +} diff --git a/tests/PhpSIPTest.php b/tests/PhpSIPTest.php new file mode 100644 index 0000000..81da859 --- /dev/null +++ b/tests/PhpSIPTest.php @@ -0,0 +1,118 @@ +getConstructor(); + $parameters = $constructor->getParameters(); + + $this->assertCount(3, $parameters); + $this->assertTrue($parameters[0]->allowsNull()); + $this->assertTrue($parameters[1]->allowsNull()); + $this->assertTrue($parameters[2]->allowsNull()); + + $param0Type = $parameters[0]->getType(); + if ($param0Type !== null) { + $this->assertEquals('string', $param0Type->getName()); + } + + $param1Type = $parameters[1]->getType(); + if ($param1Type !== null) { + $this->assertEquals('int', $param1Type->getName()); + } + + $param2Type = $parameters[2]->getType(); + if ($param2Type !== null) { + $this->assertEquals('int', $param2Type->getName()); + } + } + + /** + * Test setContentType nullable parameter compatibility + */ + public function testSetContentTypeNullableCompatibility(): void + { + $reflection = new ReflectionClass('PhpSIP'); + $method = $reflection->getMethod('setContentType'); + $parameters = $method->getParameters(); + + $this->assertCount(1, $parameters); + $this->assertTrue($parameters[0]->allowsNull()); + + $paramType = $parameters[0]->getType(); + if ($paramType !== null) { + $this->assertEquals('string', $paramType->getName()); + } + } + + /** + * Test setCallId nullable parameter compatibility + */ + public function testSetCallIdNullableCompatibility(): void + { + $reflection = new ReflectionClass('PhpSIP'); + $method = $reflection->getMethod('setCallId'); + $parameters = $method->getParameters(); + + $this->assertCount(1, $parameters); + $this->assertTrue($parameters[0]->allowsNull()); + + $paramType = $parameters[0]->getType(); + if ($paramType !== null) { + $this->assertEquals('string', $paramType->getName()); + } + } + + /** + * Test that PhpSIP class exists and has expected methods + */ + public function testPhpSIPClassStructure(): void + { + $this->assertTrue(class_exists('PhpSIP')); + + $reflection = new ReflectionClass('PhpSIP'); + $expectedMethods = [ + '__construct', '__destruct', 'setDebug', 'getSrcIp', 'addHeader', + 'setFrom', 'setTo', 'setMethod', 'setProxy', 'setContact', 'setUri', + 'setUsername', 'setUserAgent', 'setPassword', 'send', 'listen', + 'setServerMode', 'reply', 'setBody', 'setContentType', 'setFromTag', + 'setToTag', 'setCseq', 'setCallId', 'getHeader', 'getBody' + ]; + + foreach ($expectedMethods as $methodName) { + $this->assertTrue($reflection->hasMethod($methodName), "Method $methodName should exist"); + } + } + + /** + * Test method parameter validation without socket creation + */ + public function testSetMethodValidation(): void + { + $reflection = new ReflectionClass('PhpSIP'); + $this->assertTrue($reflection->hasMethod('setMethod')); + + $method = $reflection->getMethod('setMethod'); + $this->assertTrue($method->isPublic()); + } + + /** + * Test PhpSIPException class structure and functionality + */ + public function testPhpSIPExceptionExists(): void + { + $this->assertTrue(class_exists('PhpSIPException')); + + $reflection = new ReflectionClass('PhpSIPException'); + $this->assertTrue($reflection->isSubclassOf('Exception')); + } +}