<?php declare(strict_types=1);

namespace Newland\Toubiz\Poi\Neos\Tests\Unit\LinkHandler\Filter\Items;


use Neos\Flow\Tests\FunctionalTestCase;
use Newland\NeosTestingHelpers\InteractsWithNodes;
use Newland\Toubiz\Poi\Neos\Filter\ArticleFilterFactory;
use Newland\Toubiz\Poi\Neos\Filter\Items\ArticleRoot;
use Newland\Toubiz\Poi\Neos\Filter\Items\AttributeCheckboxList;
use Newland\Toubiz\Sync\Neos\Domain\Filter\ArticleFilter;
use Newland\Toubiz\Sync\Neos\Domain\Model\Article;
use Newland\Toubiz\Sync\Neos\Tests\Factory\ArticleFactory;
use Newland\Toubiz\Sync\Neos\Tests\Factory\AttributeFactory;

class AttributeCheckboxListTest extends FunctionalTestCase
{
    use InteractsWithNodes;
    protected static $testablePersistenceEnabled = true;

    /** @var ArticleFactory */
    protected $articleFactory;

    /** @var AttributeFactory */
    protected $attributeFactory;

    /** @var ArticleFilterFactory */
    protected $filterFactory;

    public function setUp(): void
    {
        parent::setUp();
        $this->articleFactory = new ArticleFactory($this->objectManager);
        $this->attributeFactory = new AttributeFactory($this->objectManager);
        $this->filterFactory = new ArticleFilterFactory($this->initializeNode('/sites/foo'));
    }

    public function testFindsArticlesWhereAttributeHasValue(): void
    {
        // Note : combination setting does not change anything here since we only have 1 state
        $articles = $this->setupSimpleEntitiesAndFilter('OR');
        $filter = $articles['filter'];
        unset($articles['filter']);

        $filter->setState([ 'tag' => [ 'foo' ] ]);
        $ids = array_map(
            function (Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $filter->getArticleQuery()->getQuery()->execute()
        );

        $this->assertContains($articles['foo']->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($articles['bar']->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($articles['baz']->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($articles['fooBar']->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($articles['fooBaz']->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($articles['barBaz']->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($articles['fooBarBaz']->getPersistenceObjectIdentifier(), $ids);
    }

    public function testCombinesOptionsWithOr(): void
    {
        $articles = $this->setupSimpleEntitiesAndFilter('OR');
        $filter = $articles['filter'];
        unset($articles['filter']);

        $filter->setState([ 'tag' => [ 'foo', 'bar' ] ]);
        $ids = array_map(
            function (Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $filter->getArticleQuery()->getQuery()->execute()
        );

        $this->assertContains($articles['foo']->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($articles['bar']->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($articles['baz']->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($articles['fooBar']->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($articles['fooBaz']->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($articles['barBaz']->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($articles['fooBarBaz']->getPersistenceObjectIdentifier(), $ids);
    }

    public function testCombinesOptionsWithAnd(): void
    {
        $articles = $this->setupSimpleEntitiesAndFilter('AND');
        $filter = $articles['filter'];
        unset($articles['filter']);

        $filter->setState([ 'tag' => [ 'foo', 'bar' ] ]);
        $ids = array_map(
            function (Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $filter->getArticleQuery()->getQuery()->execute()
        );

        $this->assertNotContains(
            $articles['foo']->getPersistenceObjectIdentifier(),
            $ids,
            'Filter for (foo && bar) should not contain [foo]'
        );
        $this->assertNotContains(
            $articles['bar']->getPersistenceObjectIdentifier(),
            $ids,
            'Filter for (foo && bar) should not contain [bar]'
        );
        $this->assertNotContains(
            $articles['baz']->getPersistenceObjectIdentifier(),
            $ids,
            'Filter for (foo && bar) should not contain [baz]'
        );
        $this->assertContains(
            $articles['fooBar']->getPersistenceObjectIdentifier(),
            $ids,
            'Filter for (foo && bar) should contain [foo,bar]'
        );
        $this->assertNotContains(
            $articles['fooBaz']->getPersistenceObjectIdentifier(),
            $ids,
            'Filter for (foo && bar) should not contain [foo, baz]'
        );
        $this->assertNotContains(
            $articles['barBaz']->getPersistenceObjectIdentifier(),
            $ids,
            'Filter for (foo && bar) should not contain [bar, baz]'
        );
        $this->assertContains(
            $articles['fooBarBaz']->getPersistenceObjectIdentifier(),
            $ids,
            'Filter for (foo && bar) should contain [foo, bar, baz]'
        );
    }

    public function testCombinationOfMultipleListsWithAndPossible(): void
    {
        // tag=foo, num=4
        $first = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'foo' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 4 ]),
                ],
            ]
        );
        // tag=bar, num=4
        $second = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'bar' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 4 ]),
                ],
            ]
        );
        // tag=baz, num=7
        $third = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'baz' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 7 ]),
                ],
            ]
        );


        /** @var ArticleRoot $filter */
        $filter = $this->filterFactory->createFilter(
            [
                'combine' => 'AND',
                'children' => [
                    'tags' => [
                        'type' => AttributeCheckboxList::class,
                        'queryString' => 'tag',
                        'combine' => 'OR',
                        'databaseColumn' => 'entity.Persistence_Object_Identifier',
                        'dataSource' => 'newland-neosfiltering-tests-example',
                        'dataSourceArguments' => [
                            [ 'label' => 'foo', 'value' => 'tag:foo' ],
                            [ 'label' => 'bar', 'value' => 'tag:bar' ],
                            [ 'label' => 'baz', 'value' => 'tag:baz' ],
                        ],
                    ],
                    'num' => [
                        'type' => AttributeCheckboxList::class,
                        'queryString' => 'num',
                        'combine' => 'OR',
                        'databaseColumn' => 'entity.Persistence_Object_Identifier',
                        'dataSource' => 'newland-neosfiltering-tests-example',
                        'dataSourceArguments' => [
                            [ 'label' => '4', 'value' => 'num:4', 'attributeType' => 'number' ],
                            [ 'label' => '7', 'value' => 'num:7', 'attributeType' => 'number' ],
                        ],
                    ],
                ],
            ]
        );

        $filter->setState([ 'tag' => [ 'tag:foo' ], 'num' => [ 'num:4' ] ]);
        $this->assertCount(1, $filter->getArticleQuery()->getQuery()->execute());
    }

    public function testCombinationOfMultipleListsWithOrPossible(): void
    {
        // tag=foo, num=4
        $first = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'foo' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 4 ]),
                ],
            ]
        );
        // tag=bar, num=4
        $second = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'bar' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 4 ]),
                ],
            ]
        );
        // tag=baz, num=7
        $third = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'baz' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 7 ]),
                ],
            ]
        );


        /** @var ArticleRoot $filter */
        $filter = $this->filterFactory->createFilter(
            [
                'combine' => 'OR',
                'children' => [
                    'tags' => [
                        'type' => AttributeCheckboxList::class,
                        'queryString' => 'tag',
                        'combine' => 'OR',
                        'databaseColumn' => 'entity.Persistence_Object_Identifier',
                        'dataSource' => 'newland-neosfiltering-tests-example',
                        'dataSourceArguments' => [
                            [ 'label' => 'foo', 'value' => 'tag:foo' ],
                            [ 'label' => 'bar', 'value' => 'tag:bar' ],
                            [ 'label' => 'baz', 'value' => 'tag:baz' ],
                        ],
                    ],
                    'num' => [
                        'type' => AttributeCheckboxList::class,
                        'queryString' => 'num',
                        'combine' => 'OR',
                        'databaseColumn' => 'entity.Persistence_Object_Identifier',
                        'dataSource' => 'newland-neosfiltering-tests-example',
                        'dataSourceArguments' => [
                            [ 'label' => '4', 'value' => 'num:4', 'attributeType' => 'number' ],
                            [ 'label' => '7', 'value' => 'num:7', 'attributeType' => 'number' ],
                        ],
                    ],
                ],
            ]
        );

        $filter->setState([ 'tag' => [ 'tag:foo' ], 'num' => [ 'num:4' ] ]);
        $this->assertCount(2, $filter->getArticleQuery()->getQuery()->execute());
    }

    public function testSupportsAttributesWithMultipleNames(): void
    {

        // tag=foo, num=4
        $first = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'foo' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 4 ]),
                ],
            ]
        );
        // tag=bar, num=4
        $second = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'bar' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 4 ]),
                ],
            ]
        );
        // tag=baz, num=7
        $third = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'foo' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 7 ]),
                ],
            ]
        );


        /** @var ArticleRoot $filter */
        $filter = $this->filterFactory->createFilter(
            [
                'combine' => 'AND',
                'children' => [
                    'prop' => [
                        'type' => AttributeCheckboxList::class,
                        'queryString' => 'prop',
                        'combine' => 'OR',
                        'databaseColumn' => 'entity.Persistence_Object_Identifier',
                        'dataSource' => 'newland-neosfiltering-tests-example',
                        'dataSourceArguments' => [
                            [ 'label' => 'foo', 'value' => 'tag:foo' ],
                            [ 'label' => 'bar', 'value' => 'tag:bar' ],
                            [ 'label' => 'baz', 'value' => 'tag:baz' ],
                            [ 'label' => '4', 'value' => 'num:4', 'attributeType' => 'number' ],
                            [ 'label' => '7', 'value' => 'num:7', 'attributeType' => 'number' ],
                        ],
                    ],
                ],
            ]
        );

        $filter->setState([ 'prop' => [ 'tag:foo' ] ]);
        $ids = array_map(
            function (Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $filter->getArticleQuery()->getQuery()->execute()
        );

        $this->assertContains($first->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($second->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($third->getPersistenceObjectIdentifier(), $ids);
    }

    public function testSupportsAttributesWithMultipleNamesAndNiceQueryStrings(): void
    {

        // tag=foo, num=4
        $first = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'foo' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 4 ]),
                ],
            ]
        );
        // tag=bar, num=4
        $second = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'bar' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 4 ]),
                ],
            ]
        );
        // tag=baz, num=7
        $third = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'baz' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 7 ]),
                ],
            ]
        );


        /** @var ArticleRoot $filter */
        $filter = $this->filterFactory->createFilter(
            [
                'combine' => 'AND',
                'children' => [
                    'prop' => [
                        'type' => AttributeCheckboxList::class,
                        'queryString' => 'prop',
                        'combine' => 'OR',
                        'databaseColumn' => 'entity.Persistence_Object_Identifier',
                        'dataSource' => 'newland-neosfiltering-tests-example',
                        'dataSourceArguments' => [
                            [ 'label' => 'foo', 'value' => 'tag:foo', 'queryString' => 'foo' ],
                            [ 'label' => 'bar', 'value' => 'tag:bar', 'queryString' => 'bar' ],
                            [ 'label' => 'baz', 'value' => 'tag:baz', 'queryString' => 'baz' ],
                            [ 'label' => '4', 'value' => 'num:4', 'attributeType' => 'number', 'queryString' => '4' ],
                            [ 'label' => '7', 'value' => 'num:7', 'attributeType' => 'number', 'queryString' => '7' ],
                        ],
                    ],
                ],
            ]
        );

        $filter->setState([ 'prop' => [ 'foo', '4' ] ]);
        $ids = array_map(
            function (Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $filter->getArticleQuery()->getQuery()->execute()
        );

        $this->assertContains($first->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($second->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($third->getPersistenceObjectIdentifier(), $ids);
    }

    public function testCombinesAttributesWithMultipleNamesWithAnd(): void
    {

        // tag=foo, num=4
        $first = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'foo' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 4 ]),
                ],
            ]
        );
        // tag=bar, num=4
        $second = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'bar' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 4 ]),
                ],
            ]
        );
        // tag=baz, num=7
        $third = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'foo' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 7 ]),
                ],
            ]
        );


        /** @var ArticleRoot $filter */
        $filter = $this->filterFactory->createFilter(
            [
                'combine' => 'AND',
                'children' => [
                    'prop' => [
                        'type' => AttributeCheckboxList::class,
                        'queryString' => 'prop',
                        'combine' => 'AND',
                        'databaseColumn' => 'entity.Persistence_Object_Identifier',
                        'dataSource' => 'newland-neosfiltering-tests-example',
                        'dataSourceArguments' => [
                            [ 'label' => 'foo', 'value' => 'tag:foo' ],
                            [ 'label' => 'bar', 'value' => 'tag:bar' ],
                            [ 'label' => 'baz', 'value' => 'tag:baz' ],
                            [ 'label' => '4', 'value' => 'num:4', 'attributeType' => 'number' ],
                            [ 'label' => '7', 'value' => 'num:7', 'attributeType' => 'number' ],
                        ],
                    ],
                ],
            ]
        );

        $filter->setState([ 'prop' => [ 'tag:foo', 'num:4' ] ]);
        $ids = array_map(
            function (Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $filter->getArticleQuery()->getQuery()->execute()
        );

        $this->assertContains($first->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($second->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($third->getPersistenceObjectIdentifier(), $ids);
    }

    public function testCombinesAttributesWithMultipleNamesWithOr(): void
    {

        // tag=foo, num=4
        $first = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'foo' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 4 ]),
                ],
            ]
        );
        // tag=bar, num=4
        $second = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'bar' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 4 ]),
                ],
            ]
        );
        // tag=baz, num=7
        $third = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'foo' ]),
                    $this->attributeFactory->create([ 'name' => 'num', 'data' => 7 ]),
                ],
            ]
        );


        /** @var ArticleRoot $filter */
        $filter = $this->filterFactory->createFilter(
            [
                'combine' => 'AND',
                'children' => [
                    'prop' => [
                        'type' => AttributeCheckboxList::class,
                        'queryString' => 'prop',
                        'combine' => 'OR',
                        'databaseColumn' => 'entity.Persistence_Object_Identifier',
                        'dataSource' => 'newland-neosfiltering-tests-example',
                        'dataSourceArguments' => [
                            [ 'label' => 'foo', 'value' => 'tag:foo' ],
                            [ 'label' => 'bar', 'value' => 'tag:bar' ],
                            [ 'label' => 'baz', 'value' => 'tag:baz' ],
                            [ 'label' => '4', 'value' => 'num:4', 'attributeType' => 'number' ],
                            [ 'label' => '7', 'value' => 'num:7', 'attributeType' => 'number' ],
                        ],
                    ],
                ],
            ]
        );

        $filter->setState([ 'prop' => [ 'tag:foo', 'num:7' ] ]);
        $ids = array_map(
            function (Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $filter->getArticleQuery()->getQuery()->execute()
        );

        $this->assertContains($first->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($second->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($third->getPersistenceObjectIdentifier(), $ids);
    }

    public function testAcceptsStateUsingValue(): void
    {
        /** @var ArticleRoot $filter */
        $filter = $this->filterFactory->createFilter(
            [
                'combine' => 'AND',
                'children' => [
                    'prop' => [
                        'type' => AttributeCheckboxList::class,
                        'queryString' => 'prop',
                        'combine' => 'AND',
                        'databaseColumn' => 'entity.Persistence_Object_Identifier',
                        'dataSource' => 'newland-neosfiltering-tests-example',
                        'dataSourceArguments' => [
                            [ 'label' => 'foo', 'value' => 'tag:foo', 'queryString' => 'foo' ],
                            [ 'label' => 'bar', 'value' => 'tag:bar', 'queryString' => 'bar' ],
                            [ 'label' => 'baz', 'value' => 'tag:baz', 'queryString' => 'baz' ],
                            [ 'label' => '4', 'value' => 'num:4', 'attributeType' => 'number', 'queryString' => '4' ],
                            [ 'label' => '7', 'value' => 'num:7', 'attributeType' => 'number', 'queryString' => '7' ],
                        ],
                    ],
                ],
            ]
        );

        $filter->setState([ 'prop' => [ 'tag:foo', 'num:4' ] ]);
        $this->assertEquals('tag:foo', $filter->getChildrenItems()[0]->getState()[0]['value']);
        $this->assertEquals('num:4', $filter->getChildrenItems()[0]->getState()[1]['value']);
    }

    public function testAcceptsStateUsingNameAndValue(): void
    {
        /** @var ArticleRoot $filter */
        $filter = $this->filterFactory->createFilter(
            [
                'combine' => 'AND',
                'children' => [
                    'prop' => [
                        'type' => AttributeCheckboxList::class,
                        'queryString' => 'prop',
                        'combine' => 'AND',
                        'databaseColumn' => 'entity.Persistence_Object_Identifier',
                        'dataSource' => 'newland-neosfiltering-tests-example',
                        'dataSourceArguments' => [
                            [ 'label' => 'foo', 'value' => 'tag:foo', 'queryString' => 'foo' ],
                            [ 'label' => 'bar', 'value' => 'tag:bar', 'queryString' => 'bar' ],
                            [ 'label' => 'baz', 'value' => 'tag:baz', 'queryString' => 'baz' ],
                            [ 'label' => '4', 'value' => 'num:4', 'attributeType' => 'number', 'queryString' => '4' ],
                            [ 'label' => '7', 'value' => 'num:7', 'attributeType' => 'number', 'queryString' => '7' ],
                        ],
                    ],
                ],
            ]
        );

        $filter->setState([ 'prop' => [ 'foo', '4' ] ]);
        $this->assertEquals('tag:foo', $filter->getChildrenItems()[0]->getState()[0]['value']);
        $this->assertEquals('num:4', $filter->getChildrenItems()[0]->getState()[1]['value']);
    }

    public function testMultipleAttributeNamesCanBeSpecifiedInSpecialDataSourceField(): void
    {
        $foo = $this->articleFactory->create(
            [ 'attributes' => [ $this->attributeFactory->create([ 'name' => 'foo', 'data' => 'some value' ]) ] ]
        );

        $bar = $this->articleFactory->create([
            'attributes' => [ $this->attributeFactory->create([ 'name' => 'bar', 'data' => 'some value' ]) ] ]
        );

        $fooBar = $this->articleFactory->create([
            'attributes' => [
                $this->attributeFactory->create([ 'name' => 'foo', 'data' => 'some value' ]) ,
                $this->attributeFactory->create([ 'name' => 'bar', 'data' => 'some value' ]) ,
            ]
        ]);

        $baz = $this->articleFactory->create([
            'attributes' => [ $this->attributeFactory->create([ 'name' => 'baz', 'data' => 'some value' ]) ] ]
        );


        /** @var ArticleRoot $filter */
        $filter = $this->filterFactory->createFilter(
            [
                'combine' => 'AND',
                'children' => [
                    'prop' => [
                        'type' => AttributeCheckboxList::class,
                        'queryString' => 'prop',
                        'combine' => 'AND',
                        'databaseColumn' => 'entity.Persistence_Object_Identifier',
                        'dataSource' => 'newland-neosfiltering-tests-example',
                        'dataSourceArguments' => [
                            [
                                'value' => 'multiple',
                                'attributeValues' => [ 'foo:*', 'bar:*' ],
                                'queryString' => 'multiple'
                            ],
                        ],
                    ],
                ],
            ]
        );
        $filter->setState([ 'prop' => [ 'multiple' ] ]);

        $ids = array_map(
            function(Article $article) { return $article->getPersistenceObjectIdentifier(); },
            (array) $filter->getArticleQuery()->getQuery()->execute()
        );

        $this->assertContains($foo->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($fooBar->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($bar->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($baz->getPersistenceObjectIdentifier(), $ids);
    }

    public function testFindsAttributeOnlyByName(): void
    {

        // name=tag, data=foo
        $first = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'foo' ])
                ],
            ]
        );
        // name=tag, data=bar
        $second = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'bar' ]),
                ],
            ]
        );
        // name=notTag, data=foo
        $third = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'test', 'data' => 'foo' ]),
                ],
            ]
        );

        /** @var ArticleRoot $filter */
        $filter = $this->filterFactory->createFilter(
            [
                'combine' => 'AND',
                'children' => [
                    'prop' => [
                        'type' => AttributeCheckboxList::class,
                        'queryString' => 'prop',
                        'combine' => 'OR',
                        'databaseColumn' => 'entity.Persistence_Object_Identifier',
                        'dataSource' => 'newland-neosfiltering-tests-example',
                        'dataSourceArguments' => [
                            [ 'label' => 'allTagData', 'value' => 'tag:*' ],
                            [ 'label' => 'testFoo', 'value' => 'test:foo' ],
                        ],
                    ],
                ],
            ]
        );

        $filter->setState([ 'prop' => [ 'tag:*' ] ]);
        $ids = array_map(
            function (Article $article) {
                return $article->getPersistenceObjectIdentifier();
            },
            $filter->getArticleQuery()->getQuery()->execute()
        );

        $this->assertContains($first->getPersistenceObjectIdentifier(), $ids);
        $this->assertContains($second->getPersistenceObjectIdentifier(), $ids);
        $this->assertNotContains($third->getPersistenceObjectIdentifier(), $ids);
    }

    private function setupSimpleEntitiesAndFilter(string $combine): array
    {
        $foo = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'foo' ]),
                ],
            ]
        );
        $bar = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'bar' ]),
                ],
            ]
        );
        $baz = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'baz' ]),
                ],
            ]
        );
        $fooBar = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'foo' ]),
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'bar' ]),
                ],
            ]
        );
        $fooBaz = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'foo' ]),
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'baz' ]),
                ],
            ]
        );
        $barBaz = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'bar' ]),
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'baz' ]),
                ],
            ]
        );
        $fooBarBaz = $this->articleFactory->create(
            [
                'attributes' => [
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'foo' ]),
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'bar' ]),
                    $this->attributeFactory->create([ 'name' => 'tag', 'data' => 'baz' ]),
                ],
            ]
        );

        /** @var ArticleRoot $filter */
        $filter = $this->filterFactory->createFilter(
            [
                'combine' => 'AND',
                'children' => [
                    'tag' => [
                        'type' => AttributeCheckboxList::class,
                        'queryString' => 'tag',
                        'combine' => $combine,
                        'databaseColumn' => 'entity.Persistence_Object_Identifier',
                        'dataSource' => 'newland-neosfiltering-tests-example',
                        'dataSourceArguments' => [
                            [ 'label' => 'foo', 'value' => 'tag:foo', 'queryString' => 'foo' ],
                            [ 'label' => 'bar', 'value' => 'tag:bar', 'queryString' => 'bar' ],
                            [ 'label' => 'baz', 'value' => 'tag:baz', 'queryString' => 'baz' ],
                        ],
                    ],
                ],
            ]
        );

        return compact('filter', 'foo', 'bar', 'baz', 'fooBar', 'fooBaz', 'barBaz', 'fooBarBaz');
    }

}
