Salome HOME
48204e0d765f2bc9a582962ad3504553bc197030
[tools/py2cpp.git] / src / Test / ConversionTest.cxx
1 // Copyright (C) 2019-2024 EDF
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 "ConversionTest.hxx"
20 #include "py2cpp.hxx"
21
22 void ConversionTest::setUp()
23 {
24   Py_Initialize();
25 }
26
27 void ConversionTest::tearDown()
28 {
29   Py_Finalize();
30 }
31
32 void ConversionTest::cleanUp(){}
33
34 void ConversionTest::basicTest()
35 {
36   CPPUNIT_ASSERT(42==py2cpp::fromPyPtr<int>(py2cpp::toPyPtr(42)));
37   CPPUNIT_ASSERT(4.2==py2cpp::fromPyPtr<double>(py2cpp::toPyPtr(4.2)));
38   CPPUNIT_ASSERT(py2cpp::fromPyPtr<bool>(py2cpp::toPyPtr(true)));
39   CPPUNIT_ASSERT(!py2cpp::fromPyPtr<bool>(py2cpp::toPyPtr(false)));
40   std::string toto;
41   toto = py2cpp::fromPyPtr<std::string>(py2cpp::toPyPtr(std::string("toto")));
42   CPPUNIT_ASSERT(toto == "toto");
43
44   auto v = std::make_tuple(4, 4.2);
45   py2cpp::PyPtr obj = py2cpp::toPyPtr(v);
46
47   std::string s1;
48   double d;
49   int i;
50   std::tuple<int&, double&> tup(i, d);
51   py2cpp::fromPyPtr(obj, tup);
52   CPPUNIT_ASSERT(4==std::get<0>(tup));
53   CPPUNIT_ASSERT(4.2==std::get<1>(tup));
54   int i2;
55   double d2;
56   py2cpp::pyResult(i2, d2) = obj;
57   CPPUNIT_ASSERT(4==i2);
58   CPPUNIT_ASSERT(4.2==d2);
59   py2cpp::pyResult(i2) = py2cpp::toPyPtr(42);
60   CPPUNIT_ASSERT(42 == i2);
61   py2cpp::PyPtr copy(obj);
62   i2=0; d2=0.;
63   py2cpp::pyResult(i2, d2) = copy;
64   CPPUNIT_ASSERT(4==i2);
65   CPPUNIT_ASSERT(4.2==d2);
66   py2cpp::PyPtr copy2;
67   copy2 = obj;
68   i2=0; d2=0.;
69   py2cpp::pyResult(i2, d2) = copy2;
70   CPPUNIT_ASSERT(4==i2);
71   CPPUNIT_ASSERT(4.2==d2);
72 }
73
74 void ConversionTest::functionTest()
75 {
76   int i;
77   double d;
78   std::string str;
79   py2cpp::PyFunction fn;
80
81   CPPUNIT_ASSERT(fn.load("TestPy2cpp", "f1"));
82   CPPUNIT_ASSERT(fn);
83   py2cpp::pyResult(i, d) = fn(5, 4.8);
84   CPPUNIT_ASSERT(4==i);
85   CPPUNIT_ASSERT(6.7==d);
86   CPPUNIT_ASSERT(0==py2cpp::getLastPyError().size());
87
88   fn.load("TestPy2cpp", "f2");
89   CPPUNIT_ASSERT(fn);
90   py2cpp::pyResult(str) = fn();
91   CPPUNIT_ASSERT(str=="Hello world!");
92   CPPUNIT_ASSERT(0==py2cpp::getLastPyError().size());
93
94   fn.load("TestPy2cpp", "f3");
95   CPPUNIT_ASSERT(fn);
96   py2cpp::pyResult(d, str) = fn(7, 2, "Toto");
97   CPPUNIT_ASSERT(3.5 == d);
98   CPPUNIT_ASSERT(str == "Toto is here!");
99   CPPUNIT_ASSERT(0==py2cpp::getLastPyError().size());
100
101   CPPUNIT_ASSERT(!fn.load("nonexistent","nonexistent"));
102   CPPUNIT_ASSERT(!fn);
103   CPPUNIT_ASSERT(0 < py2cpp::getLastPyError().size());
104 }
105
106 void ConversionTest::vectorTest()
107 {
108   std::vector<double> v = {1.1, 2.2, 3.3, 4.4};
109   py2cpp::PyPtr obj = py2cpp::toPyPtr(v);
110   py2cpp::fromPyPtr(obj, v);
111
112   std::vector<double> result;
113   py2cpp::PyFunction fn;
114   fn.load("TestPy2cpp", "add1ToList");
115   py2cpp::pyResult(result) = fn(v);
116
117   CPPUNIT_ASSERT(std::vector<double>({2.1, 3.2, 4.3, 5.4}) == result);
118
119   auto tup = std::make_tuple(4, 4.2);
120   py2cpp::PyPtr pyTup = py2cpp::toPyPtr(tup);
121   py2cpp::fromPyPtr(pyTup, result);
122   CPPUNIT_ASSERT(std::vector<double>({4, 4.2}) == result);
123 }
124
125 void ConversionTest::listTest()
126 {
127   std::list<double> v = {1.1, 2.2, 3.3, 4.4};
128   py2cpp::PyPtr obj = py2cpp::toPyPtr(v);
129   py2cpp::fromPyPtr(obj, v);
130
131   std::list<double> result;
132   py2cpp::PyFunction fn;
133   fn.load("TestPy2cpp", "add1ToList");
134   py2cpp::pyResult(result) = fn(v);
135
136   CPPUNIT_ASSERT(std::list<double>({2.1, 3.2, 4.3, 5.4}) == result);
137
138   auto tup = std::make_tuple(4, 4.2);
139   py2cpp::PyPtr pyTup = py2cpp::toPyPtr(tup);
140   py2cpp::fromPyPtr(pyTup, result);
141   CPPUNIT_ASSERT(std::list<double>({4, 4.2}) == result);
142 }
143
144 void ConversionTest::pyobjTest()
145 {
146   py2cpp::PyFunction objcall;
147   objcall.load("TestPy2cpp","MyClass");
148   CPPUNIT_ASSERT(objcall);
149   py2cpp::PyPtr obj = objcall(std::list<std::string>({"Toto", "Titi", "Zaza"}),
150                               std::vector<double>({5.5, 2.7, 1.8, 9.2}));
151   py2cpp::PyFunction objFn1, objFn2, objFn3;
152   objFn1.load(obj, "namesTogether");
153   objFn2.load(obj, "valuesSum");
154   objFn3.load(obj, "addVal");
155   std::string strResult;
156   double dbResult;
157   py2cpp::pyResult(strResult) = objFn1();
158   py2cpp::pyResult(dbResult) = objFn2();
159   CPPUNIT_ASSERT(strResult == "Toto-Titi-Zaza");
160   CPPUNIT_ASSERT(19.2 == dbResult);
161
162   objFn3(1);
163   py2cpp::pyResult(dbResult) = objFn2();
164   CPPUNIT_ASSERT(23.2 == dbResult);
165
166   py2cpp::PyFunction myObjectSize;
167   myObjectSize.load("TestPy2cpp", "myObjectSize");
168   int i;
169   py2cpp::pyResult(i) = myObjectSize(obj);
170   CPPUNIT_ASSERT(7==i);
171   CPPUNIT_ASSERT(obj.getAttr("names").repr() == "['Toto', 'Titi', 'Zaza']");
172   CPPUNIT_ASSERT(obj.getAttr("values").repr() == "[6.5, 3.7, 2.8, 10.2]");
173
174   objFn1.load("TestPy2cpp","newobj");
175   py2cpp::PyPtr newobj;
176   py2cpp::pyResult(newobj, i) = objFn1(obj, std::vector<int>({1,2,3}));
177   CPPUNIT_ASSERT(6==i);
178   CPPUNIT_ASSERT(newobj.getAttr("names").repr() == "['Toto', 'Titi', 'Zaza']");
179   CPPUNIT_ASSERT(newobj.getAttr("values").repr() == "[1, 2, 3]");
180 }
181
182 void ConversionTest::pyErrorTest()
183 {
184   double d;
185   std::string str;
186   py2cpp::PyFunction fn;
187   fn.load("TestPy2cpp", "f3");
188   try
189   {
190     fn(7, 0, "problem");
191     CPPUNIT_FAIL("Expected exception 'py2cpp::ExecutionException'!");
192   }
193   catch (const py2cpp::ExecutionException& err)
194   {
195     str = err.what();
196     CPPUNIT_ASSERT(str.find("ZeroDivisionError:") != std::string::npos) ;
197   }
198
199   try
200   {
201     py2cpp::pyResult(d, str) = fn(7, 0, "problem");
202     CPPUNIT_FAIL("Expected exception 'py2cpp::ExecutionException'!");
203   }
204   catch (const py2cpp::ExecutionException& err)
205   {
206     str = err.what();
207     CPPUNIT_ASSERT(str.find("ZeroDivisionError:") != std::string::npos) ;
208   }
209 }
210
211 void ConversionTest::castErrorTest()
212 {
213   int i;
214   double d;
215   std::string str;
216   std::vector<int> vi;
217   std::vector<double> vd;
218   std::vector<std::string> vs;
219   std::map<std::string, std::vector<double> > msvd;
220   py2cpp::ConversionCheck check;
221   py2cpp::PyPtr obj;
222
223   obj = py2cpp::toPyPtr(42);
224   check = py2cpp::fromPyPtr(obj, d);
225   CPPUNIT_ASSERT(check);
226   check = py2cpp::fromPyPtr(obj, vi);
227   CPPUNIT_ASSERT(check.getMessage() ==
228 "Cannot convert the python object <42> to c++ type std::vector.\n");
229   check = py2cpp::fromPyPtr(obj, str);
230   CPPUNIT_ASSERT(check.getMessage() ==
231 "Cannot convert the python object <42> to c++ type std::string.\n");
232   check = py2cpp::fromPyPtr(obj, msvd);
233   CPPUNIT_ASSERT(check.getMessage() ==
234 "Cannot convert the python object <42> to c++ type std::map.\n");
235
236   obj = py2cpp::toPyPtr(std::vector<int>({1,2,3,4,5,6}));
237   check = py2cpp::fromPyPtr(obj, i);
238   CPPUNIT_ASSERT(check.getMessage() ==
239 "Cannot convert the python object <[1, 2, 3, 4, 5, 6]> to c++ type int.\n");
240   check = py2cpp::fromPyPtr(obj, d);
241   CPPUNIT_ASSERT(check.getMessage() ==
242 "Cannot convert the python object <[1, 2, 3, 4, 5, 6]> to c++ type double.\n");
243   check = py2cpp::fromPyPtr(obj, vi);
244   CPPUNIT_ASSERT(check);
245   check = py2cpp::fromPyPtr(obj, vd);
246   CPPUNIT_ASSERT(check);
247   check = py2cpp::fromPyPtr(obj, str);
248   CPPUNIT_ASSERT(check.getMessage() ==
249 "Cannot convert the python object <[1, 2, 3, 4, 5, 6]> to c++ type std::string.\n"
250   );
251
252   check = py2cpp::fromPyPtr(obj, vs);
253   CPPUNIT_ASSERT(check.getMessage() ==
254 "Cannot convert the python object <1> to c++ type std::string.\n"
255 "Cannot convert the python object <[1, 2, 3, 4, 5, 6]> to c++ type std::vector.\n"
256   );
257   check = py2cpp::fromPyPtr(obj, msvd);
258   CPPUNIT_ASSERT(check.getMessage() ==
259 "Cannot convert the python object <[1, 2, 3, 4, 5, 6]> to c++ type std::map.\n");
260   
261   std::map<int, double> mid({ {1, 1.1},{2, 2.2},{3, 3.3},{4, 4.4},{5, 5.5}});
262   obj = py2cpp::toPyPtr(mid);
263   check = py2cpp::fromPyPtr(obj, i);
264   // Cannot check the message because the string representation of the python
265   // dictionary may change.
266   CPPUNIT_ASSERT(!check);
267   check = py2cpp::fromPyPtr(obj, vd);
268   CPPUNIT_ASSERT(!check);
269   check = py2cpp::fromPyPtr(obj, msvd);
270   CPPUNIT_ASSERT(!check);
271
272   std::map<std::string, double> msd({ {"1", 1.1},{"2", 2.2},{"3", 3.3},
273                                     {"4", 4.4},{"5", 5.5}});
274   obj = py2cpp::toPyPtr(msd);
275   check = py2cpp::fromPyPtr(obj, msvd);
276   CPPUNIT_ASSERT(!check);
277
278   std::map<std::string, std::vector<std::string> > msvs ;
279   msvs["a"] = std::vector<std::string>({"azer", "aqwx"});
280   msvs["b"] = std::vector<std::string>({"bn,", "bvcxw"});
281   obj = py2cpp::toPyPtr(msvs);
282   check = py2cpp::fromPyPtr(obj, msvd);
283   CPPUNIT_ASSERT(!check);
284 }
285
286 CPPUNIT_TEST_SUITE_REGISTRATION( ConversionTest );
287 #include "TestMain.cxx"