<?php
/**
 * This file is part of PDepend.
 *
 * Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   * Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in
 *     the documentation and/or other materials provided with the
 *     distribution.
 *
 *   * Neither the name of Manuel Pichler nor the names of his
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 *
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 */

namespace PDepend\Source\Language\PHP\Features\PHP82;

use PDepend\Source\AST\ASTCompoundExpression;
use PDepend\Source\AST\ASTConstantDeclarator;
use PDepend\Source\AST\ASTConstantDefinition;
use PDepend\Source\AST\ASTMemberPrimaryPrefix;
use PDepend\Source\AST\ASTNode;
use PDepend\Source\AST\ASTProperty;
use PDepend\Source\AST\ASTPropertyPostfix;

/**
 * @copyright 2008-2017 Manuel Pichler. All rights reserved.
 * @license http://www.opensource.org/licenses/bsd-license.php BSD License
 * @covers \PDepend\Source\Language\PHP\PHPParserVersion82
 * @group unittest
 * @group php8.2
 */
class FetchPropertiesOfEnumsInConstExpressionsTest extends PHPParserVersion82Test
{
    /**
     * @return void
     */
    public function testEnumConst()
    {
        $enums = $this->parseCodeResourceForTest()
            ->current()
            ->getEnums();

        $this->assertSame(1, $enums->count());

        $enum = $enums->current();
        $constants = $enum->getConstants();

        $this->assertCount(1, $constants);
        $this->assertInstanceOf('PDepend\\Source\\AST\\ASTArray', $constants['C']);

        $elements = $constants['C']->getChildren();
        $this->assertCount(1, $elements);
        $children = $elements[0]->getChildren();
        $this->assertCount(2, $children);

        $this->assertSame('self::B->value', $this->constructImage($children[0]));
        $this->assertSame('self::B', $this->constructImage($children[1]));
    }

    public function testVariousUsages()
    {
        $classes = $this->parseCodeResourceForTest()
            ->current()
            ->getClasses();

        $d = $classes[0];
        $this->assertSame('D', $d->getName());

        $f = $classes[1];
        $this->assertSame('F', $f->getName());

        $properties = $f->getProperties();
        $this->assertSame(1, $properties->count());

        /** @var ASTProperty $property */
        $property = $properties->current();
        $this->assertSame('E::Foo->name', $this->constructImage($property->getDefaultValue()));

        $g = $classes[2];
        $this->assertSame('G', $g->getName());

        /** @var ASTConstantDefinition[] $constants */
        $constants = $g->getChildren();
        $this->assertCount(1, $constants);

        /** @var ASTConstantDeclarator[] $declarators */
        $declarators = $constants[0]->getChildren();
        $declaration = $declarators[0];

        $this->assertSame('C', $declaration->getImage());
        $this->assertSame('E::Foo->{VALUE}', $this->constructImage($declaration->getValue()->getValue()));
    }

    public function constructImage(ASTNode $node)
    {
        $self = $this;

        return implode($node->getImage(), array_map(function ($child) use ($self) {
            if ($child instanceof ASTCompoundExpression) {
                return '{' . $self->constructImage($child) . '}';
            }

            if ($child instanceof ASTMemberPrimaryPrefix || $child instanceof ASTPropertyPostfix) {
                return $self->constructImage($child);
            }

            return $child->getImage();
        }, $node->getChildren()));
    }
}
