Salome HOME
[EDF27816] : fix all non regression tests
[modules/yacs.git] / src / py2yacs / Test / Py2yacsTest.cxx
1 // Copyright (C) 2006-2022  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 #include <Python.h>
20 #include <fstream>
21 #include <string>
22 #include <sstream>
23
24 #include "Py2yacsTest.hxx"
25 #include "py2yacs.hxx"
26 #include "Proc.hxx"
27 #include "Executor.hxx"
28 #include "PythonCppUtils.hxx"
29
30 #include "RuntimeSALOME.hxx"
31 #include "PythonPorts.hxx"
32 #include "InputPort.hxx"
33 //#include "parsers.hxx"
34
35 void Py2yacsTest::setUp()
36 {
37   YACS::ENGINE::RuntimeSALOME::setRuntime();
38   //YACS::ENGINE::getRuntime()->init();
39 }
40
41 void Py2yacsTest::tearDown()
42 {
43   //YACS::ENGINE::getRuntime()->fini();
44 }
45
46 static
47 void verifyCorrectPycode(const char * code_py, const char * function_name,
48                          int nbInputPorts, const char** input_ports,
49                          int nbOutputPorts, const char** output_ports)
50 {
51   std::cerr << std::endl;
52   std::cerr << "-----------------------------------------------" << std::endl;
53   std::cerr << code_py << std::endl;
54   std::cerr << "-----------------------------------------------" << std::endl;
55   std::cerr << "Function :" << function_name << std::endl;
56   Py2yacs parser;
57   try
58   {
59     parser.load(code_py);
60   }
61   catch(Py2yacsException& e)
62   {
63     CPPUNIT_FAIL(e.what());
64   }
65   catch(std::exception& e)
66   {
67     CPPUNIT_FAIL(e.what());
68   }
69   catch(...)
70   {
71     CPPUNIT_FAIL("Unknown exception");
72   }
73   YACS::ENGINE::Proc* p = parser.createProc(function_name);
74   CPPUNIT_ASSERT( p != NULL);
75   YACS::ENGINE::Node* n = p->getChildByShortName("default_name");
76   CPPUNIT_ASSERT( n != NULL);
77   CPPUNIT_ASSERT( n->getNumberOfInputPorts() == nbInputPorts);
78   for(int i = 0; i < nbInputPorts; i++)
79     CPPUNIT_ASSERT( n->getInputPort(input_ports[i]) != NULL);
80   CPPUNIT_ASSERT( n->getNumberOfOutputPorts() == nbOutputPorts);
81   for(int i = 0; i < nbOutputPorts; i++)
82     CPPUNIT_ASSERT( n->getOutputPort(output_ports[i]) != NULL);
83   delete p;
84 }
85
86 static
87 void verifyWrongPycode(const char* code_py, const char* function_name,
88                        const char* error_message)
89 {
90   Py2yacs parser;
91   try
92   {
93     parser.load(code_py);
94     YACS::ENGINE::Proc* p = parser.createProc(function_name);
95     CPPUNIT_FAIL("Exception expected and no exception occured.");
96   }
97   catch(Py2yacsException& e)
98   {
99     std::string what = e.what();
100     std::cerr << std::endl;
101     std::cerr << "-----------------------------------------------" << std::endl;
102     std::cerr << code_py << std::endl;
103     std::cerr << "-----------------------------------------------" << std::endl;
104     std::cerr << "Function :" << function_name << std::endl;
105     std::cerr << "==========EXCEPTION TEXT=======================" << std::endl;
106     std::cerr << what << std::endl;
107     std::cerr << "===============================================" << std::endl;
108     CPPUNIT_ASSERT(what.find(error_message) != std::string::npos);
109   }
110   catch(std::exception& e)
111   {
112     CPPUNIT_FAIL(e.what());
113   }
114 }
115
116 static
117 void verifyWrongParser(const char* parser_module, const char* parser_function,
118                        const char* error_message)
119 {
120   const char* code_py = "def f():\n"
121                         "  return\n";
122   Py2yacs parser(parser_module, parser_function);
123   try
124   {
125     parser.load(code_py);
126     CPPUNIT_FAIL("Exception expected and no exception occured.");
127   }
128   catch(Py2yacsException& e)
129   {
130     std::string what = e.what();
131     std::cerr << std::endl;
132     std::cerr << "==========EXCEPTION TEXT=======================" << std::endl;
133     std::cerr << what << std::endl;
134     std::cerr << "===============================================" << std::endl;
135     CPPUNIT_ASSERT(what.find(error_message) != std::string::npos);
136   }
137   catch(std::exception& e)
138   {
139     CPPUNIT_FAIL(e.what());
140   }
141 }
142
143 void Py2yacsTest::t1()
144 {
145   const char * code_py = "def f1(a, b, c):\n"
146                          "  y = a*b + c\n"
147                          "  return y\n";
148   const char* input_ports[] = {"a", "b", "c"};
149   const char* output_ports[] = {"y"};
150   verifyCorrectPycode(code_py, "f1", 3, input_ports, 1, output_ports);
151 }
152
153 void Py2yacsTest::t2()
154 {
155   const char * code_py = "def f1(a, b, c):\n"
156                          "  x = a + b + c\n"
157                          "  y = a*b + c\n"
158                          "  z = a*b*c\n"
159                          "  return x, y, z\n";
160   const char* input_ports[] = {"a", "b", "c"};
161   const char* output_ports[] = {"x", "y", "z"};
162   verifyCorrectPycode(code_py, "f1", 3, input_ports, 3, output_ports);
163 }
164
165 void Py2yacsTest::t3()
166 {
167   const char * code_py = "def f1(a, b, c):\n"
168                          "  print(a)\n"
169                          "  print(b)\n"
170                          "  print(c)\n";
171   const char* input_ports[] = {"a", "b", "c"};
172   const char** output_ports;
173   verifyCorrectPycode(code_py, "f1", 3, input_ports, 0, output_ports);
174 }
175
176 void Py2yacsTest::t4()
177 {
178   const char * code_py = "def f1():\n"
179                          "  print('toto')\n"
180                          "  return\n";
181   const char* input_ports[] = {"a", "b", "c"};
182   const char** output_ports;
183   verifyCorrectPycode(code_py, "f1", 0, input_ports, 0, output_ports);
184 }
185
186 void Py2yacsTest::t5()
187 {
188   const char * code_py = "def f1(a):\n"
189                          "  x = -a\n"
190                          "  if a > 0:\n"
191                          "    return a\n"
192                          "  else:\n"
193                          "    return x\n"
194                          "class ignoremoi:\n"
195                          "  def ignoreF(t):\n"
196                          "    return t+1\n"
197                          "def f2(v):\n"
198                          "  ret = f1(v)\n"
199                          "  return ret\n";
200   const char* input_ports[] = {"v"};
201   const char* output_ports[] = {"ret"};
202   verifyCorrectPycode(code_py, "f2", 1, input_ports, 1, output_ports);
203 }
204
205 void Py2yacsTest::no_multiple_returns()
206 {
207   const char * code_py = "def f(a):\n"
208                          "  x = -a\n"
209                          "  if a > 0:\n"
210                          "    return a\n"
211                          "  else:\n"
212                          "    return x\n";
213   verifyWrongPycode(code_py, "f", "multiple returns.");
214 }
215
216 void Py2yacsTest::unaccepted_statement()
217 {
218   const char * code_py = "def f(a):\n"
219                          "  return a\n"
220                          "x=5\n";
221   verifyWrongPycode(code_py, "f", "not accepted statement");
222 }
223
224 /* // This is now accepted
225 void Py2yacsTest::unaccepted_statement2()
226 {
227   const char * code_py = "def f(a):\n"
228                          "  return a\n"
229                          "if __name__ == '__main__':"
230                          "  print('toto')\n";
231   verifyWrongPycode(code_py, "f", "not accepted statement");
232 }*/
233
234 void Py2yacsTest::unaccepted_return()
235 {
236   const char * code_py = "def f(a):\n"
237                          "  return 7\n";
238   verifyWrongPycode(code_py, "f", "invalid type returned");
239 }
240
241 void Py2yacsTest::unaccepted_return2()
242 {
243   const char * code_py = "def f1(a):\n"
244                          "  return 7\n"
245                          "def f2(x):\n"
246                          "  return f1(x)\n";
247   verifyWrongPycode(code_py, "f2", "invalid type returned");
248 }
249
250 void Py2yacsTest::syntaxError()
251 {
252   const char * code_py = "bla bla bla\n"
253                          "  return f1(x)\n";
254   verifyWrongPycode(code_py, "f2", "invalid syntax");
255 }
256
257 void Py2yacsTest::badFunctionName()
258 {
259   const char * code_py = "def f1(a):\n"
260                          "  x=7\n"
261                          "  return x\n"
262                          "def f2(x):\n"
263                          "  y=8\n"
264                          "  return y\n";
265   verifyWrongPycode(code_py, "nonexistant", "Function not found:");
266 }
267
268 void Py2yacsTest::schemaExec()
269 {
270   const char * code_py = "def f(a):\n"
271                          "  x = a\n"
272                          "  return x\n";
273   Py2yacs parser;
274   try
275   {
276     parser.load(code_py);
277   }
278   catch(Py2yacsException& e)
279   {
280     CPPUNIT_FAIL(e.what());
281   }
282   catch(...)
283   {
284     CPPUNIT_FAIL("Unknown exception");
285   }
286   YACS::ENGINE::Proc* p = parser.createProc("f");
287   CPPUNIT_ASSERT( p != NULL);
288   YACS::ENGINE::Node* n = p->getChildByShortName("default_name");
289   CPPUNIT_ASSERT( n != NULL);
290   CPPUNIT_ASSERT( n->getInputPort("a") != NULL);
291   CPPUNIT_ASSERT( n->getOutputPort("x") != NULL);
292   // run the schema
293   n->getInputPort("a")->edInit(42.);
294   YACS::ENGINE::Executor executor;
295   executor.RunW(p, 0);
296   // verify the output port value
297   YACS::ENGINE::OutputPyPort* var = dynamic_cast<YACS::ENGINE::OutputPyPort*>(n->getOutputPort("x"));
298   CPPUNIT_ASSERT(var);
299   double x = -2.0;
300   PyObject* pyVal = var->get();
301   {
302     AutoGIL agil;
303     CPPUNIT_ASSERT(pyVal);
304     x = PyFloat_AsDouble(pyVal);
305     CPPUNIT_ASSERT( PyErr_Occurred()==nullptr );// check pyVal is interpretable as float
306   }
307   CPPUNIT_ASSERT_DOUBLES_EQUAL(42., x, 1.E-12);
308   p->shutdown(10); // kill all the containers
309 }
310
311 // Test the behaviour when there is an error in the python parser
312 void Py2yacsTest::parserErrors()
313 {
314   verifyWrongParser("bad_parsers", "p1", "0 positional arguments");
315   verifyWrongParser("bad_parsers", "p2", "'str' object has no attribute 'name'");
316   verifyWrongParser("bad_parsers", "p3", "should be a python list");
317   verifyWrongParser("bad_parsers", "p4", "unsupported operand type");
318   verifyWrongParser("bad_parsers", "f", "Cannot find the parsing function");
319   verifyWrongParser("err_py2yacs_invalid", "get_properties", "invalid syntax");
320   verifyWrongParser("no_file", "f", "Failed to load");
321   verifyWrongParser("bad_parsers", "p5", "is not a string");
322   verifyWrongParser("bad_parsers", "p6", "is not a string");
323   verifyWrongParser("bad_parsers", "p7", "is not a string");
324   verifyWrongParser("bad_parsers", "p8", "Attribute 'name' should be a string.");
325   verifyWrongParser("bad_parsers", "p9", "Not a python list");
326   verifyWrongParser("bad_parsers", "p10", "is not a string");
327 }
328
329 void Py2yacsTest::globalVerification()
330 {
331   std::ifstream file_stream("exemple_py2yacs.py");
332   if(!file_stream)
333     return;
334
335   std::stringstream buffer;
336   buffer << file_stream.rdbuf();
337   Py2yacs parser;
338   parser.load(buffer.str());
339   std::list<FunctionProperties>::const_iterator it_fp;
340   const std::list<FunctionProperties>& functions = parser.getFunctionProperties();
341   for(it_fp=functions.begin();it_fp!=functions.end();it_fp++)
342   {
343     std::cerr << "Function :" << it_fp->_name << std::endl;
344     std::list<std::string>::const_iterator it;
345     std::cerr << "Input ports :" ;
346     for(it=it_fp->_input_ports.begin();it!=it_fp->_input_ports.end();it++)
347       std::cerr << *it << ",";
348     std::cerr << std::endl;
349     std::cerr << "Output ports :" ;
350     for(it=it_fp->_output_ports.begin();it!=it_fp->_output_ports.end();it++)
351       std::cerr << *it << ",";
352     std::cerr << std::endl;
353     std::cerr << "Imports :" ;
354     for(it=it_fp->_imports.begin();it!=it_fp->_imports.end();it++)
355       std::cerr << *it << ",";
356     std::cerr << std::endl;
357     std::cerr << "Errors :" ;
358     for(it=it_fp->_errors.begin();it!=it_fp->_errors.end();it++)
359       std::cerr << *it << std::endl;
360     std::cerr << std::endl;
361     std::cerr << "-----------------------------------------" << std::endl;
362   }
363
364 }