PHP Classes

File: tests/Unit/Encoding/DynamicCodecTest.php

Recommend this page to a friend!
  Packages of Gianfrancesco Aurecchia   OPC UA Client   tests/Unit/Encoding/DynamicCodecTest.php   Download  
File: tests/Unit/Encoding/DynamicCodecTest.php
Role: Example script
Content type: text/plain
Description: Example script
Class: OPC UA Client
Control devices that support the OPC UA protocol
Author: By
Last change:
Date: 7 days ago
Size: 10,175 bytes
 

Contents

Class file image Download
<?php

declare(strict_types=1);

use
PhpOpcua\Client\Encoding\BinaryDecoder;
use
PhpOpcua\Client\Encoding\BinaryEncoder;
use
PhpOpcua\Client\Encoding\DataTypeMapping;
use
PhpOpcua\Client\Encoding\DynamicCodec;
use
PhpOpcua\Client\Encoding\StructureDefinitionParser;
use
PhpOpcua\Client\Types\BuiltinType;
use
PhpOpcua\Client\Types\NodeId;
use
PhpOpcua\Client\Types\StructureDefinition;
use
PhpOpcua\Client\Types\StructureField;

describe('DataTypeMapping', function () {

   
it('resolves standard built-in types', function () {
       
expect(DataTypeMapping::resolve(NodeId::numeric(0, 1)))->toBe(BuiltinType::Boolean);
       
expect(DataTypeMapping::resolve(NodeId::numeric(0, 6)))->toBe(BuiltinType::Int32);
       
expect(DataTypeMapping::resolve(NodeId::numeric(0, 11)))->toBe(BuiltinType::Double);
       
expect(DataTypeMapping::resolve(NodeId::numeric(0, 12)))->toBe(BuiltinType::String);
       
expect(DataTypeMapping::resolve(NodeId::numeric(0, 13)))->toBe(BuiltinType::DateTime);
    });

   
it('returns null for custom types', function () {
       
expect(DataTypeMapping::resolve(NodeId::numeric(2, 5001)))->toBeNull();
       
expect(DataTypeMapping::resolve(NodeId::string(1, 'MyType')))->toBeNull();
    });

   
it('returns null for unknown ns=0 identifiers', function () {
       
expect(DataTypeMapping::resolve(NodeId::numeric(0, 9999)))->toBeNull();
    });
});

describe('StructureDefinitionParser', function () {

   
it('parses a simple structure definition', function () {
       
$encoder = new BinaryEncoder();
       
$encoder->writeNodeId(NodeId::numeric(2, 5001));
       
$encoder->writeNodeId(NodeId::numeric(0, 22));
       
$encoder->writeUInt32(StructureDefinition::STRUCTURE);
       
$encoder->writeInt32(3);

        foreach ([
'x', 'y', 'z'] as $name) {
           
$encoder->writeString($name);
           
$encoder->writeLocalizedText(new PhpOpcua\Client\Types\LocalizedText(null, null));
           
$encoder->writeNodeId(NodeId::numeric(0, 11));
           
$encoder->writeInt32(-1);
           
$encoder->writeInt32(0);
           
$encoder->writeUInt32(0);
           
$encoder->writeBoolean(false);
        }

       
$decoder = new BinaryDecoder($encoder->getBuffer());
       
$def = StructureDefinitionParser::parse($decoder);

       
expect($def->structureType)->toBe(StructureDefinition::STRUCTURE);
       
expect($def->fields)->toHaveCount(3);
       
expect($def->fields[0]->name)->toBe('x');
       
expect($def->fields[0]->dataType->identifier)->toBe(11);
       
expect($def->fields[1]->name)->toBe('y');
       
expect($def->fields[2]->name)->toBe('z');
       
expect($def->defaultEncodingId->identifier)->toBe(5001);
    });

   
it('parses a definition with optional fields', function () {
       
$encoder = new BinaryEncoder();
       
$encoder->writeNodeId(NodeId::numeric(2, 6001));
       
$encoder->writeNodeId(NodeId::numeric(0, 22));
       
$encoder->writeUInt32(StructureDefinition::WITH_OPTIONAL_FIELDS);
       
$encoder->writeInt32(2);

       
$encoder->writeString('required');
       
$encoder->writeLocalizedText(new PhpOpcua\Client\Types\LocalizedText(null, null));
       
$encoder->writeNodeId(NodeId::numeric(0, 6));
       
$encoder->writeInt32(-1);
       
$encoder->writeInt32(0);
       
$encoder->writeUInt32(0);
       
$encoder->writeBoolean(false);

       
$encoder->writeString('optional');
       
$encoder->writeLocalizedText(new PhpOpcua\Client\Types\LocalizedText(null, null));
       
$encoder->writeNodeId(NodeId::numeric(0, 12));
       
$encoder->writeInt32(-1);
       
$encoder->writeInt32(0);
       
$encoder->writeUInt32(0);
       
$encoder->writeBoolean(true);

       
$decoder = new BinaryDecoder($encoder->getBuffer());
       
$def = StructureDefinitionParser::parse($decoder);

       
expect($def->structureType)->toBe(StructureDefinition::WITH_OPTIONAL_FIELDS);
       
expect($def->fields[0]->isOptional)->toBeFalse();
       
expect($def->fields[1]->isOptional)->toBeTrue();
    });
});

describe('DynamicCodec', function () {

   
it('decodes a simple structure with scalar fields', function () {
       
$def = new StructureDefinition(
           
StructureDefinition::STRUCTURE,
            [
                new
StructureField('x', NodeId::numeric(0, 11)),
                new
StructureField('y', NodeId::numeric(0, 11)),
                new
StructureField('z', NodeId::numeric(0, 11)),
            ],
           
NodeId::numeric(2, 5001),
        );
       
$codec = new DynamicCodec($def);

       
$encoder = new BinaryEncoder();
       
$encoder->writeDouble(1.5);
       
$encoder->writeDouble(2.5);
       
$encoder->writeDouble(3.5);

       
$decoder = new BinaryDecoder($encoder->getBuffer());
       
$result = $codec->decode($decoder);

       
expect($result)->toBe(['x' => 1.5, 'y' => 2.5, 'z' => 3.5]);
    });

   
it('encodes a simple structure', function () {
       
$def = new StructureDefinition(
           
StructureDefinition::STRUCTURE,
            [
                new
StructureField('x', NodeId::numeric(0, 11)),
                new
StructureField('y', NodeId::numeric(0, 11)),
            ],
           
NodeId::numeric(2, 5001),
        );
       
$codec = new DynamicCodec($def);

       
$encoder = new BinaryEncoder();
       
$codec->encode($encoder, ['x' => 1.0, 'y' => 2.0]);

       
$decoder = new BinaryDecoder($encoder->getBuffer());
       
expect($decoder->readDouble())->toBe(1.0);
       
expect($decoder->readDouble())->toBe(2.0);
    });

   
it('round-trips decode/encode for mixed types', function () {
       
$def = new StructureDefinition(
           
StructureDefinition::STRUCTURE,
            [
                new
StructureField('name', NodeId::numeric(0, 12)),
                new
StructureField('value', NodeId::numeric(0, 11)),
                new
StructureField('count', NodeId::numeric(0, 6)),
                new
StructureField('active', NodeId::numeric(0, 1)),
            ],
           
NodeId::numeric(2, 5001),
        );
       
$codec = new DynamicCodec($def);

       
$original = ['name' => 'sensor', 'value' => 42.5, 'count' => 100, 'active' => true];

       
$enc = new BinaryEncoder();
       
$codec->encode($enc, $original);

       
$dec = new BinaryDecoder($enc->getBuffer());
       
$decoded = $codec->decode($dec);

       
expect($decoded)->toBe($original);
    });

   
it('handles array fields', function () {
       
$def = new StructureDefinition(
           
StructureDefinition::STRUCTURE,
            [
                new
StructureField('values', NodeId::numeric(0, 11), valueRank: 1),
            ],
           
NodeId::numeric(2, 5001),
        );
       
$codec = new DynamicCodec($def);

       
$encoder = new BinaryEncoder();
       
$encoder->writeInt32(3);
       
$encoder->writeDouble(10.0);
       
$encoder->writeDouble(20.0);
       
$encoder->writeDouble(30.0);

       
$decoder = new BinaryDecoder($encoder->getBuffer());
       
$result = $codec->decode($decoder);

       
expect($result['values'])->toBe([10.0, 20.0, 30.0]);
    });

   
it('handles optional fields present', function () {
       
$def = new StructureDefinition(
           
StructureDefinition::WITH_OPTIONAL_FIELDS,
            [
                new
StructureField('required', NodeId::numeric(0, 6)),
                new
StructureField('optional', NodeId::numeric(0, 12), isOptional: true),
            ],
           
NodeId::numeric(2, 6001),
        );
       
$codec = new DynamicCodec($def);

       
$encoder = new BinaryEncoder();
       
$encoder->writeUInt32(1);
       
$encoder->writeInt32(42);
       
$encoder->writeString('hello');

       
$decoder = new BinaryDecoder($encoder->getBuffer());
       
$result = $codec->decode($decoder);

       
expect($result['required'])->toBe(42);
       
expect($result['optional'])->toBe('hello');
    });

   
it('handles optional fields absent', function () {
       
$def = new StructureDefinition(
           
StructureDefinition::WITH_OPTIONAL_FIELDS,
            [
                new
StructureField('required', NodeId::numeric(0, 6)),
                new
StructureField('optional', NodeId::numeric(0, 12), isOptional: true),
            ],
           
NodeId::numeric(2, 6001),
        );
       
$codec = new DynamicCodec($def);

       
$encoder = new BinaryEncoder();
       
$encoder->writeUInt32(0);
       
$encoder->writeInt32(42);

       
$decoder = new BinaryDecoder($encoder->getBuffer());
       
$result = $codec->decode($decoder);

       
expect($result['required'])->toBe(42);
       
expect($result['optional'])->toBeNull();
    });

   
it('handles union with active field', function () {
       
$def = new StructureDefinition(
           
StructureDefinition::UNION,
            [
                new
StructureField('intVal', NodeId::numeric(0, 6)),
                new
StructureField('strVal', NodeId::numeric(0, 12)),
            ],
           
NodeId::numeric(2, 7001),
        );
       
$codec = new DynamicCodec($def);

       
$encoder = new BinaryEncoder();
       
$encoder->writeUInt32(2);
       
$encoder->writeString('test');

       
$decoder = new BinaryDecoder($encoder->getBuffer());
       
$result = $codec->decode($decoder);

       
expect($result['_switchField'])->toBe(2);
       
expect($result['strVal'])->toBe('test');
    });

   
it('handles union with no active field', function () {
       
$def = new StructureDefinition(
           
StructureDefinition::UNION,
            [
                new
StructureField('intVal', NodeId::numeric(0, 6)),
            ],
           
NodeId::numeric(2, 7001),
        );
       
$codec = new DynamicCodec($def);

       
$encoder = new BinaryEncoder();
       
$encoder->writeUInt32(0);

       
$decoder = new BinaryDecoder($encoder->getBuffer());
       
$result = $codec->decode($decoder);

       
expect($result['_switchField'])->toBe(0);
    });

   
it('exposes the definition via getDefinition()', function () {
       
$def = new StructureDefinition(StructureDefinition::STRUCTURE, [], NodeId::numeric(2, 1));
       
$codec = new DynamicCodec($def);

       
expect($codec->getDefinition())->toBe($def);
    });
});