3030import static org .hisp .dhis .dxf2 .Constants .PROGRAM_RULE_VARIABLE_NAME_INVALID_KEYWORDS ;
3131import static org .hisp .dhis .feedback .ErrorCode .E4051 ;
3232import static org .hisp .dhis .feedback .ErrorCode .E4052 ;
33+ import static org .hisp .dhis .feedback .ErrorCode .E4059 ;
34+ import static org .hisp .dhis .feedback .ErrorCode .E4089 ;
35+ import static org .hisp .dhis .feedback .ErrorCode .E4090 ;
36+ import static org .hisp .dhis .feedback .ErrorCode .E4091 ;
37+ import static org .hisp .dhis .feedback .ErrorCode .E4092 ;
3338import static org .junit .jupiter .api .Assertions .assertEquals ;
3439import static org .junit .jupiter .api .Assertions .assertTrue ;
3540import static org .mockito .ArgumentMatchers .anyString ;
41+ import static org .mockito .Mockito .lenient ;
3642import static org .mockito .Mockito .when ;
3743
3844import java .util .Collections ;
3945import java .util .List ;
46+ import java .util .stream .Stream ;
4047import org .hibernate .Session ;
4148import org .hibernate .SessionFactory ;
4249import org .hibernate .query .Query ;
50+ import org .hisp .dhis .common .ValueType ;
51+ import org .hisp .dhis .dataelement .DataElement ;
4352import org .hisp .dhis .dxf2 .metadata .objectbundle .ObjectBundle ;
4453import org .hisp .dhis .feedback .ErrorReport ;
4554import org .hisp .dhis .importexport .ImportStrategy ;
4655import org .hisp .dhis .program .Program ;
56+ import org .hisp .dhis .program .ProgramStage ;
4757import org .hisp .dhis .programrule .ProgramRuleVariable ;
58+ import org .hisp .dhis .programrule .ProgramRuleVariableSourceType ;
59+ import org .hisp .dhis .trackedentity .TrackedEntityAttribute ;
4860import org .junit .jupiter .api .BeforeEach ;
4961import org .junit .jupiter .api .Test ;
5062import org .junit .jupiter .api .extension .ExtendWith ;
63+ import org .junit .jupiter .params .ParameterizedTest ;
64+ import org .junit .jupiter .params .provider .MethodSource ;
5165import org .mockito .ArgumentCaptor ;
5266import org .mockito .Captor ;
5367import org .mockito .InjectMocks ;
@@ -81,32 +95,40 @@ public void setUp() {
8195 when (sessionFactory .getCurrentSession ()).thenReturn (session );
8296 when (session .createQuery (anyString (), classArgumentCaptor .capture ())).thenReturn (query );
8397 when (program .getUid ()).thenReturn ("uid" );
98+ // Common defaults; individual tests override what they need.
99+ lenient ().when (programRuleVariable .getProgram ()).thenReturn (program );
100+ lenient ().when (programRuleVariable .getName ()).thenReturn ("someVar" );
101+ lenient ().when (objectBundle .getImportMode ()).thenReturn (ImportStrategy .CREATE );
102+ lenient ().when (query .getResultList ()).thenReturn (Collections .emptyList ());
84103 }
85104
86105 @ Test
87106 void shouldFailInsertAlreadyExisting () {
88- when (programRuleVariable .getProgram ()).thenReturn (program );
89- when (objectBundle .getImportMode ()).thenReturn (ImportStrategy .CREATE );
90107 when (query .getResultList ()).thenReturn (Collections .singletonList (new ProgramRuleVariable ()));
91-
92108 when (programRuleVariable .getName ()).thenReturn ("word" );
109+ when (programRuleVariable .getSourceType ())
110+ .thenReturn (ProgramRuleVariableSourceType .CALCULATED_VALUE );
111+ when (programRuleVariable .getValueType ()).thenReturn (ValueType .TEXT );
112+
93113 List <ErrorReport > errorReports =
94114 programRuleVariableObjectBundleHook .validate (programRuleVariable , objectBundle );
115+
95116 assertEquals (1 , errorReports .size ());
96117 assertTrue (errorReports .stream ().anyMatch (e -> e .getErrorCode ().equals (E4051 )));
97118 }
98119
99120 @ Test
100121 void shouldNotFailUpdateExistingSameUid () {
101- when (programRuleVariable .getProgram ()).thenReturn (program );
102122 when (objectBundle .getImportMode ()).thenReturn (ImportStrategy .CREATE_AND_UPDATE );
123+ when (programRuleVariable .getSourceType ())
124+ .thenReturn (ProgramRuleVariableSourceType .CALCULATED_VALUE );
125+ when (programRuleVariable .getValueType ()).thenReturn (ValueType .TEXT );
103126
104127 ProgramRuleVariable existingProgramRuleVariable = new ProgramRuleVariable ();
105128 existingProgramRuleVariable .setName ("word" );
106129 existingProgramRuleVariable .setUid ("uid1" );
107130
108131 when (query .getResultList ()).thenReturn (Collections .singletonList (existingProgramRuleVariable ));
109-
110132 when (programRuleVariable .getName ()).thenReturn ("word" );
111133 when (programRuleVariable .getUid ()).thenReturn ("uid1" );
112134
@@ -118,8 +140,10 @@ void shouldNotFailUpdateExistingSameUid() {
118140
119141 @ Test
120142 void shouldNotFailUpdateExistingMoreThanOneSameUid () {
121- when (programRuleVariable .getProgram ()).thenReturn (program );
122143 when (objectBundle .getImportMode ()).thenReturn (ImportStrategy .CREATE_AND_UPDATE );
144+ when (programRuleVariable .getSourceType ())
145+ .thenReturn (ProgramRuleVariableSourceType .CALCULATED_VALUE );
146+ when (programRuleVariable .getValueType ()).thenReturn (ValueType .TEXT );
123147
124148 ProgramRuleVariable existingProgramRuleVariable = new ProgramRuleVariable ();
125149 existingProgramRuleVariable .setName ("word" );
@@ -131,7 +155,6 @@ void shouldNotFailUpdateExistingMoreThanOneSameUid() {
131155
132156 when (query .getResultList ())
133157 .thenReturn (List .of (existingProgramRuleVariable , anotherExistingProgramRuleVariable ));
134-
135158 when (programRuleVariable .getName ()).thenReturn ("word" );
136159 when (programRuleVariable .getUid ()).thenReturn ("uid1" );
137160
@@ -143,15 +166,16 @@ void shouldNotFailUpdateExistingMoreThanOneSameUid() {
143166
144167 @ Test
145168 void shouldFailUpdateExistingDifferentUid () {
146- when (programRuleVariable .getProgram ()).thenReturn (program );
147169 when (objectBundle .getImportMode ()).thenReturn (ImportStrategy .CREATE_AND_UPDATE );
170+ when (programRuleVariable .getSourceType ())
171+ .thenReturn (ProgramRuleVariableSourceType .CALCULATED_VALUE );
172+ when (programRuleVariable .getValueType ()).thenReturn (ValueType .TEXT );
148173
149174 ProgramRuleVariable existingProgramRuleVariable = new ProgramRuleVariable ();
150175 existingProgramRuleVariable .setName ("word" );
151176 existingProgramRuleVariable .setUid ("uid1" );
152177
153178 when (query .getResultList ()).thenReturn (Collections .singletonList (existingProgramRuleVariable ));
154-
155179 when (programRuleVariable .getName ()).thenReturn ("word" );
156180 when (programRuleVariable .getUid ()).thenReturn ("uid2" );
157181
@@ -164,11 +188,12 @@ void shouldFailUpdateExistingDifferentUid() {
164188
165189 @ Test
166190 void shouldFailValidationInvalidCountAndInvalidName () {
167- when (programRuleVariable .getProgram ()).thenReturn (program );
168- when (objectBundle .getImportMode ()).thenReturn (ImportStrategy .CREATE );
169191 when (query .getResultList ()).thenReturn (Collections .singletonList (new ProgramRuleVariable ()));
170192 when (programRuleVariable .getName ())
171193 .thenReturn ("Word " + PROGRAM_RULE_VARIABLE_NAME_INVALID_KEYWORDS .get (0 ) + " Word" );
194+ when (programRuleVariable .getSourceType ())
195+ .thenReturn (ProgramRuleVariableSourceType .CALCULATED_VALUE );
196+ when (programRuleVariable .getValueType ()).thenReturn (ValueType .TEXT );
172197
173198 List <ErrorReport > errorReports =
174199 programRuleVariableObjectBundleHook .validate (programRuleVariable , objectBundle );
@@ -180,8 +205,10 @@ void shouldFailValidationInvalidCountAndInvalidName() {
180205
181206 @ Test
182207 void shouldFailValidationInvalidName () {
183- when (programRuleVariable .getProgram ()).thenReturn (program );
184208 when (objectBundle .getImportMode ()).thenReturn (ImportStrategy .CREATE_AND_UPDATE );
209+ when (programRuleVariable .getSourceType ())
210+ .thenReturn (ProgramRuleVariableSourceType .CALCULATED_VALUE );
211+ when (programRuleVariable .getValueType ()).thenReturn (ValueType .TEXT );
185212 List <ErrorReport > errorReports ;
186213
187214 for (String invalidKeyWord : PROGRAM_RULE_VARIABLE_NAME_INVALID_KEYWORDS ) {
@@ -207,9 +234,11 @@ void shouldFailValidationInvalidName() {
207234
208235 @ Test
209236 void shouldPassValidationWithValidName () {
210- when (programRuleVariable .getProgram ()).thenReturn (program );
211- when (programRuleVariable .getName ()).thenReturn ("WordAndWord" );
212237 when (objectBundle .getImportMode ()).thenReturn (ImportStrategy .CREATE_AND_UPDATE );
238+ when (programRuleVariable .getName ()).thenReturn ("WordAndWord" );
239+ when (programRuleVariable .getSourceType ())
240+ .thenReturn (ProgramRuleVariableSourceType .CALCULATED_VALUE );
241+ when (programRuleVariable .getValueType ()).thenReturn (ValueType .TEXT );
213242
214243 List <ErrorReport > errorReports =
215244 programRuleVariableObjectBundleHook .validate (programRuleVariable , objectBundle );
@@ -221,4 +250,136 @@ void shouldPassValidationWithValidName() {
221250 programRuleVariableObjectBundleHook .validate (programRuleVariable , objectBundle );
222251 assertEquals (0 , errorReports1 .size ());
223252 }
253+
254+ static Stream <ProgramRuleVariableSourceType > dataElementSourceTypes () {
255+ return ProgramRuleVariableSourceType .getDataTypes ().stream ();
256+ }
257+
258+ @ ParameterizedTest
259+ @ MethodSource ("dataElementSourceTypes" )
260+ void shouldFailForAllDataElementSourceTypesWhenDataElementIsNull (
261+ ProgramRuleVariableSourceType sourceType ) {
262+ when (programRuleVariable .getSourceType ()).thenReturn (sourceType );
263+ when (programRuleVariable .getDataElement ()).thenReturn (null );
264+
265+ List <ErrorReport > errorReports =
266+ programRuleVariableObjectBundleHook .validate (programRuleVariable , objectBundle );
267+
268+ assertTrue (errorReports .stream ().anyMatch (e -> e .getErrorCode ().equals (E4059 )));
269+ }
270+
271+ @ Test
272+ void shouldPassWhenDataElementSourceTypeHasDataElement () {
273+ when (programRuleVariable .getSourceType ())
274+ .thenReturn (ProgramRuleVariableSourceType .DATAELEMENT_CURRENT_EVENT );
275+ when (programRuleVariable .getDataElement ()).thenReturn (new DataElement ());
276+
277+ List <ErrorReport > errorReports =
278+ programRuleVariableObjectBundleHook .validate (programRuleVariable , objectBundle );
279+
280+ assertEquals (0 , errorReports .size ());
281+ }
282+
283+ @ Test
284+ void shouldFailWhenTeAttributeSourceTypeHasNoAttribute () {
285+ when (programRuleVariable .getSourceType ())
286+ .thenReturn (ProgramRuleVariableSourceType .TEI_ATTRIBUTE );
287+ when (programRuleVariable .getAttribute ()).thenReturn (null );
288+
289+ List <ErrorReport > errorReports =
290+ programRuleVariableObjectBundleHook .validate (programRuleVariable , objectBundle );
291+
292+ assertEquals (1 , errorReports .size ());
293+ assertTrue (errorReports .stream ().anyMatch (e -> e .getErrorCode ().equals (E4089 )));
294+ }
295+
296+ @ Test
297+ void shouldPassWhenTeAttributeSourceTypeHasAttribute () {
298+ when (programRuleVariable .getSourceType ())
299+ .thenReturn (ProgramRuleVariableSourceType .TEI_ATTRIBUTE );
300+ when (programRuleVariable .getAttribute ()).thenReturn (new TrackedEntityAttribute ());
301+
302+ List <ErrorReport > errorReports =
303+ programRuleVariableObjectBundleHook .validate (programRuleVariable , objectBundle );
304+
305+ assertEquals (0 , errorReports .size ());
306+ }
307+
308+ @ Test
309+ void shouldPassWhenCalculatedValueSourceTypeHasValueType () {
310+ when (programRuleVariable .getSourceType ())
311+ .thenReturn (ProgramRuleVariableSourceType .CALCULATED_VALUE );
312+ when (programRuleVariable .getValueType ()).thenReturn (ValueType .TEXT );
313+
314+ List <ErrorReport > errorReports =
315+ programRuleVariableObjectBundleHook .validate (programRuleVariable , objectBundle );
316+
317+ assertEquals (0 , errorReports .size ());
318+ }
319+
320+ @ Test
321+ void shouldFailWhenSourceTypeIsMissing () {
322+ when (programRuleVariable .getSourceType ()).thenReturn (null );
323+
324+ List <ErrorReport > errorReports =
325+ programRuleVariableObjectBundleHook .validate (programRuleVariable , objectBundle );
326+
327+ assertEquals (1 , errorReports .size ());
328+ assertTrue (errorReports .stream ().anyMatch (e -> e .getErrorCode ().equals (E4090 )));
329+ }
330+
331+ @ Test
332+ void shouldFailWhenProgramStageMissingForProgramStageDataElementSourceType () {
333+ when (programRuleVariable .getSourceType ())
334+ .thenReturn (ProgramRuleVariableSourceType .DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE );
335+ when (programRuleVariable .getDataElement ()).thenReturn (new DataElement ());
336+ when (programRuleVariable .getProgramStage ()).thenReturn (null );
337+
338+ List <ErrorReport > errorReports =
339+ programRuleVariableObjectBundleHook .validate (programRuleVariable , objectBundle );
340+
341+ assertEquals (1 , errorReports .size ());
342+ assertTrue (errorReports .stream ().anyMatch (e -> e .getErrorCode ().equals (E4091 )));
343+ }
344+
345+ @ Test
346+ void shouldPassWhenDataElementAndProgramStagePresentForProgramStageSourceType () {
347+ when (programRuleVariable .getSourceType ())
348+ .thenReturn (ProgramRuleVariableSourceType .DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE );
349+ when (programRuleVariable .getDataElement ()).thenReturn (new DataElement ());
350+ when (programRuleVariable .getProgramStage ()).thenReturn (new ProgramStage ());
351+
352+ List <ErrorReport > errorReports =
353+ programRuleVariableObjectBundleHook .validate (programRuleVariable , objectBundle );
354+
355+ assertEquals (0 , errorReports .size ());
356+ }
357+
358+ @ Test
359+ void shouldFailWhenCalculatedValueHasNoValueType () {
360+ when (programRuleVariable .getSourceType ())
361+ .thenReturn (ProgramRuleVariableSourceType .CALCULATED_VALUE );
362+ when (programRuleVariable .getValueType ()).thenReturn (null );
363+
364+ List <ErrorReport > errorReports =
365+ programRuleVariableObjectBundleHook .validate (programRuleVariable , objectBundle );
366+
367+ assertEquals (1 , errorReports .size ());
368+ assertTrue (errorReports .stream ().anyMatch (e -> e .getErrorCode ().equals (E4092 )));
369+ }
370+
371+ @ Test
372+ void shouldFailWhenBothDataElementAndProgramStageMissingForProgramStageSourceType () {
373+ when (programRuleVariable .getSourceType ())
374+ .thenReturn (ProgramRuleVariableSourceType .DATAELEMENT_NEWEST_EVENT_PROGRAM_STAGE );
375+ when (programRuleVariable .getDataElement ()).thenReturn (null );
376+ when (programRuleVariable .getProgramStage ()).thenReturn (null );
377+
378+ List <ErrorReport > errorReports =
379+ programRuleVariableObjectBundleHook .validate (programRuleVariable , objectBundle );
380+
381+ assertEquals (2 , errorReports .size ());
382+ assertTrue (errorReports .stream ().anyMatch (e -> e .getErrorCode ().equals (E4059 )));
383+ assertTrue (errorReports .stream ().anyMatch (e -> e .getErrorCode ().equals (E4091 )));
384+ }
224385}
0 commit comments