1+ <?php
2+
3+ /**
4+ * SPDX-FileCopyrightText: 2026 LibreCode coop and LibreCode contributors
5+ * SPDX-License-Identifier: AGPL-3.0-or-later
6+ */
7+
8+ declare (strict_types=1 );
9+
10+ namespace OCA \ProfileFields \Tests \Unit \Service ;
11+
12+ use InvalidArgumentException ;
13+ use OCA \ProfileFields \Db \FieldDefinition ;
14+ use OCA \ProfileFields \Enum \FieldType ;
15+ use OCA \ProfileFields \Service \FieldDefinitionService ;
16+ use OCA \ProfileFields \Service \FieldDefinitionValidator ;
17+ use OCA \ProfileFields \Service \ImportPayloadValidator ;
18+ use OCP \IUserManager ;
19+ use PHPUnit \Framework \MockObject \MockObject ;
20+ use PHPUnit \Framework \TestCase ;
21+
22+ class ImportPayloadValidatorTest extends TestCase {
23+ private FieldDefinitionService &MockObject $ fieldDefinitionService ;
24+ private IUserManager &MockObject $ userManager ;
25+ private ImportPayloadValidator $ validator ;
26+
27+ protected function setUp (): void {
28+ parent ::setUp ();
29+ $ this ->fieldDefinitionService = $ this ->createMock (FieldDefinitionService::class);
30+ $ this ->userManager = $ this ->createMock (IUserManager::class);
31+ $ this ->validator = new ImportPayloadValidator (
32+ new FieldDefinitionValidator (),
33+ $ this ->fieldDefinitionService ,
34+ $ this ->userManager ,
35+ );
36+ }
37+
38+ public function testValidateAcceptsVersionedPayload (): void {
39+ $ this ->fieldDefinitionService ->expects ($ this ->once ())
40+ ->method ('findByFieldKey ' )
41+ ->with ('cost_center ' )
42+ ->willReturn (null );
43+
44+ $ this ->userManager ->expects ($ this ->once ())
45+ ->method ('userExists ' )
46+ ->with ('alice ' )
47+ ->willReturn (true );
48+
49+ $ validated = $ this ->validator ->validate ([
50+ 'schema_version ' => 1 ,
51+ 'definitions ' => [[
52+ 'field_key ' => 'cost_center ' ,
53+ 'label ' => 'Cost center ' ,
54+ 'type ' => FieldType::TEXT ->value ,
55+ 'admin_only ' => false ,
56+ 'user_editable ' => false ,
57+ 'user_visible ' => true ,
58+ 'initial_visibility ' => 'users ' ,
59+ 'sort_order ' => 1 ,
60+ 'active ' => true ,
61+ ]],
62+ 'values ' => [[
63+ 'field_key ' => 'cost_center ' ,
64+ 'user_uid ' => 'alice ' ,
65+ 'value ' => ['value ' => 'finance ' ],
66+ 'current_visibility ' => 'users ' ,
67+ 'updated_by_uid ' => 'admin ' ,
68+ 'updated_at ' => '2026-03-15T12:00:00+00:00 ' ,
69+ ]],
70+ ]);
71+
72+ $ this ->assertSame (1 , $ validated ['schema_version ' ]);
73+ $ this ->assertSame ('cost_center ' , $ validated ['definitions ' ][0 ]['field_key ' ]);
74+ $ this ->assertSame (['value ' => 'finance ' ], $ validated ['values ' ][0 ]['value ' ]);
75+ }
76+
77+ public function testRejectUnsupportedSchemaVersion (): void {
78+ $ this ->expectException (InvalidArgumentException::class);
79+ $ this ->expectExceptionMessage ('schema_version must be 1 ' );
80+
81+ $ this ->validator ->validate ([
82+ 'schema_version ' => 2 ,
83+ 'definitions ' => [],
84+ 'values ' => [],
85+ ]);
86+ }
87+
88+ public function testRejectMissingDestinationUser (): void {
89+ $ this ->fieldDefinitionService ->expects ($ this ->once ())
90+ ->method ('findByFieldKey ' )
91+ ->with ('cost_center ' )
92+ ->willReturn (null );
93+
94+ $ this ->userManager ->expects ($ this ->once ())
95+ ->method ('userExists ' )
96+ ->with ('ghost ' )
97+ ->willReturn (false );
98+
99+ $ this ->expectException (InvalidArgumentException::class);
100+ $ this ->expectExceptionMessage ('values[0].user_uid does not exist in destination instance ' );
101+
102+ $ this ->validator ->validate ([
103+ 'schema_version ' => 1 ,
104+ 'definitions ' => [[
105+ 'field_key ' => 'cost_center ' ,
106+ 'label ' => 'Cost center ' ,
107+ 'type ' => FieldType::TEXT ->value ,
108+ ]],
109+ 'values ' => [[
110+ 'field_key ' => 'cost_center ' ,
111+ 'user_uid ' => 'ghost ' ,
112+ 'value ' => ['value ' => 'finance ' ],
113+ 'current_visibility ' => 'users ' ,
114+ 'updated_by_uid ' => 'admin ' ,
115+ 'updated_at ' => '2026-03-15T12:00:00+00:00 ' ,
116+ ]],
117+ ]);
118+ }
119+
120+ public function testRejectIncompatibleExistingDefinition (): void {
121+ $ existingDefinition = new FieldDefinition ();
122+ $ existingDefinition ->setId (7 );
123+ $ existingDefinition ->setFieldKey ('cost_center ' );
124+ $ existingDefinition ->setLabel ('Cost center ' );
125+ $ existingDefinition ->setType (FieldType::NUMBER ->value );
126+ $ existingDefinition ->setAdminOnly (false );
127+ $ existingDefinition ->setUserEditable (false );
128+ $ existingDefinition ->setUserVisible (true );
129+ $ existingDefinition ->setInitialVisibility ('users ' );
130+
131+ $ this ->fieldDefinitionService ->expects ($ this ->once ())
132+ ->method ('findByFieldKey ' )
133+ ->with ('cost_center ' )
134+ ->willReturn ($ existingDefinition );
135+
136+ $ this ->expectException (InvalidArgumentException::class);
137+ $ this ->expectExceptionMessage ('definitions[0].field_key conflicts with an incompatible existing definition ' );
138+
139+ $ this ->validator ->validate ([
140+ 'schema_version ' => 1 ,
141+ 'definitions ' => [[
142+ 'field_key ' => 'cost_center ' ,
143+ 'label ' => 'Cost center ' ,
144+ 'type ' => FieldType::TEXT ->value ,
145+ ]],
146+ 'values ' => [],
147+ ]);
148+ }
149+ }
0 commit comments