<?php

declare(strict_types=1);

/*
 * Copyright (c) 2023-2024 François Kooman <fkooman@tuxed.net>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

namespace fkooman\Radius\Tests;

use fkooman\Radius\AttributeCollection;
use fkooman\Radius\Exception\AttributeCollectionException;
use fkooman\Radius\Utils;
use PHPUnit\Framework\TestCase;
use RangeException;

/**
 * @covers \fkooman\Radius\AttributeCollection
 *
 * @uses \fkooman\Radius\Utils
 */
class AttributeCollectionTest extends TestCase
{
    public function testAdd(): void
    {
        $attributeCollection = new AttributeCollection();
        $attributeCollection->add('User-Name', 'foo');
        $this->assertSame('0105666f6f', bin2hex($attributeCollection->toBytes()));
    }

    public function testAddInvalidLength(): void
    {
        // User-Password MUST be at least length 16
        $this->expectException(RangeException::class);
        $this->expectExceptionMessage('string length MUST be >= 16 octets');
        $attributeCollection = new AttributeCollection();
        $attributeCollection->add('User-Password', 'xyz');
    }

    public function testGet(): void
    {
        $attributeCollection = AttributeCollection::fromBytes(hex2bin('0105666f6f'));
        $this->assertSame(['foo'], $attributeCollection->get('User-Name'));
    }

    public function testGetNoneExistent(): void
    {
        $attributeCollection = AttributeCollection::fromBytes(hex2bin('0105666f6f'));
        $this->assertSame([], $attributeCollection->get('Reply-Message'));
    }

    public function testGetOne(): void
    {
        $attributeCollection = AttributeCollection::fromBytes(hex2bin('0105666f6f'));
        $this->assertSame('foo', $attributeCollection->getOne('User-Name'));
    }

    public function testGetOneNoneExistent(): void
    {
        $attributeCollection = AttributeCollection::fromBytes(hex2bin('0105666f6f'));
        $this->assertNull($attributeCollection->getOne('Reply-Message'));
    }

    public function testGetOneMoreThanOne(): void
    {
        $this->expectException(AttributeCollectionException::class);
        $this->expectExceptionMessage('there are 2 values for "Reply-Message"');
        $attributeCollection = new AttributeCollection();
        $attributeCollection->add('Reply-Message', 'foo');
        $attributeCollection->add('Reply-Message', 'bar');
        $attributeCollection->getOne('Reply-Message');
    }

    public function testRequireOne(): void
    {
        $attributeCollection = AttributeCollection::fromBytes(hex2bin('0105666f6f'));
        $this->assertSame('foo', $attributeCollection->requireOne('User-Name'));
    }

    public function testRequireOneNoneExistent(): void
    {
        $this->expectException(AttributeCollectionException::class);
        $this->expectExceptionMessage('there are no values for "Reply-Message"');
        $attributeCollection = AttributeCollection::fromBytes(hex2bin('0105666f6f'));
        $attributeCollection->requireOne('Reply-Message');
    }

    public function testAddVsa(): void
    {
        $attributeCollection = new AttributeCollection();
        $attributeCollection->add('3076.25', 'foobar');
        $this->assertSame('1a0e00000c041908666f6f626172', bin2hex($attributeCollection->toBytes()));
    }

    public function testGetVsa(): void
    {
        $attributeCollection = AttributeCollection::fromBytes(hex2bin('1a0e00000c041908666f6f626172'));
        $this->assertSame(['foobar'], $attributeCollection->get('3076.25'));
    }

    public function testSet(): void
    {
        $attributeCollection = new AttributeCollection();
        $attributeCollection->set('User-Name', 'foo');
        $this->assertSame('0105666f6f', bin2hex($attributeCollection->toBytes()));
        $attributeCollection->set('User-Name', 'bar');
        $this->assertSame('0105626172', bin2hex($attributeCollection->toBytes()));
    }

    public function testSetNasIpAddress(): void
    {
        $attributeCollection = new AttributeCollection();
        $attributeCollection->set('NAS-IP-Address', Utils::ipAddressToBytes('192.168.16.5'));
        $this->assertSame([hex2bin('c0a81005')], $attributeCollection->get('NAS-IP-Address'));
    }
}
