Uploaded From CV. Swandhana Server

This commit is contained in:
Duidev Software House
2025-01-27 08:16:55 +07:00
commit 6b3be42361
15186 changed files with 2328862 additions and 0 deletions

No files matched your search

+111
View File
@@ -0,0 +1,111 @@
<?php
declare(strict_types=1);
namespace Aranyasen\HL7\Tests;
use Aranyasen\HL7\Message;
use Aranyasen\HL7\Messages\ACK;
use Aranyasen\HL7\Segments\MSH;
use Exception;
class AckTest extends TestCase
{
/**
* @throws Exception
*/
public function test()
{
$msg = new Message();
$msg->addSegment(new MSH());
$msh = $msg->getSegmentByIndex(0);
$msh->setField(15, 'AL');
$msh->setField(16, 'NE');
$ack = new ACK($msg);
$seg1 = $ack->getSegmentByIndex(1);
self::assertSame('CA', $seg1->getField(1), 'Error code is CA');
$msg = new Message();
$msh = new MSH();
$msh->setField(15);
$msh->setField(16, 'NE');
$msg->addSegment($msh);
$ack = new ACK($msg);
$seg1 = $ack->getSegmentByIndex(1);
self::assertSame('CA', $seg1->getField(1), 'Error code is CA');
$msg = new Message();
$msh = new MSH();
$msh->setField(16);
$msh->setField(15);
$msg->addSegment($msh);
$ack = new ACK($msg);
$seg1 = $ack->getSegmentByIndex(1);
self::assertSame('AA', $seg1->getField(1), 'Error code is AA');
$ack->setAckCode('E');
self::assertSame('AE', $seg1->getField(1), 'Error code is AE');
$ack->setAckCode('CR');
self::assertSame('CR', $seg1->getField(1), 'Error code is CR');
$ack->setAckCode('CR', 'XX');
self::assertSame('XX', $seg1->getField(3), 'Set message and code');
$msg = new Message();
$msg->addSegment(new MSH());
$msh = $msg->getSegmentByIndex(0);
$msh->setField(16, 'NE');
$msh->setField(11, 'P');
$msh->setField(12, '2.4');
$msh->setField(15, 'NE');
$ack = new ACK($msg);
$seg0 = $ack->getSegmentByIndex(0);
self::assertSame('P', $seg0->getField(11), 'Field 11 is P');
self::assertSame('2.4', $seg0->getField(12), 'Field 12 is 2.4');
self::assertSame('NE', $seg0->getField(15), 'Field 15 is NE');
self::assertSame('NE', $seg0->getField(16), 'Field 16 is NE');
$ack = new ACK($msg);
$ack->setErrorMessage('Some error');
$seg1 = $ack->getSegmentByIndex(1);
self::assertSame('Some error', $seg1->getField(3), 'Setting error message');
self::assertSame('CE', $seg1->getField(1), 'Code CE after setting message');
}
/** @test
* @throws Exception
*/
public function a_MSH_can_be_provided_to_get_the_fields_from(): void
{
$msg = new Message("MSH|^~\\&|1|\rPV1|1|O|^AAAA1^^^BB|");
$msh = new MSH(
[
'MSH', '^~\&', 'HL7 Corp', 'HL7 HQ', 'VISION', 'MISYS', '200404061744', '', ['DFT', 'P03'], 'TC-22222',
'T', '2.3',
]
);
$ack = new ACK($msg, $msh);
self::assertSame("MSH|^~\&|VISION|MISYS|HL7 Corp|HL7 HQ|||ACK|\nMSA|AA|TC-22222|\n", $ack->toString(true));
}
/**
* @test
* @throws Exception
*/
public function globals_can_be_passed_to_constructor(): void
{
$msg = new Message("MSH|^~\\&|1|\rPV1|1|O|^AAAA1^^^BB|");
$ack = new ACK($msg, null, ['SEGMENT_SEPARATOR' => '\r\n']);
self::assertSame("MSH|^~\&|1||||||ACK|\r\nMSA|AA|\r\n", $ack->toString(true));
}
}
+86
View File
@@ -0,0 +1,86 @@
<?php
declare(strict_types=1);
namespace Aranyasen\HL7\Tests;
use Aranyasen\Exceptions\HL7ConnectionException;
use Aranyasen\Exceptions\HL7Exception;
use Aranyasen\HL7\Message;
use Aranyasen\HL7\Connection;
use RuntimeException;
class ConnectionTest extends TestCase
{
use Hl7ListenerTrait;
protected int $port = 12011;
protected function tearDown(): void
{
$this->deletePipe();
parent::tearDown();
}
/**
* @test
* @throws HL7ConnectionException
* @throws HL7Exception
*/
public function a_message_can_be_sent_to_a_hl7_server(): void
{
if (!extension_loaded('pcntl')) {
self::markTestSkipped("Extension pcntl_fork is not loaded");
}
$pid = pcntl_fork();
if ($pid === -1) {
throw new RuntimeException('Could not fork');
}
if (!$pid) { // In child process
$this->createTcpServer($this->port, 1);
}
if ($pid) { // in Parent process...
sleep(2); // Give a second to server (child) to start up. TODO: Speed up by polling
$connection = new Connection('localhost', $this->port);
$msg = new Message("MSH|^~\\&|1|\rPV1|1|O|^AAAA1^^^BB|", null, true, true);
$ack = $connection->send($msg);
self::assertInstanceOf(Message::class, $ack);
self::assertSame('MSH|^~\&|1||||||ACK|\nMSA|AA|\n|\n', $ack->toString());
self::assertStringContainsString("MSH|^~\\&|1|\nPV1|1|O|^AAAA1^^^BB|", $this->getWhatServerGot());
$this->closeTcpSocket($connection->getSocket()); // Clean up listener
pcntl_wait($status); // Wait till child is closed
}
}
/**
* @test
* @throws HL7ConnectionException
* @throws HL7Exception
*/
public function do_not_wait_for_ack_after_sending_if_corresponding_parameter_is_set(): void
{
if (!extension_loaded('pcntl')) {
self::markTestSkipped("Extension pcntl_fork is not loaded");
}
$pid = pcntl_fork();
if ($pid === -1) {
throw new RuntimeException('Could not fork');
}
if (!$pid) { // In child process
$this->createTcpServer($this->port, 1);
}
if ($pid) { // in Parent process...
sleep(2); // Give a second to server (child) to start up
$connection = new Connection('localhost', $this->port);
$msg = new Message("MSH|^~\\&|1|\rPV1|1|O|^AAAA1^^^BB|", null, true, true);
self::assertNull($connection->send($msg, ' UTF-8', true));
$this->closeTcpSocket($connection->getSocket()); // Clean up listener
pcntl_wait($status); // Wait till child is closed
}
}
}
+187
View File
@@ -0,0 +1,187 @@
<?php
declare(strict_types=1);
namespace Aranyasen\HL7\Tests;
use Aranyasen\Exceptions\HL7Exception;
use Aranyasen\HL7;
use Aranyasen\HL7\Segments\PID;
use DMS\PHPUnitExtensions\ArraySubset\Assert;
class HL7Test extends TestCase
{
/** @test
* @throws HL7Exception
*/
public function hl7_message_can_be_created_using_factory_class(): void
{
$msg = HL7::build()->createMessage();
self::assertIsObject($msg);
self::assertSame(HL7\Message::class, $msg::class);
}
/** @test
* @throws HL7Exception
*/
public function factory_creates_a_msh_segment_with_defaults_when_no_message_string_provided(): void
{
$msg = HL7::build()->createMessage();
self::assertStringContainsString('MSH|^~\&|||||', $msg->toString(true));
}
/** @test
* @throws HL7Exception
*/
public function a_message_can_be_built_from_a_provided_hl7_string(): void
{
$msg = HL7::from("MSH|^~\\&|1|\rABC|||xxx|\r")->createMessage();
self::assertSame("MSH|^~\\&|1|\nABC|||xxx|\n", $msg->toString(true));
}
/** @test
* @throws HL7Exception
*/
public function hl7_property_in_a_given_hl7_string_can_be_overridden(): void
{
self::markTestSkipped('property cannot be overridden yet in Message() constructor');
$msg = HL7::from("MSH|^~\\&|1|\rABC|||xxx|\r")
->withEscapeCharacter('=')
->createMessage();
self::assertSame("MSH|^~=&|1|\nABC|||xxx|\n", $msg->toString(true));
}
/**
* @test
* @throws HL7Exception
*/
public function hl7_properties_can_be_set_using_chained_methods(): void
{
$msg = HL7::build()
->withSegmentSeparator('[')
->withFieldSeparator('#')
->withComponentSeparator('*')
->withSubcomponentSeparator('}')
->withRepetitionSeparator('`')
->withEscapeCharacter('=')
->withHL7Version('555.666')
->createMessage();
self::assertStringContainsString('MSH#*`=}#', $msg->toString(true));
}
/**
* @test
* @throws Exception
*/
public function empty_subfields_can_be_retained_if_needed(): void
{
$msg = HL7::from("MSH|^~\\&|1|\rPV1|1|O|^AAAA1^^^BB|")->keepEmptySubfields()->createMessage();
Assert::assertArraySubset(['', 'AAAA1', '', '', 'BB'], $msg->getSegmentByIndex(1)->getField(3));
}
/** @test
* @throws HL7Exception
*/
public function indices_of_each_segment_can_be_reset_when_message_is_composed(): void
{
// Create a message with a PID segment
$msg1 = HL7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|")->createMessage();
$msg1->addSegment(new PID());
self::assertSame(
"MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|1|\n",
$msg1->toString(true),
'PID index in first message is 1'
);
// Create another message with a PID segment
$msg2 = Hl7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|")->createMessage();
$msg2->addSegment(new PID());
self::assertSame(
"MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|2|\n",
$msg2->toString(true),
'PID index gets incremented'
);
// Create another message with a PID segment, this time with resetIndices()
$msg3 = Hl7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|")
->resetIndices()
->createMessage();
$msg3->addSegment(new PID());
self::assertSame("MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|1|\n", $msg3->toString(true), 'PID index resets to 1');
// Create a message with a PID segment
$msg4 = Hl7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|")->createMessage();
$msg4->addSegment(new PID());
self::assertSame(
"MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|2|\n",
$msg4->toString(true),
'PID index gets incremented'
);
$msg5 = Hl7::from("MSH|^~\&|||||||ORM^O01||P|2.3.1|")->createMessage();
$msg5->resetSegmentIndices();
$msg5->addSegment(new PID());
self::assertSame("MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|1|\n", $msg5->toString(true), 'PID index resets to 1');
}
/**
* @test
* @throws HL7Exception
*/
public function auto_increment_of_segment_indices_can_be_avoided(): void
{
$hl7String = "MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "OBX|1||11^AA|\n" . "OBX|1||22^BB|\n";
$msg = Hl7::from($hl7String)
->createMessage();
self::assertSame(
"MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "OBX|1||11^AA|\n" . "OBX|2||22^BB|\n",
$msg->toString(true),
'without autoIncrementIndices(false), each instance is auto-incremented'
);
$msg = Hl7::from($hl7String)
->autoIncrementIndices(false)
->createMessage();
self::assertSame(
"MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "OBX|1||11^AA|\n" . "OBX|1||22^BB|\n",
$msg->toString(true)
);
$msg = Hl7::from("MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "PID|||3^0\n")
->autoIncrementIndices(false)
->createMessage();
self::assertSame(
"MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "PID|||3^0|\n",
$msg->toString(true),
"With auto-incrementing off, a segment index shouldn't be inserted if not present"
);
}
/** @test
* @throws HL7Exception
*/
public function repetition_separation_character_can_be_ignored(): void
{
$message = Hl7::from("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1")
->createMessage();
self::assertIsArray(
$message->getSegmentByIndex(1)->getField(3),
'By default repetition should be split into array'
);
$message = Hl7::from("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1")
->doNotSplitRepetition() // Ignore repetition separator character
->createMessage();
$patientIdentifierList = $message->getSegmentByIndex(1)->getField(3);
self::assertIsArray($patientIdentifierList);
self::assertSame(['3', '0~4', '1'], $patientIdentifierList);
}
/** @test */
public function it_throws_exception_when_multiple_character_property_is_provided(): void
{
$this->expectException(HL7Exception::class);
$this->expectExceptionMessage("Parameter should be a single character. Received: 'aa'");
HL7::build()->withSegmentSeparator('aa');
}
}
+154
View File
@@ -0,0 +1,154 @@
<?php
declare(strict_types=1);
namespace Aranyasen\HL7\Tests;
use Aranyasen\Exceptions\HL7Exception;
use Aranyasen\HL7\Message;
use Aranyasen\HL7\Messages\ACK;
use Exception;
use RuntimeException;
/**
* Trait Hl7ListenerTrait
*
* Create a TCP socket server to receive HL7 messages. It responds to HL7 messages with an ACK
* It also creates a pipe so client can get back exactly what it sent. Useful for testing...
* To close the server, send "\n" or "shutdown\n"
* @package Aranyasen\HL7\Tests
*/
trait Hl7ListenerTrait
{
private string $pipeName = "pipe1";
// As per MLLP protocol, the sender prefixes and suffixes the HL7 message with certain codes. If these need to be
// overwritten, simply declare these after the 'use Hl7ListenerTrait' statement in the calling class
protected string $MESSAGE_PREFIX = "\013";
protected string $MESSAGE_SUFFIX = "\034\015";
public function writeToPipe(string $value): void
{
$pipe = fopen($this->pipeName, 'wb');
fwrite($pipe, $value);
}
public function readFromPipe(): string
{
$pipe = fopen($this->pipeName, 'rb');
return fread($pipe, 1024);
}
public function getWhatServerGot(): string
{
return $this->readFromPipe();
}
/**
* @param int $port
* @param int $totalClientsToConnect How many clients are expected to connect to this server, once it's up
* @throws HL7Exception
*/
public function createTcpServer(int $port, int $totalClientsToConnect): void
{
if (!extension_loaded('sockets')) {
throw new RuntimeException("need ext-sockets to run this");
}
if (($socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) {
throw new RuntimeException(
'socket_create() failed: reason: ' . socket_strerror(socket_last_error()) . "\n"
);
}
// This is to avoid "address already in use" error while doing ->bind()
if (!socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1)) {
echo socket_strerror(socket_last_error($socket));
exit(-1);
}
if (($ret = socket_bind($socket, "localhost", $port)) === false) {
throw new RuntimeException('socket_bind() failed: reason: ' . socket_strerror($ret) . "\n");
}
if (($ret = socket_listen($socket, 5)) === false) {
throw new RuntimeException('socket_listen() failed: reason: ' . socket_strerror($ret) . "\n");
}
$clientCount = 0;
while (true) { // Loop over each client
if (($clientSocket = socket_accept($socket)) === false) {
echo 'socket_accept() failed: reason: ' . socket_strerror(socket_last_error()) . "\n";
socket_close($clientSocket);
exit();
}
if ($clientSocket === false) {
continue;
}
$clientCount++;
$clientName = 'Unknown';
socket_getpeername($clientSocket, $clientName);
// echo "Client {$clientCount} ({$clientName}) connected\n"; // Uncomment to debug
while (true) { // Keep reading a given client until they send "shutdown" or an empty string
$buffer = socket_read($clientSocket, 1024); // Keeps reading until bytes exhaust, /n or /r
if (false === $buffer) {
break;
}
// echo "\n--- From client: '$buffer' ---\n\n"; // Uncomment to debug
if (!$buffer || empty(trim($buffer)) || false !== stripos($buffer, 'shutdown')) {
break;
}
$ackString = $this->getAckString($buffer);
$message = $this->MESSAGE_PREFIX . $ackString . $this->MESSAGE_SUFFIX;
socket_write($clientSocket, $message, strlen($message));
// Also write to a pipe/msg queue for client to get the actual message
$this->writeToPipe($buffer);
}
socket_shutdown($clientSocket);
socket_close($clientSocket);
if ($totalClientsToConnect > 0 && $clientCount >= $totalClientsToConnect) {
break;
}
}
socket_close($socket);
exit(0); // Child process needs it
}
/**
* @param $socket
*/
public function closeTcpSocket($socket): void
{
$msg = "\n"; // Or send "shutdown\n"
socket_write($socket, $msg, strlen($msg)); // Tell the client to shutdown
}
/**
* @return string ACK string
* @throws HL7Exception
* @throws Exception
*/
private function getAckString(string $hl7): string
{
// Remove message prefix and suffix
$hl7 = preg_replace('/^' . $this->MESSAGE_PREFIX . '/', '', $hl7);
$hl7 = preg_replace('/' . $this->MESSAGE_SUFFIX . '$/', '', $hl7);
$msg = new Message(trim($hl7), null, true, true);
return (new ACK($msg))->toString();
}
/**
* Clean up temporary pipe file generated for testing
*/
private function deletePipe(): void
{
if (file_exists($this->pipeName)) {
unlink($this->pipeName);
}
}
}
+638
View File
@@ -0,0 +1,638 @@
<?php
declare(strict_types=1);
namespace Aranyasen\HL7\Tests;
use Aranyasen\Exceptions\HL7Exception;
use Aranyasen\HL7\Message;
use Aranyasen\HL7\Segment;
use Aranyasen\HL7\Segments\MSH;
use Aranyasen\HL7\Segments\OBR;
use Aranyasen\HL7\Segments\OBX;
use Aranyasen\HL7\Segments\PID;
use Exception;
use InvalidArgumentException;
use DMS\PHPUnitExtensions\ArraySubset\Assert;
class MessageTest extends TestCase
{
/** @test */
public function segments_can_be_retrieved_using_index(): void
{
$msg = new Message("MSH|^~\\&|1|\rABC|\r");
self::assertSame('ABC', $msg->getSegmentByIndex(1)->getName());
}
/** @test */
public function segmentByIndex_returns_null_when_target_index_is_beyond_the_total_number_of_segments(): void
{
$msg = new Message("MSH|^~\\&|1|\rABC|\r");
self::assertNull($msg->getSegmentByIndex(2));
}
/** @test */
public function it_throws_error_when_field_separator_control_char_doesnt_match_the_actual_field_separators(): void
{
$this->expectException(HL7Exception::class);
$msg = new Message("MSH|^~\\&#\r");
}
/**
* @test
* @throws Exception
*/
public function subfields_can_be_retained_when_required(): void
{
$msg = new Message("MSH|^~\\&|1|\rPV1|1|O|^AAAA1^^^BB|", null, true);
$pv1 = $msg->getSegmentByIndex(1);
$fields = $pv1->getField(3);
Assert::assertArraySubset(['', 'AAAA1', '', '', 'BB'], $fields);
}
/** @test */
public function segments_can_be_added_to_existing_message(): void
{
$msg = new Message();
$msg->addSegment(new MSH());
$msg->addSegment(new Segment('PID'));
$seg0 = $msg->getSegmentByIndex(0);
$seg1 = $msg->getSegmentByIndex(1);
self::assertSame('MSH', $seg0->getName(), 'Segment 0 name MSH');
self::assertSame('PID', $seg1->getName(), 'Segment 1 name PID');
}
/** @test */
public function fields_can_be_added_to_existing_segments(): void
{
$msg = new Message();
$msg->addSegment(new MSH());
$msg->addSegment(new Segment('ABC'));
$seg0 = $msg->getSegmentByIndex(0);
$seg1 = $msg->getSegmentByIndex(1);
$seg0->setField(3, 'XXX');
$seg1->setField(2, 'Foo');
self::assertSame('XXX', $seg0->getField(3), '3d field of MSH');
self::assertSame('Foo', $seg1->getField(2), '2nd field of ABC');
self::assertSame('XXX', $msg->getSegmentByIndex(0)->getField(3), '3d field of MSH');
}
/** @test */
public function control_characters_are_properly_set_from_MSH_Segment(): void
{
$msg = new Message("MSH|^~\\&|1|\rABC|||xxx|\r");
self::assertSame("^~\\&", $msg->getSegmentByIndex(0)->getField(2), 'Encoding characters');
}
/**
* @test
* @throws Exception
*/
public function control_characters_can_be_customized_using_second_argument(): void
{
$msg = new Message("MSH|^~\\&|1|\nABC|||xxx|\n", ['SEGMENT_SEPARATOR' => '\r\n']);
self::assertSame('MSH|^~\\&|1|\r\nABC|||xxx|\r\n', $msg->toString(), 'Custom line-endings');
self::assertSame(
"MSH|^~\\&|1|\r\nABC|||xxx|\r\n",
$msg->toString(true),
'toString() respects custom line-endings'
);
}
/** @test
* @throws HL7Exception
*/
public function message_can_be_converted_to_string(): void
{
$msg = new Message("MSH|^~\\&|1|\rABC|||xxx|\r");
self::assertSame('MSH|^~\\&|1|\nABC|||xxx|\n', $msg->toString(), 'String representation of message');
self::assertSame(
"MSH|^~\\&|1|\nABC|||xxx|\n",
$msg->toString(true),
'Pretty print representation of message'
);
}
/** @test
* @throws HL7Exception
*/
public function toString_method_throws_exception_when_message_empty(): void
{
$msg = new Message();
$this->expectException(HL7Exception::class);
$msg->toString();
}
/** @test */
public function fields_and_subfields_can_be_set_properly(): void
{
$msg = new Message("MSH|^~\\&|1|\rABC|||xx^x&y&z^yy^zz|\r");
$segment1 = $msg->getSegmentByIndex(1);
$fields = $segment1->getField(3);
self::assertSame($fields[0], 'xx', 'Composed field');
self::assertSame($fields[1][1], 'y', 'Subcomposed field');
}
/** @test */
public function fields_can_be_separated_by_custom_character(): void
{
$msg = new Message("MSH*^~\\&*1\rABC***xxx\r"); // Use * as a field separator
self::assertSame(
'MSH*^~\&*1*\nABC***xxx*\n',
$msg->toString(),
'String representation of message with * as field separator'
);
self::assertSame('1', $msg->getSegmentByIndex(0)->getField(3), '3d field of MSH');
}
/** @test */
public function components_of_a_field_can_be_separated_by_custom_character(): void
{
$msg = new Message("MSH|*~\\&|1\rABC|||x*y*z\r");
$field = $msg->getSegmentByIndex(1)->getField(3);
self::assertSame('x', $field[0], 'Composed field with * as separator between subfields');
}
/** @test */
public function subcomponents_can_be_separated_by_custom_character(): void
{
$msg = new Message("MSH|^~\\@|1\rABC|||a^x@y@z^b\r");
$field = $msg->getSegmentByIndex(1)->getField(3);
self::assertSame('y', $field[1][1], 'Subcomposed field with @ as separator');
}
/** @test */
public function segments_can_be_added_from_message(): void
{
$msg = new Message();
$msg->addSegment(new Segment('XXX'));
self::assertSame('XXX', $msg->getSegmentByIndex(0)->getName(), 'Add segment');
}
/** @test */
public function segment_can_be_removed_from_message(): void
{
$msg = new Message("MSH|^~\\&|1|\nAAA|1||xxx|\nBBB|1|\nBBB|2|");
$segment = $msg->getFirstSegmentInstance('BBB');
$msg->removeSegment($segment);
self::assertSame("MSH|^~\\&|1|\nAAA|1||xxx|\nBBB|2|\n", $msg->toString(true));
$msg = new Message("MSH|^~\\&|1|\nAAA|1||xxx|\nBBB|1|a|\nBBB|2|b|\nBBB|3|c|");
$segment = $msg->getSegmentsByName('BBB')[1];
$msg->removeSegment($segment, true);
self::assertSame(
"MSH|^~\\&|1|\nAAA|1||xxx|\nBBB|1|a|\nBBB|2|c|\n",
$msg->toString(true),
'Should reset index of subsequent segments'
);
$msg = new Message("MSH|^~\\&|1|\nAAA|1||xxx|\nPID|1|\nBBB|2|");
$segment = $msg->getFirstSegmentInstanceByClass(PID::class);
$msg->removeSegment($segment);
self::assertSame("MSH|^~\\&|1|\nAAA|1||xxx|\nBBB|2|\n", $msg->toString(true));
}
/** @test */
public function segments_can_be_removed_from_message_using_index(): void
{
$msg = new Message();
$msg->addSegment(new Segment('XXX'));
$msg->addSegment(new Segment('YYY'));
$msg->removeSegmentByIndex(0);
self::assertSame('YYY', $msg->getSegmentByIndex(0)->getName(), 'Remove segment');
}
/**
* @test
* @throws Exception
*/
public function segments_can_be_removed_by_name(): void
{
$msg = new Message("MSH|^~\\&|1|\nAAA|1||xxx|\nAAA|2||\nBBB|1|\n");
$count = $msg->removeSegmentsByName('AAA');
self::assertSame("MSH|^~\\&|1|\nBBB|1|\n", $msg->toString(true), 'Removes consecutive segments');
self::assertSame(2, $count);
$msg = new Message("MSH|^~\\&|1|\nAAA|1||xxx|\nBBB|1|\nAAA|2|\n");
$count = $msg->removeSegmentsByName('AAA');
self::assertSame("MSH|^~\\&|1|\nBBB|1|\n", $msg->toString(true), 'removes non-consecutive segments');
self::assertSame(2, $count);
}
/** @test */
public function a_new_segment_can_be_inserted_between_two_existing_segments(): void
{
$msg = new Message();
$msg->addSegment(new Segment('AAA'));
$msg->addSegment(new Segment('BBB'));
$msg->insertSegment(new Segment('XXX'), 1);
self::assertSame('XXX', $msg->getSegmentByIndex(1)->getName(), 'Inserted segment');
self::assertSame('BBB', $msg->getSegmentByIndex(2)->getName(), 'Existing segment should shift');
}
/** @test */
public function MSH_segment_can_be_inserted_with_new_control_characters(): void
{
$msg = new Message();
$msh = new MSH(['MSH', '#~\&', '', '', '', '', '', '', ['AAA', 'BBB'], '', '', '555']);
$msg->insertSegment($msh, 0);
self::assertSame('MSH', $msg->getSegmentByIndex(0)->getName(), 'Inserted MSH');
self::assertSame(
'MSH|#~\&|||||||AAA#BBB|||555|\n',
$msg->toString(),
'Component separator should be # and version should be 555'
);
}
/** @test */
public function insertSegment_appends_when_the_target_index_is_same_as_the_count_of_total_segments(): void
{
$msg = new Message("MSH|^~\\&|1|\rAAA|1", null, true);
$msg->insertSegment(new Segment('XXX'), 2);
self::assertSame('MSH|^~\&|1|\nAAA|1|\nXXX|\n', $msg->toString());
}
/** @test */
public function it_should_not_be_possible_to_insert_segment_beyond_last_index(): void
{
$msg = new Message();
$this->expectException(InvalidArgumentException::class);
$msg->insertSegment(new Segment('ZZ1'), 3);
self::assertEmpty($msg->getSegmentByIndex(3), 'Erroneous insert');
}
/** @test */
public function a_segment_can_be_overwritten(): void
{
$msg = new Message();
$msg->addSegment(new Segment('AAA'));
$msg->setSegment(new Segment('BBB'), 0);
self::assertCount(0, $msg->getSegmentsByName('AAA'), 'No AAA segment anymore');
self::assertSame('BBB', $msg->getSegmentByIndex(0)->getName(), 'BBB should have replaced AAA');
}
/** @test */
public function setSegment_throws_exception_when_the_target_index_is_beyond_total_count_of_segments(): void
{
$this->expectException(InvalidArgumentException::class);
$msg = new Message("MSH|^~\\&|1|\nAAA|1|\n");
$msg->setSegment(new Segment('BBB'), 3);
}
/** @test */
public function setSegment_resets_control_characters_when_adding_MSH_segment_at_0th_index(): void
{
$msg = new Message();
$msh = new MSH(['MSH', '#~\&', '', '', '', '', '', '', ['AAA', 'BBB'], '', '', '555']);
$msg->setSegment($msh, 0);
self::assertSame(
'MSH|#~\&|||||||AAA#BBB|||555|\n',
$msg->toString(),
'Component separator should be # and version should be 555'
);
}
/** @test */
public function same_segment_type_can_be_added_multiple_times(): void
{
$msg = new Message();
$msg->addSegment(new Segment('AAA'));
$msg->addSegment(new Segment('AAA'));
self::assertCount(2, $msg->getSegmentsByName('AAA'), 'Message should have 2 AAAs');
}
/** @test
* @throws Exception
*/
public function field_separator_can_be_changed_after_message_creation(): void
{
$msg = new Message();
$msh = new MSH([]);
$msh->setField(1, '*');
$msh->setField(2, 'abcd');
$msg->addSegment($msh);
self::assertSame('MSH*abcd*\n', $msg->toString(), '* should be used as field separator');
$msh->setField(1, '|');
self::assertSame('MSH|abcd|\n', $msg->toString(), 'Field separator should be changed to |');
}
/**
* @test
* @throws Exception
*/
public function a_message_can_be_constructed_from_a_string(): void
{
$str = 'MSH|^~\&|Aranya HL7|Aranya HQ|VISION|MISYS|200404061744||DFT^P03|TC-2743|P^T|2.3|||AL|NE||ASCII||| |';
$msg = new Message($str);
self::assertCount(1, $msg->getSegments(), 'Message from string');
}
/** @test */
public function a_message_can_be_converted_to_a_string(): void
{
$str = 'MSH|^~\&|Aranya HL7|Aranya HQ|VISION|MISYS|200404061744||DFT^P03|TC-2743|P^T|2.3|||AL|NE||ASCII||| |';
$msg = new Message($str);
self::assertSame("$str\n", $msg->toString(true), 'Message to string with subcomponents');
}
/** @test */
public function a_segment_can_be_retrieved_as_a_string(): void
{
$msg = new Message("MSH*^~\\&*1\rXXX*a^b^c*a^b1&b2^c*xxx\r");
self::assertSame("MSH*^~\\&*1*", $msg->getSegmentAsString(0), 'MSH segment as string');
$xxx = new Segment('XXX');
$xxx->setField(2, ['a', ['b1', 'b2'], 'c']);
$msg->addSegment($xxx);
self::assertSame('XXX*a^b^c*a^b1&b2^c*xxx*', $msg->getSegmentAsString(1), 'XXX segment as string');
self::assertSame('XXX**a^b1&b2^c*', $msg->getSegmentAsString(2), 'XXX segment as string');
// Get segment field as string
self::assertSame('1', $msg->getSegmentFieldAsString(0, 3), 'MSH(3) as string');
self::assertSame('a^b1&b2^c', $msg->getSegmentFieldAsString(1, 2), 'XXX(2) as string');
}
/** @test */
public function getSegmentAsString_returns_null_if_the_target_segment_doesnt_exist(): void
{
$msg = new Message("MSH|^~\\&|1|\nABC|");
self::assertNull($msg->getSegmentAsString(5));
}
/** @test */
public function getSegmentFieldAsString_returns_null_if_the_target_segment_doesnt_exist(): void
{
$msg = new Message("MSH|^~\\&|1|\nABC|");
self::assertNull($msg->getSegmentFieldAsString(5, 1));
}
/** @test */
public function getSegmentFieldAsString_returns_null_if_the_target_field_doesnt_exist(): void
{
$msg = new Message("MSH|^~\\&|1|\nABC|");
self::assertNull($msg->getSegmentFieldAsString(1, 5));
}
/**
* @test
*/
public function an_exception_will_be_throw_in_invalid_string(): void
{
$this->expectException(HL7Exception::class);
$this->expectExceptionMessage('Not a valid message: invalid control segment');
new Message("I'm an invalid message");
}
/** @test */
public function segment_ending_bar_can_be_omitted(): void
{
$msg = new Message("MSH|^~\\&|1|\nABC|||xxx|\n", ['SEGMENT_ENDING_BAR' => false]);
self::assertSame("MSH|^~\\&|1\nABC|||xxx\n", $msg->toString(true), 'No ending bar on each segment');
$msg = new Message("MSH|^~\\&|1|\nABC|||xxx|\n");
self::assertSame("MSH|^~\\&|1|\nABC|||xxx|\n", $msg->toString(true), 'Ending bar retains by default');
}
/** @test */
public function segment_index_can_be_retrieved_from_a_message(): void
{
$message = new Message("MSH|^~\\&|1|\n");
$pid = new PID();
$message->addSegment($pid);
self::assertSame(1, $message->getSegmentIndex($pid));
$message = new Message("MSH|^~\\&|1|\nABC|||xxx|\n");
$pid = new PID();
$message->addSegment($pid);
self::assertSame(2, $message->getSegmentIndex($pid));
}
/** @test */
public function segmentIndex_returns_null_if_the_target_segment_is_not_found(): void
{
$message = new Message("MSH|^~\\&|1|\nABC|\n");
self::assertNull($message->getSegmentIndex(new Segment('XXX')));
}
/** @test */
public function message_type_can_be_checked(): void
{
$msg = new Message("MSH|^~\&|||||||ORM^O01||P|2.3.1|");
self::assertTrue($msg->isOrm());
self::assertFalse($msg->isOru());
self::assertFalse($msg->isSiu());
$msg = new Message("MSH|^~\&|||||||ORU^O01||P|2.3.1|");
self::assertTrue($msg->isOru());
self::assertFalse($msg->isOrm());
self::assertFalse($msg->isSiu());
$msg = new Message("MSH|^~\&|||||||SIU^S12||P|2.3.1|");
self::assertTrue($msg->isSiu());
self::assertFalse($msg->isOrm());
self::assertFalse($msg->isOru());
$msg = new Message("MSH|^~\&|||||||ADT^A01|");
self::assertTrue($msg->isAdt());
self::assertFalse($msg->isOrm());
self::assertFalse($msg->isOru());
}
/**
* The segment classes use static properties to maintain segment-index. This is required as one can add new segments
* to a given message object and expect the index to auto-increment. The side effect to this is, if you create a
* second message, adding the same segments will now start indexing from their index in the last message instead of
* 1! This happens because static properties are class properties, not object ones, and thus shared across all
* objects.
*
* To counter this, use 'true' in the 4th argument while creating a message, or call resetSegmentIndices()
* explicitly.
*
* This test verifies both.
*
* @test
* @throws Exception
*/
public function segment_id_can_be_reset_on_demand(): void
{
PID::resetIndex(); // Start with a clean slate
// Create a message with a PID segment
$msg1 = new Message("MSH|^~\&|||||||ORM^O01||P|2.3.1|");
$msg1->addSegment(new PID());
self::assertSame(
"MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|1|\n",
$msg1->toString(true),
'PID index in first message is 1'
);
// Create another message with a PID segment
$msg2 = new Message("MSH|^~\&|||||||ORM^O01||P|2.3.1|");
$msg2->addSegment(new PID());
self::assertSame(
"MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|2|\n",
$msg2->toString(true),
'PID index gets incremented'
);
// Create another message with a PID segment, this time 4th argument to message as true
$msg3 = new Message("MSH|^~\&|||||||ORM^O01||P|2.3.1|", resetIndices: true);
$msg3->addSegment(new PID());
self::assertSame("MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|1|\n", $msg3->toString(true), 'PID index resets to 1');
// Create a message with a PID segment
$msg4 = new Message("MSH|^~\&|||||||ORM^O01||P|2.3.1|");
$msg4->addSegment(new PID());
self::assertSame(
"MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|2|\n",
$msg4->toString(true),
'PID index gets incremented'
);
$msg5 = new Message("MSH|^~\&|||||||ORM^O01||P|2.3.1|");
$msg5->resetSegmentIndices();
$msg5->addSegment(new PID());
self::assertSame("MSH|^~\&|||||||ORM^O01||P|2.3.1|\nPID|1|\n", $msg5->toString(true), 'PID index resets to 1');
}
/**
* @test
* @throws Exception
*/
public function segment_index_autoincrement_can_be_avoided(): void
{
$hl7String = "MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "OBX|1||11^AA|\n" . "OBX|1||22^BB|\n";
$msg = new Message($hl7String, resetIndices: true);
self::assertSame(
"MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "OBX|1||11^AA|\n" . "OBX|2||22^BB|\n",
$msg->toString(true),
'without 5th argument as false, each instance is auto-incremented'
);
$msg = new Message($hl7String, null, true, true, false);
self::assertSame(
"MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "OBX|1||11^AA|\n" . "OBX|1||22^BB|\n",
$msg->toString(true)
);
$msg = new Message("MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "PID|||3^0\n", null, true, false, false);
self::assertSame(
"MSH|^~\&|||||||ORU^R01|00001|P|2.3.1|\n" . "PID|||3^0|\n",
$msg->toString(true),
"With auto-incrementing off, a segment index shouldn't be inserted if not present"
);
}
/** @test */
public function a_segments_presence_can_be_checked(): void
{
$message = new Message("MSH|^~\&|||||||ORM^O01||P|2.3.1|");
self::assertFalse($message->hasSegment('PID'));
$message->addSegment(new PID());
self::assertTrue($message->hasSegment('PID'));
}
/** @test */
public function first_of_the_given_segment_name_can_be_easily_obtained_using_a_helper_method(): void
{
$message = new Message("MSH|^~\&|||||||ORM^O01||P|2.3.1|");
$message->addSegment(new PID());
$firstPidSegment = $message->getFirstSegmentInstance('PID');
self::assertNotNull($firstPidSegment);
self::assertIsObject($firstPidSegment);
self::assertInstanceOf(PID::class, $firstPidSegment);
$firstPidSegment = $message->getFirstSegmentInstanceByClass(PID::class);
self::assertNotNull($firstPidSegment);
self::assertIsObject($firstPidSegment);
self::assertInstanceOf(PID::class, $firstPidSegment);
self::assertNull($message->getFirstSegmentInstance('XXX'), 'Non existing segment should return null');
}
/** @test */
public function message_can_be_verified_as_empty(): void
{
self::assertTrue((new Message())->isEmpty());
self::assertFalse((new Message("MSH|^~\&|||||||ORM^O01||P|2.3.1|"))->isEmpty());
}
/** @test */
public function field_with_repetition_separator_splits_into_array_by_default(): void
{
$message = new Message("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1"); // Repetition separator is ~
$patientIdentifierList = $message->getSegmentByIndex(1)->getField(3);
self::assertIsArray($patientIdentifierList);
self::assertSame('3', $patientIdentifierList[0][0]);
self::assertSame('0', $patientIdentifierList[0][1]);
self::assertSame('4', $patientIdentifierList[1][0]);
self::assertSame('1', $patientIdentifierList[1][1]);
}
/** @test */
public function field_with_repetition_separator_can_be_split_into_array(): void
{
$message = new Message("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1", doNotSplitRepetition: false);
$patientIdentifierList = $message->getSegmentByIndex(1)->getField(3);
self::assertIsArray($patientIdentifierList);
self::assertSame('3', $patientIdentifierList[0][0]);
self::assertSame('0', $patientIdentifierList[0][1]);
self::assertSame('4', $patientIdentifierList[1][0]);
self::assertSame('1', $patientIdentifierList[1][1]);
}
/** @test */
public function repetition_separation_character_can_be_ignored(): void
{
$message = new Message("MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1", doNotSplitRepetition: true);
$pid = $message->getSegmentByIndex(1);
$patientIdentifierList = $pid->getField(3);
self::assertIsArray($patientIdentifierList);
self::assertSame(['3', '0~4', '1'], $patientIdentifierList);
}
/** @test */
public function a_message_can_be_saved_in_a_file(): void
{
$hl7File = __DIR__ . DIRECTORY_SEPARATOR . 'hl7_test_' . random_int(100, 1000) . '.hl7';
$message = new Message("MSH|^~\&|");
$message->toFile($hl7File);
self::assertFileExists($hl7File);
self::assertSame($message->toString(true), file_get_contents($hl7File));
if (file_exists($hl7File)) {
unlink($hl7File);
}
}
/** @test */
public function segments_can_be_retrieved_by_class(): void
{
$message = new Message(
"MSH|^~\&|||||||ADT^A01||P|2.3.1|\nPID|||3^0~4^1\nOBX|1|||\nOBX|2|||",
doNotSplitRepetition: true
);
$MSHs = $message->getSegmentsByClass(MSH::class);
self::assertCount(1, $MSHs);
self::assertInstanceOf(MSH::class, $MSHs[0]);
$PIDs = $message->getSegmentsByClass(PID::class);
self::assertCount(1, $PIDs);
self::assertInstanceOf(PID::class, $PIDs[0]);
$OBXs = $message->getSegmentsByClass(OBX::class);
self::assertCount(2, $OBXs);
self::assertInstanceOf(OBX::class, $OBXs[0]);
$OBRs = $message->getSegmentsByClass(OBR::class);
self::assertCount(0, $OBRs);
}
}
+123
View File
@@ -0,0 +1,123 @@
<?php
declare(strict_types=1);
namespace Aranyasen\HL7\Tests;
use Aranyasen\HL7\Segment;
use InvalidArgumentException;
class SegmentTest extends TestCase
{
/** @test */
public function it_throws_error_when_segment_name_has_less_than_3_characters(): void
{
$this->expectException(InvalidArgumentException::class);
new Segment('XX');
}
/** @test */
public function it_throws_exception_when_a_blank_string_is_passed_as_segment_name(): void
{
$this->expectException(InvalidArgumentException::class);
new Segment('');
}
/** @test */
public function it_throws_exception_when_segment_name_is_not_in_upper_case(): void
{
$this->expectException(InvalidArgumentException::class);
new Segment('xxx');
}
/** @test */
public function field_at_a_given_nonzero_index_can_be_set(): void
{
$seg = new Segment('XXX');
$seg->setField(1, 'YYY');
self::assertSame('YYY', $seg->getField(1), 'Field 1 is YYY');
}
/** @test */
public function field_at_index_0_can_not_be_changed(): void
{
$seg = new Segment('XXX');
$seg->setField(0, 'YYY');
self::assertNotSame('YYY', $seg->getField(0), 'Field 0 has not been changed');
self::assertSame('XXX', $seg->getField(0), 'Field 0 is still the same');
self::assertSame('XXX', $seg->getName(), 'Segment name is still the same');
}
/** @test */
public function a_segment_can_be_constructed_from_an_array(): void
{
$seg = new Segment('XXX', ['a', 'b', 'c', ['p', 'q', 'r'], 'd']);
self::assertSame('c', $seg->getField(3), 'Constructor with array');
self::assertSame('r', $seg->getField(4)[2], 'Constructor with array for composed fields');
}
/** @test */
public function field_can_be_cleared(): void
{
$segment = new Segment('XXX', ['a']);
self::assertSame('a', $segment->getField(1));
$segment->clearField(1);
self::assertNull($segment->getField(1), 'Field 1 should be NULL');
}
/** @test */
public function field_can_be_set_using_array(): void
{
$seg = new Segment('XXX');
$seg->setField(3, ['1', '2', '3']);
self::assertIsArray($seg->getField(3), 'Composed field 1^2^3');
self::assertCount(3, $seg->getField(3), 'Getting composed fields as array');
self::assertSame('2', $seg->getField(3)[1], 'Getting single value from composed field');
}
/** @test */
public function fields_from_a_given_position_to_end_can_be_retrieved_in_an_array(): void
{
$seg = new Segment('XXX');
$seg->setField(8, 'aaa');
self::assertCount(7, $seg->getFields(2), 'Getting all fields from 2nd index');
}
/** @test */
public function a_chunk_of_fields_can_be_retrieved_from_a_segment(): void
{
$seg = new Segment('XXX');
$seg->setField(8, 'aaa');
self::assertCount(3, $seg->getFields(2, 4), 'Getting fields from 2 till 4');
}
/** @test */
public function setting_field_beyond_last_index_creates_empty_fields_in_between(): void
{
$seg = new Segment('XXX');
$seg->setField(8, 'aaa');
self::assertCount(9, $seg->getFields(), 'Number of fields in segment');
}
/** @test */
public function total_size_of_a_segment_can_be_obtained(): void
{
$seg = new Segment('XXX');
$seg->setField(8, ['']);
self::assertSame(8, $seg->size(), 'Size operator');
$seg->setField(12, 'x');
self::assertSame(12, $seg->size(), 'Size operator');
}
/** @test */
public function a_field_can_have_0_as_a_value(): void
{
$segment = new Segment('XXX');
$segment->setField(1, 0);
self::assertSame(0, $segment->getField(1));
$segment->setField(1, '0');
self::assertSame('0', $segment->getField(1));
}
}
+82
View File
@@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace Aranyasen\HL7\Tests\Segments;
use Aranyasen\HL7\Segments\MSH;
use Aranyasen\HL7\Tests\TestCase;
use Exception;
class MSHTest extends TestCase
{
/** @test */
public function MSH_formed_without_any_arguments_should_have_mandatory_fields_set_automatically(): void
{
$msh = new MSH();
self::assertSame('|', $msh->getField(1));
self::assertSame('^~\\&', $msh->getField(2));
self::assertSame('2.3', $msh->getVersionId());
self::assertNotEmpty($msh->getDateTimeOfMessage());
self::assertMatchesRegularExpression('/\d{14}/', $msh->getDateTimeOfMessage());
self::assertNotEmpty($msh->getMessageControlId());
}
/** @test
* @throws Exception
*/
public function an_array_of_fields_can_be_passed_to_constructor_to_construct_MSH(): void
{
$msh = new MSH(
[
'MSH', '^~\&', 'HL7 Corp', 'HL7 HQ', 'VISION', 'MISYS', '200404061744', '', ['DFT', 'P03'], 'TC-22222',
'T', '2.3',
]
);
self::assertSame(
[
'MSH', '', '^~\&', 'HL7 Corp', 'HL7 HQ', 'VISION', 'MISYS', '200404061744', '', ['DFT', 'P03'],
'TC-22222', 'T', '2.3',
],
$msh->getFields()
);
}
/** @test */
public function field_separator_can_be_set(): void
{
$msh = new MSH();
$msh->setField(1, '*');
self::assertSame('*', $msh->getField(1), 'MSH Field sep field (MSH(1))');
}
/** @test */
public function more_than_one_character_as_field_separator_is_not_accepted(): void
{
$msh = new MSH();
$msh->setField(1, 'xx');
self::assertSame('|', $msh->getField(1), 'MSH Field sep field (MSH(1))');
}
/** @test */
public function version_id_can_be_string_or_array_for_v2_7_onwards(): void
{
$msh = new MSH();
$msh->setVersionId('2.3');
self::assertSame('2.3', $msh->getVersionId());
$msh->setVersionId(['2.7', 'NZL', '1.0']);
self::assertSame(['2.7', 'NZL', '1.0'], $msh->getVersionId());
}
/** @test */
public function index_2_in_MSH_accepts_only_4_character_strings(): void
{
$msh = new MSH();
$msh->setField(2, 'xxxx');
self::assertSame('xxxx', $msh->getField(2), 'Special fields not changed');
$msh->setField(2, 'yyyyy');
self::assertSame('xxxx', $msh->getField(2), 'Special fields not changed');
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace Aranyasen\HL7\Tests\Segments;
use Aranyasen\HL7\Message;
use Aranyasen\HL7\Segments\NK1;
use Aranyasen\HL7\Tests\TestCase;
class NK1Test extends TestCase
{
/** @test */
public function NK1_segment_can_be_parsed_from_a_HL7_message(): void
{
$msg = new Message("MSH|^~\\&|1|\nNK1|1|John^Doe|\n");
$nk1Segments = $msg->getSegmentsByName('NK1');
self::assertIsArray($nk1Segments);
self::assertCount(1, $nk1Segments);
self::assertSame(['John', 'Doe'], $nk1Segments[0]->getNKName());
}
/** @test */
public function next_of_kin_name_can_be_set_and_get(): void
{
$nk1Segment = new NK1();
$nk1Segment->setNKName("John Doe");
self::assertSame("John Doe", $nk1Segment->getNKName());
}
}
+22
View File
@@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace Aranyasen\HL7\Tests\Segments;
use Aranyasen\HL7\Segments\OBX;
use Aranyasen\HL7\Tests\TestCase;
class OBXTest extends TestCase
{
/** @test */
public function segment_id_automatically_increments_when_a_new_instance_is_created(): void
{
OBX::resetIndex(); // Previous tests would have incremented the static $index variable
$obx = new OBX();
$this->assertSame(1, $obx->getID());
$obx = new OBX();
$this->assertSame(2, $obx->getID());
}
}
+73
View File
@@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
namespace Aranyasen\HL7\Tests\Segments;
use Aranyasen\Exceptions\HL7Exception;
use Aranyasen\HL7\Message;
use Aranyasen\HL7\Segments\PID;
use Aranyasen\HL7\Tests\TestCase;
use InvalidArgumentException;
class PIDTest extends TestCase
{
/**
* @dataProvider validSexValues
* @test
*/
public function PID_8_should_accept_value_for_sex_as_per_hl7_standard(string $validSexValue): void
{
$pidSegment = (new PID());
$pidSegment->setSex($validSexValue);
self::assertSame($validSexValue, $pidSegment->getSex(), "Sex should have been set with '$validSexValue'");
self::assertSame($validSexValue, $pidSegment->getField(8), "Sex should have been set with '$validSexValue'");
}
/**
* @dataProvider invalidSexValues
* @test
* @param string $invalidSexValue
*/
public function PID_8_should_not_accept_non_standard_values_for_sex(string $invalidSexValue): void
{
$pidSegment = (new PID());
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage("Sex should one of 'A', 'F', 'M', 'N', 'O' or 'U'. Given: '$invalidSexValue'");
$pidSegment->setSex($invalidSexValue);
self::assertEmpty($pidSegment->getSex(), "Sex should not have been set with value: $invalidSexValue");
self::assertEmpty($pidSegment->getField(8), "Sex should not have been set with value: $invalidSexValue");
}
/** @test
* @throws HL7Exception
*/
public function PID_5_should_parse_properly(): void
{
$messageString = "MSH|^~\\&|1|\r" .
'PID|||||' .
'Test &""&firstname &""&""^F^N N^^^^F^^^^""~Test &""&Test^Test^""^^^^B~""&""&""^^^^^^P~^Lastname^^^^^N|' .
"\r";
$msg = new Message($messageString, null, false, true, true, true);
self::assertSame(
'MSH|^~\&|1|\nPID|1||||Test &""&firstname &""&""^F^N N^F^""~Test &""&Test^Test^""^B~""&""&""^P~^' .
'Lastname^N|\n',
$msg->toString()
);
}
public function validSexValues(): array
{
return [
['A'], ['F'], ['M'], ['N'], ['O'], ['U']
];
}
public function invalidSexValues(): array
{
return [
['B'], ['Z'], ['z'], ['a']
];
}
}
+20
View File
@@ -0,0 +1,20 @@
<?php
namespace Aranyasen\HL7\Tests;
use PHPUnit\Framework\TestCase as TC;
abstract class TestCase extends TC
{
protected function setUp(): void
{
parent::setUp();
//
}
protected function tearDown(): void
{
// Any tearDown should appear before parent::tearDown()
parent::tearDown();
}
}