From a55f1e1ce5767df693a569caf48b1b9d75499dbf Mon Sep 17 00:00:00 2001 From: ArrayIterator Date: Fri, 10 Nov 2023 17:59:23 +0700 Subject: [PATCH] add unit test files --- tests/Packet/HeaderTest.php | 35 ++++ tests/Packet/MessageTest.php | 41 +++++ tests/Utils/BufferTest.php | 213 +++++++++++++++++++++ tests/Utils/LookupTest.php | 348 +++++++++++++++++++++++++++++++++++ 4 files changed, 637 insertions(+) create mode 100644 tests/Packet/HeaderTest.php create mode 100644 tests/Packet/MessageTest.php create mode 100644 tests/Utils/BufferTest.php create mode 100644 tests/Utils/LookupTest.php diff --git a/tests/Packet/HeaderTest.php b/tests/Packet/HeaderTest.php new file mode 100644 index 0000000..dd41309 --- /dev/null +++ b/tests/Packet/HeaderTest.php @@ -0,0 +1,35 @@ +assertInstanceOf( + LengthException::class, + $e, + sprintf( + '%1$s::fromMessage("") should throw %2$s', + Header::class, + LengthException::class + ) + ); + } + } +} diff --git a/tests/Packet/MessageTest.php b/tests/Packet/MessageTest.php new file mode 100644 index 0000000..dc17a7f --- /dev/null +++ b/tests/Packet/MessageTest.php @@ -0,0 +1,41 @@ +assertSame( + (string) new Message($message), + $message, + sprintf( + '%s->__tostring() should identical "%2$s"', + Message::class, + $message + ) + ); + } + + public function testGetMessage() + { + $message = md5(microtime()); + $this->assertSame( + (new Message($message))->getMessage(), + $message, + sprintf( + '%s->getMessage() should identical "%2$s"', + Message::class, + $message + ) + ); + } +} diff --git a/tests/Utils/BufferTest.php b/tests/Utils/BufferTest.php new file mode 100644 index 0000000..bad770b --- /dev/null +++ b/tests/Utils/BufferTest.php @@ -0,0 +1,213 @@ +assertSame( + $printed, + $read, + sprintf( + '%s::read("%2$s", $offset, 7) should return "%3$s"', + Buffer::class, + $buffer, + $printed + ) + ); + $this->assertSame( + $readLength, + $offset, + sprintf( + 'Offset from %s::read("%2$s", $offset, 7) should %3$d', + Buffer::class, + $buffer, + $readLength + ) + ); + // offset maximum should strlen($buffer) + $read = Buffer::read($buffer, $offset, 1000); + $this->assertSame( + $skipped, + $read, + sprintf( + '%s::read("%2$s", $offset, 1000) should return "%3$s"', + Buffer::class, + $buffer, + $skipped + ) + ); + $this->assertSame( + strlen($buffer), + $offset, + sprintf( + 'Offset from %s::read("%2$s", $offset, 1000) should %3$d', + Buffer::class, + $buffer, + strlen($buffer) + ) + ); + } + + public function testCreateHeaderMessage() + { + $header = Header::createQueryHeader(); + $this->assertSame( + $header->getMessage(), + Buffer::createHeaderMessage($header), + sprintf( + '%1$s::createHeaderMessage($header) should identical with $header->getMessage()', + Buffer::class + ) + ); + } + + public function testCompressLabel() + { + $domain = 'example.com'; + $label = Buffer::compressLabel($domain); + $this->assertNotSame( + $domain, + $label, + sprintf( + '%1$s::compressLabel("%2$s") should not identical with "%2$s"', + Buffer::class, + $domain + ) + ); + } + + public function testReadLabel() + { + $offset = 0; + $domain = 'example.com'; + $label = Buffer::compressLabel($domain); + $read = Buffer::readLabel($label, $offset); + $this->assertGreaterThan( + 0, + $offset, + sprintf( + 'Offset from %1$s::readLabel($label, $offset) should greater than 0', + Buffer::class + ) + ); + $this->assertNotSame( + $label, + $read, + sprintf( + '%1$s::readLabel($label, $offset) should not identical with $label', + Buffer::class + ) + ); + $this->assertSame( + $domain, + $read, + sprintf( + '%1$s::readLabel($label, $offset) should identical with $label', + Buffer::class + ) + ); + $this->assertEmpty( + Buffer::readLabel($label, $offset), + sprintf( + 'With next offset of %1$s::readLabel($label, $offset) should empty', + Buffer::class + ) + ); + $underscore = 'example_com'; // underscore separator + // fallback offset + $offset = 0; + $read = Buffer::readLabel($label, $offset, '_'); + $this->assertGreaterThan( + 0, + $offset, + sprintf( + 'Offset from %1$s::readLabel($label, $offset, "_") should greater than 0', + Buffer::class + ) + ); + $this->assertNotSame( + $label, + $read, + sprintf( + '%1$s::readLabel($label, $offset, "_") should not identical with $label', + Buffer::class + ) + ); + $this->assertNotSame( + $domain, + $read, + sprintf( + '%1$s::readLabel($label, $offset, "_") should not identical with "%2$s"', + Buffer::class, + $domain + ) + ); + $this->assertSame( + $underscore, + $read, + sprintf( + '%1$s::readLabel($label, $offset) should identical with "%2$s"', + Buffer::class, + $underscore + ) + ); + } + + public function testCompressHeader() + { + $header = Buffer::compressHeader( + 'A', + 'IN' + ); + $this->assertGreaterThanOrEqual( + 10, + strlen($header), + sprintf( + '%1$s::compressHeader("A", "IN") length should 10 or greater', + Buffer::class + ) + ); + } + + public function testCreateQuestionMessage() + { + $question = Question::fromFilteredResponse( + 'example.com', + Lookup::RR_TYPES['A'], + Lookup::QCLASS_IN + ); + $header = Buffer::compressHeader( + $question->getType(), + $question->getClass() + ); + $message = Buffer::createQuestionMessage($question); + // header is on the end of binary string + $this->assertStringEndsWith( + $header, + $message, + sprintf( + '%1$s::createQuestionMessage(%2$s) should ending with header', + Buffer::class, + Question::class, + ) + ); + } +} diff --git a/tests/Utils/LookupTest.php b/tests/Utils/LookupTest.php new file mode 100644 index 0000000..7e49d2a --- /dev/null +++ b/tests/Utils/LookupTest.php @@ -0,0 +1,348 @@ +assertInstanceOf( + EmptyArgumentException::class, + $exception, + sprintf( + '%1$s::Lookup::resourceClass() empty argument should throw %2$s', + Lookup::class, + EmptyArgumentException::class + ) + ); + $exception = null; + try { + // invalid + Lookup::resourceClass(0xffffff); + } catch (Throwable $exception) { + } + $this->assertInstanceOf( + InvalidArgumentException::class, + $exception, + sprintf( + '%1$s::resourceClass() out of range integer argument should throw %2$s', + Lookup::class, + InvalidArgumentException::class + ) + ); + + $this->assertInstanceOf( + Any::class, + Lookup::resourceClass('*'), + sprintf( + '%1$s::resourceClass("*") should return object instance of %2$s', + Lookup::class, + Any::class + ) + ); + $this->assertInstanceOf( + IN::class, + Lookup::resourceClass(Lookup::QCLASS_IN), + sprintf( + '%1$s::resourceClass(%1$s::QCLASS_IN) should return object instance of %2$s', + Lookup::class, + IN::class + ) + ); + } + + public function testResourceOpcode() + { + $exception = null; + try { + // empty + Lookup::resourceOpcode(''); + } catch (Throwable $exception) { + } + $this->assertInstanceOf( + EmptyArgumentException::class, + $exception, + sprintf( + '%1$s::resourceOpcode() empty argument should throw %2$s', + Lookup::class, + EmptyArgumentException::class + ) + ); + try { + // empty + Lookup::resourceOpcode('INVALID'); + } catch (Throwable $exception) { + } + $this->assertInstanceOf( + InvalidArgumentException::class, + $exception, + sprintf( + '%1$s::resourceOpcode() invalid argument should throw %2$s', + Lookup::class, + InvalidArgumentException::class + ) + ); + $this->assertInstanceOf( + \InvalidArgumentException::class, + $exception, + sprintf( + '%1$s::resourceOpcode() invalid argument should throw %2$s', + Lookup::class, + \InvalidArgumentException::class + ) + ); + $this->assertInstanceOf( + Query::class, + Lookup::resourceOpcode(Lookup::OPCODE_QUERY), + sprintf( + '%1$s::resourceOpcode(%1$s::OPCODE_QUERY) should return object instance of %2$s', + Lookup::class, + Query::class + ) + ); + $this->assertInstanceOf( + IQuery::class, + Lookup::resourceOpcode(Lookup::OPCODE_IQUERY), + sprintf( + '%1$s::resourceOpcode(%1$s::OPCODE_IQUERY) should return object instance of %2$s', + Lookup::class, + IQuery::class + ) + ); + $this->assertInstanceOf( + Status::class, + Lookup::resourceOpcode(Lookup::OPCODE_STATUS), + sprintf( + '%1$s::resourceOpcode(%1$s::OPCODE_STATUS) should return object instance of %2$s', + Lookup::class, + Status::class + ) + ); + $this->assertInstanceOf( + DSO::class, + Lookup::resourceOpcode(Lookup::OPCODE_DSO), + sprintf( + '%1$s::resourceOpcode(%1$s::OPCODE_DSO) should return object instance of %2$s', + Lookup::class, + DSO::class + ) + ); + $this->assertInstanceOf( + Notify::class, + Lookup::resourceOpcode(Lookup::OPCODE_NOTIFY), + sprintf( + '%1$s::resourceOpcode(%1$s::OPCODE_NOTIFY) should return object instance of %2$s', + Lookup::class, + Notify::class + ) + ); + $this->assertInstanceOf( + Update::class, + Lookup::resourceOpcode(Lookup::OPCODE_UPDATE), + sprintf( + '%1$s::resourceOpcode(%1$s::OPCODE_UPDATE) should return object instance of %2$s', + Lookup::class, + Update::class + ) + ); + } + + public function testResourceType() + { + $exception = null; + try { + // empty + Lookup::resourceType(''); + } catch (Throwable $exception) { + } + $this->assertInstanceOf( + EmptyArgumentException::class, + $exception, + sprintf( + '%1$s::resourceType() empty argument should throw %2$s', + Lookup::class, + EmptyArgumentException::class + ) + ); + try { + // empty + Lookup::resourceType('INVALID'); + } catch (Throwable $exception) { + } + $this->assertInstanceOf( + InvalidArgumentException::class, + $exception, + sprintf( + '%1$s::resourceType() invalid argument should throw %2$s', + Lookup::class, + InvalidArgumentException::class + ) + ); + /** + * @uses QType no need to test QType again + */ + $this->assertInstanceOf( + QType::class, + Lookup::resourceType('A'), + sprintf( + '%1$s::resourceType("A") should return object instance of %2$s', + Lookup::class, + QType::class + ) + ); + $this->assertSame( + 'A', + Lookup::resourceType('A')->getName(), + sprintf( + '%1$s::resourceType("A")->getName() should "A"', + Lookup::class + ) + ); + } + + public function testSocket() + { + /* + * protocol:string, server:string, port:int, socket: resource + */ + // use only one! + $dnsServer = new DnsServerStorage(new Google()); + try { + $socketDefinition = Lookup::socket( + $dnsServer, + true, // use udp, + $serverLists + ); + $this->assertIsArray( + $serverLists, + sprintf( + '%s::socket(a, v, $serverLists) - $serverLists should reference as array', + Lookup::class + ) + ); + $this->assertArrayHasKey( + 'protocol', + $socketDefinition, + sprintf( + '%s::socket() result array should contain key %s', + Lookup::class, + 'protocol' + ) + ); + $this->assertArrayHasKey( + 'server', + $socketDefinition, + sprintf( + '%s::socket() result array should contain key %s', + Lookup::class, + 'server' + ) + ); + $this->assertArrayHasKey( + 'port', + $socketDefinition, + sprintf( + '%s::socket() result array should contain key %s', + Lookup::class, + 'port' + ) + ); + $this->assertArrayHasKey( + 'socket', + $socketDefinition, + sprintf( + '%s::socket() result array should contain key %s', + Lookup::class, + 'socket' + ) + ); + $this->assertIsString( + $socketDefinition['protocol'], + sprintf( + '%s::socket()[\'protocol\'] should returning string', + Lookup::class, + ) + ); + $this->assertSame( + $socketDefinition['protocol'], + 'udp', + sprintf( + '%s::socket()[\'protocol\'] should "udp"', + Lookup::class, + ) + ); + $this->assertIsString( + $socketDefinition['server'], + sprintf( + '%s::socket()[\'server\'] should returning string', + Lookup::class, + ) + ); + $this->assertIsInt( + $socketDefinition['port'], + sprintf( + '%s::socket()[\'port\'] should returning int', + Lookup::class, + ) + ); + $this->assertIsBool( + is_resource($socketDefinition['socket']), + sprintf( + '%s::socket()[\'socket\'] should returning resource', + Lookup::class, + ) + ); + fclose($socketDefinition['socket']); + unset($socketDefinition['socket']); + } catch (Throwable) { + } + $dnsServer = new DnsServerStorage(CustomDnsServer::create('https://invalid-ns')); + try { + Lookup::socket( + $dnsServer, + true, // use udp, + $serverLists + ); + } catch (Throwable $e) { + $this->assertInstanceOf( + RequestException::class, + $e, + sprintf( + '%1$s::socket() throwable should return object instance of %2$s', + Lookup::class, + RequestException::class + ) + ); + } + } +}