From 930824d01a070989f511c74cfb25a0cf593ae28e Mon Sep 17 00:00:00 2001 From: qth2hi Date: Mon, 28 Oct 2024 20:25:35 +0100 Subject: [PATCH 01/21] Updated self test and code snippet generator --- test/JPP_TestUsecases.csv | 6 + test/JPP_TestUsecases.html | 392 ++++++-- test/JPP_TestUsecases.rst | 62 +- test/JPP_TestUsecases.txt | 26 +- test/component_test.py | 4 +- .../test_08_NAMING_CONVENTION_BADCASE.py | 80 ++ ...test_09_COMPOSITE_EXPRESSIONS_GOODCASE.py} | 4 +- ... test_10_COMPOSITE_EXPRESSIONS_BADCASE.py} | 4 +- ...E.py => test_11_CODE_COMMENTS_GOODCASE.py} | 4 +- ...st_12_COMMON_SYNTAX_VIOLATIONS_BADCASE.py} | 4 +- ... => test_13_IMPLICIT_CREATION_GOODCASE.py} | 4 +- ...y => test_14_IMPLICIT_CREATION_BADCASE.py} | 4 +- ...E.py => test_15_CYCLIC_IMPORTS_BADCASE.py} | 4 +- ...SE.py => test_16_PATH_FORMATS_GOODCASE.py} | 4 +- ....py => test_17_BLOCKED_SLICING_BADCASE.py} | 4 +- ...SE.py => test_18_NESTED_LISTS_GOODCASE.py} | 4 +- ....py => test_19_STRING_INDICES_GOODCASE.py} | 4 +- ...est_20_NOT_EXISTING_PARAMETERS_BADCASE.py} | 4 +- ...ASE.py => test_21_LINE_BREAKS_GOODCASE.py} | 4 +- ...y => test_22_SELF_ASSIGNMENTS_GOODCASE.py} | 4 +- ...t_23_ASSIGNMENTS_BY_REFERENCE_GOODCASE.py} | 4 +- ...py => test_24_PARAMETER_SCOPE_GOODCASE.py} | 4 +- ....py => test_25_PARAMETER_SCOPE_BADCASE.py} | 4 +- test/testconfig/TestConfig.py | 256 ++++- test/testfiles/jpp-test_config_0401.jsonp | 54 ++ test/testfiles/jpp-test_config_0450.jsonp | 18 + test/testfiles/jpp-test_config_0451.jsonp | 18 + test/testfiles/jpp-test_config_0452.jsonp | 18 + test/testfiles/jpp-test_config_0453.jsonp | 18 + test/testfiles/jpp-test_config_0454.jsonp | 18 + test/testfiles/jpp-test_config_0455.jsonp | 18 + test/testfiles/jpp-test_config_0456.jsonp | 18 + test/testfiles/jpp-test_config_0457.jsonp | 18 + test/testfiles/jpp-test_config_0458.jsonp | 18 + test/testfiles/jpp-test_config_0459.jsonp | 17 + test/testfiles/jpp-test_config_0460.jsonp | 17 + test/testfiles/jpp-test_config_0461.jsonp | 17 + test/testfiles/jpp-test_config_0462.jsonp | 17 + test/testfiles/jpp-test_config_0463.jsonp | 17 + test/testfiles/jpp-test_config_0464.jsonp | 17 + test/testfiles/jpp-test_config_0465.jsonp | 18 + test/testfiles/jpp-test_config_0466.jsonp | 18 + test/testtools/GenSnippetsJPP.py | 872 +++++++++++++++++- 43 files changed, 1976 insertions(+), 144 deletions(-) create mode 100644 test/pytest/pytestfiles/test_08_NAMING_CONVENTION_BADCASE.py rename test/pytest/pytestfiles/{test_08_COMPOSITE_EXPRESSIONS_GOODCASE.py => test_09_COMPOSITE_EXPRESSIONS_GOODCASE.py} (99%) rename test/pytest/pytestfiles/{test_09_COMPOSITE_EXPRESSIONS_BADCASE.py => test_10_COMPOSITE_EXPRESSIONS_BADCASE.py} (98%) rename test/pytest/pytestfiles/{test_10_CODE_COMMENTS_GOODCASE.py => test_11_CODE_COMMENTS_GOODCASE.py} (96%) rename test/pytest/pytestfiles/{test_11_COMMON_SYNTAX_VIOLATIONS_BADCASE.py => test_12_COMMON_SYNTAX_VIOLATIONS_BADCASE.py} (97%) rename test/pytest/pytestfiles/{test_12_IMPLICIT_CREATION_GOODCASE.py => test_13_IMPLICIT_CREATION_GOODCASE.py} (98%) rename test/pytest/pytestfiles/{test_13_IMPLICIT_CREATION_BADCASE.py => test_14_IMPLICIT_CREATION_BADCASE.py} (98%) rename test/pytest/pytestfiles/{test_14_CYCLIC_IMPORTS_BADCASE.py => test_15_CYCLIC_IMPORTS_BADCASE.py} (97%) rename test/pytest/pytestfiles/{test_15_PATH_FORMATS_GOODCASE.py => test_16_PATH_FORMATS_GOODCASE.py} (96%) rename test/pytest/pytestfiles/{test_16_BLOCKED_SLICING_BADCASE.py => test_17_BLOCKED_SLICING_BADCASE.py} (99%) rename test/pytest/pytestfiles/{test_17_NESTED_LISTS_GOODCASE.py => test_18_NESTED_LISTS_GOODCASE.py} (96%) rename test/pytest/pytestfiles/{test_18_STRING_INDICES_GOODCASE.py => test_19_STRING_INDICES_GOODCASE.py} (97%) rename test/pytest/pytestfiles/{test_19_NOT_EXISTING_PARAMETERS_BADCASE.py => test_20_NOT_EXISTING_PARAMETERS_BADCASE.py} (99%) rename test/pytest/pytestfiles/{test_20_LINE_BREAKS_GOODCASE.py => test_21_LINE_BREAKS_GOODCASE.py} (96%) rename test/pytest/pytestfiles/{test_21_SELF_ASSIGNMENTS_GOODCASE.py => test_22_SELF_ASSIGNMENTS_GOODCASE.py} (96%) rename test/pytest/pytestfiles/{test_22_ASSIGNMENTS_BY_REFERENCE_GOODCASE.py => test_23_ASSIGNMENTS_BY_REFERENCE_GOODCASE.py} (96%) rename test/pytest/pytestfiles/{test_23_PARAMETER_SCOPE_GOODCASE.py => test_24_PARAMETER_SCOPE_GOODCASE.py} (98%) rename test/pytest/pytestfiles/{test_24_PARAMETER_SCOPE_BADCASE.py => test_25_PARAMETER_SCOPE_BADCASE.py} (98%) create mode 100644 test/testfiles/jpp-test_config_0401.jsonp create mode 100644 test/testfiles/jpp-test_config_0450.jsonp create mode 100644 test/testfiles/jpp-test_config_0451.jsonp create mode 100644 test/testfiles/jpp-test_config_0452.jsonp create mode 100644 test/testfiles/jpp-test_config_0453.jsonp create mode 100644 test/testfiles/jpp-test_config_0454.jsonp create mode 100644 test/testfiles/jpp-test_config_0455.jsonp create mode 100644 test/testfiles/jpp-test_config_0456.jsonp create mode 100644 test/testfiles/jpp-test_config_0457.jsonp create mode 100644 test/testfiles/jpp-test_config_0458.jsonp create mode 100644 test/testfiles/jpp-test_config_0459.jsonp create mode 100644 test/testfiles/jpp-test_config_0460.jsonp create mode 100644 test/testfiles/jpp-test_config_0461.jsonp create mode 100644 test/testfiles/jpp-test_config_0462.jsonp create mode 100644 test/testfiles/jpp-test_config_0463.jsonp create mode 100644 test/testfiles/jpp-test_config_0464.jsonp create mode 100644 test/testfiles/jpp-test_config_0465.jsonp create mode 100644 test/testfiles/jpp-test_config_0466.jsonp diff --git a/test/JPP_TestUsecases.csv b/test/JPP_TestUsecases.csv index 52d6dca9..da2e919c 100644 --- a/test/JPP_TestUsecases.csv +++ b/test/JPP_TestUsecases.csv @@ -67,6 +67,12 @@ JPP_0369|VALUE_DETECTION|BADCASE|JSON file with expression starting with '${' an JPP_0370|VALUE_DETECTION|BADCASE|JSON file with expression starting with '${' and ending with '}', further matching '${' and '}' in between (not all nested) (invalid syntax 4) JPP_0371|VALUE_DETECTION|BADCASE|JSON file with expression starting with '${' and ending with '}', further matching '${' and '}' in between (not all nested) (invalid syntax 5) JPP_0400|NAMING_CONVENTION|GOODCASE|JSON file with several parameter names w.r.t. the naming convention +JPP_0450|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (1) +JPP_0451|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (2) +JPP_0452|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (3) +JPP_0453|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (4) +JPP_0454|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (5) +JPP_0455|NAMING_CONVENTION|BADCASE|JSON file with several invalid parameter names (6) JPP_0500|COMPOSITE_EXPRESSIONS|GOODCASE|JSON file with composite data structure (nested lists and dictionaries 1) JPP_0501|COMPOSITE_EXPRESSIONS|GOODCASE|JSON file with composite data structure (nested lists and dictionaries 2) JPP_0502|COMPOSITE_EXPRESSIONS|GOODCASE|JSON file with composite data structure (nested lists and dictionaries 3 / some key names with dots inside) diff --git a/test/JPP_TestUsecases.html b/test/JPP_TestUsecases.html index 90c0d544..66f808c4 100644 --- a/test/JPP_TestUsecases.html +++ b/test/JPP_TestUsecases.html @@ -2272,6 +2272,204 @@ 68 + + + +JPP_0450 + + + + +NAMING_CONVENTION + + + + +BADCASE + + + + +JSON file with several invalid parameter names (1)
+Expected: All names are accepted (in definition and in reference) + + +
+ + + + + + + +69 + + + + + +JPP_0451 + + + + +NAMING_CONVENTION + + + + +BADCASE + + + + +JSON file with several invalid parameter names (2)
+Expected: All names are accepted (in definition and in reference) + + +
+ + + + + + + +70 + + + + + +JPP_0452 + + + + +NAMING_CONVENTION + + + + +BADCASE + + + + +JSON file with several invalid parameter names (3)
+Expected: All names are accepted (in definition and in reference) + + +
+ + + + + + + +71 + + + + + +JPP_0453 + + + + +NAMING_CONVENTION + + + + +BADCASE + + + + +JSON file with several invalid parameter names (4)
+Expected: All names are accepted (in definition and in reference) + + +
+ + + + + + + +72 + + + + + +JPP_0454 + + + + +NAMING_CONVENTION + + + + +BADCASE + + + + +JSON file with several invalid parameter names (5)
+Expected: All names are accepted (in definition and in reference) + + +
+ + + + + + + +73 + + + + + +JPP_0455 + + + + +NAMING_CONVENTION + + + + +BADCASE + + + + +JSON file with several invalid parameter names (6)
+Expected: All names are accepted (in definition and in reference) + + +
+ + + + + + + +74 + + @@ -2303,7 +2501,7 @@ -69 +75 @@ -2337,7 +2535,7 @@ -70 +76 @@ -2371,7 +2569,7 @@ -71 +77 @@ -2404,7 +2602,7 @@ -72 +78 @@ -2437,7 +2635,7 @@ -73 +79 @@ -2470,7 +2668,7 @@ -74 +80 @@ -2503,7 +2701,7 @@ -75 +81 @@ -2536,7 +2734,7 @@ -76 +82 @@ -2569,7 +2767,7 @@ -77 +83 @@ -2602,7 +2800,7 @@ -78 +84 @@ -2635,7 +2833,7 @@ -79 +85 @@ -2668,7 +2866,7 @@ -80 +86 @@ -2701,7 +2899,7 @@ -81 +87 @@ -2734,7 +2932,7 @@ -82 +88 @@ -2767,7 +2965,7 @@ -83 +89 @@ -2800,7 +2998,7 @@ -84 +90 @@ -2833,7 +3031,7 @@ -85 +91 @@ -2867,7 +3065,7 @@ -86 +92 @@ -2901,7 +3099,7 @@ -87 +93 @@ -2934,7 +3132,7 @@ -88 +94 @@ -2967,7 +3165,7 @@ -89 +95 @@ -3000,7 +3198,7 @@ -90 +96 @@ -3033,7 +3231,7 @@ -91 +97 @@ -3066,7 +3264,7 @@ -92 +98 @@ -3099,7 +3297,7 @@ -93 +99 @@ -3132,7 +3330,7 @@ -94 +100 @@ -3165,7 +3363,7 @@ -95 +101 @@ -3198,7 +3396,7 @@ -96 +102 @@ -3231,7 +3429,7 @@ -97 +103 @@ -3264,7 +3462,7 @@ -98 +104 @@ -3297,7 +3495,7 @@ -99 +105 @@ -3330,7 +3528,7 @@ -100 +106 @@ -3363,7 +3561,7 @@ -101 +107 @@ -3396,7 +3594,7 @@ -102 +108 @@ -3429,7 +3627,7 @@ -103 +109 @@ -3462,7 +3660,7 @@ -104 +110 @@ -3495,7 +3693,7 @@ -105 +111 @@ -3528,7 +3726,7 @@ -106 +112 @@ -3561,7 +3759,7 @@ -107 +113 @@ -3594,7 +3792,7 @@ -108 +114 @@ -3627,7 +3825,7 @@ -109 +115 @@ -3660,7 +3858,7 @@ -110 +116 @@ -3693,7 +3891,7 @@ -111 +117 @@ -3726,7 +3924,7 @@ -112 +118 @@ -3759,7 +3957,7 @@ -113 +119 @@ -3793,7 +3991,7 @@ -114 +120 @@ -3826,7 +4024,7 @@ -115 +121 @@ -3859,7 +4057,7 @@ -116 +122 @@ -3892,7 +4090,7 @@ -117 +123 @@ -3925,7 +4123,7 @@ -118 +124 @@ -3958,7 +4156,7 @@ -119 +125 @@ -3991,7 +4189,7 @@ -120 +126 @@ -4024,7 +4222,7 @@ -121 +127 @@ -4057,7 +4255,7 @@ -122 +128 @@ -4090,7 +4288,7 @@ -123 +129 @@ -4123,7 +4321,7 @@ -124 +130 @@ -4156,7 +4354,7 @@ -125 +131 @@ -4189,7 +4387,7 @@ -126 +132 @@ -4222,7 +4420,7 @@ -127 +133 @@ -4255,7 +4453,7 @@ -128 +134 @@ -4288,7 +4486,7 @@ -129 +135 @@ -4321,7 +4519,7 @@ -130 +136 @@ -4354,7 +4552,7 @@ -131 +137 @@ -4387,7 +4585,7 @@ -132 +138 @@ -4420,7 +4618,7 @@ -133 +139 @@ -4453,7 +4651,7 @@ -134 +140 @@ -4486,7 +4684,7 @@ -135 +141 @@ -4519,7 +4717,7 @@ -136 +142 @@ -4552,7 +4750,7 @@ -137 +143 @@ -4585,7 +4783,7 @@ -138 +144 @@ -4618,7 +4816,7 @@ -139 +145 @@ -4651,7 +4849,7 @@ -140 +146 @@ -4684,7 +4882,7 @@ -141 +147 @@ -4717,7 +4915,7 @@ -142 +148 @@ -4750,7 +4948,7 @@ -143 +149 @@ -4783,7 +4981,7 @@ -144 +150 @@ -4816,7 +5014,7 @@ -145 +151 @@ -4849,7 +5047,7 @@ -146 +152 @@ -4882,7 +5080,7 @@ -147 +153 @@ -4915,7 +5113,7 @@ -148 +154 @@ -4948,7 +5146,7 @@ -149 +155 @@ -4981,7 +5179,7 @@ -150 +156 @@ -5014,7 +5212,7 @@ -151 +157 @@ -5047,7 +5245,7 @@ -152 +158 @@ -5080,7 +5278,7 @@ -153 +159 @@ -5113,7 +5311,7 @@ -154 +160 @@ -5146,7 +5344,7 @@ -155 +161 @@ -5179,7 +5377,7 @@ -156 +162 @@ -5212,7 +5410,7 @@ -157 +163 @@ -5245,7 +5443,7 @@ -158 +164 @@ -5278,7 +5476,7 @@ -159 +165 @@ -5311,7 +5509,7 @@ -160 +166 @@ -5344,7 +5542,7 @@ -161 +167 @@ -5377,7 +5575,7 @@ -162 +168 @@ -5410,7 +5608,7 @@ -163 +169 @@ -5443,7 +5641,7 @@ -164 +170 @@ -5476,7 +5674,7 @@
 

-
Generated: 25.10.2024 - 20:21:51
+
Generated: 28.10.2024 - 20:15:13
 
diff --git a/test/JPP_TestUsecases.rst b/test/JPP_TestUsecases.rst index 9d46a977..9fdc90dd 100644 --- a/test/JPP_TestUsecases.rst +++ b/test/JPP_TestUsecases.rst @@ -739,6 +739,66 @@ Test Use Cases ---- +* **Test JPP_0450** + + [NAMING_CONVENTION / BADCASE] + + **JSON file with several invalid parameter names (1)** + + Expected: All names are accepted (in definition and in reference) + +---- + +* **Test JPP_0451** + + [NAMING_CONVENTION / BADCASE] + + **JSON file with several invalid parameter names (2)** + + Expected: All names are accepted (in definition and in reference) + +---- + +* **Test JPP_0452** + + [NAMING_CONVENTION / BADCASE] + + **JSON file with several invalid parameter names (3)** + + Expected: All names are accepted (in definition and in reference) + +---- + +* **Test JPP_0453** + + [NAMING_CONVENTION / BADCASE] + + **JSON file with several invalid parameter names (4)** + + Expected: All names are accepted (in definition and in reference) + +---- + +* **Test JPP_0454** + + [NAMING_CONVENTION / BADCASE] + + **JSON file with several invalid parameter names (5)** + + Expected: All names are accepted (in definition and in reference) + +---- + +* **Test JPP_0455** + + [NAMING_CONVENTION / BADCASE] + + **JSON file with several invalid parameter names (6)** + + Expected: All names are accepted (in definition and in reference) + +---- + * **Test JPP_0500** [COMPOSITE_EXPRESSIONS / GOODCASE] @@ -1721,5 +1781,5 @@ Test Use Cases ---- -Generated: 25.10.2024 - 20:21:51 +Generated: 28.10.2024 - 20:15:13 diff --git a/test/JPP_TestUsecases.txt b/test/JPP_TestUsecases.txt index 2b0cf434..95564c2f 100644 --- a/test/JPP_TestUsecases.txt +++ b/test/JPP_TestUsecases.txt @@ -310,6 +310,30 @@ Test JPP_0400 / NAMING_CONVENTION / GOODCASE Description: JSON file with several parameter names w.r.t. the naming convention Expectation: All names are accepted (in definition and in reference) ------------------------------------------------------------------------------------------------------------------------ +Test JPP_0450 / NAMING_CONVENTION / BADCASE +Description: JSON file with several invalid parameter names (1) +Expectation: All names are accepted (in definition and in reference) +------------------------------------------------------------------------------------------------------------------------ +Test JPP_0451 / NAMING_CONVENTION / BADCASE +Description: JSON file with several invalid parameter names (2) +Expectation: All names are accepted (in definition and in reference) +------------------------------------------------------------------------------------------------------------------------ +Test JPP_0452 / NAMING_CONVENTION / BADCASE +Description: JSON file with several invalid parameter names (3) +Expectation: All names are accepted (in definition and in reference) +------------------------------------------------------------------------------------------------------------------------ +Test JPP_0453 / NAMING_CONVENTION / BADCASE +Description: JSON file with several invalid parameter names (4) +Expectation: All names are accepted (in definition and in reference) +------------------------------------------------------------------------------------------------------------------------ +Test JPP_0454 / NAMING_CONVENTION / BADCASE +Description: JSON file with several invalid parameter names (5) +Expectation: All names are accepted (in definition and in reference) +------------------------------------------------------------------------------------------------------------------------ +Test JPP_0455 / NAMING_CONVENTION / BADCASE +Description: JSON file with several invalid parameter names (6) +Expectation: All names are accepted (in definition and in reference) +------------------------------------------------------------------------------------------------------------------------ Test JPP_0500 / COMPOSITE_EXPRESSIONS / GOODCASE Description: JSON file with composite data structure (nested lists and dictionaries 1) Expectation: JsonPreprocessor returns expected value @@ -704,5 +728,5 @@ Test JPP_2508 / PARAMETER_SCOPE / BADCASE Description: JSON file containing a parameter with missing scope (9) Expectation: JsonPreprocessor returns expected value ------------------------------------------------------------------------------------------------------------------------ -Generated: 25.10.2024 - 20:21:51 +Generated: 28.10.2024 - 20:15:13 diff --git a/test/component_test.py b/test/component_test.py index c110ed1f..c92156ae 100644 --- a/test/component_test.py +++ b/test/component_test.py @@ -22,8 +22,8 @@ # # -------------------------------------------------------------------------------------------------------------- # -VERSION = "0.48.1" -VERSION_DATE = "25.10.2024" +VERSION = "0.49.0" +VERSION_DATE = "28.10.2024" # # -------------------------------------------------------------------------------------------------------------- #TM*** diff --git a/test/pytest/pytestfiles/test_08_NAMING_CONVENTION_BADCASE.py b/test/pytest/pytestfiles/test_08_NAMING_CONVENTION_BADCASE.py new file mode 100644 index 00000000..7b3484b7 --- /dev/null +++ b/test/pytest/pytestfiles/test_08_NAMING_CONVENTION_BADCASE.py @@ -0,0 +1,80 @@ +# ************************************************************************************************************** +# Copyright 2020-2023 Robert Bosch GmbH +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# -------------------------------------------------------------------------------------------------------------- +# +# test_08_NAMING_CONVENTION_BADCASE.py +# +# XC-HWP/ESW3-Queckenstedt +# +# 28.10.2024 - 20:15:13 +# +# -------------------------------------------------------------------------------------------------------------- + +import pytest +from pytestlibs.CExecute import CExecute + +# -------------------------------------------------------------------------------------------------------------- + +class Test_NAMING_CONVENTION_BADCASE: + +# -------------------------------------------------------------------------------------------------------------- + # Expected: All names are accepted (in definition and in reference) + @pytest.mark.parametrize( + "Description", ["JSON file with several invalid parameter names (1)",] + ) + def test_JPP_0450(self, Description): + nReturn = CExecute.Execute("JPP_0450") + assert nReturn == 0 +# -------------------------------------------------------------------------------------------------------------- + # Expected: All names are accepted (in definition and in reference) + @pytest.mark.parametrize( + "Description", ["JSON file with several invalid parameter names (2)",] + ) + def test_JPP_0451(self, Description): + nReturn = CExecute.Execute("JPP_0451") + assert nReturn == 0 +# -------------------------------------------------------------------------------------------------------------- + # Expected: All names are accepted (in definition and in reference) + @pytest.mark.parametrize( + "Description", ["JSON file with several invalid parameter names (3)",] + ) + def test_JPP_0452(self, Description): + nReturn = CExecute.Execute("JPP_0452") + assert nReturn == 0 +# -------------------------------------------------------------------------------------------------------------- + # Expected: All names are accepted (in definition and in reference) + @pytest.mark.parametrize( + "Description", ["JSON file with several invalid parameter names (4)",] + ) + def test_JPP_0453(self, Description): + nReturn = CExecute.Execute("JPP_0453") + assert nReturn == 0 +# -------------------------------------------------------------------------------------------------------------- + # Expected: All names are accepted (in definition and in reference) + @pytest.mark.parametrize( + "Description", ["JSON file with several invalid parameter names (5)",] + ) + def test_JPP_0454(self, Description): + nReturn = CExecute.Execute("JPP_0454") + assert nReturn == 0 +# -------------------------------------------------------------------------------------------------------------- + # Expected: All names are accepted (in definition and in reference) + @pytest.mark.parametrize( + "Description", ["JSON file with several invalid parameter names (6)",] + ) + def test_JPP_0455(self, Description): + nReturn = CExecute.Execute("JPP_0455") + assert nReturn == 0 +# -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_08_COMPOSITE_EXPRESSIONS_GOODCASE.py b/test/pytest/pytestfiles/test_09_COMPOSITE_EXPRESSIONS_GOODCASE.py similarity index 99% rename from test/pytest/pytestfiles/test_08_COMPOSITE_EXPRESSIONS_GOODCASE.py rename to test/pytest/pytestfiles/test_09_COMPOSITE_EXPRESSIONS_GOODCASE.py index 7940b512..77bac8f6 100644 --- a/test/pytest/pytestfiles/test_08_COMPOSITE_EXPRESSIONS_GOODCASE.py +++ b/test/pytest/pytestfiles/test_09_COMPOSITE_EXPRESSIONS_GOODCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_08_COMPOSITE_EXPRESSIONS_GOODCASE.py +# test_09_COMPOSITE_EXPRESSIONS_GOODCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_09_COMPOSITE_EXPRESSIONS_BADCASE.py b/test/pytest/pytestfiles/test_10_COMPOSITE_EXPRESSIONS_BADCASE.py similarity index 98% rename from test/pytest/pytestfiles/test_09_COMPOSITE_EXPRESSIONS_BADCASE.py rename to test/pytest/pytestfiles/test_10_COMPOSITE_EXPRESSIONS_BADCASE.py index 5f4fad9f..875b9e00 100644 --- a/test/pytest/pytestfiles/test_09_COMPOSITE_EXPRESSIONS_BADCASE.py +++ b/test/pytest/pytestfiles/test_10_COMPOSITE_EXPRESSIONS_BADCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_09_COMPOSITE_EXPRESSIONS_BADCASE.py +# test_10_COMPOSITE_EXPRESSIONS_BADCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_10_CODE_COMMENTS_GOODCASE.py b/test/pytest/pytestfiles/test_11_CODE_COMMENTS_GOODCASE.py similarity index 96% rename from test/pytest/pytestfiles/test_10_CODE_COMMENTS_GOODCASE.py rename to test/pytest/pytestfiles/test_11_CODE_COMMENTS_GOODCASE.py index f6691e0a..54a6e275 100644 --- a/test/pytest/pytestfiles/test_10_CODE_COMMENTS_GOODCASE.py +++ b/test/pytest/pytestfiles/test_11_CODE_COMMENTS_GOODCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_10_CODE_COMMENTS_GOODCASE.py +# test_11_CODE_COMMENTS_GOODCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_11_COMMON_SYNTAX_VIOLATIONS_BADCASE.py b/test/pytest/pytestfiles/test_12_COMMON_SYNTAX_VIOLATIONS_BADCASE.py similarity index 97% rename from test/pytest/pytestfiles/test_11_COMMON_SYNTAX_VIOLATIONS_BADCASE.py rename to test/pytest/pytestfiles/test_12_COMMON_SYNTAX_VIOLATIONS_BADCASE.py index d9bbfa14..efd2e0d8 100644 --- a/test/pytest/pytestfiles/test_11_COMMON_SYNTAX_VIOLATIONS_BADCASE.py +++ b/test/pytest/pytestfiles/test_12_COMMON_SYNTAX_VIOLATIONS_BADCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_11_COMMON_SYNTAX_VIOLATIONS_BADCASE.py +# test_12_COMMON_SYNTAX_VIOLATIONS_BADCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_12_IMPLICIT_CREATION_GOODCASE.py b/test/pytest/pytestfiles/test_13_IMPLICIT_CREATION_GOODCASE.py similarity index 98% rename from test/pytest/pytestfiles/test_12_IMPLICIT_CREATION_GOODCASE.py rename to test/pytest/pytestfiles/test_13_IMPLICIT_CREATION_GOODCASE.py index 10cc388a..eeb952f4 100644 --- a/test/pytest/pytestfiles/test_12_IMPLICIT_CREATION_GOODCASE.py +++ b/test/pytest/pytestfiles/test_13_IMPLICIT_CREATION_GOODCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_12_IMPLICIT_CREATION_GOODCASE.py +# test_13_IMPLICIT_CREATION_GOODCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_13_IMPLICIT_CREATION_BADCASE.py b/test/pytest/pytestfiles/test_14_IMPLICIT_CREATION_BADCASE.py similarity index 98% rename from test/pytest/pytestfiles/test_13_IMPLICIT_CREATION_BADCASE.py rename to test/pytest/pytestfiles/test_14_IMPLICIT_CREATION_BADCASE.py index ebea1965..79f20f60 100644 --- a/test/pytest/pytestfiles/test_13_IMPLICIT_CREATION_BADCASE.py +++ b/test/pytest/pytestfiles/test_14_IMPLICIT_CREATION_BADCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_13_IMPLICIT_CREATION_BADCASE.py +# test_14_IMPLICIT_CREATION_BADCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_14_CYCLIC_IMPORTS_BADCASE.py b/test/pytest/pytestfiles/test_15_CYCLIC_IMPORTS_BADCASE.py similarity index 97% rename from test/pytest/pytestfiles/test_14_CYCLIC_IMPORTS_BADCASE.py rename to test/pytest/pytestfiles/test_15_CYCLIC_IMPORTS_BADCASE.py index 63ba8d9a..717a3fd4 100644 --- a/test/pytest/pytestfiles/test_14_CYCLIC_IMPORTS_BADCASE.py +++ b/test/pytest/pytestfiles/test_15_CYCLIC_IMPORTS_BADCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_14_CYCLIC_IMPORTS_BADCASE.py +# test_15_CYCLIC_IMPORTS_BADCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_15_PATH_FORMATS_GOODCASE.py b/test/pytest/pytestfiles/test_16_PATH_FORMATS_GOODCASE.py similarity index 96% rename from test/pytest/pytestfiles/test_15_PATH_FORMATS_GOODCASE.py rename to test/pytest/pytestfiles/test_16_PATH_FORMATS_GOODCASE.py index 7f72340e..560c2aeb 100644 --- a/test/pytest/pytestfiles/test_15_PATH_FORMATS_GOODCASE.py +++ b/test/pytest/pytestfiles/test_16_PATH_FORMATS_GOODCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_15_PATH_FORMATS_GOODCASE.py +# test_16_PATH_FORMATS_GOODCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_16_BLOCKED_SLICING_BADCASE.py b/test/pytest/pytestfiles/test_17_BLOCKED_SLICING_BADCASE.py similarity index 99% rename from test/pytest/pytestfiles/test_16_BLOCKED_SLICING_BADCASE.py rename to test/pytest/pytestfiles/test_17_BLOCKED_SLICING_BADCASE.py index 15ea20ac..435ae11b 100644 --- a/test/pytest/pytestfiles/test_16_BLOCKED_SLICING_BADCASE.py +++ b/test/pytest/pytestfiles/test_17_BLOCKED_SLICING_BADCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_16_BLOCKED_SLICING_BADCASE.py +# test_17_BLOCKED_SLICING_BADCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_17_NESTED_LISTS_GOODCASE.py b/test/pytest/pytestfiles/test_18_NESTED_LISTS_GOODCASE.py similarity index 96% rename from test/pytest/pytestfiles/test_17_NESTED_LISTS_GOODCASE.py rename to test/pytest/pytestfiles/test_18_NESTED_LISTS_GOODCASE.py index a57ee943..5d679bf3 100644 --- a/test/pytest/pytestfiles/test_17_NESTED_LISTS_GOODCASE.py +++ b/test/pytest/pytestfiles/test_18_NESTED_LISTS_GOODCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_17_NESTED_LISTS_GOODCASE.py +# test_18_NESTED_LISTS_GOODCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_18_STRING_INDICES_GOODCASE.py b/test/pytest/pytestfiles/test_19_STRING_INDICES_GOODCASE.py similarity index 97% rename from test/pytest/pytestfiles/test_18_STRING_INDICES_GOODCASE.py rename to test/pytest/pytestfiles/test_19_STRING_INDICES_GOODCASE.py index 337a3b86..b373d9ce 100644 --- a/test/pytest/pytestfiles/test_18_STRING_INDICES_GOODCASE.py +++ b/test/pytest/pytestfiles/test_19_STRING_INDICES_GOODCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_18_STRING_INDICES_GOODCASE.py +# test_19_STRING_INDICES_GOODCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_19_NOT_EXISTING_PARAMETERS_BADCASE.py b/test/pytest/pytestfiles/test_20_NOT_EXISTING_PARAMETERS_BADCASE.py similarity index 99% rename from test/pytest/pytestfiles/test_19_NOT_EXISTING_PARAMETERS_BADCASE.py rename to test/pytest/pytestfiles/test_20_NOT_EXISTING_PARAMETERS_BADCASE.py index eab1e72d..7f1192d2 100644 --- a/test/pytest/pytestfiles/test_19_NOT_EXISTING_PARAMETERS_BADCASE.py +++ b/test/pytest/pytestfiles/test_20_NOT_EXISTING_PARAMETERS_BADCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_19_NOT_EXISTING_PARAMETERS_BADCASE.py +# test_20_NOT_EXISTING_PARAMETERS_BADCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_20_LINE_BREAKS_GOODCASE.py b/test/pytest/pytestfiles/test_21_LINE_BREAKS_GOODCASE.py similarity index 96% rename from test/pytest/pytestfiles/test_20_LINE_BREAKS_GOODCASE.py rename to test/pytest/pytestfiles/test_21_LINE_BREAKS_GOODCASE.py index f70070e9..1dc80dcf 100644 --- a/test/pytest/pytestfiles/test_20_LINE_BREAKS_GOODCASE.py +++ b/test/pytest/pytestfiles/test_21_LINE_BREAKS_GOODCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_20_LINE_BREAKS_GOODCASE.py +# test_21_LINE_BREAKS_GOODCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_21_SELF_ASSIGNMENTS_GOODCASE.py b/test/pytest/pytestfiles/test_22_SELF_ASSIGNMENTS_GOODCASE.py similarity index 96% rename from test/pytest/pytestfiles/test_21_SELF_ASSIGNMENTS_GOODCASE.py rename to test/pytest/pytestfiles/test_22_SELF_ASSIGNMENTS_GOODCASE.py index 9e9d73d5..c3bb9d90 100644 --- a/test/pytest/pytestfiles/test_21_SELF_ASSIGNMENTS_GOODCASE.py +++ b/test/pytest/pytestfiles/test_22_SELF_ASSIGNMENTS_GOODCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_21_SELF_ASSIGNMENTS_GOODCASE.py +# test_22_SELF_ASSIGNMENTS_GOODCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_22_ASSIGNMENTS_BY_REFERENCE_GOODCASE.py b/test/pytest/pytestfiles/test_23_ASSIGNMENTS_BY_REFERENCE_GOODCASE.py similarity index 96% rename from test/pytest/pytestfiles/test_22_ASSIGNMENTS_BY_REFERENCE_GOODCASE.py rename to test/pytest/pytestfiles/test_23_ASSIGNMENTS_BY_REFERENCE_GOODCASE.py index 8f5509fa..471caf70 100644 --- a/test/pytest/pytestfiles/test_22_ASSIGNMENTS_BY_REFERENCE_GOODCASE.py +++ b/test/pytest/pytestfiles/test_23_ASSIGNMENTS_BY_REFERENCE_GOODCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_22_ASSIGNMENTS_BY_REFERENCE_GOODCASE.py +# test_23_ASSIGNMENTS_BY_REFERENCE_GOODCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_23_PARAMETER_SCOPE_GOODCASE.py b/test/pytest/pytestfiles/test_24_PARAMETER_SCOPE_GOODCASE.py similarity index 98% rename from test/pytest/pytestfiles/test_23_PARAMETER_SCOPE_GOODCASE.py rename to test/pytest/pytestfiles/test_24_PARAMETER_SCOPE_GOODCASE.py index 1ca0190e..06e8a5c6 100644 --- a/test/pytest/pytestfiles/test_23_PARAMETER_SCOPE_GOODCASE.py +++ b/test/pytest/pytestfiles/test_24_PARAMETER_SCOPE_GOODCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_23_PARAMETER_SCOPE_GOODCASE.py +# test_24_PARAMETER_SCOPE_GOODCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/pytest/pytestfiles/test_24_PARAMETER_SCOPE_BADCASE.py b/test/pytest/pytestfiles/test_25_PARAMETER_SCOPE_BADCASE.py similarity index 98% rename from test/pytest/pytestfiles/test_24_PARAMETER_SCOPE_BADCASE.py rename to test/pytest/pytestfiles/test_25_PARAMETER_SCOPE_BADCASE.py index d4f8b4c0..180e8d3a 100644 --- a/test/pytest/pytestfiles/test_24_PARAMETER_SCOPE_BADCASE.py +++ b/test/pytest/pytestfiles/test_25_PARAMETER_SCOPE_BADCASE.py @@ -14,11 +14,11 @@ # limitations under the License. # -------------------------------------------------------------------------------------------------------------- # -# test_24_PARAMETER_SCOPE_BADCASE.py +# test_25_PARAMETER_SCOPE_BADCASE.py # # XC-HWP/ESW3-Queckenstedt # -# 25.10.2024 - 20:31:28 +# 28.10.2024 - 20:15:13 # # -------------------------------------------------------------------------------------------------------------- diff --git a/test/testconfig/TestConfig.py b/test/testconfig/TestConfig.py index 59b655e2..c26fb548 100644 --- a/test/testconfig/TestConfig.py +++ b/test/testconfig/TestConfig.py @@ -22,7 +22,7 @@ # # -------------------------------------------------------------------------------------------------------------- # -# 25.10.2024 +# 28.10.2024 # # !!! Temporarily tests are deactivated by the following line commented out: # # # listofdictUsecases.append(dictUsecase) @@ -1707,6 +1707,260 @@ listofdictUsecases.append(dictUsecase) del dictUsecase # -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0401" +dictUsecase['DESCRIPTION'] = "JSON file with several parameter names containing: blank, backslash, 4Byte character" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "GOODCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0401.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = None +dictUsecase['EXPECTEDRETURN'] = """ +""" +# # # listofdictUsecases.append(dictUsecase) # several issues +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0450" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (1)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0450.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = """Invalid key name: "%A". Key names have to start with a letter, digit or underscore.""" +dictUsecase['EXPECTEDRETURN'] = None +listofdictUsecases.append(dictUsecase) +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0451" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (2)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0451.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = """Invalid key name: "%A". Key names have to start with a letter, digit or underscore.""" +dictUsecase['EXPECTEDRETURN'] = None +listofdictUsecases.append(dictUsecase) +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0452" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (3)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0452.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = """Invalid key name: "%A". Key names have to start with a letter, digit or underscore.""" +dictUsecase['EXPECTEDRETURN'] = None +listofdictUsecases.append(dictUsecase) +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0453" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (4)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0453.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = """Invalid key name: "par%am".""" # error message to be extended +dictUsecase['EXPECTEDRETURN'] = None +listofdictUsecases.append(dictUsecase) +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0454" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (5)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0454.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = """Invalid key name: "par%am".""" # error message to be extended +dictUsecase['EXPECTEDRETURN'] = None +listofdictUsecases.append(dictUsecase) +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0455" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (6)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0455.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = """Invalid key name: "par%am".""" # error message to be extended +dictUsecase['EXPECTEDRETURN'] = None +listofdictUsecases.append(dictUsecase) +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0456" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (7)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0456.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDRETURN'] = None +# # # listofdictUsecases.append(dictUsecase) # blanks inside name not allowed but currently accepted +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0457" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (8)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0457.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDRETURN'] = None +# # # listofdictUsecases.append(dictUsecase) # blanks inside name not allowed but currently accepted +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0458" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (9)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0458.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDRETURN'] = None +# # # listofdictUsecases.append(dictUsecase) # blanks inside name not allowed but currently accepted +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0459" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (10)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0459.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDRETURN'] = None +# # # listofdictUsecases.append(dictUsecase) # empty name not allowed but currently accepted +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0460" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (11)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0460.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDRETURN'] = None +# # # listofdictUsecases.append(dictUsecase) # empty name not allowed but currently accepted +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0461" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (12)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0461.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDRETURN'] = None +# # # listofdictUsecases.append(dictUsecase) # empty name not allowed but currently accepted +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0462" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (13)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0462.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDRETURN'] = None +# # # listofdictUsecases.append(dictUsecase) # name contains blanks only, waiting for final error message +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0463" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (14)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0463.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDRETURN'] = None +# # # listofdictUsecases.append(dictUsecase) # name contains blanks only, waiting for final error message +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0464" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (15)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0464.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDRETURN'] = None +# # # listofdictUsecases.append(dictUsecase) # name contains blanks only, waiting for final error message +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0465" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (16)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0465.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDRETURN'] = None +# # # listofdictUsecases.append(dictUsecase) # invalid name accepted and usage causes: 'local variable 'tmpList03' referenced before assignment'! +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- +dictUsecase = {} +dictUsecase['TESTID'] = "JPP_0466" +dictUsecase['DESCRIPTION'] = "JSON file with several invalid parameter names (17)" +dictUsecase['EXPECTATION'] = "All names are accepted (in definition and in reference)" +dictUsecase['SECTION'] = "NAMING_CONVENTION" +dictUsecase['SUBSECTION'] = "BADCASE" +dictUsecase['HINT'] = None +dictUsecase['COMMENT'] = None +dictUsecase['JSONFILE'] = r"..\testfiles\jpp-test_config_0466.jsonp" +dictUsecase['EXPECTEDEXCEPTION'] = None # TODO +dictUsecase['EXPECTEDRETURN'] = None +# # # listofdictUsecases.append(dictUsecase) # invalid name accepted and usage causes: 'local variable 'tmpList03' referenced before assignment'! +del dictUsecase +# -------------------------------------------------------------------------------------------------------------- diff --git a/test/testfiles/jpp-test_config_0401.jsonp b/test/testfiles/jpp-test_config_0401.jsonp new file mode 100644 index 00000000..bdd29d2d --- /dev/null +++ b/test/testfiles/jpp-test_config_0401.jsonp @@ -0,0 +1,54 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + // -- blank, backslash, 4Byte character + " param " : 1, + "p21" : ${param}, + // + "B" : {" param " : 1}, + "p22" : ${B}['param'], + // + "C" : [1, {" param " : 1}, 2], + "p23" : ${C}[1]['param'], + // + "par\\am" : 1, + "p24" : ${par\\am}, + // + "D" : {"par\\am" : 1}, + "p25" : ${D}['par\\am'], + // + "E" : [1, {"par\\am" : 1}, 2], + "p26" : ${E}[1]['par\\am'], + // + "path\\to\\file" : "C:\\Users\\Example\\file.txt" + // + "par𠼭am" : 1, + "p27" : ${par𠼭am}, + // + "F" : {"par𠼭am" : 1}, + "p28" : ${F}['par𠼭am'], + // + "G" : [1, {"par𠼭am" : 1}, 2], + "p29" : ${G}[1]['par𠼭am'], + // + "𠼭param" : 1, + "p30" : ${𠼭param}, + // + "H" : {"𠼭param" : 1}, + "p31" : ${H}['𠼭param'], + // + "K" : [1, {"𠼭param" : 1}, 2], + "p32" : ${K}[1]['𠼭param'], +} diff --git a/test/testfiles/jpp-test_config_0450.jsonp b/test/testfiles/jpp-test_config_0450.jsonp new file mode 100644 index 00000000..37d70f04 --- /dev/null +++ b/test/testfiles/jpp-test_config_0450.jsonp @@ -0,0 +1,18 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "%A" : 1, + "p01" : ${%A} +} diff --git a/test/testfiles/jpp-test_config_0451.jsonp b/test/testfiles/jpp-test_config_0451.jsonp new file mode 100644 index 00000000..85767bb5 --- /dev/null +++ b/test/testfiles/jpp-test_config_0451.jsonp @@ -0,0 +1,18 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "B" : {"%A" : 1}, + "p02" : ${B}['%A'] +} diff --git a/test/testfiles/jpp-test_config_0452.jsonp b/test/testfiles/jpp-test_config_0452.jsonp new file mode 100644 index 00000000..20d89afb --- /dev/null +++ b/test/testfiles/jpp-test_config_0452.jsonp @@ -0,0 +1,18 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "C" : [1, {"%A" : 1}, 2], + "p03" : ${C}[1]['%A'] +} diff --git a/test/testfiles/jpp-test_config_0453.jsonp b/test/testfiles/jpp-test_config_0453.jsonp new file mode 100644 index 00000000..241ee64b --- /dev/null +++ b/test/testfiles/jpp-test_config_0453.jsonp @@ -0,0 +1,18 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "par%am" : 1, + "p04" : ${par%am} +} diff --git a/test/testfiles/jpp-test_config_0454.jsonp b/test/testfiles/jpp-test_config_0454.jsonp new file mode 100644 index 00000000..10c0c39f --- /dev/null +++ b/test/testfiles/jpp-test_config_0454.jsonp @@ -0,0 +1,18 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "D" : {"par%am" : 1}, + "p05" : ${D}['par%am'] +} diff --git a/test/testfiles/jpp-test_config_0455.jsonp b/test/testfiles/jpp-test_config_0455.jsonp new file mode 100644 index 00000000..e7fa3774 --- /dev/null +++ b/test/testfiles/jpp-test_config_0455.jsonp @@ -0,0 +1,18 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "E" : [1, {"par%am" : 1}, 2], + "p06" : ${E}[1]['par%am'] +} diff --git a/test/testfiles/jpp-test_config_0456.jsonp b/test/testfiles/jpp-test_config_0456.jsonp new file mode 100644 index 00000000..153d2f9e --- /dev/null +++ b/test/testfiles/jpp-test_config_0456.jsonp @@ -0,0 +1,18 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "par am" : 1, + "p04" : ${par am} +} diff --git a/test/testfiles/jpp-test_config_0457.jsonp b/test/testfiles/jpp-test_config_0457.jsonp new file mode 100644 index 00000000..9b607b56 --- /dev/null +++ b/test/testfiles/jpp-test_config_0457.jsonp @@ -0,0 +1,18 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "F" : {"par am" : 1}, + "p05" : ${F}['par am'] +} diff --git a/test/testfiles/jpp-test_config_0458.jsonp b/test/testfiles/jpp-test_config_0458.jsonp new file mode 100644 index 00000000..74413ee6 --- /dev/null +++ b/test/testfiles/jpp-test_config_0458.jsonp @@ -0,0 +1,18 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "G" : [1, {"par am" : 1}, 2], + "p06" : ${G}[1]['par am'] +} diff --git a/test/testfiles/jpp-test_config_0459.jsonp b/test/testfiles/jpp-test_config_0459.jsonp new file mode 100644 index 00000000..d4b69c6e --- /dev/null +++ b/test/testfiles/jpp-test_config_0459.jsonp @@ -0,0 +1,17 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "" : 1 +} diff --git a/test/testfiles/jpp-test_config_0460.jsonp b/test/testfiles/jpp-test_config_0460.jsonp new file mode 100644 index 00000000..8196a871 --- /dev/null +++ b/test/testfiles/jpp-test_config_0460.jsonp @@ -0,0 +1,17 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "B" : {"" : 1} +} diff --git a/test/testfiles/jpp-test_config_0461.jsonp b/test/testfiles/jpp-test_config_0461.jsonp new file mode 100644 index 00000000..3aad0d87 --- /dev/null +++ b/test/testfiles/jpp-test_config_0461.jsonp @@ -0,0 +1,17 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "C" : [1, {"" : 1}, 2] +} diff --git a/test/testfiles/jpp-test_config_0462.jsonp b/test/testfiles/jpp-test_config_0462.jsonp new file mode 100644 index 00000000..1a9f2d68 --- /dev/null +++ b/test/testfiles/jpp-test_config_0462.jsonp @@ -0,0 +1,17 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + " " : 1 +} diff --git a/test/testfiles/jpp-test_config_0463.jsonp b/test/testfiles/jpp-test_config_0463.jsonp new file mode 100644 index 00000000..fc26b989 --- /dev/null +++ b/test/testfiles/jpp-test_config_0463.jsonp @@ -0,0 +1,17 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "B" : {" " : 1} +} diff --git a/test/testfiles/jpp-test_config_0464.jsonp b/test/testfiles/jpp-test_config_0464.jsonp new file mode 100644 index 00000000..155566fa --- /dev/null +++ b/test/testfiles/jpp-test_config_0464.jsonp @@ -0,0 +1,17 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "C" : [1, {" " : 1}, 2] +} diff --git a/test/testfiles/jpp-test_config_0465.jsonp b/test/testfiles/jpp-test_config_0465.jsonp new file mode 100644 index 00000000..36a1bc93 --- /dev/null +++ b/test/testfiles/jpp-test_config_0465.jsonp @@ -0,0 +1,18 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + "$A:" : 1, + "p01" : ${$A:} +} diff --git a/test/testfiles/jpp-test_config_0466.jsonp b/test/testfiles/jpp-test_config_0466.jsonp new file mode 100644 index 00000000..98292803 --- /dev/null +++ b/test/testfiles/jpp-test_config_0466.jsonp @@ -0,0 +1,18 @@ +// Copyright 2020-2024 Robert Bosch GmbH +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +//************************************************************************** +{ + ":::" : 1, + "p01" : ${:::} +} diff --git a/test/testtools/GenSnippetsJPP.py b/test/testtools/GenSnippetsJPP.py index 5cad1131..b52644df 100644 --- a/test/testtools/GenSnippetsJPP.py +++ b/test/testtools/GenSnippetsJPP.py @@ -22,8 +22,8 @@ # # ************************************************************************************************************** # -VERSION = "0.28.0" -VERSION_DATE = "18.04.2024" +VERSION = "0.30.0" +VERSION_DATE = "28.10.2024" # # ************************************************************************************************************** @@ -432,8 +432,15 @@ def __ExecuteJPPSnippets(self, sHeadline="UNKNOWN", listCodeSnippets=[]): oJPPJSONFILE.Write(f"// created at {NOW}") oJPPJSONFILE.Write(sCodeSnippet) del oJPPJSONFILE - # execute temporary JSON file - dictReturned, sException, bSuccess, sResult = self.__ExecuteJPPFile(JPPJSONFILE) + + # -------------------------------------------------------------------------------------------------------------- + # === (alternative 1) execute temporary JSON file + # dictReturned, sException, bSuccess, sResult = self.__ExecuteJPPFile(JPPJSONFILE) + # + # === (alternative 2) execute temporary JSON string + dictReturned, sException, bSuccess, sResult = self.__ExecuteJPPString(sCodeSnippet) + # -------------------------------------------------------------------------------------------------------------- + # PrettyPrint(bSuccess, sPrefix="(bSuccess)") # PrettyPrint(sResult, sPrefix="(sResult)") # PrettyPrint(dictReturned, sPrefix="(dictReturned)") @@ -509,6 +516,42 @@ def __ExecuteJPPFile(self, sJSONFile=None): # eof def __ExecuteJPPFile(self, sJSONFile=None): + def __ExecuteJPPString(self, sJSONString=None): + + sMethod = "__ExecuteJPPString" + + bSuccess = None + sResult = "UNKNOWN" + dictReturned = None + sException = None + + if sJSONString is None: + sResult = CString.FormatResult(sMethod, None, "sJSONString is None") + return dictReturned, sException, bSuccess, sResult + + # use either own or common JsonPreprocessor object + oJsonPreprocessor = None + if self.__oJsonPreprocessor is None: + oJsonPreprocessor = CJsonPreprocessor() + else: + oJsonPreprocessor = self.__oJsonPreprocessor + + # execute JsonPreprocessor + dictReturned = None + sException = None + try: + dictReturned = oJsonPreprocessor.jsonLoads(sJSONString) + except Exception as reason: + sException = f"'{reason}'" + + del oJsonPreprocessor + + bSuccess = True + sResult = "done" + return dictReturned, sException, bSuccess, sResult + + # eof def __ExecuteJPPString(self, sJSONFile=None): + # -------------------------------------------------------------------------------------------------------------- # eof class CExecutor(): @@ -2348,6 +2391,819 @@ def GetSeveralParticularSnippets(self): } """) +# -------------------------------------------------------------------------------------------------------------- +# 28.10.2024 +# code snippets taken from latest issues + + listCodeSnippets.append("""{ + "keyP" : "A", + "newparam" : ${keyP}[${keyP}] +} +""") + + listCodeSnippets.append("""{ + "dictP" : {"A" : 1, "B" : 2}, + "newparam" : ${dictP}['${dictP}'] +} +""") + + listCodeSnippets.append("""{ + "dictP1" : {"A" : 1 , "B" : 2}, + "dictP2" : {"1" : "C", "2" : "D"}, + "newparam" : ${dictP2}['${dictP1}['A']'] +} +""") + + listCodeSnippets.append("""{ + "newparam" : ${listP}['${listP}'] +} +""") + + listCodeSnippets.append("""{ + "indexP" : 0, + "newparam" : ${indexP}[${indexP}] +} +""") + + listCodeSnippets.append("""{ + "listparam" : ["A","B","C"], + ${{listparam}[0] : "value"} +} +""") + + listCodeSnippets.append("""{ + "listparam1" : ["A", "B"], + "listparam2" : [1, 2], + ${listparam1}[${listparam2}] : 3 +} +""") + + listCodeSnippets.append("""{ + "listparam1" : ["A", "B"], + "listparam2" : [1, 2], + "param" : ${listparam1}[${listparam2}] +} +""") + + listCodeSnippets.append("""{ + "params" : {"A" : []} +} +""") + + listCodeSnippets.append("""{ + "params" : {"A" : ["B", []]} +} +""") + + listCodeSnippets.append("""{ + "listparam" : ["A", "B"], + "newparam" : ${listparam}[20] +} +""") + + listCodeSnippets.append("""{ + "dictparam" : {"A" : 1, "B" : 2}, + "newparam" : ${dictparam}['AB'] +} +""") + +# -------------------------------------------------------------------------------------------------------------- + +# -- NAMING_CONVENTION + + # 0400 + listCodeSnippets.append("""{ + "A" : 1, + "check01" : ${A}, + // Bug: https://github.com/test-fullautomation/python-jsonpreprocessor/issues/357#issuecomment-2435677836 + // 'The parameter '${0}' is not available!'! + "0" : 2, + "check02" : ${0}, + "_" : 3, + "check03" : ${_}, + // + "Ax" : 4, + "check04" : ${Ax}, + "0x" : 5, + "check05" : ${0x}, + "_x" : 6, + "check06" : ${_x}, + // + "param+1" : 7, + "check07" : ${param+1}, + "param-2" : 8, + "check08" : ${param-2}, + "param*3" : 9, + "check09" : ${param*3}, + "param/4" : 10, + // bug: https://github.com/test-fullautomation/python-jsonpreprocessor/issues/356#issuecomment-2435708593 + // Expecting ',' delimiter + "check10" : ${param/4}, + // + "p01" : {"A" : 7}, + "check11" : ${p01}['A'], + "p02" : {"0" : 8}, + "check12" : ${p02}['0'], + "p03" : {"_" : 9}, + "check13" : ${p03}['_'], + // + "p04" : {"Ax" : 10}, + "check14" : ${p04}['Ax'], + "p05" : {"0x" : 11}, + "check15" : ${p05}['0x'], + "p06" : {"_x" : 12}, + "check16" : ${p06}['_x'], + // + "p07" : {"param+1" : 13}, + "check17" : ${p07}['param+1'], + "p08" : {"param-2" : 14}, + "check18" : ${p08}['param-2'], + "p09" : {"param*3" : 15}, + "check19" : ${p09}['param*3'], + "p10" : {"param/4" : 16}, + // Expecting ',' delimiter + "check20" : ${p10}['param/4'], + // + "p11" : [1, {"A" : 17}, 2], + "check21" : ${p11}[1]['A'], + "p12" : [1, {"0" : 18}, 2], + "check22" : ${p12}[1]['0'], + "p13" : [1, {"_" : 19}, 2], + "check23" : ${p13}[1]['_'], + // + "p14" : [1, {"Ax" : 20}, 2], + "check24" : ${p14}[1]['Ax'], + "p15" : [1, {"0x" : 21}, 2], + "check25" : ${p15}[1]['0x'], + "p16" : [1, {"_x" : 22}, 2], + "check26" : ${p16}[1]['_x'], + // + "p17" : [1, {"param+1" : 23}, 2], + "check27" : ${p17}[1]['param+1'], + "p18" : [1, {"param-2" : 24}, 2], + "check28" : ${p18}[1]['param-2'], + "p19" : [1, {"param*3" : 25}, 2], + "check29" : ${p19}[1]['param*3'], + "p20" : [1, {"param/4" : 26}, 2] + // Expecting ',' delimiter + "check30" : ${p20}[1]['param/4'] +} +""") + + # -- blank, backslash, chinese character + + listCodeSnippets.append("""{ + " param " : 1, + "p21" : ${param} +} +""") + + listCodeSnippets.append("""{ + "B" : {" param " : 1}, + "p22" : ${B}['param'] +} +""") + + listCodeSnippets.append("""{ + "C" : [1, {" param " : 1}, 2], + "p23" : ${C}[1]['param'] +} +""") + + listCodeSnippets.append("""{ + "par\\am" : 1, + "p24" : ${par\\am} +} +""") + + listCodeSnippets.append("""{ + "D" : {"par\\am" : 1}, + "p25" : ${D}['par\\am'] +} +""") + + listCodeSnippets.append("""{ + "E" : [1, {"par\\am" : 1}, 2], + "p26" : ${E}[1]['par\\am'] +} +""") + + listCodeSnippets.append("""{ + "path_to_file" : "C:\\Users\\Example\\file.txt" +} +""") + + listCodeSnippets.append("""{ + "path\\to\\file" : "root_path" +} +""") + + listCodeSnippets.append("""{ + "path\\to\\file" : "C:\\Users\\Example\\file.txt" +} +""") + + listCodeSnippets.append("""{ + "par𠼭am" : 1, + "p27" : ${par𠼭am} +} +""") + + listCodeSnippets.append("""{ + "F" : {"par𠼭am" : 1}, + "p28" : ${F}['par𠼭am'] +} +""") + + listCodeSnippets.append("""{ + "G" : [1, {"par𠼭am" : 1}, 2], + "p29" : ${G}[1]['par𠼭am'] +} +""") + + listCodeSnippets.append("""{ + "𠼭param" : 1, + "p30" : ${𠼭param} +} +""") + + listCodeSnippets.append("""{ + "H" : {"𠼭param" : 1}, + "p31" : ${H}['𠼭param'] +} +""") + + listCodeSnippets.append("""{ + "K" : [1, {"𠼭param" : 1}, 2], + "p32" : ${K}[1]['𠼭param'] +} +""") + + + listCodeSnippets.append("""{ + "%A" : 1, + "p01" : ${%A} +} +""") + + listCodeSnippets.append("""{ + "B" : {"%A" : 1}, + "p02" : ${B}['%A'] +} +""") + + listCodeSnippets.append("""{ + "C" : [1, {"%A" : 1}, 2], + "p03" : ${C}[1]['%A'] +} +""") + + listCodeSnippets.append("""{ + "par%am" : 1, + "p04" : ${par%am} +} +""") + + listCodeSnippets.append("""{ + "D" : {"par%am" : 1}, + "p05" : ${D}['par%am'] +} +""") + + listCodeSnippets.append("""{ + "E" : [1, {"par%am" : 1}, 2], + "p06" : ${E}[1]['par%am'] +} +""") + + listCodeSnippets.append("""{ + "par am" : 1, + "p04" : ${par am} +} +""") + + listCodeSnippets.append("""{ + "F" : {"par am" : 1}, + "p05" : ${F}['par am'] +} +""") + + listCodeSnippets.append("""{ + "G" : [1, {"par am" : 1}, 2], + "p06" : ${G}[1]['par am'] +} +""") + + listCodeSnippets.append("""{ + "" : 1 +} +""") + + listCodeSnippets.append("""{ + "B" : {"" : 1} +} +""") + + listCodeSnippets.append("""{ + "C" : [1, {"" : 1}, 2] +} +""") + + listCodeSnippets.append("""{ + " " : 1 +} +""") + + listCodeSnippets.append("""{ + "B" : {" " : 1} +} +""") + + listCodeSnippets.append("""{ + "C" : [1, {" " : 1}, 2] +} +""") + + listCodeSnippets.append("""{ + "$A:" : 1, + "p01" : ${$A:} +} +""") + + listCodeSnippets.append("""{ + ":::" : 1, + "p01" : ${:::} +} +""") + + + # listCodeSnippets.append("""{ +# } +# """) + +# -------------------------------------------------------------------------------------------------------------- + +# - parameter scope + + listCodeSnippets.append("""{ + "param" : 1, + "params" : {"001" : { + "param" : 2, + ${params}['001']['param'] : 3 + } + } +} +""") + + listCodeSnippets.append("""{ + "param" : 1, + "params" : {"001" : { + "param" : 2, + ${params.001.param} : 3 + } + } +} +""") + + listCodeSnippets.append("""{ + "param" : 1, + "params" : {"001" : { + "param" : 2 + } + }, + ${params}['001']['param'] : 3 +} +""") + + listCodeSnippets.append("""{ + "param" : 1, + "params" : {"001" : { + "param" : 2 + } + }, + ${params.001.param} : 3 +} +""") + + listCodeSnippets.append("""{ + // https://github.com/test-fullautomation/python-jsonpreprocessor/issues/349 + "C" : 1, + "params" : [ + 2, + {"A" : 3, + "B" : [ + { + "C" : 4, + ${params}[1]['B'][0]['C'] : 10, + "D" : 5 + }, + 6 + ] + }, + 7 + ] +} +""") + + listCodeSnippets.append("""{ + // https://github.com/test-fullautomation/python-jsonpreprocessor/issues/349 + // 'A key with name '${params.1.B.0.C}' does not exist at this position. Use the ' : ' syntax to create a new key.'! + + "C" : 1, + "params" : [ + 2, + {"A" : 3, + "B" : [ + { + "C" : 4, + ${params.1.B.0.C} : 10, + "D" : 5 + }, + 6 + ] + }, + 7 + ] +} +""") + + listCodeSnippets.append("""{ + // https://github.com/test-fullautomation/python-jsonpreprocessor/issues/349 + // {C} [INT] : 10 + + "C" : 1, + "params" : [ + 2, + {"A" : 3, + "B" : [ + { + "C" : 4, + "D" : 5 + }, + 6 + ] + }, + 7 + ], + ${params}[1]['B'][0]['C'] : 10 +} +""") + + listCodeSnippets.append("""{ + "C" : 1, + "params" : [ + 2, + {"A" : 3, + "B" : [ + { + "C" : 4, + "D" : 5 + }, + 6 + ] + }, + 7 + ], + ${params.1.B.0.C} : 10 +} +""") + + listCodeSnippets.append("""{ + ${param} : 1 +} +""") + + listCodeSnippets.append("""{ + "param" : 1, + "params" : {"001" : { + ${param} : 2 + } + } +} +""") + + listCodeSnippets.append("""{ + "param" : 1, + "params" : {"001" : { + "param" : 2, + ${param} : 3 + } + } +} +""") + + listCodeSnippets.append("""{ + "params" : {"001" : { + ${params}['001'] : 1 + } + } +} +""") + + listCodeSnippets.append("""{ + "params" : {"001" : { + ${params.001} : 1 + } + } +} +""") + + listCodeSnippets.append("""{ + // https://github.com/test-fullautomation/python-jsonpreprocessor/issues/349 + // invalid output + "C" : 1, + "params" : [ + 2, + {"A" : 3, + "B" : [ + { + "C" : 4, + ${C} : 10, + "D" : 5 + }, + 6 + ] + }, + 7 + ] +} +""") + + listCodeSnippets.append("""{ + "C" : 1, + "params" : [ + 2, + {"A" : 3, + "B" : [ + { + ${C} : 10, + "D" : 5 + }, + 6 + ] + }, + 7 + ] +} +""") + + listCodeSnippets.append("""{ + "C" : 1, + "params" : [ + 2, + {"A" : 3, + "B" : [ + { + ${params}[1]['B'][0]['C'] : 10, + "D" : 5 + }, + 6 + ] + }, + 7 + ] +} +""") + + listCodeSnippets.append("""{ + "C" : 1, + "params" : [ + 2, + {"A" : 3, + "B" : [ + { + ${params.1.B.0.C} : 10, + "D" : 5 + }, + 6 + ] + }, + 7 + ] +} +""") + +# -------------------------------------------------------------------------------------------------------------- + +# -- BLOCKED_DATA_TYPES + + listCodeSnippets.append("""{ + "testlist" : [1,2,3], + "param" : "${testlist}" +} +""") + + listCodeSnippets.append("""{ + "testlist" : [1,2,3], + "param" : "A_${testlist}_B" +} +""") + + listCodeSnippets.append("""{ + "testdict" : {"A" : 1, "B" : 2}, + "param" : "${testdict}" +} +""") + + listCodeSnippets.append("""{ + "testdict" : {"A" : 1, "B" : 2}, + "param" : "A_${testdict}_B" +} +""") + + listCodeSnippets.append("""{ + "testlist" : [1,2,3], + "testdict" : {"A" : 1, "B" : 2}, + "param" : "A_${testlist}_${testdict}_B" +} +""") + + listCodeSnippets.append("""{ + "testdict" : {"A" : 1, "B" : 2}, + "param" : [1,"${testdict}",3] +} +""") + + listCodeSnippets.append("""{ + "testlist" : [1,2,3], + "param" : {"A" : 1, "B" : "${testlist}"} +} +""") + + listCodeSnippets.append("""{ + "testlist" : [1,2,3], + "param" : {"A" : [{"A" : 1, "B" : 2}, {"C" : 3, "D" : [1,2,"${testlist}",3]}], "E" : 5} +} +""") + + listCodeSnippets.append("""{ + "testdict" : {"A" : 1, "B" : 2}, + "param" : {"A" : [{"A" : 1, "B" : 2}, {"C" : 3, "D" : [1,2,"${testdict}",3]}], "E" : 5} +} +""") + + # -- blocked dynamic key names + + listCodeSnippets.append("""{ + "param1" : "A", + "${param1}" : "B" +} +""") + + listCodeSnippets.append("""{ + "param1" : "A", + "A.${param1}.B" : "B" +} +""") + + listCodeSnippets.append("""{ + "testlist" : [1,2,3], + "${testlist}" : "B" +} +""") + + listCodeSnippets.append("""{ + "testdict" : {"A" : 1, "B" : 2}, + "A.${testdict}.B" : "B" +} +""") + + listCodeSnippets.append("""{ + "param1" : "A", + "param1" : {"A" : 1, "${param1}" : 2} +} +""") + + listCodeSnippets.append("""{ + "param1" : "A", + "param1" : {"A" : 1, "A.${param1}.B" : 2} +} +""") + + listCodeSnippets.append("""{ + "testlist" : [1,2,3], + "param1" : {"A" : 1, "${testlist}" : 2} +} +""") + + listCodeSnippets.append("""{ + "testdict" : {"A" : 1, "B" : 2}, + "param1" : {"A" : 1, "A.${testdict}.B" : 2} +} +""") + + listCodeSnippets.append("""{ + "param" : "X", + "testdict" : {"A" : 1, "B" : 2}, + ${testdict}['${param}'] : 3 +} +""") + + listCodeSnippets.append("""{ + "testdict" : {"A" : 1, "B" : 2, "X" : 3}, + "param" : "X", + ${testdict}['${param}'] : 4 +} +""") + + listCodeSnippets.append("""{ + "param" : "X", + "testdict" : {"A" : 1, "B" : 2}, + ${testdict}[${param}] : 3 +} +""") + + listCodeSnippets.append("""{ + "testdict" : {"A" : 1, "B" : 2, "X" : 3}, + "param" : "X", + ${testdict}[${param}] : 4 +} +""") + + listCodeSnippets.append("""{ + "param" : "X", + "testdict" : {"A" : 1, "B" : 2}, + ${testdict.${param}} : 3 +} +""") + + listCodeSnippets.append("""{ + "testdict" : {"A" : 1, "B" : 2, "X" : 3}, + "param" : "X", + ${testdict.${param}} : 4 +} +""") + +# -------------------------------------------------------------------------------------------------------------- + + listCodeSnippets.append("""{ + // implicit creation in ascending dotdict syntax: + ${testdict1.subKey1} : {"subKey2" : {"subKey3" : {"subKey4" : 1}}}, + ${testdict1.subKey1.subKey2} : {"subKey3" : {"subKey4" : 2}}, + ${testdict1.subKey1.subKey2.subKey3} : {"subKey4" : 3}, + ${testdict1.subKey1.subKey2.subKey3.subKey4} : 4, + // + // implicit creation in descending dotdict syntax: + ${testdict2.subKey1.subKey2.subKey3.subKey4} : 5, + ${testdict2.subKey1.subKey2.subKey3} : {"subKey4" : 6}, + ${testdict2.subKey1.subKey2} : {"subKey3" : {"subKey4" : 7}}, + ${testdict2.subKey1} : {"subKey2" : {"subKey3" : {"subKey4" : 8}}}, + // + // cross check: + "testdict3" : {"subKey1" : {"subKey2" : {"subKey3" : {"subKey4" : 30}}}}, + "testdict4" : {"subKey1" : {"subKey2" : {"subKey3" : {"subKey4" : 40}}}} +} +""") + +# -------------------------------------------------------------------------------------------------------------- + + # -- some special cases + + listCodeSnippets.append("""{ + "params" : {"001" : {"param" : 1}}, + ${params.001.param} : 2 +} +""") + + listCodeSnippets.append("""{ + ${params}['001']['param1'] : 1, + ${params.1.param2} : 2, + ${params.a001.param3} : 3 +} +""") + + listCodeSnippets.append("""{ + ${params.001.param} : 2 +} +""") + + listCodeSnippets.append("""{ + "param1" : "A", + "testdict" : {"A" : 1, "B" : 2}, + ${testdict}["${param1}"] : 3 +} +""") + + + listCodeSnippets.append("""{ + "A" : [1, 2], + "A" : [3, 4] +} +""") + + listCodeSnippets.append("""{ + "B" : {"param1" : 1}, + "B" : {"param2" : 1} +} +""") + + listCodeSnippets.append("""{ + // within key names slicing doesn't make sense + "A" : {"$B:" : 1}, + "p02" : ${A}['$B:'] +} +""") + # listCodeSnippets.append("""{ # } @@ -3074,8 +3930,8 @@ def GetNamingConventions(self): sDataStructure1 = """ "param*01*1" : "value", "param2" : "val*02*ue", - "${param2}" : 1, - "dictParam" : {"key*03*A" : 2, "keyB" : {"key*04*C" : 3}}""" + "dictParam" : {"key*03*A" : 2, "keyB" : {"key*04*C" : 3}}, + "listParam" : [1, {"key*05*D" : 4, "keyE" : {"key*06*F" : 5}}, 2]""" sCodeSnippetPattern = """{ ####DATASTRUCTURE#### @@ -3087,9 +3943,9 @@ def GetNamingConventions(self): # expression and placeholder per iteration. All remaining placeholders in current iteration are replaced by elements # from a list of filler expressions (simple letters) that are only used to complete the code snippet, but are not in focus. - listExpressions = ["-", "+", "*", "|", "/", "$", "%", "#", "\\", "\\\\"] + listExpressions = ["+", "-", "*", "/" , "|", "$", "%", "#", "\\", "\\\\", "𠼭", "€", "ß", "{", "}", "[", "]", "'"] - listPlaceholders = ["*01*", "*02*", "*03*", "*04*"] + listPlaceholders = ["*01*", "*02*", "*03*", "*04*", "*05*", "*06*"] listPositions = listPlaceholders[:] # to support a nested iteration of the same list; better readibility of code because of different names From d9b5acf6f34f957168be86906b768eaea25a6cdd Mon Sep 17 00:00:00 2001 From: qth2hi Date: Tue, 29 Oct 2024 18:26:40 +0100 Subject: [PATCH 02/21] Code snippet generator: "blocked substitutions" snippets automated --- test/testtools/GenSnippetsJPP.py | 116 ++++++++++++++++++------------- 1 file changed, 68 insertions(+), 48 deletions(-) diff --git a/test/testtools/GenSnippetsJPP.py b/test/testtools/GenSnippetsJPP.py index b52644df..813defaf 100644 --- a/test/testtools/GenSnippetsJPP.py +++ b/test/testtools/GenSnippetsJPP.py @@ -22,8 +22,8 @@ # # ************************************************************************************************************** # -VERSION = "0.30.0" -VERSION_DATE = "28.10.2024" +VERSION = "0.31.0" +VERSION_DATE = "29.10.2024" # # ************************************************************************************************************** @@ -1802,7 +1802,7 @@ def GetSeveralParticularSnippets(self): "param01" : ${stringParam}[${index}], "param02" : "${stringParam}[${index}]", // - "param03" : ${indexList}[${indexList}[${index}]], // returns STR instead of INT + "param03" : ${indexList}[${indexList}[${index}]], "param04" : "${indexList}[${indexList}[${index}]]", // "param05" : ${stringParam}[${indexList}[${indexList}[${index}]]], @@ -2462,9 +2462,16 @@ def GetSeveralParticularSnippets(self): """) listCodeSnippets.append("""{ - "dictparam" : {"A" : 1, "B" : 2}, + "dictparam" : {"A" : 1, "B" : 2}, "newparam" : ${dictparam}['AB'] } +""") + + listCodeSnippets.append("""{ + "strParam" : "ABC", + "param1" : [1, {"001" : "${strParam}"}, 2], + "param2" : ${param1}[1]['001'] +} """) # -------------------------------------------------------------------------------------------------------------- @@ -3204,6 +3211,12 @@ def GetSeveralParticularSnippets(self): } """) + listCodeSnippets.append("""{ + "index" : 1, + "listvalues" : [1, 2, 3], + "param" : ${listvalues}[+${index}] +} +""") # listCodeSnippets.append("""{ # } @@ -3981,62 +3994,69 @@ def GetNamingConventions(self): # -------------------------------------------------------------------------------------------------------------- def GetBlockedSubstitutions(self): - """Several snippets containing blocked dollar operator substitutions + """Several snippets containing blocked dollar operator substitutions (because of data type or dynamic key names)" """ - sHeadline = "Several snippets containing blocked dollar operator substitutions" + sHeadline = "Several snippets containing blocked dollar operator substitutions (because of data type or dynamic key names)" - listCodeSnippets = [] + # data structure 1 + sDataStructure1 = """ "*01*" : "*02*", + "param1" : {"*03*" : 5, "009" : "M_*04*_N", "011" : "OP"}, + "param2" : ["Q_*05*_R", {"*06*" : 6, "010" : "*07*_*07*", "012" : "ST"}, "*08*_*08*"], + "param3" : ${param1}['*09*'], + "param4" : ${param2}[1]['*10*'], + "param5" : ${param1.*11*}, + "param6" : ${param2.1.*12*}""" + + sDefinitions = """ "strParam" : "ABC", + "intParam" : 11, + "floatParam" : 22.22, + "dictParam" : {"A" : 3, "B" : 4}, + "listParam" : ["C", "D"], +""" - listCodeSnippets.append("""{ - "dictParam" : {"A" : 0, "B" : 1}, - "param" : "${dictParam}" + sCodeSnippetPattern = """{ +####DEFINITIONS#### +####DATASTRUCTURE#### } -""") +""" - listCodeSnippets.append("""{ - "listParam" : ["A", "B"], - "param" : "${listParam}" -} -""") + # We have a list of expressions and we have a list of placeholders like used in sDataStructure1. + # The followig code runs in a nested loop: Every expression is placed at every placeholder position. Only one single + # expression and placeholder per iteration. All remaining placeholders in current iteration are replaced by elements + # from a list of filler expressions (simple letters) that are only used to complete the code snippet, but are not in focus. - listCodeSnippets.append("""{ - "floatParam" : 1.2, - "param" : "${floatParam}" -} -""") + listExpressions = ["${strParam}", "${intParam}" , "${floatParam}" , "${dictParam}" , "${listParam}"] - listCodeSnippets.append("""{ - "dictParam" : {"A" : 0, "B" : 1}, - "${dictParam}" : 1 -} -""") + listPlaceholders = ["*01*", "*02*", "*03*", "*04*", "*05*", "*06*", "*07*", "*08*", "*09*", "*10*", "*11*", "*12*"] - listCodeSnippets.append("""{ - "listParam" : ["A", "B"], - "${listParam}" : 1 -} -""") + listPositions = listPlaceholders[:] # to support a nested iteration of the same list; better readibility of code because of different names - listCodeSnippets.append("""{ - "floatParam" : 1.2, - "${floatParam}" : 1 -} -""") + listFiller = ["001","002","003","004","005","006","007","008","009","010","011","012"] # as much elements as in listPlaceholders - listCodeSnippets.append("""{ - "keyA" : "keyA", - "dictParam" : {"${keyA}" : 1} -} -""") + # put all things together - listCodeSnippets.append("""{ - "keyA" : "keyA", - "keyB" : "keyB", - "dictParam" : {"keyA" : {}}, - ${dictParam.keyA}['${keyB}_2'] : 2 -} -""") + listCodeSnippets = [] + + # sDataStructure1 + + for sExpression in listExpressions: + for sPosition in listPositions: + sDataStructure = sDataStructure1 # init a new data structure from pattern sDataStructure1 + sCodeSnippet = sCodeSnippetPattern # init a new code snippet from code snippet pattern + oFiller = CListElements(listFiller) # init a new filler object (= content for remaining placeholders) + for sPlaceholder in listPlaceholders: + sFiller = oFiller.GetElement() + if sPosition == sPlaceholder: + sDataStructure = sDataStructure.replace(sPlaceholder, sExpression) + else: + sDataStructure = sDataStructure.replace(sPlaceholder, f"{sFiller}") + # eof for sPlaceholder in listPlaceholders: + sCodeSnippet = sCodeSnippet.replace("####DEFINITIONS####", sDefinitions) + sCodeSnippet = sCodeSnippet.replace("####DATASTRUCTURE####", sDataStructure) + listCodeSnippets.append(sCodeSnippet) + # eof for sPosition in listPositions: + # eof for sExpression in listExpressions: return sHeadline, listCodeSnippets From a086d5af100c2591d8cec41e34573870dabb0121 Mon Sep 17 00:00:00 2001 From: mas2hc Date: Wed, 30 Oct 2024 18:39:46 +0700 Subject: [PATCH 03/21] Enhancement - Implemented dynamic path of imported file --- JsonPreprocessor/CJsonPreprocessor.py | 173 +++++++++++++++++--------- 1 file changed, 111 insertions(+), 62 deletions(-) diff --git a/JsonPreprocessor/CJsonPreprocessor.py b/JsonPreprocessor/CJsonPreprocessor.py index 12149d1c..402298dc 100644 --- a/JsonPreprocessor/CJsonPreprocessor.py +++ b/JsonPreprocessor/CJsonPreprocessor.py @@ -190,6 +190,7 @@ def __init__(self, syntax: CSyntaxType = CSyntaxType.python , currentCfg : dict self.jsonPath = None self.masterFile = None self.handlingFile = [] + self.bDynamicImport = False self.lImportedFiles = [] self.recursive_level = 0 self.syntax = syntax @@ -232,6 +233,7 @@ def __reset(self) -> None: self.jsonPath = None self.masterFile = None self.handlingFile = [] + self.bDynamicImport = False self.lImportedFiles = [] self.recursive_level = 0 self.dUpdatedParams = {} @@ -267,29 +269,34 @@ def __processImportFiles(self, input_data : dict) -> dict: sCheckElement = CNameMangling.DUPLICATEDKEY_01.value for key, value in input_data: if re.match('^\s*\[\s*import\s*\]\s*', key.lower()): - currJsonPath = self.jsonPath - abs_path_file = CString.NormalizePath(value, sReferencePathAbs = currJsonPath) - - # Use recursive_level and lImportedFiles to avoid cyclic import - self.recursive_level = self.recursive_level + 1 # increase recursive level - - # length of lImportedFiles should equal to recursive_level - self.lImportedFiles = self.lImportedFiles[:self.recursive_level] if self.masterFile is not None else \ - self.lImportedFiles[:self.recursive_level-1] - if abs_path_file in self.lImportedFiles: - raise Exception(f"Cyclic imported json file '{abs_path_file}'!") - - oJsonImport = self.jsonLoad(abs_path_file) - self.jsonPath = currJsonPath - tmpOutdict = copy.deepcopy(out_dict) - for k1, v1 in tmpOutdict.items(): - for k2, v2 in oJsonImport.items(): - if k2 == k1: - del out_dict[k1] - del tmpOutdict - out_dict.update(oJsonImport) - - self.recursive_level = self.recursive_level - 1 # descrease recursive level + if '${' in value: + self.bDynamicImport = True + value = CString.NormalizePath(value, sReferencePathAbs = self.jsonPath) + out_dict[key] = value + else: + currJsonPath = self.jsonPath + abs_path_file = CString.NormalizePath(value, sReferencePathAbs = currJsonPath) + + # Use recursive_level and lImportedFiles to avoid cyclic import + self.recursive_level = self.recursive_level + 1 # increase recursive level + + # length of lImportedFiles should equal to recursive_level + self.lImportedFiles = self.lImportedFiles[:self.recursive_level] if self.masterFile is not None else \ + self.lImportedFiles[:self.recursive_level-1] + if abs_path_file in self.lImportedFiles: + raise Exception(f"Cyclic imported json file '{abs_path_file}'!") + + oJsonImport = self.jsonLoad(abs_path_file) + self.jsonPath = currJsonPath + tmpOutdict = copy.deepcopy(out_dict) + for k1, v1 in tmpOutdict.items(): + for k2, v2 in oJsonImport.items(): + if k2 == k1: + del out_dict[k1] + del tmpOutdict + out_dict.update(oJsonImport) + + self.recursive_level = self.recursive_level - 1 # descrease recursive level else: if self.bDuplicatedKeys: specialCharacters = r'$[]{}' @@ -535,22 +542,27 @@ def __getNestedValue(sNestedParam : str): exec(sExec, locals(), ldict) tmpValue = ldict['value'] except Exception as error: - self.__reset() - sNestedParam = self.__removeTokenStr(sNestedParam) - errorMsg = '' - for errorType in self.pythonTypeError: - if errorType in str(error): - errorMsg = f"Could not resolve expression '{sNestedParam.replace('$$', '$')}'." - if errorMsg != '': - errorMsg = errorMsg + f" Reason: {error}" if ' or slices' not in str(error) else \ - errorMsg + f" Reason: {str(error).replace(' or slices', '')}" + if self.bDynamicImport: + sNestedParam = self.__removeTokenStr(sNestedParam) + tmpValue = sNestedParam.replace('$$', '$') + pass else: - if isinstance(error, KeyError) and re.search(r"\[\s*" + str(error) + "\s*\]", sNestedParam): - errorMsg = f"Could not resolve expression '{sNestedParam.replace('$$', '$')}'. \ -Reason: Key error {error}" + self.__reset() + sNestedParam = self.__removeTokenStr(sNestedParam) + errorMsg = '' + for errorType in self.pythonTypeError: + if errorType in str(error): + errorMsg = f"Could not resolve expression '{sNestedParam.replace('$$', '$')}'." + if errorMsg != '': + errorMsg = errorMsg + f" Reason: {error}" if ' or slices' not in str(error) else \ + errorMsg + f" Reason: {str(error).replace(' or slices', '')}" else: - errorMsg = f"The parameter '{sNestedParam.replace('$$', '$')}' is not available!" - raise Exception(errorMsg) + if isinstance(error, KeyError) and re.search(r"\[\s*" + str(error) + "\s*\]", sNestedParam): + errorMsg = f"Could not resolve expression '{sNestedParam.replace('$$', '$')}'. \ +Reason: Key error {error}" + else: + errorMsg = f"The parameter '{sNestedParam.replace('$$', '$')}' is not available!" + raise Exception(errorMsg) return tmpValue specialCharacters = r'[]{}' @@ -656,16 +668,21 @@ def __getNestedValue(sNestedParam : str): exec(sExec, locals(), ldict) tmpValue = ldict['value'] except Exception as error: - self.__reset() - errorMsg = '' - for errorType in self.pythonTypeError: - if errorType in str(error): - errorMsg = f"Could not resolve expression '{sNestedParam.replace('$$', '$')}'." - if errorMsg != '': - errorMsg = errorMsg + f" Reason: {error}" + if self.bDynamicImport: + sNestedParam = self.__removeTokenStr(sNestedParam) + tmpValue = sNestedParam.replace('$$', '$') + pass else: - errorMsg = f"The parameter '{sNestedParam.replace('$$', '$')}' is not available!" - raise Exception(errorMsg) + self.__reset() + errorMsg = '' + for errorType in self.pythonTypeError: + if errorType in str(error): + errorMsg = f"Could not resolve expression '{sNestedParam.replace('$$', '$')}'." + if errorMsg != '': + errorMsg = errorMsg + f" Reason: {error}" + else: + errorMsg = f"The parameter '{sNestedParam.replace('$$', '$')}' is not available!" + raise Exception(errorMsg) return tmpValue else: rootVar = re.search(pattern, var[0], re.UNICODE)[0] @@ -1148,7 +1165,7 @@ def __handleList(lInput : list, bNested : bool) -> list: initValue = v while isinstance(v, str) and "${" in v: sLoopCheck = v - if v.count('${')==1 and CNameMangling.STRINGCONVERT.value not in v: # re.match(pattern, v) + if v.count('${')==1 and CNameMangling.STRINGCONVERT.value not in v: if '.' in v: paramInValue = self.__handleDotInNestedParam(v) paramInValue = self.__multipleReplace(paramInValue, {'${':'', '}':''}) @@ -1428,6 +1445,51 @@ def __removeTokenStr(self, sInput : str) -> str: sInput = sInput.replace(tokenStr.value, '') return sInput + def __preCheckJsonFile(self, sInput, CJSONDecoder): + ''' +Checks and handle dynamic path of imported file. +**Arguments:** + +* ``sInput`` + + / *Condition*: required / *Type*: str / + +* ``CJSONDecoder`` + + / *Condition*: required / *Type*: str / + +**Returns:** + +* ``sInput`` + + / *Type*: str / + ''' + try: + self.jsonCheck = json.loads(sInput, cls=CJSONDecoder, object_pairs_hook=self.__processImportFiles) + except Exception as error: + failedJsonDoc = self.__getFailedJsonDoc(error) + jsonException = "not defined" + if failedJsonDoc is None: + jsonException = f"{error}\nIn file: '{self.handlingFile.pop(-1)}'" if len(self.handlingFile)>0 else f"{error}" + else: + jsonException = f"{error}\nNearby: '{failedJsonDoc}'\nIn file: '{self.handlingFile.pop(-1)}'" if len(self.handlingFile)>0 else \ + f"{error}\nNearby: '{failedJsonDoc}'" + self.__reset() + raise Exception(jsonException) + sJson = '' + while re.search(r"'\s*\[\s*import\s*\]\s*'", str(self.jsonCheck)): + self.__checkDotInParamName(self.jsonCheck) + oJson, bNested = self.__updateAndReplaceNestedParam(self.jsonCheck) + sJson = json.dumps(oJson) + checkDynamicImport = re.search(r'("\s*\[\s*import\s*\]\s*"\s*:\s*"[^"]+")', sJson) + if checkDynamicImport is None or '${' in checkDynamicImport[0]: + raise Exception('TBD') + else: + sJson = re.sub(r'"\s*\[\s*import\s*\]\s*":\s*"[${]+[^"]+"', checkDynamicImport[0], sJson) + self.__preCheckJsonFile(sJson, CJSONDecoder) + self.bDynamicImport = False + return sJson if sJson!='' else sInput + def jsonLoad(self, jFile : str): """ This method is the entry point of JsonPreprocessor. @@ -1518,7 +1580,7 @@ def __handleDuplicatedKey(dInput : dict, parentParams : str = '') -> dict: self.__reset() formatOverwritten1 = re.sub(r'^\[([^\[]+)\]', '${\\1}', parentParams) formatOverwritten1 = formatOverwritten1 + f"['{origK}']" - formatOverwritten2 = self.__multipleReplace(parentParams, {"]['" : ".", "']['" : ".", "[" : "", "']" : ""}) + formatOverwritten2 = self.__multipleReplace(parentParams, {"]['":".", "']['":".", "[":"", "']":"", "]":""}) formatOverwritten2 = "${" + formatOverwritten2 + f".{origK}}}" raise Exception(f"Missing scope for parameter '${{{origK}}}'. To change the value of this parameter, \ an absolute path must be used: '{formatOverwritten1}' or '{formatOverwritten2}'.") @@ -1734,20 +1796,7 @@ def __handleLastElement(sInput : str) -> str: # verifying duplicated keys later. if firstLevel: self.bDuplicatedKeys = False - try: - self.jsonCheck = json.loads(sJsonDataUpdated, - cls=CJSONDecoder, - object_pairs_hook=self.__processImportFiles) - except Exception as error: - failedJsonDoc = self.__getFailedJsonDoc(error) - jsonException = "not defined" - if failedJsonDoc is None: - jsonException = f"{error}\nIn file: '{self.handlingFile.pop(-1)}'" if len(self.handlingFile)>0 else f"{error}" - else: - jsonException = f"{error}\nNearby: '{failedJsonDoc}'\nIn file: '{self.handlingFile.pop(-1)}'" if len(self.handlingFile)>0 else \ - f"{error}\nNearby: '{failedJsonDoc}'" - self.__reset() - raise Exception(jsonException) + sJsonDataUpdated = self.__preCheckJsonFile(sJsonDataUpdated, CJSONDecoder) self.bDuplicatedKeys = True # Load Json object with checking duplicated keys feature is enabled. From 8f90062a58c9e38ef5f04d5d931fdc4158a90ddf Mon Sep 17 00:00:00 2001 From: mas2hc Date: Wed, 30 Oct 2024 18:56:48 +0700 Subject: [PATCH 04/21] Update history and version for 0.8.2 --- JsonPreprocessor/JsonPreprocessor.pdf | Bin 418593 -> 418812 bytes JsonPreprocessor/version.py | 4 ++-- .../release_items_JsonPreprocessor.json | 11 +++++++++++ packagedoc/additional_docs/History.tex | 3 +++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/JsonPreprocessor/JsonPreprocessor.pdf b/JsonPreprocessor/JsonPreprocessor.pdf index 0495713bf19235966f507d9dccd1ed842eb375d7..b6c2e7a22fcaea89a0d24fe5b34e491e79c28aa5 100644 GIT binary patch delta 49720 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 l84T%xeE;IANJ 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