FunctionsTest.php 8.24 KB
Newer Older
1 2 3 4
<?php

namespace MongoDB\Tests;

5
use MongoDB\Exception\InvalidArgumentException;
6
use MongoDB\Model\BSONArray;
7
use MongoDB\Model\BSONDocument;
8 9 10 11 12
use function MongoDB\apply_type_map_to_document;
use function MongoDB\create_field_path_type_map;
use function MongoDB\generate_index_name;
use function MongoDB\is_first_key_operator;
use function MongoDB\is_mapreduce_output_inline;
13
use function MongoDB\is_pipeline;
14 15 16 17

/**
 * Unit tests for utility functions.
 */
18
class FunctionsTest extends TestCase
19
{
20 21 22 23 24
    /**
     * @dataProvider provideDocumentAndTypeMap
     */
    public function testApplyTypeMapToDocument($document, array $typeMap, $expectedDocument)
    {
25
        $this->assertEquals($expectedDocument, apply_type_map_to_document($document, $typeMap));
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
    }

    public function provideDocumentAndTypeMap()
    {
        return [
            [
                [
                    'x' => 1,
                    'y' => (object) ['foo' => 'bar'],
                    'z' => [1, 2, 3],
                ],
                [
                    'root' => 'object',
                    'document' => 'stdClass',
                    'array' => 'array',
                ],
                (object) [
                    'x' => 1,
                    'y' => (object) ['foo' => 'bar'],
                    'z' => [1, 2, 3],
                ],
            ],
            [
                [
                    'x' => 1,
                    'y' => (object) ['foo' => 'bar'],
                    'z' => [1, 2, 3],
                ],
                [
55 56 57
                    'root' => BSONDocument::class,
                    'document' => BSONDocument::class,
                    'array' => BSONArray::class,
58 59 60 61 62 63 64
                ],
                new BSONDocument([
                    'x' => 1,
                    'y' => new BSONDocument(['foo' => 'bar']),
                    'z' => new BSONArray([1, 2, 3]),
                ]),
            ],
65 66 67
            [
                [
                    'x' => 1,
68
                    'random' => ['foo' => 'bar'],
69 70
                    'value' => [
                        'bar' => 'baz',
71
                        'embedded' => ['foo' => 'bar'],
72 73 74 75 76 77
                    ],
                ],
                [
                    'root' => 'array',
                    'document' => 'stdClass',
                    'array' => 'array',
78
                    'fieldPaths' => ['value' => 'array'],
79 80 81
                ],
                [
                    'x' => 1,
82
                    'random' => (object) ['foo' => 'bar'],
83 84
                    'value' => [
                        'bar' => 'baz',
85
                        'embedded' => (object) ['foo' => 'bar'],
86 87
                    ],
                ],
88
            ],
89 90 91
        ];
    }

92 93 94 95 96
    /**
     * @dataProvider provideIndexSpecificationDocumentsAndGeneratedNames
     */
    public function testGenerateIndexName($document, $expectedName)
    {
97
        $this->assertSame($expectedName, generate_index_name($document));
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
    }

    public function provideIndexSpecificationDocumentsAndGeneratedNames()
    {
        return [
            [ ['x' => 1], 'x_1' ],
            [ ['x' => -1, 'y' => 1], 'x_-1_y_1' ],
            [ ['x' => '2dsphere', 'y' => 1 ], 'x_2dsphere_y_1' ],
            [ (object) ['x' => 1], 'x_1' ],
            [ new BSONDocument(['x' => 1]), 'x_1' ],
        ];
    }

    /**
     * @dataProvider provideInvalidDocumentValues
     */
    public function testGenerateIndexNameArgumentTypeCheck($document)
    {
116
        $this->expectException(InvalidArgumentException::class);
117
        generate_index_name($document);
118 119 120 121 122 123 124
    }

    /**
     * @dataProvider provideIsFirstKeyOperatorDocuments
     */
    public function testIsFirstKeyOperator($document, $isFirstKeyOperator)
    {
125
        $this->assertSame($isFirstKeyOperator, is_first_key_operator($document));
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
    }

    public function provideIsFirstKeyOperatorDocuments()
    {
        return [
            [ ['y' => 1], false ],
            [ (object) ['y' => 1], false ],
            [ new BSONDocument(['y' => 1]), false ],
            [ ['$set' => ['y' => 1]], true ],
            [ (object) ['$set' => ['y' => 1]], true ],
            [ new BSONDocument(['$set' => ['y' => 1]]), true ],
        ];
    }

    /**
     * @dataProvider provideInvalidDocumentValues
     */
    public function testIsFirstKeyOperatorArgumentTypeCheck($document)
    {
145
        $this->expectException(InvalidArgumentException::class);
146
        is_first_key_operator($document);
147 148
    }

149 150 151 152 153
    /**
     * @dataProvider provideMapReduceOutValues
     */
    public function testIsMapReduceOutputInline($out, $isInline)
    {
154
        $this->assertSame($isInline, is_mapreduce_output_inline($out));
155 156 157 158 159 160 161 162 163 164 165
    }

    public function provideMapReduceOutValues()
    {
        return [
            [ 'collectionName', false ],
            [ ['inline' => 1], true ],
            [ ['inline' => 0], true ], // only the key is significant
            [ ['replace' => 'collectionName'], false ],
        ];
    }
166 167 168 169 170 171

    /**
     * @dataProvider provideTypeMapValues
     */
    public function testCreateFieldPathTypeMap(array $expected, array $typeMap, $fieldPath = 'field')
    {
172
        $this->assertEquals($expected, create_field_path_type_map($typeMap, $fieldPath));
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
    }

    public function provideTypeMapValues()
    {
        return [
            'No root type' => [
                ['document' => 'array', 'root' => 'object'],
                ['document' => 'array'],
            ],
            'No field path' => [
                ['root' => 'object', 'fieldPaths' => ['field' => 'array']],
                ['root' => 'array'],
            ],
            'Field path exists' => [
                ['root' => 'object', 'fieldPaths' => ['field' => 'array', 'field.field' => 'object']],
                ['root' => 'array', 'fieldPaths' => ['field' => 'object']],
            ],
            'Nested field path' => [
                ['root' => 'object', 'fieldPaths' => ['field' => 'object', 'field.nested' => 'array']],
                ['root' => 'object', 'fieldPaths' => ['nested' => 'array']],
            ],
            'Array field path converted to array' => [
                [
                    'root' => 'object',
                    'array' => 'MongoDB\Model\BSONArray',
                    'fieldPaths' => [
                        'field' => 'array',
                        'field.$' => 'object',
                        'field.$.nested' => 'array',
202
                    ],
203 204 205 206
                ],
                [
                    'root' => 'object',
                    'array' => 'MongoDB\Model\BSONArray',
207
                    'fieldPaths' => ['nested' => 'array'],
208 209 210 211 212 213 214 215 216 217
                ],
                'field.$',
            ],
            'Array field path without root key' => [
                [
                    'root' => 'object',
                    'array' => 'MongoDB\Model\BSONArray',
                    'fieldPaths' => [
                        'field' => 'array',
                        'field.$.nested' => 'array',
218
                    ],
219 220 221
                ],
                [
                    'array' => 'MongoDB\Model\BSONArray',
222
                    'fieldPaths' => ['nested' => 'array'],
223 224 225 226 227
                ],
                'field.$',
            ],
        ];
    }
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256

    /**
     * @dataProvider providePipelines
     */
    public function testIsPipeline($expected, $pipeline)
    {
        $this->assertSame($expected, is_pipeline($pipeline));
    }

    public function providePipelines()
    {
        return [
            'Not an array' => [false, (object) []],
            'Empty array' => [false, []],
            'Non-sequential indexes in array' => [false, [1 => ['$group' => []]]],
            'Update document instead of pipeline' => [false, ['$set' => ['foo' => 'bar']]],
            'Invalid pipeline stage' => [false, [['group' => []]]],
            'Update with DbRef' => [false, ['x' => ['$ref' => 'foo', '$id' => 'bar']]],
            'Valid pipeline' => [
                true,
                [
                    ['$match' => ['foo' => 'bar']],
                    ['$group' => ['_id' => 1]],
                ],
            ],
            'False positive with DbRef in numeric field' => [true, ['0' => ['$ref' => 'foo', '$id' => 'bar']]],
            'DbRef in numeric field as object' => [false, (object) ['0' => ['$ref' => 'foo', '$id' => 'bar']]],
        ];
    }
257
}