File: GH9230Test.php

package info (click to toggle)
doctrine 3.5.1%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 11,552 kB
  • sloc: php: 108,302; xml: 1,340; makefile: 35; sh: 14
file content (157 lines) | stat: -rw-r--r-- 4,848 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
<?php

declare(strict_types=1);

namespace Doctrine\Tests\ORM\Functional\Ticket;

use Doctrine\ORM\Mapping\Column;
use Doctrine\ORM\Mapping\Entity;
use Doctrine\ORM\Mapping\GeneratedValue;
use Doctrine\ORM\Mapping\Id;
use Doctrine\Tests\OrmFunctionalTestCase;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\Attributes\Group;

#[Group('GH-9230')]
class GH9230Test extends OrmFunctionalTestCase
{
    protected function setUp(): void
    {
        parent::setUp();

        // ensure entity table exists
        $this->setUpEntitySchema([GH9230Entity::class]);
    }

    protected function tearDown(): void
    {
        parent::tearDown();

        $connection = static::$sharedConn;
        if ($connection === null) {
            return;
        }

        // remove persisted entities
        $connection->executeStatement('DELETE FROM GH9230Entity');
    }

    /**
     * This does not work before the fix in PR#9663, but is does work after the fix is applied
     */
    public static function failingValuesBeforeFix(): array
    {
        return [
            'string=""' => ['name', '', 'test name'],
            'string="0"' => ['name', '0', 'test name'],
            'string=null' => ['name', null, 'test name'],

            'int=0' => ['counter', 0, 1],
            'int=null' => ['counter', null, 1],

            'bool=false' => ['enabled', false, true],
            'bool=null' => ['enabled', null, true],

            'float=0.0' => ['price', 0.0, 1.1],
            'float=-0.0' => ['price', -0.0, 1.1],
            'float=null' => ['price', null, 1.1],

            'json=[]' => ['extra', [], 1],
            'json=0' => ['extra', 0, 1],
            'json=0.0' => ['extra', 0.0, 1],
            'json=false' => ['extra', false, 1],
            'json=""' => ['extra', ['', 1], ['""', '1']],
            'json=null' => ['enabled', null, 1],
        ];
    }

    /**
     * This already works before the fix in PR#9663 is applied because none of these are falsy values in php
     */
    public static function succeedingValuesBeforeFix(): array
    {
        return [
            'string="test"' => ['name', 'test', 'test2'],
            'int=1' => ['counter', 1, 1],
            'bool=true' => ['enabled', true, 1],
            'json=[null]' => ['extra', [null], 1],
            'json=1' => ['extra', 1, 1],
            'json=1.1' => ['extra', 1.1, 1],
            'json=true' => ['extra', true, 1],
            'json="test"' => ['extra', 'test', 'test'],
            'json="1"' => ['extra', '1', 1],
        ];
    }

    #[DataProvider('failingValuesBeforeFix')]
    #[DataProvider('succeedingValuesBeforeFix')]
    public function testIssue(string $property, $falsyValue, $truthyValue): void
    {
        $counter1            = new GH9230Entity();
        $counter1->$property = $falsyValue;

        $counter2            = new GH9230Entity();
        $counter2->$property = $truthyValue;

        $this->_em->persist($counter1);
        $this->_em->persist($counter2);
        $this->_em->flush();

        $this->_em->clear();

        $persistedCounter1 = $this->_em->find(GH9230Entity::class, $counter1->id);
        $persistedCounter2 = $this->_em->find(GH9230Entity::class, $counter2->id);

        // Assert entities were persisted
        self::assertInstanceOf(GH9230Entity::class, $persistedCounter1);
        self::assertInstanceOf(GH9230Entity::class, $persistedCounter2);
        self::assertEquals($falsyValue, $persistedCounter1->$property);
        self::assertEquals($truthyValue, $persistedCounter2->$property);

        $this->_em->clear();

        $counterRepository = $this->_em->getRepository(GH9230Entity::class);

        $query = $counterRepository->createQueryBuilder('counter')
            ->select('counter.' . $property)
            ->getQuery();

        $values = $query->getSingleColumnResult();

        // Assert that there are 2 values returned.
        // This fails when there is a falsy value in the array,
        // because the first falsy value halts the hydration process (before the fix is applied).
        self::assertCount(2, $values);
    }
}


#[Entity]
class GH9230Entity
{
    /** @var int */
    #[Column(name: 'id', type: 'integer')]
    #[Id]
    #[GeneratedValue(strategy: 'AUTO')]
    public $id;

    /** @var ?string */
    #[Column(name: 'name', type: 'string', nullable: true)]
    public $name;

    /** @var ?int */
    #[Column(name: 'counter', type: 'integer', nullable: true)]
    public $counter;

    /** @var ?bool */
    #[Column(name: 'enabled', type: 'boolean', nullable: true)]
    public $enabled;

    /** @var ?float */
    #[Column(name: 'price', type: 'decimal', scale: 1, precision: 2, nullable: true)]
    public $price;

    /** @var mixed[] */
    #[Column(name: 'extra', type: 'json', nullable: true)]
    public $extra;
}