<?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 testPerformanceIsWithinReasonableBounds(): void
    {
        /** @var ArticleRoot $filter */
        $filter = $this->filterFactory->createFilter([
            'combine' => 'AND',
            'children' => [
                'page' => [
                    'type' => 'pagination_input',
                    'queryString' => 'page'
                ],
                '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' ],
                    ],
                ]
            ]
        ]);

        // Creating 2.500 articles with 10 attributes each.
        // That results in 25.000 attributes.
        // That's not a lot - but more than that will make sqlite unhappy
        for($i = 0; $i < 2500; $i++) {
            switch ($i % 3) {
                case 0: $tag = 'foo'; break;
                case 1: $tag = 'bar'; break;
                case 2: $tag = 'baz'; break;
            }
            $attributes = $this->attributeFactory->createMultiple(9);
            $attributes[] = $this->attributeFactory->create([ 'name' => 'tag', 'data' => $tag ]);
            $this->articleFactory->create(['attributes' => $attributes]);
        }

        $start = microtime(true);
        $filter->getArticleQuery()->getQuery()->execute();
        $delta = microtime(true) - $start;
        $this->assertLessThan(.05, $delta, 'Query should be less than 50ms');
    }

    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']);
    }

    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');
    }

}
