diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..2f0f4a0
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,20 @@
+language: php
+
+sudo: false
+
+cache:
+ directories:
+ - $HOME/.composer/cache
+
+php:
+ - 5.6
+ - 7.0
+
+before_install:
+ - travis_retry composer self-update
+
+install:
+ - travis_retry composer update --no-interaction
+
+script:
+ - composer test-ci
\ No newline at end of file
diff --git a/README.md b/README.md
index f478cd8..1c522f0 100644
--- a/README.md
+++ b/README.md
@@ -2,12 +2,12 @@
Implementation of the basic functionality of the Modbus TCP and UDP based protocol using PHP.
-**NOTE: This is a fork to fix & update the library code (and code alone). Notably, the tests are probably all broken.**
+**NOTE: This is a fork to fix & update the library code (and code alone).**
-> **What's new**
->
-> This fork adds a namespace and fixes issues encountered when porting to PHP 7
+##What's new
+* This fork adds a namespace and fixes issues encountered when porting to PHP 7
+* Fixes/replaces old MS Windows specific tests
## Implemented features
@@ -26,6 +26,7 @@ Implementation of the basic functionality of the Modbus TCP and UDP based protoc
## Requirements
* The PHP extension php_sockets.dll should be enabled (server php.ini file)
+ * PHP 5.3.2 (5.6 for tests)
## Example
@@ -53,6 +54,19 @@ Use the `setTimeout($seconds)` and `setSocketTimeout($read_timeout_sec, $write_t
Most of the code is (to some extent) commented and documented with PhpDoc. You should get useful tooltips in your IDE.
+## Tests
+
+To run the test suite, you need install the dependencies via composer, then
+run PHPUnit.
+
+NB: PHP 5.6+ is required for tests
+
+ composer install
+ composer test # or under Windows vendor\bin\phunit.bat
+
+To report test coverage (created inside ./report/html):
+
+ composer test-coverage
## GoogleCode legacy docs & downloads
diff --git a/composer.json b/composer.json
index d52d076..9adf523 100644
--- a/composer.json
+++ b/composer.json
@@ -32,5 +32,10 @@
"psr-4": {
"Tests\\": "tests/"
}
+ },
+ "scripts": {
+ "test": "vendor/bin/phpunit",
+ "test-ci": "vendor/bin/phpunit --coverage-clover report/coverage.xml",
+ "test-coverage": "vendor/bin/phpunit --coverage-html report/html"
}
}
diff --git a/examples/example_750841_Mmemory.php b/examples/example_750841_Mmemory.php
index 6fa8f90..4cb5f03 100644
--- a/examples/example_750841_Mmemory.php
+++ b/examples/example_750841_Mmemory.php
@@ -1,12 +1,10 @@
- |
- |
- |
+ |
+ |
+ |
|
|
|
diff --git a/examples/example_datatype.php b/examples/example_datatype.php
index aeb0a7b..402bdf9 100644
--- a/examples/example_datatype.php
+++ b/examples/example_datatype.php
@@ -1,12 +1,10 @@
./tests/*
-
-
-
-
-
src
diff --git a/tests/ModbusMaster/Fc15WriteMultipleCoilsTest.php b/tests/ModbusMaster/Fc15WriteMultipleCoilsTest.php
index bc59828..2d7a178 100644
--- a/tests/ModbusMaster/Fc15WriteMultipleCoilsTest.php
+++ b/tests/ModbusMaster/Fc15WriteMultipleCoilsTest.php
@@ -18,4 +18,24 @@ class Fc15WriteMultipleCoilsTest extends MockServerTestCase
$packetWithoutTransactionId = substr($clientData[0], 4);
$this->assertEquals('00000008000f300000030105', $packetWithoutTransactionId);
}
+
+ public function testFc15WriteMultipleCoilsWithMultiWordPacket()
+ {
+ $mockResponse = 'a51100000006000f00000020';
+ $clientData = static::executeWithMockServer($mockResponse, function ($port) {
+ $modbus = new ModbusMaster('127.0.0.1', 'TCP');
+ $modbus->port = $port;
+
+ $this->assertTrue($modbus->fc15(0, 0,
+ [
+ 1, 0, 1, 1, 0, 1, 1, 1,
+ 1, 1, 1, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ ]));
+ });
+
+ $packetWithoutTransactionId = substr($clientData[0], 4);
+ $this->assertEquals('0000000b000f0000002004ed0ff0ff', $packetWithoutTransactionId);
+ }
}
\ No newline at end of file
diff --git a/tests/ModbusMaster/MockServerTestCase.php b/tests/ModbusMaster/MockServerTestCase.php
index b6e93fd..ba80b51 100644
--- a/tests/ModbusMaster/MockServerTestCase.php
+++ b/tests/ModbusMaster/MockServerTestCase.php
@@ -23,6 +23,11 @@ abstract class MockServerTestCase extends TestCase
$clientData[] = $output;
});
+ if (strpos(PHP_OS, 'WIN') === false || getenv('MOCKSERVER_TIMEOUT_USEC') !== false) {
+ // wait to spin up. needed for linux. unnessecary on Windows 10.
+ // Ugly but even with 150ms sleep test run faster on Linux
+ usleep(getenv('MOCKSERVER_TIMEOUT_USEC') ?: 150000);
+ }
$closure($port);
});
diff --git a/tests/ModbusMaster/ModbusExceptionTest.php b/tests/ModbusMaster/ModbusExceptionTest.php
index 0d31651..aa1c6df 100644
--- a/tests/ModbusMaster/ModbusExceptionTest.php
+++ b/tests/ModbusMaster/ModbusExceptionTest.php
@@ -1,38 +1,42 @@
expectException(\Exception::class);
- $this->expectExceptionMessage("Unknown socket protocol, should be 'TCP' or 'UDP'");
-
$modbus = new ModbusMaster('127.0.0.1', 'Mismatch');
$modbus->readCoils(0, 256, 1);
}
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage socket_connect() failed. Reason: ()No connection could be made because the target machine actively refused it
+ */
public function testPortClosedException()
{
- $this->expectException(\Exception::class);
- $this->expectExceptionMessage('socket_connect() failed. Reason: ()No connection could be made because the target machine actively refused it.');
-
$modbus = new ModbusMasterTcp('127.0.0.1');
$modbus->setSocketTimeout(0.2, 0.2);
$modbus->readCoils(0, 256, 1);
}
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessageRegExp /Watchdog time expired \[ 0\.5 sec \]!!! Connection to 127\.0\.0\.1:.* is not established/
+ */
public function testTimeoutException()
{
- $this->expectException(\Exception::class);
$mockResponse = '89130000000400010101'; // respond with 1 byte (00000001 bits set) [1]
static::executeWithMockServer($mockResponse, function ($port) {
- $this->expectExceptionMessage("Watchdog time expired [ 0.5 sec ]!!! Connection to 127.0.0.1:{$port} is not established.");
-
$modbus = new ModbusMaster('127.0.0.1', 'UDP');
$modbus->port = $port;
$modbus->setTimeout(0.5);
@@ -42,12 +46,12 @@ class ModbusExceptionTest extends MockServerTestCase
}, 'UDP', 1);
}
-
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage Modbus response error code: 3 (ILLEGAL DATA VALUE)
+ */
public function testThrowIllegalDataValueException()
{
- $this->expectException(\Exception::class);
- $this->expectExceptionMessage('Modbus response error code: 3 (ILLEGAL DATA VALUE)');
-
$mockResponse = 'da8700000003008303'; // respond with 1 WORD (2 bytes) [0, 3]
$clientData = static::executeWithMockServer($mockResponse, function ($port) {
$modbus = new ModbusMaster('127.0.0.1', 'TCP');
diff --git a/tests/ModbusMaster/UdpFc1ReadCoilsTest.php b/tests/ModbusMaster/UdpFc1ReadCoilsTest.php
index 78a6e34..a2d563e 100644
--- a/tests/ModbusMaster/UdpFc1ReadCoilsTest.php
+++ b/tests/ModbusMaster/UdpFc1ReadCoilsTest.php
@@ -13,7 +13,7 @@ class UdpFc1ReadCoilsTest extends MockServerTestCase
$modbus = new ModbusMasterUdp('127.0.0.1');
$modbus->port = $port;
- usleep(50000); // no idea how to fix this. wait for server to "warm" up or modbus UDP socket will timeout. does not occur with TCP
+ usleep(150000); // no idea how to fix this. wait for server to "warm" up or modbus UDP socket will timeout. does not occur with TCP
$this->assertEquals([1], $modbus->readCoils(0, 256, 1));
}, 'UDP');
diff --git a/tests/PhpType/Bytes2MixedTest.php b/tests/PhpType/Bytes2MixedTest.php
index fcaa25b..3692910 100644
--- a/tests/PhpType/Bytes2MixedTest.php
+++ b/tests/PhpType/Bytes2MixedTest.php
@@ -6,7 +6,7 @@ use PHPUnit\Framework\TestCase;
class PhpTypeBytes2Mixed extends TestCase
{
- const DATA = [
+ private $data = [
"0" => 125, // 32098 (DINT)
"1" => 98,
"2" => 0,
@@ -31,15 +31,15 @@ class PhpTypeBytes2Mixed extends TestCase
public function testUnsignedInt()
{
- $this->assertEquals(32098, PhpType::bytes2unsignedInt(array_slice(self::DATA, 0, 4)));
+ $this->assertEquals(32098, PhpType::bytes2unsignedInt(array_slice($this->data, 0, 4)));
}
public function testSignedInt()
{
- $this->assertEquals(0, PhpType::bytes2signedInt(array_slice(self::DATA, 4, 4)));
- $this->assertEquals(0, PhpType::bytes2signedInt(array_slice(self::DATA, 8, 4)));
- $this->assertEquals(-1, PhpType::bytes2signedInt(array_slice(self::DATA, 12, 4)));
- $this->assertEquals(-25000, PhpType::bytes2signedInt(array_slice(self::DATA, 16, 2)));
- $this->assertEquals(25000, PhpType::bytes2signedInt(array_slice(self::DATA, 18, 2)));
+ $this->assertEquals(0, PhpType::bytes2signedInt(array_slice($this->data, 4, 4)));
+ $this->assertEquals(0, PhpType::bytes2signedInt(array_slice($this->data, 8, 4)));
+ $this->assertEquals(-1, PhpType::bytes2signedInt(array_slice($this->data, 12, 4)));
+ $this->assertEquals(-25000, PhpType::bytes2signedInt(array_slice($this->data, 16, 2)));
+ $this->assertEquals(25000, PhpType::bytes2signedInt(array_slice($this->data, 18, 2)));
}
}
diff --git a/tests/PhpType/Bytes2RealTest.php b/tests/PhpType/Bytes2RealTest.php
index 2fd7b80..1bb7458 100644
--- a/tests/PhpType/Bytes2RealTest.php
+++ b/tests/PhpType/Bytes2RealTest.php
@@ -7,7 +7,7 @@ use PHPUnit_Framework_TestCase;
class Bytes2Real extends PHPUnit_Framework_TestCase
{
- const DATA = [
+ private $data = [
0 => 0,
1 => 0,
2 => 68,
@@ -24,8 +24,8 @@ class Bytes2Real extends PHPUnit_Framework_TestCase
public function testByte2Real()
{
- $this->assertEquals(1000, PhpType::bytes2float(array_slice(self::DATA, 0, 4)));
- $this->assertEquals(2000, PhpType::bytes2float(array_slice(self::DATA, 4, 4)));
- $this->assertEquals(1.25, PhpType::bytes2float(array_slice(self::DATA, 8, 4)));
+ $this->assertEquals(1000, PhpType::bytes2float(array_slice($this->data, 0, 4)));
+ $this->assertEquals(2000, PhpType::bytes2float(array_slice($this->data, 4, 4)));
+ $this->assertEquals(1.25, PhpType::bytes2float(array_slice($this->data, 8, 4)));
}
}
diff --git a/tests/PhpType/Bytes2SignedIntTest.php b/tests/PhpType/Bytes2SignedIntTest.php
index 362a30d..dcf4467 100644
--- a/tests/PhpType/Bytes2SignedIntTest.php
+++ b/tests/PhpType/Bytes2SignedIntTest.php
@@ -6,7 +6,7 @@ use PHPUnit\Framework\TestCase;
class Bytes2SignedInt extends TestCase
{
- const DATA = [
+ private $data = [
0xFF, // -1
0xFF,
0xFF,
@@ -31,12 +31,12 @@ class Bytes2SignedInt extends TestCase
public function testByte2SignedInt()
{
- $this->assertEquals(-1, PhpType::bytes2signedInt(array_slice(self::DATA, 0, 2)));
- $this->assertEquals(-1, PhpType::bytes2signedInt(array_slice(self::DATA, 0, 4)));
+ $this->assertEquals(-1, PhpType::bytes2signedInt(array_slice($this->data, 0, 2)));
+ $this->assertEquals(-1, PhpType::bytes2signedInt(array_slice($this->data, 0, 4)));
- $this->assertEquals(0, PhpType::bytes2signedInt(array_slice(self::DATA, 4, 4)));
- $this->assertEquals(1, PhpType::bytes2signedInt(array_slice(self::DATA, 8, 4)));
- $this->assertEquals(-2147483648, PhpType::bytes2signedInt(array_slice(self::DATA, 12, 4)));
- $this->assertEquals(2147483647, PhpType::bytes2signedInt(array_slice(self::DATA, 16, 4)));
+ $this->assertEquals(0, PhpType::bytes2signedInt(array_slice($this->data, 4, 4)));
+ $this->assertEquals(1, PhpType::bytes2signedInt(array_slice($this->data, 8, 4)));
+ $this->assertEquals(-2147483648, PhpType::bytes2signedInt(array_slice($this->data, 12, 4)));
+ $this->assertEquals(2147483647, PhpType::bytes2signedInt(array_slice($this->data, 16, 4)));
}
}
diff --git a/tests/PhpType/Bytes2StringTest.php b/tests/PhpType/Bytes2StringTest.php
index 8b5d788..851c331 100644
--- a/tests/PhpType/Bytes2StringTest.php
+++ b/tests/PhpType/Bytes2StringTest.php
@@ -6,7 +6,7 @@ use PHPUnit\Framework\TestCase;
class Bytes2String extends TestCase
{
- const DATA = [ // String "Hello word!"
+ private $data = [ // String "Hello word!"
0x48, //H
0x65, //e
0x6c, //l
@@ -26,7 +26,7 @@ class Bytes2String extends TestCase
public function testBytesToString()
{
- $this->assertEquals('eHll oowlr!da', PhpType::bytes2string(self::DATA));
- $this->assertEquals('Hello world!', PhpType::bytes2string(self::DATA, true));
+ $this->assertEquals('eHll oowlr!da', PhpType::bytes2string($this->data));
+ $this->assertEquals('Hello world!', PhpType::bytes2string($this->data, true));
}
}
diff --git a/tests/PhpType/Bytes2UnSignedIntTest.php b/tests/PhpType/Bytes2UnSignedIntTest.php
index 2c424fc..14e2698 100644
--- a/tests/PhpType/Bytes2UnSignedIntTest.php
+++ b/tests/PhpType/Bytes2UnSignedIntTest.php
@@ -6,7 +6,7 @@ use PHPUnit\Framework\TestCase;
class Bytes2UnSignedIntTest extends TestCase
{
- const DATA = [
+ private $data = [
0xFF, // -1
0xFF,
0xFF,
@@ -31,12 +31,12 @@ class Bytes2UnSignedIntTest extends TestCase
public function testByte2SignedInt()
{
- $this->assertEquals(65535, PhpType::bytes2unsignedInt(array_slice(self::DATA, 0, 2)));
- $this->assertEquals(4294967295, PhpType::bytes2unsignedInt(array_slice(self::DATA, 0, 4)));
+ $this->assertEquals(65535, PhpType::bytes2unsignedInt(array_slice($this->data, 0, 2)));
+ $this->assertEquals(4294967295, PhpType::bytes2unsignedInt(array_slice($this->data, 0, 4)));
- $this->assertEquals(0, PhpType::bytes2unsignedInt(array_slice(self::DATA, 4, 4)));
- $this->assertEquals(1, PhpType::bytes2unsignedInt(array_slice(self::DATA, 8, 4)));
- $this->assertEquals(2147483648, PhpType::bytes2unsignedInt(array_slice(self::DATA, 12, 4)));
- $this->assertEquals(2147483647, PhpType::bytes2unsignedInt(array_slice(self::DATA, 16, 4)));
+ $this->assertEquals(0, PhpType::bytes2unsignedInt(array_slice($this->data, 4, 4)));
+ $this->assertEquals(1, PhpType::bytes2unsignedInt(array_slice($this->data, 8, 4)));
+ $this->assertEquals(2147483648, PhpType::bytes2unsignedInt(array_slice($this->data, 12, 4)));
+ $this->assertEquals(2147483647, PhpType::bytes2unsignedInt(array_slice($this->data, 16, 4)));
}
}
diff --git a/tests/PhpType/PhpTypeArrayExceptionWithTextArrayTest.php b/tests/PhpType/PhpTypeArrayExceptionWithTextArrayTest.php
index 0565a13..62efe58 100644
--- a/tests/PhpType/PhpTypeArrayExceptionWithTextArrayTest.php
+++ b/tests/PhpType/PhpTypeArrayExceptionWithTextArrayTest.php
@@ -6,22 +6,26 @@ use PHPUnit\Framework\TestCase;
class PhpTypeArrayExceptionWithTextArrayTest extends TestCase
{
- const DATA = [
+ private $data = [
"0" => 100, // 32098 (DINT)
"1" => "e",
"2" => 0,
"3" => 0
];
+ /**
+ * @expectedException \Exception
+ */
public function testExceptionWhenSize2ContainsString()
{
- $this->expectException(\Exception::class);
- PhpType::bytes2unsignedInt(array_slice(self::DATA, 0, 2));
+ PhpType::bytes2unsignedInt(array_slice($this->data, 0, 2));
}
+ /**
+ * @expectedException \Exception
+ */
public function testExceptionWhenSize4ContainsString()
{
- $this->expectException(\Exception::class);
- PhpType::bytes2unsignedInt(array_slice(self::DATA, 0, 4));
+ PhpType::bytes2unsignedInt(array_slice($this->data, 0, 4));
}
}
diff --git a/tests/PhpType/PhpTypeArraySizeExceptionsTest.php b/tests/PhpType/PhpTypeArraySizeExceptionsTest.php
index 6003ad4..1782fc2 100644
--- a/tests/PhpType/PhpTypeArraySizeExceptionsTest.php
+++ b/tests/PhpType/PhpTypeArraySizeExceptionsTest.php
@@ -6,7 +6,7 @@ use PHPUnit\Framework\TestCase;
class PhpTypeArraySizeExceptionsTest extends TestCase
{
- const DATA = [
+ private $data = [
"0" => 100, // 32098 (DINT)
"1" => 2,
"2" => 0,
@@ -15,32 +15,38 @@ class PhpTypeArraySizeExceptionsTest extends TestCase
"5" => 2
];
+ /**
+ * @expectedException \Exception
+ */
public function testExceptionWhenSizeShort()
{
- $this->expectException(\Exception::class);
- PhpType::bytes2unsignedInt(array_slice(self::DATA, 0, 1));
+ PhpType::bytes2unsignedInt(array_slice($this->data, 0, 1));
}
+ /**
+ * @expectedException \Exception
+ */
public function testExceptionWhenSizeShort3()
{
- $this->expectException(\Exception::class);
- PhpType::bytes2unsignedInt(array_slice(self::DATA, 0, 3));
+ PhpType::bytes2unsignedInt(array_slice($this->data, 0, 3));
}
+ /**
+ * @expectedException \Exception
+ */
public function testExceptionWhenSizeLong()
{
- $this->expectException(\Exception::class);
- PhpType::bytes2unsignedInt(array_slice(self::DATA, 0, 5));
+ PhpType::bytes2unsignedInt(array_slice($this->data, 0, 5));
}
public function testNoExceptionWhenSize2()
{
- $this->assertEquals(25602, PhpType::bytes2unsignedInt(array_slice(self::DATA, 0, 2)));
+ $this->assertEquals(25602, PhpType::bytes2unsignedInt(array_slice($this->data, 0, 2)));
}
public function testNoExceptionWhenSize4()
{
- $this->assertEquals(25602, PhpType::bytes2unsignedInt(array_slice(self::DATA, 0, 4)));
+ $this->assertEquals(25602, PhpType::bytes2unsignedInt(array_slice($this->data, 0, 4)));
}
}
\ No newline at end of file