]> gerrit.simantics Code Review - simantics/fmil.git/blob - org.simantics.fmil.core/native/FMILibrary/Test/FMI1/fmi1_xml_parsing_test.c
Merge "Added getters and setters for all FMI data types."
[simantics/fmil.git] / org.simantics.fmil.core / native / FMILibrary / Test / FMI1 / fmi1_xml_parsing_test.c
1 #include <stdlib.h>
2 #include <fmilib.h>
3 #include <stdio.h>
4 #include "config_test.h"
5
6 static const int NO_LOG_EXPECTED_MSG = 0;
7 static const int DO_LOG_EXPECTED_MSG = 1;
8
9 static int did_log_expected_msg;
10 static char *expected_message = "Invalid structured ScalarVariable name";
11 static char *name_check_test_directory;
12
13 char *concat(char *s1, char *s2)
14 {
15     size_t len1 = strlen(s1);
16     size_t len2 = strlen(s2);
17     /* +1 for the zero-terminator */
18     char *result = (char *) malloc((len1 + len2 + 1) * sizeof(char));
19     if (result == NULL) {
20         exit(CTEST_RETURN_FAIL);
21     }
22     memcpy(result, s1, len1);
23     memcpy(result + len1, s2, len2 + 1); /* +1 to copy the null-terminator */
24     return result;
25 }
26
27 void importlogger(jm_callbacks* c, jm_string module,\r
28         jm_log_level_enu_t log_level, jm_string message)\r
29 {\r
30     printf("module = %s, log level = %d: %s\n", module, log_level, message);\r
31     if (!strncmp(expected_message, message, strlen(expected_message))) {\r
32         did_log_expected_msg = 1;\r
33     }\r
34 }
35
36 void destroy_parse_test_callbacks(jm_callbacks *cb) {
37     fmi_import_free_context((fmi_import_context_t *)cb->context);
38     free(cb);
39 }
40
41 jm_callbacks* create_parse_test_callbacks(void) {
42     jm_callbacks *cb;
43
44     cb = (jm_callbacks *) malloc(sizeof(jm_callbacks));\r
45     cb->malloc = malloc;\r
46     cb->calloc = calloc;\r
47     cb->realloc = realloc;\r
48     cb->free = free;\r
49     cb->logger = importlogger;\r
50     cb->log_level = jm_log_level_all;\r
51     cb->context = fmi_import_allocate_context(cb);
52
53     return cb;
54 }
55
56 fmi1_import_t* test_parser(jm_callbacks *cb, char *xml_dir, int should_log_expected_msg, int configuration)
57 {
58     fmi1_import_t *fmu;
59     char *full_path;
60
61     if (configuration != 0) {
62         fmi_import_set_configuration((fmi_import_context_t *)cb->context, configuration);
63     }
64
65     did_log_expected_msg = 0;
66     full_path = concat(name_check_test_directory, xml_dir);
67     fmu = fmi1_import_parse_xml((fmi_import_context_t *)cb->context, full_path);
68
69     free(full_path);
70     if (fmu == NULL) {
71         exit(CTEST_RETURN_FAIL);
72     }
73     if (should_log_expected_msg != did_log_expected_msg) {
74         exit(CTEST_RETURN_FAIL);
75     }
76
77     return fmu;
78 }
79
80 void test_parser_with_cleanup(char *xml_dir, int should_log_expected_msg, int configuration) {
81     jm_callbacks* cb = create_parse_test_callbacks();
82     
83     fmi1_import_t* fmu = test_parser(cb, xml_dir, should_log_expected_msg, configuration);
84     fmi1_import_free(fmu);
85     destroy_parse_test_callbacks(cb);
86 }
87
88 void fail_name_check(char *xml_dir)
89 {
90     test_parser_with_cleanup(xml_dir, DO_LOG_EXPECTED_MSG, FMI_IMPORT_NAME_CHECK);
91     test_parser_with_cleanup(xml_dir, NO_LOG_EXPECTED_MSG, 0);
92 }
93
94 void pass_name_check(char *xml_dir)
95 {
96     test_parser_with_cleanup(xml_dir, NO_LOG_EXPECTED_MSG, FMI_IMPORT_NAME_CHECK);
97 }
98
99 void parser_log_expected_message(char *xml_dir)
100 {
101     test_parser_with_cleanup(xml_dir, DO_LOG_EXPECTED_MSG, 0);
102 }
103
104 void parser_no_log_expected_message(char *xml_dir)
105 {
106     test_parser_with_cleanup(xml_dir, NO_LOG_EXPECTED_MSG, 0);
107 }
108
109 typedef int (*fmu_test_f)(fmi1_import_t* fmu);
110
111 void test_parsing_and_fmu(char *xml_dir, fmu_test_f fmu_test, int should_log_expected_msg)
112 {
113     jm_callbacks* cb = create_parse_test_callbacks();
114     
115     fmi1_import_t* fmu = test_parser(cb, xml_dir, should_log_expected_msg, 0);
116     if (!fmu_test(fmu)) {
117         exit(CTEST_RETURN_FAIL);
118     }
119     fmi1_import_free(fmu);
120
121     destroy_parse_test_callbacks(cb);
122 }
123
124 void test_parsing_fail_and_fmu(char *xml_dir, fmu_test_f fmu_test)
125 {
126     test_parsing_and_fmu(xml_dir, fmu_test, DO_LOG_EXPECTED_MSG);
127 }
128
129 void test_parsing_pass_and_fmu(char *xml_dir, fmu_test_f fmu_test)
130 {
131     test_parsing_and_fmu(xml_dir, fmu_test, NO_LOG_EXPECTED_MSG);
132 }
133
134 void test_variable_naming_conventions(void) {
135     /* Test scalar variable names
136      *
137      * Every test below has a corresponding modelDescription in
138      * Test/FMI1/parser_test_xmls/naming_conventions_xmls/
139      * What is passed to these macros are names of directories containing
140      * modelDescriptions.
141      */
142
143     /* Test examples mentioned */
144     fail_name_check("naming_conventions_xmls/examples/foo");
145     fail_name_check("naming_conventions_xmls/examples/derderx");
146     pass_name_check("naming_conventions_xmls/examples/derx2");
147
148     /* FMI 1.0 standard examples from the documentaiton */
149     pass_name_check("naming_conventions_xmls/standard/vehicle.engine.speed");
150     pass_name_check("naming_conventions_xmls/standard/resistor12.u");
151     pass_name_check("naming_conventions_xmls/standard/v_min");
152     pass_name_check("naming_conventions_xmls/standard/robot.axis.motor234");
153     pass_name_check("naming_conventions_xmls/standard/derpipe34.T142");
154
155     /* Implementation test examples */
156     fail_name_check("naming_conventions_xmls/implementation/empty");
157     fail_name_check("naming_conventions_xmls/implementation/-0");
158     pass_name_check("naming_conventions_xmls/implementation/_0");
159     pass_name_check("naming_conventions_xmls/implementation/a0");
160     fail_name_check("naming_conventions_xmls/implementation/0a");
161     fail_name_check("naming_conventions_xmls/implementation/0");
162
163     /* q-name tests */
164     fail_name_check("naming_conventions_xmls/q-name/empty");
165     pass_name_check("naming_conventions_xmls/q-name/space");
166     fail_name_check("naming_conventions_xmls/q-name/backslash");
167     pass_name_check("naming_conventions_xmls/q-name/q-char");
168     pass_name_check("naming_conventions_xmls/q-name/escape");
169     pass_name_check("naming_conventions_xmls/q-name/chinese"); /* this should fail in FMI 2.0 */
170
171     /* der() tests */
172     pass_name_check("naming_conventions_xmls/der/dera32"); /* this should fail in FMI 2.0 */
173     fail_name_check("naming_conventions_xmls/der/dera12");
174     pass_name_check("naming_conventions_xmls/der/dera32-no-space");
175     pass_name_check("naming_conventions_xmls/der/dera");
176     fail_name_check("naming_conventions_xmls/der/dera-no-closing-parenthesis");
177     pass_name_check("naming_conventions_xmls/der/somederthing");
178     pass_name_check("naming_conventions_xmls/der/der0");
179     fail_name_check("naming_conventions_xmls/der/der2");
180     fail_name_check("naming_conventions_xmls/der/adera");
181
182     /* array and hierarchy tests */
183     pass_name_check("naming_conventions_xmls/array/n0");
184     fail_name_check("naming_conventions_xmls/array/a1comma");
185     pass_name_check("naming_conventions_xmls/array/a12345678");
186     pass_name_check("naming_conventions_xmls/array/a12345678space"); /* this should fail in FMI 2.0 */
187     pass_name_check("naming_conventions_xmls/array/a1.a3");
188     pass_name_check("naming_conventions_xmls/array/a.a123");
189     fail_name_check("naming_conventions_xmls/array/aspace1");
190     fail_name_check("naming_conventions_xmls/array/a1space");
191     pass_name_check("naming_conventions_xmls/array/a1space1"); /* this should fail in FMI 2.0 */
192     fail_name_check("naming_conventions_xmls/array/aspacebracket1");
193     fail_name_check("naming_conventions_xmls/array/a-1");
194     pass_name_check("naming_conventions_xmls/array/a1");
195     pass_name_check("naming_conventions_xmls/array/a.a");
196     pass_name_check("naming_conventions_xmls/array/a");
197
198     /* list of variables */
199     fail_name_check("naming_conventions_xmls/list/aemptyc");
200     expected_message = "Two variables with the same name";
201     pass_name_check("naming_conventions_xmls/list/cba");
202     fail_name_check("naming_conventions_xmls/list/acad");
203
204     /* flat hierarchy test */
205     fail_name_check("naming_conventions_xmls/flat/acad");
206     pass_name_check("naming_conventions_xmls/flat/q-char-nonescaped");
207 }
208
209 int should_have_no_vars(fmi1_import_t* fmu) {
210     fmi1_import_variable_list_t* vars;
211
212     vars = fmi1_import_get_variable_list(fmu);
213     return fmi1_import_get_variable_list_size(vars) == 0;
214 }
215
216 int should_have_1_no_alias_var(fmi1_import_t* fmu) {
217     fmi1_import_variable_list_t* vars;
218     fmi1_import_variable_t* var;
219
220     vars = fmi1_import_get_variable_list(fmu);
221     if (fmi1_import_get_variable_list_size(vars) != 1) {
222         return 0;
223     }
224
225     var = fmi1_import_get_variable(vars, 0);
226     return (fmi1_import_get_variable_alias_kind(var) == fmi1_variable_is_not_alias);
227 }
228
229 int should_have_size_2_alias_group(fmi1_import_t* fmu) {
230     fmi1_import_variable_list_t* vars;
231     fmi1_import_variable_t* var;
232
233     vars = fmi1_import_get_variable_list(fmu);
234
235     if (fmi1_import_get_variable_list_size(vars) != 2) {
236         return 0;
237     }
238
239     var = fmi1_import_get_variable(vars, 0);
240     if (fmi1_import_get_variable_alias_kind(var) != fmi1_variable_is_not_alias) {
241         return 0;
242     }
243
244     var = fmi1_import_get_variable(vars, 1);
245     return (fmi1_import_get_variable_alias_kind(var) == fmi1_variable_is_alias);
246 }
247
248 int should_have_size_2_no_alis(fmi1_import_t* fmu) {
249     fmi1_import_variable_list_t* vars;
250     fmi1_import_variable_t* var;
251
252     vars = fmi1_import_get_variable_list(fmu);
253
254     if (fmi1_import_get_variable_list_size(vars) != 2) {
255         return 0;
256     }
257
258     var = fmi1_import_get_variable(vars, 0);
259     if (fmi1_import_get_variable_alias_kind(var) != fmi1_variable_is_not_alias) {
260         return 0;
261     }
262
263     var = fmi1_import_get_variable(vars, 1);
264     return (fmi1_import_get_variable_alias_kind(var) == fmi1_variable_is_not_alias);
265 }
266
267 int should_have_size_3_alias_group(fmi1_import_t* fmu) {
268     fmi1_import_variable_list_t* vars;
269     fmi1_import_variable_t* var;
270
271     vars = fmi1_import_get_variable_list(fmu);
272
273     if (fmi1_import_get_variable_list_size(vars) != 3) {
274         return 0;
275     }
276
277     var = fmi1_import_get_variable(vars, 0);
278     if (fmi1_import_get_variable_alias_kind(var) != fmi1_variable_is_not_alias) {
279         return 0;
280     }
281
282     var = fmi1_import_get_variable(vars, 1);
283     if (fmi1_import_get_variable_alias_kind(var) != fmi1_variable_is_alias) {
284         return 0;
285     }
286
287     var = fmi1_import_get_variable(vars, 2);
288     return (fmi1_import_get_variable_alias_kind(var) == fmi1_variable_is_negated_alias);
289 }
290
291 void test_alias_set_error_handling(void) {
292     /* Test that we log errors for incorrect alias set and 
293      * that incorrect alias variables are removed or that
294      * variable that should be alias variables becomes alias */
295
296     expected_message = "Alias set with vr=0 (type=Real) do not have a 'noAlias' variable.";
297     parser_log_expected_message("alias_validation/all_alias");
298     expected_message = "Removing incorrect alias variable 'v2'";
299     test_parsing_fail_and_fmu("alias_validation/all_alias", should_have_no_vars);
300     
301     expected_message = "Alias set with vr=0 (type=Real) do not have a 'noAlias' variable.";
302     parser_log_expected_message("alias_validation/all_alias_mixed");
303     expected_message = "Removing incorrect alias variable 'v2'";
304     test_parsing_fail_and_fmu("alias_validation/all_alias_mixed", should_have_no_vars);
305
306     expected_message = "Alias set with vr=0 (type=Real) do not have a 'noAlias' variable.";
307     parser_log_expected_message("alias_validation/all_negated_alias");
308     expected_message = "Removing incorrect alias variable 'v2'";
309     test_parsing_fail_and_fmu("alias_validation/all_negated_alias", should_have_no_vars);
310
311     expected_message = "Variables v1 and v2 reference the same vr 0. Marking 'v2' as alias.";
312     test_parsing_fail_and_fmu("alias_validation/all_no_alias", should_have_size_2_alias_group);
313
314     expected_message = "Variables v1 and v2 reference the same vr 0. Marking 'v2' as alias.";
315     test_parsing_pass_and_fmu("alias_validation/small_valid_alias_set", should_have_size_2_alias_group);
316
317     expected_message = "Variables v1 and v2 reference the same vr 0. Marking 'v2' as alias.";
318     test_parsing_pass_and_fmu("alias_validation/medium_valid_alias_set", should_have_size_3_alias_group);
319
320     expected_message = "Alias set with vr=0 (type=Real) do not have a 'noAlias' variable.";
321     parser_log_expected_message("alias_validation/all_alias_two_sets");
322     expected_message = "Alias set with vr=1 (type=Real) do not have a 'noAlias' variable.";
323     test_parsing_fail_and_fmu("alias_validation/all_alias_two_sets", should_have_no_vars);
324
325     expected_message = "Variables v1 and v2 reference the same vr 0. Marking 'v2' as alias.";
326     test_parsing_pass_and_fmu("alias_validation/all_no_alias_two_sets", should_have_size_2_no_alis);
327
328     expected_message = "Inconsistent start values in alias set";
329     parser_no_log_expected_message("alias_validation/consistent_real_start_values");
330
331     expected_message = "Inconsistent start values in alias set";
332     parser_no_log_expected_message("alias_validation/consistent_int_start_values");
333
334     expected_message = "Inconsistent start values in alias set";
335     parser_no_log_expected_message("alias_validation/consistent_enum_start_values");
336
337     expected_message = "Inconsistent start values in alias set";
338     parser_no_log_expected_message("alias_validation/consistent_bool_start_values");
339
340     expected_message = "Inconsistent start values in alias set";
341     parser_no_log_expected_message("alias_validation/consistent_str_start_values");
342
343     expected_message = "Inconsistent start values in alias set, "
344         "start value '1.0"; /* Cannot check more of message due to potential roundings */
345     test_parsing_fail_and_fmu("alias_validation/inconsistent_real_start_values",
346         should_have_1_no_alias_var);
347
348     expected_message = "Inconsistent start values in alias set, "
349         "start value '1' of 'v1' does not match "
350         "start value '3' of 'v2'.";
351     test_parsing_fail_and_fmu("alias_validation/inconsistent_int_start_values",
352         should_have_1_no_alias_var);
353
354     expected_message = "Inconsistent start values in alias set, "
355         "start value '1' of 'v1' does not match "
356         "start value '2' of 'v2'.";
357     test_parsing_fail_and_fmu("alias_validation/inconsistent_enum_start_values",
358         should_have_1_no_alias_var);
359
360     expected_message = "Inconsistent start values in alias set, "
361         "start value 'true' of 'v1' does not match "
362         "start value 'false' of 'v2'.";
363     test_parsing_fail_and_fmu("alias_validation/inconsistent_bool_start_values",
364         should_have_1_no_alias_var);
365
366     expected_message = "Inconsistent start values in alias set, "
367         "start value 'a' of 'v1' does not match "
368         "start value 'b' of 'v2'.";
369     test_parsing_fail_and_fmu("alias_validation/inconsistent_str_start_values",
370         should_have_1_no_alias_var);
371
372     expected_message = "Inconsistent start values in alias set, "
373         "start value '1.0"; /* Cannot check more of message due to potential roundings */
374     test_parsing_fail_and_fmu("alias_validation/inconsistent_neg_real_start_values",
375         should_have_1_no_alias_var);
376
377     expected_message = "Inconsistent start values in alias set, "
378         "start value '1' of 'v1' does not match "
379         "start value '1' of 'v2'(negated alias).";
380     test_parsing_fail_and_fmu("alias_validation/inconsistent_neg_int_start_values",
381         should_have_1_no_alias_var);
382
383     expected_message = "Inconsistent start values in alias set, "
384         "start value '1' of 'v1' does not match "
385         "start value '1' of 'v2'(negated alias).";
386     test_parsing_fail_and_fmu("alias_validation/inconsistent_neg_enum_start_values",
387         should_have_1_no_alias_var);
388
389     expected_message = "Inconsistent start values in alias set, "
390         "start value 'true' of 'v1' does not match "
391         "start value 'true' of 'v2'(negated alias).";
392     test_parsing_fail_and_fmu("alias_validation/inconsistent_neg_bool_start_values",
393         should_have_1_no_alias_var);
394
395     expected_message = "Inconsistent start values in alias set, "
396         "start value 'a' of 'v1' does not match "
397         "start value 'a' of 'v2'(negated alias).";
398     test_parsing_fail_and_fmu("alias_validation/inconsistent_neg_str_start_values",
399         should_have_1_no_alias_var);
400
401     expected_message = "Inconsistent start values in alias set";
402     parser_no_log_expected_message("alias_validation/consistent_real_start_values2");
403
404     expected_message = "Inconsistent start values in alias set, "
405         "start value '1' of 'v2' does not match "
406         "start value '3' of 'v3'.";
407     parser_log_expected_message("alias_validation/inconsistent_int_start_values2");
408
409     expected_message = "Inconsistent start values in alias set";
410     test_parsing_pass_and_fmu("alias_validation/consistent_real_zero_start_values", should_have_size_2_alias_group);
411 }
412
413 void test_deprecation_errors(void) {
414     /* Test that we give errors for deprecated behviour
415      *
416      * Every test below has a corresponding modelDescription in
417      * Test/FMI1/parser_test_xmls/deprecated/
418      * What is passed to these macros are names of directories containing
419      * modelDescriptions.
420      */
421
422     expected_message = "Found capability flag canSignalEvents which have been "
423         "deprecated as it fills no function";
424     parser_log_expected_message("deprecated/canSignalEvents");
425 }
426
427 int main(int argc, char *argv[])
428 {
429     if (argc == 2) {\r
430         name_check_test_directory = argv[1];\r
431     } else {
432         printf("Usage: %s <path to folder naming_conventions_xmls>\n", argv[0]);\r
433         exit(CTEST_RETURN_FAIL);
434     }
435
436     test_variable_naming_conventions();
437     test_deprecation_errors();
438     test_alias_set_error_handling();
439
440     return 0;
441 }