1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 
25 #include "pxr/pxr.h"
26 #include "pxr/base/tf/pyFunction.h"
27 #include "pxr/base/tf/pyInterpreter.h"
28 #include "pxr/base/tf/pyUtils.h"
29 
30 #include <boost/function.hpp>
31 
32 #include <boost/python/def.hpp>
33 #include <boost/python/dict.hpp>
34 #include <boost/python/extract.hpp>
35 #include <boost/python/import.hpp>
36 
37 #include <functional>
38 
39 using namespace boost::python;
40 PXR_NAMESPACE_USING_DIRECTIVE
41 
42 static const char VoidFuncSource[] = "def VoidFunc(): pass\n";
43 static const char BoolFuncSource[] = "def BoolFunc(): return True\n";
44 static const char IntFuncSource[] = "def IntFunc(): return 13\n";
45 #if PY_MAJOR_VERSION < 3
46 static const char LongFuncSource[] = "def LongFunc(): return 17L\n";
47 #endif
48 static const char DoubleFuncSource[] = "def DoubleFunc(): return 19.0\n";
49 static const char StringFuncSource[] = "def StringFunc(): return 'a string'\n";
50 static const char ObjectFuncSource[] = "def ObjectFunc(): return testObject\n";
51 
52 template <typename T>
53 static void
AssertCallResult(object callable,T const & expected)54 AssertCallResult(object callable, T const &expected)
55 {
56     extract<std::function<T()>> stdFunc(callable);
57     TF_AXIOM(stdFunc.check());
58     TF_AXIOM(stdFunc()() == expected);
59 
60     extract<boost::function<T()>> boostFunc(callable);
61     TF_AXIOM(boostFunc.check());
62     TF_AXIOM(boostFunc()() == expected);
63 }
64 
65 static void
AssertCallVoid(object callable)66 AssertCallVoid(object callable)
67 {
68     // As there's no result to check, all we care about is that calling the
69     // function does not throw.
70     extract<std::function<void()>> stdFunc(callable);
71     TF_AXIOM(stdFunc.check());
72     stdFunc()();
73 
74     extract<boost::function<void()>> boostFunc(callable);
75     TF_AXIOM(boostFunc.check());
76     boostFunc()();
77 }
78 
79 static object
DefineFunc(const char * funcName,const char * funcSource,dict testEnv)80 DefineFunc(const char *funcName, const char *funcSource, dict testEnv)
81 {
82     TfPyRunString(funcSource, Py_single_input, testEnv);
83     return testEnv[funcName];
84 }
85 
86 int
main(int argc,char ** argv)87 main(int argc, char **argv)
88 {
89     TfPyInitialize();
90 
91     TfPyLock lock;
92 
93     // Import Tf to make sure that we get the function wrappings defined in
94     // wrapFunction.cpp.
95     object tfModule = import("pxr.Tf");
96     TF_AXIOM(!tfModule.is_none());
97 
98     // Store our test functions in this dictionary rather than the main module.
99     dict testEnv;
100 
101     testEnv.update(import(TfPyBuiltinModuleName).attr("__dict__"));
102 
103     // Expected results of calling functions
104     const bool expectedBool = true;
105     const int expectedInt = 13;
106 #if PY_MAJOR_VERSION < 3
107     const long expectedLong = 17;
108 #endif
109     const double expectedDouble = 19;
110     const std::string expectedString = "a string";
111     object expectedObject = TfPyEvaluate("object()");
112     testEnv["testObject"] = expectedObject;
113 
114     // Define and test regular functions
115     object voidFunc = DefineFunc("VoidFunc", VoidFuncSource, testEnv);
116     TF_AXIOM(!voidFunc.is_none());
117     object boolFunc = DefineFunc("BoolFunc", BoolFuncSource, testEnv);
118     TF_AXIOM(!boolFunc.is_none());
119     object intFunc = DefineFunc("IntFunc", IntFuncSource, testEnv);
120     TF_AXIOM(!intFunc.is_none());
121 
122 #if PY_MAJOR_VERSION < 3
123     object longFunc = DefineFunc("LongFunc", LongFuncSource, testEnv);
124     TF_AXIOM(!longFunc.is_none());
125 #endif
126 
127     object doubleFunc = DefineFunc("DoubleFunc", DoubleFuncSource, testEnv);
128     TF_AXIOM(!doubleFunc.is_none());
129     object stringFunc = DefineFunc("StringFunc", StringFuncSource, testEnv);
130     TF_AXIOM(!stringFunc.is_none());
131     object objectFunc = DefineFunc("ObjectFunc", ObjectFuncSource, testEnv);
132     TF_AXIOM(!objectFunc.is_none());
133 
134     AssertCallVoid(voidFunc);
135     AssertCallResult<bool>(boolFunc, expectedBool);
136     AssertCallResult<int>(intFunc, expectedInt);
137 #if PY_MAJOR_VERSION < 3
138     AssertCallResult<long>(longFunc, expectedLong);
139 #endif
140     AssertCallResult<double>(doubleFunc, expectedDouble);
141     AssertCallResult<std::string>(stringFunc, expectedString);
142     AssertCallResult<object>(objectFunc, expectedObject);
143 
144     // Define and test lambda functions
145     object voidLambda = TfPyEvaluate("lambda: None");
146     TF_AXIOM(!voidLambda.is_none());
147     object boolLambda = TfPyEvaluate("lambda: True");
148     TF_AXIOM(!boolLambda.is_none());
149     object intLambda = TfPyEvaluate("lambda: 13");
150     TF_AXIOM(!intLambda.is_none());
151 #if PY_MAJOR_VERSION < 3
152     object longLambda = TfPyEvaluate("lambda: 17L");
153     TF_AXIOM(!longLambda.is_none());
154 #endif
155     object doubleLambda = TfPyEvaluate("lambda: 19.0");
156     TF_AXIOM(!doubleLambda.is_none());
157     object stringLambda = TfPyEvaluate("lambda: 'a string'");
158     TF_AXIOM(!stringLambda.is_none());
159     object objectLambda = TfPyEvaluate("lambda: testObject", testEnv);
160     TF_AXIOM(!objectLambda.is_none());
161 
162     AssertCallVoid(voidLambda);
163     AssertCallResult<bool>(boolLambda, expectedBool);
164     AssertCallResult<int>(intLambda, expectedInt);
165 #if PY_MAJOR_VERSION < 3
166     AssertCallResult<long>(longLambda, expectedLong);
167 #endif
168     AssertCallResult<double>(doubleLambda, expectedDouble);
169     AssertCallResult<std::string>(stringLambda, expectedString);
170     AssertCallResult<object>(objectLambda, expectedObject);
171 }
172