Skip to content

Commit de7dc05

Browse files
author
Enno Woortmann
committed
Add regression tests for issue #117: serialization skipping nested properties with same name as outer optional property
1 parent 32a85b1 commit de7dc05

4 files changed

Lines changed: 186 additions & 1 deletion

File tree

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
}
1212
],
1313
"require": {
14-
"wol-soft/php-json-schema-model-generator-production": "^0.21.0",
14+
"wol-soft/php-json-schema-model-generator-production": "^0.21.1",
1515
"wol-soft/php-micro-template": "^1.10.2",
1616

1717
"php": ">=8.4",
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PHPModelGenerator\Tests\Issues\Issue;
6+
7+
use PHPModelGenerator\Model\GeneratorConfiguration;
8+
use PHPModelGenerator\Tests\Issues\AbstractIssueTestCase;
9+
10+
class Issue117Test extends AbstractIssueTestCase
11+
{
12+
private function getConfig(): GeneratorConfiguration
13+
{
14+
return (new GeneratorConfiguration())->setSerialization(true)->setImmutable(false);
15+
}
16+
17+
/**
18+
* The basic case from the issue report: outer optional 'name' not provided,
19+
* inner required 'name' must still appear in the serialized output.
20+
*/
21+
public function testNestedRequiredPropertyNotSkippedWhenOuterOptionalPropertyHasSameName(): void
22+
{
23+
$className = $this->generateClassFromFile(
24+
'nestedObjectSamePropertyName.json',
25+
$this->getConfig(),
26+
false,
27+
false,
28+
);
29+
30+
$object = new $className(['dog' => ['name' => 'woofy']]);
31+
32+
$this->assertSame(
33+
['dog' => ['name' => 'woofy']],
34+
$object->toArray(),
35+
);
36+
}
37+
38+
/**
39+
* When the outer optional 'name' IS provided it must appear in the output,
40+
* and the inner 'name' must appear too.
41+
*/
42+
public function testBothOuterAndInnerPropertyIncludedWhenOuterProvided(): void
43+
{
44+
$className = $this->generateClassFromFile(
45+
'nestedObjectSamePropertyName.json',
46+
$this->getConfig(),
47+
false,
48+
false,
49+
);
50+
51+
$object = new $className(['name' => 'Alice', 'dog' => ['name' => 'woofy']]);
52+
53+
$this->assertSame(
54+
['name' => 'Alice', 'dog' => ['name' => 'woofy']],
55+
$object->toArray(),
56+
);
57+
}
58+
59+
/**
60+
* User-supplied $except must still exclude the property at ALL levels
61+
* (this is the intentional global-except behaviour).
62+
*/
63+
public function testUserSuppliedExceptExcludesPropertyAtAllLevels(): void
64+
{
65+
$className = $this->generateClassFromFile(
66+
'nestedObjectSamePropertyName.json',
67+
$this->getConfig(),
68+
false,
69+
false,
70+
);
71+
72+
$object = new $className(['name' => 'Alice', 'dog' => ['name' => 'woofy']]);
73+
74+
$this->assertSame(
75+
['dog' => []],
76+
$object->toArray(['name']),
77+
);
78+
}
79+
80+
/**
81+
* Three levels of nesting with 'name' at each level: outer optional not provided,
82+
* both inner levels must include their 'name'.
83+
*/
84+
public function testMultiLevelNestedRequiredPropertyNotSkipped(): void
85+
{
86+
$className = $this->generateClassFromFile(
87+
'nestedObjectSamePropertyNameMultiLevel.json',
88+
$this->getConfig(),
89+
false,
90+
false,
91+
);
92+
93+
$object = new $className(['dog' => ['name' => 'woofy', 'puppy' => ['name' => 'fluffy']]]);
94+
95+
$this->assertSame(
96+
['dog' => ['name' => 'woofy', 'puppy' => ['name' => 'fluffy']]],
97+
$object->toArray(),
98+
);
99+
}
100+
101+
/**
102+
* After setting the outer optional 'name' via setter it must appear in the output
103+
* without affecting the inner 'name'.
104+
*/
105+
public function testSettingOuterOptionalPropertyAfterConstructionDoesNotAffectInner(): void
106+
{
107+
$className = $this->generateClassFromFile(
108+
'nestedObjectSamePropertyName.json',
109+
$this->getConfig(),
110+
false,
111+
false,
112+
);
113+
114+
$object = new $className(['dog' => ['name' => 'woofy']]);
115+
$object->setName('Alice');
116+
117+
$this->assertSame(
118+
['name' => 'Alice', 'dog' => ['name' => 'woofy']],
119+
$object->toArray(),
120+
);
121+
}
122+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"type": "object",
4+
"properties": {
5+
"name": {
6+
"type": "string"
7+
},
8+
"dog": {
9+
"type": "object",
10+
"properties": {
11+
"name": {
12+
"type": "string"
13+
}
14+
},
15+
"required": [
16+
"name"
17+
],
18+
"additionalProperties": false
19+
}
20+
},
21+
"required": [
22+
"dog"
23+
],
24+
"additionalProperties": false
25+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-07/schema#",
3+
"type": "object",
4+
"properties": {
5+
"name": {
6+
"type": "string"
7+
},
8+
"dog": {
9+
"type": "object",
10+
"properties": {
11+
"name": {
12+
"type": "string"
13+
},
14+
"puppy": {
15+
"type": "object",
16+
"properties": {
17+
"name": {
18+
"type": "string"
19+
}
20+
},
21+
"required": [
22+
"name"
23+
],
24+
"additionalProperties": false
25+
}
26+
},
27+
"required": [
28+
"name",
29+
"puppy"
30+
],
31+
"additionalProperties": false
32+
}
33+
},
34+
"required": [
35+
"dog"
36+
],
37+
"additionalProperties": false
38+
}

0 commit comments

Comments
 (0)