Best Python code snippet using localstack_python
GenApi.py
Source:GenApi.py
1# Gmsh - Copyright (C) 1997-2019 C. Geuzaine, J.-F. Remacle2#3# See the LICENSE.txt file for license information. Please report all4# issues on https://gitlab.onelab.info/gmsh/gmsh/issues.5# Contributor(s):6# Jonathan Lambrechts7import textwrap8import string9class arg:10 def __init__(self, name, value, python_value, julia_value,11 cpp_type, c_type, out):12 self.name = name13 self.value = value14 self.out = out15 self.cpp = cpp_type + " " + name + ((" = " + value) if value else "")16 self.c_arg = name17 self.c_pre = ""18 self.c_post = ""19 self.c = c_type + " " + name20 self.cwrap_arg = self.name21 self.cwrap_pre = ""22 self.cwrap_post = ""23 self.python_value = python_value if python_value is not None else value24 self.python_arg = ""25 self.python_return = ""26 self.python_pre = ""27 self.julia_value = julia_value if julia_value is not None else value28 self.julia_arg = name29 self.julia_ctype = ""30 self.julia_pre = ""31 self.julia_post = ""32 self.julia_return = name33# input types34def ibool(name, value=None, python_value=None, julia_value=None):35 a = arg(name, value, python_value, julia_value,36 "const bool", "const int", False)37 a.python_arg = "c_int(bool(" + name + "))"38 a.cwrap_arg = "(int)" + name39 a.julia_ctype = "Cint"40 return a41def iint(name, value=None, python_value=None, julia_value=None):42 a = arg(name, value, python_value, julia_value,43 "const int", "const int", False)44 a.python_arg = "c_int(" + name + ")"45 a.julia_ctype = "Cint"46 return a47def isize(name, value=None, python_value=None, julia_value=None):48 a = arg(name, value, python_value, julia_value,49 "const std::size_t", "const size_t", False)50 a.python_arg = "c_size_t(" + name + ")"51 a.julia_ctype = "Csize_t"52 return a53def idouble(name, value=None, python_value=None, julia_value=None):54 a = arg(name, value, python_value, julia_value,55 "const double", "const double", False)56 a.python_arg = "c_double(" + name + ")"57 a.julia_ctype = "Cdouble"58 return a59def istring(name, value=None, python_value=None, julia_value=None):60 a = arg(name, value, python_value, julia_value,61 "const std::string &", "const char *", False)62 a.python_arg = "c_char_p(" + name + ".encode())"63 a.cwrap_arg = name + ".c_str()"64 a.julia_ctype = "Ptr{Cchar}"65 return a66def ivoidstar(name, value=None, python_value=None, julia_value=None):67 a = arg(name, value, python_value, julia_value,68 "const void *", "const void *", False)69 a.python_arg = "c_void_p(" + name + ")"70 a.julia_ctype = "Ptr{Cvoid}"71 return a72def ivectorint(name, value=None, python_value=None, julia_value=None):73 if julia_value == "[]":74 julia_value = "Cint[]"75 a = arg(name, value, python_value, julia_value,76 "const std::vector<int> &", "const int *", False)77 api_name = "api_" + name + "_"78 api_name_n = "api_" + name + "_n_"79 a.c_pre = (" std::vector<int> " + api_name + "(" + name + ", " + name +80 " + " + name + "_n);\n")81 a.c_arg = api_name82 a.c = "int * " + name + ", size_t " + name + "_n"83 a.cwrap_pre = ("int *" + api_name + "; size_t " + api_name_n + "; " +84 "vector2ptr(" + name + ", &" + api_name + ", &" + api_name_n + ");\n")85 a.cwrap_arg = api_name + ", " + api_name_n86 a.cwrap_post = ns + "Free(" + api_name + ");\n"87 a.python_pre = api_name + ", " + api_name_n + " = _ivectorint(" + name + ")"88 a.python_arg = api_name + ", " + api_name_n89 a.julia_ctype = "Ptr{Cint}, Csize_t"90 a.julia_arg = "convert(Vector{Cint}, " + name + "), length(" + name + ")"91 return a92def ivectorsize(name, value=None, python_value=None, julia_value=None):93 if julia_value == "[]":94 julia_value = "Csize_t[]"95 a = arg(name, value, python_value, julia_value,96 "const std::vector<std::size_t> &", "const size_t *", False)97 api_name = "api_" + name + "_"98 api_name_n = "api_" + name + "_n_"99 a.c_pre = (" std::vector<std::size_t> " + api_name + "(" + name + ", " + name +100 " + " + name + "_n);\n")101 a.c_arg = api_name102 a.c = "size_t * " + name + ", size_t " + name + "_n"103 a.cwrap_pre = ("size_t *" + api_name + "; size_t " + api_name_n + "; " +104 "vector2ptr(" + name + ", &" + api_name + ", &" + api_name_n + ");\n")105 a.cwrap_arg = api_name + ", " + api_name_n106 a.cwrap_post = ns + "Free(" + api_name + ");\n"107 a.python_pre = api_name + ", " + api_name_n + " = _ivectorsize(" + name + ")"108 a.python_arg = api_name + ", " + api_name_n109 a.julia_ctype = "Ptr{Csize_t}, Csize_t"110 a.julia_arg = "convert(Vector{Csize_t}, " + name + "), length(" + name + ")"111 return a112def ivectordouble(name, value=None, python_value=None, julia_value=None):113 if julia_value == "[]":114 julia_value = "Cdouble[]"115 a = arg(name, value, python_value, julia_value,116 "const std::vector<double> &", "double **", False)117 api_name = "api_" + name + "_"118 api_name_n = "api_" + name + "_n_"119 a.c_pre = (" std::vector<double> " + api_name + "(" + name + ", " +120 name + " + " + name + "_n);\n")121 a.c_arg = api_name122 a.c = "double * " + name + ", size_t " + name + "_n"123 a.cwrap_pre = ("double *" + api_name + "; size_t " + api_name_n + "; " +124 "vector2ptr(" + name + ", &" + api_name + ", &" + api_name_n + ");\n")125 a.cwrap_arg = api_name + ", " + api_name_n126 a.cwrap_post = ns + "Free(" + api_name + ");\n"127 a.python_pre = api_name + ", " + api_name_n + " = _ivectordouble(" + name + ")"128 a.python_arg = api_name + ", " + api_name_n129 a.julia_ctype = "Ptr{Cdouble}, Csize_t"130 a.julia_arg = "convert(Vector{Cdouble}, " + name + "), length(" + name + ")"131 return a132def ivectorstring(name, value=None, python_value=None, julia_value=None):133 a = arg(name, value, python_value, julia_value,134 "const std::vector<std::string> &", "char **", False)135 api_name = "api_" + name + "_"136 api_name_n = "api_" + name + "_n_"137 a.c_pre = (" std::vector<std::string> " + api_name + "(" + name + ", " +138 name + " + " + name + "_n);\n")139 a.c_arg = api_name140 a.c = "char ** " + name + ", size_t " + name + "_n"141 a.cwrap_pre = ("char **" + api_name + "; size_t " + api_name_n + "; " +142 "vectorstring2charptrptr(" + name + ", &" + api_name + ", &" + api_name_n + ");\n")143 a.cwrap_arg = api_name + ", " + api_name_n144 a.cwrap_post = ("for(size_t i = 0; i < " + api_name_n + "; ++i){ " +145 ns + "Free(" + api_name + "[i]); } " +146 ns + "Free(" + api_name + ");\n")147 a.python_pre = api_name + ", " + api_name_n + " = _ivectorstring(" + name + ")"148 a.python_arg = api_name + ", " + api_name_n149 a.julia_ctype = "Ptr{Ptr{Cchar}}, Csize_t"150 a.julia_arg = name + ", length(" + name + ")"151 return a152def ivectorpair(name, value=None, python_value=None, julia_value=None):153 if julia_value == "[]":154 julia_value = "Tuple{Cint,Cint}[]"155 a = arg(name, value, python_value, julia_value,156 "const " + ns + "::vectorpair &", "const int *", False)157 api_name = "api_" + name + "_"158 api_name_n = "api_" + name + "_n_"159 a.c_pre = (" " + ns + "::vectorpair " + api_name + "(" + name + "_n/2);\n" +160 " for(size_t i = 0; i < " + name + "_n/2; ++i){\n" +161 " " + api_name + "[i].first = " + name + "[i * 2 + 0];\n" +162 " " + api_name + "[i].second = " + name + "[i * 2 + 1];\n" +163 " }\n")164 a.c_arg = api_name165 a.c = "int * " + name + ", size_t " + name + "_n"166 a.cwrap_pre = ("int *" + api_name + "; size_t " + api_name_n + "; " +167 "vectorpair2intptr(" + name + ", &" + api_name + ", &" +168 api_name_n + ");\n")169 a.cwrap_arg = api_name + ", " + api_name_n170 a.cwrap_post = ns + "Free(" + api_name + ");\n"171 a.python_pre = api_name + ", " + api_name_n + " = _ivectorpair(" + name + ")"172 a.python_arg = api_name + ", " + api_name_n173 a.julia_ctype = "Ptr{Cint}, Csize_t"174 a.julia_arg = ("convert(Vector{Cint}, collect(Cint, Iterators.flatten(" + name + "))), " +175 "2 * length(" + name + ")")176 return a177def ivectorvectorint(name, value=None, python_value=None, julia_value=None):178 if julia_value == "[]":179 julia_value = "Vector{Cint}[]"180 a = arg(name, value, python_value, julia_value,181 "const std::vector<std::vector<int> > &", "const int **", False)182 api_name = "api_" + name + "_"183 api_name_n = "api_" + name + "_n_"184 api_name_nn = "api_" + name + "_nn_"185 a.c_pre = (" std::vector<std::vector<int> > " + api_name +186 "(" + name + "_nn);\n" +187 " for(size_t i = 0; i < " + name + "_nn; ++i)\n" +188 " " + api_name + "[i] = std::vector<int>(" + name + "[i], " +189 name + "[i] + " + name + "_n[i]);\n")190 a.c_arg = api_name191 a.c = ("const int ** " + name + ", const size_t * " + name + "_n, " +192 "size_t " + name + "_nn")193 a.cwrap_pre = ("int **" + api_name + "; size_t *" + api_name_n + ", " +194 api_name_nn + "; " + "vectorvector2ptrptr(" + name + ", &" +195 api_name + ", &" + api_name_n + ", &" + api_name_nn + ");\n")196 a.cwrap_arg = "(const int **)" + api_name + ", " + api_name_n + ", " + api_name_nn197 a.cwrap_post = ("for(size_t i = 0; i < " + api_name_nn + "; ++i){ " +198 ns + "Free(" + api_name + "[i]); } " +199 ns + "Free(" + api_name + "); " + ns + "Free(" + api_name_n + ");\n")200 a.python_pre = (api_name + ", " + api_name_n + ", " +201 api_name_nn + " = _ivectorvectorint(" + name + ")")202 a.python_arg = api_name + ", " + api_name_n + ", " + api_name_nn203 a.julia_ctype = "Ptr{Ptr{Cint}}, Ptr{Csize_t}, Csize_t"204 a.julia_pre = (api_name_n + " = [ length(" + name + "[i]) for i in 1:length(" +205 name + ") ]")206 a.julia_arg = ("convert(Vector{Vector{Cint}}," + name + "), " + api_name_n +207 ", length(" + name + ")")208 return a209def ivectorvectorsize(name, value=None, python_value=None, julia_value=None):210 if julia_value == "[]":211 julia_value = "Vector{Csize_t}[]"212 a = arg(name, value, python_value, julia_value,213 "const std::vector<std::vector<std::size_t> > &", "const size_t **", False)214 api_name = "api_" + name + "_"215 api_name_n = "api_" + name + "_n_"216 api_name_nn = "api_" + name + "_nn_"217 a.c_pre = (" std::vector<std::vector<std::size_t> > " + api_name +218 "(" + name + "_nn);\n" +219 " for(size_t i = 0; i < " + name + "_nn; ++i)\n" +220 " " + api_name + "[i] = std::vector<std::size_t>(" + name + "[i], " +221 name + "[i] + " + name + "_n[i]);\n")222 a.c_arg = api_name223 a.c = ("const size_t ** " + name + ", const size_t * " + name + "_n, " +224 "size_t " + name + "_nn")225 a.cwrap_pre = ("size_t **" + api_name + "; size_t *" + api_name_n + ", " +226 api_name_nn + "; " + "vectorvector2ptrptr(" + name + ", &" +227 api_name + ", &" + api_name_n + ", &" + api_name_nn + ");\n")228 a.cwrap_arg = "(const size_t **)" + api_name + ", " + api_name_n + ", " + api_name_nn229 a.cwrap_post = ("for(size_t i = 0; i < " + api_name_nn + "; ++i){ " +230 ns + "Free(" + api_name + "[i]); } " +231 ns + "Free(" + api_name + "); " + ns + "Free(" + api_name_n + ");\n")232 a.python_pre = (api_name + ", " + api_name_n + ", " +233 api_name_nn + " = _ivectorvectorsize(" + name + ")")234 a.python_arg = api_name + ", " + api_name_n + ", " + api_name_nn235 a.julia_ctype = "Ptr{Ptr{Csize_t}}, Ptr{Csize_t}, Csize_t"236 a.julia_pre = (api_name_n + " = [ length(" + name + "[i]) for i in 1:length(" +237 name + ") ]")238 a.julia_arg = ("convert(Vector{Vector{Csize_t}}," + name + "), " + api_name_n +239 ", length(" + name + ")")240 return a241def ivectorvectordouble(name, value=None, python_value=None, julia_value=None):242 if julia_value == "[]":243 julia_value = "Vector{Cdouble}[]"244 a = arg(name, value, python_value, julia_value,245 "const std::vector<std::vector<double> > &", "const double**", False)246 api_name = "api_" + name + "_"247 api_name_n = "api_" + name + "_n_"248 api_name_nn = "api_" + name + "_nn_"249 a.c_pre = (" std::vector<std::vector<double> > " + api_name +250 "(" + name + "_nn);\n" +251 " for(size_t i = 0; i < " + name + "_nn; ++i)\n" +252 " " + api_name + "[i] = std::vector<double>(" + name + "[i], " +253 name + "[i] + " + name + "_n[i]);\n")254 a.c_arg = api_name255 a.c = ("const double ** " + name + ", const size_t * " + name + "_n, " +256 "size_t " + name + "_nn")257 a.cwrap_pre = ("double **" + api_name + "; size_t *" + api_name_n + ", " +258 api_name_nn + "; " +259 "vectorvector2ptrptr(" + name + ", &" + api_name + ", &" +260 api_name_n + ", &" + api_name_nn + ");\n")261 a.cwrap_arg = "(const double **)" + api_name + ", " + api_name_n + ", " + api_name_nn262 a.cwrap_post = ("for(size_t i = 0; i < " + api_name_nn + "; ++i){ " +263 ns + "Free(" + api_name + "[i]); } " +264 ns + "Free(" + api_name + "); " + ns + "Free(" + api_name_n + ");\n")265 a.python_pre = (api_name + ", " + api_name_n + ", " + api_name_nn +266 " = _ivectorvectordouble(" + name + ")")267 a.python_arg = api_name + ", " + api_name_n + ", " + api_name_nn268 a.julia_ctype = "Ptr{Ptr{Cdouble}}, Ptr{Csize_t}, Csize_t"269 a.julia_pre = (api_name_n + " = [ length(" + name + "[i]) for i in 1:length(" +270 name + ") ]")271 a.julia_arg = ("convert(Vector{Vector{Cdouble}}," + name + "), " + api_name_n +272 ", length(" + name + ")")273 return a274# output types275class oint(arg):276 rcpp_type = "int"277 rc_type = "int"278 rtexi_type = "integer value"279 rjulia_type = "Cint"280 def __init__(self, name, value=None, python_value=None, julia_value=None):281 arg.__init__(self, name, value, python_value, julia_value,282 "int &", "int *", True)283 api_name = "api_" + name + "_"284 self.c_arg = "*" + name285 self.cwrap_arg = "&" + name286 self.python_pre = api_name + " = c_int()"287 self.python_arg = "byref(" + api_name + ")"288 self.python_return = api_name + ".value"289 self.julia_ctype = "Ptr{Cint}"290 self.julia_pre = api_name + " = Ref{Cint}()"291 self.julia_arg = api_name292 self.julia_return = api_name + "[]"293class osize(arg):294 rcpp_type = "std::size_t"295 rc_type = "size_t"296 rtexi_type = "size value"297 rjulia_type = "Csize_t"298 def __init__(self, name, value=None, python_value=None, julia_value=None):299 arg.__init__(self, name, value, python_value, julia_value,300 "std::size_t &", "size_t *", True)301 api_name = "api_" + name + "_"302 self.c_arg = "*" + name303 self.cwrap_arg = "&" + name304 self.python_pre = api_name + " = c_size_t()"305 self.python_arg = "byref(" + api_name + ")"306 self.python_return = api_name + ".value"307 self.julia_ctype = "Ptr{Csize_t}"308 self.julia_pre = api_name + " = Ref{Csize_t}()"309 self.julia_arg = api_name310 self.julia_return = api_name + "[]"311class odouble(arg):312 rcpp_type = "double"313 rc_type = "double"314 rtexi_type = "floating point value"315 rjulia_type = "Cdouble"316 def __init__(self, name, value=None, python_value=None, julia_value=None):317 arg.__init__(self, name, value, python_value, julia_value,318 "double &", "double *", True)319 api_name = "api_" + name + "_"320 self.c_arg = "*" + name321 self.cwrap_arg = "&" + name322 self.python_pre = api_name + " = c_double()"323 self.python_arg = "byref(" + api_name + ")"324 self.python_return = api_name + ".value"325 self.julia_ctype = "Ptr{Cdouble}"326 self.julia_pre = api_name + " = Ref{Cdouble}()"327 self.julia_arg = api_name328 self.julia_return = api_name + "[]"329def ostring(name, value=None, python_value=None, julia_value=None):330 a = arg(name, value, python_value, julia_value,331 "std::string &", "char **", True)332 api_name = "api_" + name + "_"333 a.c_pre = " std::string " + api_name + ";\n"334 a.c_arg = api_name335 a.c_post = " *" + name + " = strdup(" + api_name + ".c_str());\n"336 a.cwrap_pre = "char *" + api_name + ";\n"337 a.cwrap_arg = "&" + api_name338 a.cwrap_post = (name + " = std::string(" + api_name + "); " +339 ns + "Free(" + api_name + ");\n")340 a.python_pre = api_name + " = c_char_p()"341 a.python_arg = "byref(" + api_name + ")"342 a.python_return = "_ostring(" + api_name + ")"343 a.julia_ctype = "Ptr{Ptr{Cchar}}"344 a.julia_pre = api_name + " = Ref{Ptr{Cchar}}()"345 a.julia_arg = api_name346 a.julia_post = name + " = unsafe_string(" + api_name + "[])"347 return a348def ovectorint(name, value=None, python_value=None, julia_value=None):349 a = arg(name, value, python_value, julia_value,350 "std::vector<int> &", "int **", True)351 api_name = "api_" + name + "_"352 api_name_n = api_name + "n_"353 a.c_pre = " std::vector<int> " + api_name + ";\n"354 a.c_arg = api_name355 a.c_post = " vector2ptr(" + api_name + ", " + name + ", " + name + "_n);\n"356 a.c = "int ** " + name + ", size_t * " + name + "_n"357 a.cwrap_pre = "int *" + api_name + "; size_t " + api_name_n + ";\n"358 a.cwrap_arg = "&" + api_name + ", " + "&" + api_name_n359 a.cwrap_post = (name + ".assign(" + api_name + ", " + api_name + " + " +360 api_name_n + "); " + ns + "Free(" + api_name + ");\n")361 a.python_pre = api_name + ", " + api_name_n + " = POINTER(c_int)(), c_size_t()"362 a.python_arg = "byref(" + api_name + "), byref(" + api_name_n + ")"363 a.python_return = "_ovectorint(" + api_name + ", " + api_name_n + ".value)"364 a.julia_ctype = "Ptr{Ptr{Cint}}, Ptr{Csize_t}"365 a.julia_pre = (api_name + " = Ref{Ptr{Cint}}()\n " +366 api_name_n + " = Ref{Csize_t}()")367 a.julia_arg = api_name + ", " + api_name_n368 a.julia_post = (name + " = unsafe_wrap(Array, " + api_name + "[], " +369 api_name_n + "[], own=true)")370 return a371def ovectorsize(name, value=None, python_value=None, julia_value=None):372 a = arg(name, value, python_value, julia_value,373 "std::vector<std::size_t> &", "size_t **", True)374 api_name = "api_" + name + "_"375 api_name_n = api_name + "n_"376 a.c_pre = " std::vector<std::size_t> " + api_name + ";\n"377 a.c_arg = api_name378 a.c_post = " vector2ptr(" + api_name + ", " + name + ", " + name + "_n);\n"379 a.c = "size_t ** " + name + ", size_t * " + name + "_n"380 a.cwrap_pre = "size_t *" + api_name + "; size_t " + api_name_n + ";\n"381 a.cwrap_arg = "&" + api_name + ", " + "&" + api_name_n382 a.cwrap_post = (name + ".assign(" + api_name + ", " + api_name + " + " +383 api_name_n + "); " + ns + "Free(" + api_name + ");\n")384 a.python_pre = api_name + ", " + api_name_n + " = POINTER(c_size_t)(), c_size_t()"385 a.python_arg = "byref(" + api_name + "), byref(" + api_name_n + ")"386 a.python_return = "_ovectorsize(" + api_name + ", " + api_name_n + ".value)"387 a.julia_ctype = "Ptr{Ptr{Csize_t}}, Ptr{Csize_t}"388 a.julia_pre = (api_name + " = Ref{Ptr{Csize_t}}()\n " +389 api_name_n + " = Ref{Csize_t}()")390 a.julia_arg = api_name + ", " + api_name_n391 a.julia_post = (name + " = unsafe_wrap(Array, " + api_name + "[], " +392 api_name_n + "[], own=true)")393 return a394def ovectordouble(name, value=None, python_value=None, julia_value=None):395 a = arg(name, value, python_value, julia_value,396 "std::vector<double> &", "double *", True)397 api_name = "api_" + name + "_"398 api_name_n = api_name + "n_"399 a.c_pre = " std::vector<double> " + api_name + ";\n"400 a.c_arg = api_name401 a.c_post = " vector2ptr(" + api_name + ", " + name + ", " + name + "_n);\n"402 a.c = "double ** " + name + ", size_t * " + name + "_n"403 a.cwrap_pre = "double *" + api_name + "; size_t " + api_name_n + ";\n"404 a.cwrap_arg = "&" + api_name + ", " + "&" + api_name_n405 a.cwrap_post = (name + ".assign(" + api_name + ", " + api_name + " + " +406 api_name_n + "); " + ns + "Free(" + api_name + ");\n")407 a.python_pre = api_name + ", " + api_name_n + " = POINTER(c_double)(), c_size_t()"408 a.python_arg = "byref(" + api_name + "), byref(" + api_name_n + ")"409 a.python_return = "_ovectordouble(" + api_name + ", " + api_name_n + ".value)"410 a.julia_ctype = "Ptr{Ptr{Cdouble}}, Ptr{Csize_t}"411 a.julia_pre = (api_name + " = Ref{Ptr{Cdouble}}()\n " +412 api_name_n + " = Ref{Csize_t}()")413 a.julia_arg = api_name + ", " + api_name_n414 a.julia_post = (name + " = unsafe_wrap(Array, " + api_name + "[], " +415 api_name_n + "[], own=true)")416 return a417def ovectorstring(name, value=None, python_value=None, julia_value=None):418 a = arg(name, value, python_value, julia_value,419 "std::vector<std::string> &", "char **", True)420 api_name = "api_" + name + "_"421 api_name_n = api_name + "n_"422 a.c_pre = " std::vector<std::string> " + api_name + ";\n"423 a.c_arg = api_name424 a.c_post = (" vectorstring2charptrptr(" + api_name + ", " + name + ", " +425 name + "_n);\n")426 a.c = "char *** " + name + ", size_t * " + name + "_n"427 a.cwrap_pre = "char **" + api_name + "; size_t " + api_name_n + ";\n"428 a.cwrap_arg = "&" + api_name + ", " + "&" + api_name_n429 a.cwrap_post = (name + ".resize(" + api_name_n + "); " +430 "for(size_t i = 0; i < " + api_name_n + "; ++i){ " +431 name + "[i] = std::string(" + api_name + "[i]); " +432 ns + "Free(" + api_name + "[i]); } " +433 ns + "Free(" + api_name + ");\n")434 a.python_pre = api_name + ", " + api_name_n + " = POINTER(POINTER(c_char))(), c_size_t()"435 a.python_arg = "byref(" + api_name + "), byref(" + api_name_n + ")"436 a.python_return = "_ovectorstring(" + api_name + ", " + api_name_n + ".value)"437 a.julia_ctype = "Ptr{Ptr{Ptr{Cchar}}}, Ptr{Csize_t}"438 a.julia_pre = (api_name + " = Ref{Ptr{Ptr{Cchar}}}()\n " +439 api_name_n + " = Ref{Csize_t}()")440 a.julia_arg = api_name + ", " + api_name_n441 a.julia_post = ("tmp_" + api_name + " = unsafe_wrap(Array, " + api_name + "[], " +442 api_name_n + "[], own=true)\n " +443 name + " = [unsafe_string(tmp_" + api_name + "[i]) for i in 1:length(tmp_" +444 api_name + ") ]")445 return a446def ovectorpair(name, value=None, python_value=None, julia_value=None):447 a = arg(name, value, python_value, julia_value,448 ns + "::vectorpair &", "int **", True)449 api_name = "api_" + name + "_"450 api_name_n = api_name + "n_"451 a.c_pre = " " + ns + "::vectorpair " + api_name + ";\n"452 a.c_arg = api_name453 a.c_post = " vectorpair2intptr(" + api_name + ", " + name + ", " + name + "_n);\n"454 a.c = "int ** " + name + ", size_t * " + name + "_n"455 a.cwrap_pre = "int *" + api_name + "; size_t " + api_name_n + ";\n"456 a.cwrap_arg = "&" + api_name + ", " + "&" + api_name_n457 a.cwrap_post = (name + ".resize(" + api_name_n + " / 2); " +458 "for(size_t i = 0; i < " + api_name_n + " / 2; ++i){ " +459 name + "[i].first = " + api_name + "[i * 2 + 0]; " +460 name + "[i].second = " + api_name + "[i * 2 + 1]; } " +461 ns + "Free(" + api_name + ");\n")462 a.python_pre = api_name + ", " + api_name_n + " = POINTER(c_int)(), c_size_t()"463 a.python_arg = "byref(" + api_name + "), byref(" + api_name_n + ")"464 a.python_return = "_ovectorpair(" + api_name + ", " + api_name_n + ".value)"465 a.julia_ctype = "Ptr{Ptr{Cint}}, Ptr{Csize_t}"466 a.julia_pre = (api_name + " = Ref{Ptr{Cint}}()\n " +467 api_name_n + " = Ref{Csize_t}()")468 a.julia_arg = api_name + ", " + api_name_n469 a.julia_post = ("tmp_" + api_name + " = unsafe_wrap(Array, " + api_name + "[], " +470 api_name_n + "[], own=true)\n " +471 name + " = [ (tmp_" + api_name + "[i], tmp_" + api_name + "[i+1]) " +472 "for i in 1:2:length(tmp_" + api_name + ") ]")473 return a474def ovectorvectorint(name, value=None, python_value=None, julia_value=None):475 a = arg(name, value, python_value, julia_value,476 "std::vector<std::vector<int> > &", "int **", True)477 api_name = "api_" + name + "_"478 api_name_n = api_name + "n_"479 api_name_nn = api_name + "nn_"480 a.c_pre = " std::vector<std::vector<int> > " + api_name + ";\n"481 a.c_arg = api_name482 a.c_post = (" vectorvector2ptrptr(" + api_name + ", " + name + ", " +483 name + "_n, " + name + "_nn);\n")484 a.c = "int *** " + name + ", size_t ** " + name + "_n, size_t *" + name + "_nn"485 a.cwrap_pre = "int **" + api_name + "; size_t *" + api_name_n + ", " + api_name_nn + ";\n"486 a.cwrap_arg = "&" + api_name + ", " + "&" + api_name_n + ", " + "&" + api_name_nn487 a.cwrap_post = (name + ".resize(" + api_name_nn + "); " +488 "for(size_t i = 0; i < " + api_name_nn + "; ++i){ " +489 name + "[i].assign(" + api_name + "[i], " + api_name + "[i] + " +490 api_name_n + "[i]); " + ns + "Free(" + api_name + "[i]); } " +491 ns + "Free(" + api_name + "); " + ns + "Free(" + api_name_n + ");\n")492 a.python_pre = (api_name + ", " + api_name_n + ", " + api_name_nn +493 " = POINTER(POINTER(c_int))(), POINTER(c_size_t)(), c_size_t()")494 a.python_arg = ("byref(" + api_name + "), byref(" + api_name_n + "), byref(" +495 api_name_nn + ")")496 a.python_return = ("_ovectorvectorint(" + api_name + ", " + api_name_n + ", " +497 api_name_nn + ")")498 a.julia_ctype = "Ptr{Ptr{Ptr{Cint}}}, Ptr{Ptr{Csize_t}}, Ptr{Csize_t}"499 a.julia_pre = (api_name + " = Ref{Ptr{Ptr{Cint}}}()\n " +500 api_name_n + " = Ref{Ptr{Csize_t}}()\n " +501 api_name_nn + " = Ref{Csize_t}()")502 a.julia_arg = api_name + ", " + api_name_n + ", " + api_name_nn503 a.julia_post = ("tmp_" + api_name + " = unsafe_wrap(Array, " + api_name + "[], " +504 api_name_nn + "[], own=true)\n " +505 "tmp_" + api_name_n + " = unsafe_wrap(Array, " + api_name_n + "[], " +506 api_name_nn + "[], own=true)\n " +507 name + " = [ unsafe_wrap(Array, tmp_" + api_name + "[i], " +508 "tmp_" + api_name_n + "[i], own=true) for i in 1:" +509 api_name_nn + "[] ]")510 return a511def ovectorvectorsize(name, value=None, python_value=None, julia_value=None):512 a = arg(name, value, python_value, julia_value,513 "std::vector<std::vector<std::size_t> > &", "size_t **", True)514 api_name = "api_" + name + "_"515 api_name_n = api_name + "n_"516 api_name_nn = api_name + "nn_"517 a.c_pre = " std::vector<std::vector<std::size_t> > " + api_name + ";\n"518 a.c_arg = api_name519 a.c_post = (" vectorvector2ptrptr(" + api_name + ", " + name + ", " +520 name + "_n, " + name + "_nn);\n")521 a.c = "size_t *** " + name + ", size_t ** " + name + "_n, size_t *" + name + "_nn"522 a.cwrap_pre = "size_t **" + api_name + "; size_t *" + api_name_n + ", " + api_name_nn + ";\n"523 a.cwrap_arg = "&" + api_name + ", " + "&" + api_name_n + ", " + "&" + api_name_nn524 a.cwrap_post = (name + ".resize(" + api_name_nn + "); " +525 "for(size_t i = 0; i < " + api_name_nn + "; ++i){ " +526 name + "[i].assign(" + api_name + "[i], " + api_name + "[i] + " +527 api_name_n + "[i]); " + ns + "Free(" + api_name + "[i]); } " +528 ns + "Free(" + api_name + "); " + ns + "Free(" + api_name_n + ");\n")529 a.python_pre = (api_name + ", " + api_name_n + ", " + api_name_nn +530 " = POINTER(POINTER(c_size_t))(), POINTER(c_size_t)(), c_size_t()")531 a.python_arg = ("byref(" + api_name + "), byref(" + api_name_n + "), byref(" +532 api_name_nn + ")")533 a.python_return = ("_ovectorvectorsize(" + api_name + ", " + api_name_n + ", " +534 api_name_nn + ")")535 a.julia_ctype = "Ptr{Ptr{Ptr{Csize_t}}}, Ptr{Ptr{Csize_t}}, Ptr{Csize_t}"536 a.julia_pre = (api_name + " = Ref{Ptr{Ptr{Csize_t}}}()\n " +537 api_name_n + " = Ref{Ptr{Csize_t}}()\n " +538 api_name_nn + " = Ref{Csize_t}()")539 a.julia_arg = api_name + ", " + api_name_n + ", " + api_name_nn540 a.julia_post = ("tmp_" + api_name + " = unsafe_wrap(Array, " + api_name + "[], " +541 api_name_nn + "[], own=true)\n " +542 "tmp_" + api_name_n + " = unsafe_wrap(Array, " + api_name_n + "[], " +543 api_name_nn + "[], own=true)\n " +544 name + " = [ unsafe_wrap(Array, tmp_" + api_name + "[i], " +545 "tmp_" + api_name_n + "[i], own=true) for i in 1:" +546 api_name_nn + "[] ]")547 return a548def ovectorvectordouble(name, value=None, python_value=None, julia_value=None):549 a = arg(name, value, python_value, julia_value,550 "std::vector<std::vector<double> > &", "double **", True)551 api_name = "api_" + name + "_"552 api_name_n = api_name + "n_"553 api_name_nn = api_name + "nn_"554 a.c_pre = " std::vector<std::vector<double> > " + api_name + ";\n"555 a.c_arg = api_name556 a.c_post = (" vectorvector2ptrptr(" + api_name + ", " + name + ", " + name +557 "_n, " + name + "_nn);\n")558 a.c = "double *** " + name + ", size_t ** " + name + "_n, size_t *" + name + "_nn"559 a.cwrap_pre = ("double **" + api_name + "; size_t *" + api_name_n + ", " +560 api_name_nn + ";\n")561 a.cwrap_arg = "&" + api_name + ", " + "&" + api_name_n + ", " + "&" + api_name_nn562 a.cwrap_post = (name + ".resize(" + api_name_nn + "); " +563 "for(size_t i = 0; i < " + api_name_nn + "; ++i){ " +564 name + "[i].assign(" + api_name + "[i], " + api_name + "[i] + " +565 api_name_n + "[i]); " + ns + "Free(" + api_name + "[i]); } " +566 ns + "Free(" + api_name + "); " + ns + "Free(" + api_name_n + ");\n")567 a.python_pre = (api_name + ", " + api_name_n + ", " + api_name_nn +568 " = POINTER(POINTER(c_double))(), POINTER(c_size_t)(), c_size_t()")569 a.python_arg = ("byref(" + api_name + "), byref(" + api_name_n + "), byref(" +570 api_name_nn + ")")571 a.python_return = ("_ovectorvectordouble(" + api_name + ", " + api_name_n + ", " +572 api_name_nn + ")")573 a.julia_ctype = "Ptr{Ptr{Ptr{Cdouble}}}, Ptr{Ptr{Csize_t}}, Ptr{Csize_t}"574 a.julia_pre = (api_name + " = Ref{Ptr{Ptr{Cdouble}}}()\n " +575 api_name_n + " = Ref{Ptr{Csize_t}}()\n " +576 api_name_nn + " = Ref{Csize_t}()")577 a.julia_arg = api_name + ", " + api_name_n + ", " + api_name_nn578 a.julia_post = ("tmp_" + api_name + " = unsafe_wrap(Array, " + api_name + "[], " +579 api_name_nn + "[], own=true)\n " +580 "tmp_" + api_name_n + " = unsafe_wrap(Array, " + api_name_n + "[], " +581 api_name_nn + "[], own=true)\n " +582 name + " = [ unsafe_wrap(Array, tmp_" + api_name + "[i], " +583 "tmp_" + api_name_n + "[i], own=true) for i in 1:" +584 api_name_nn + "[] ]")585 return a586def ovectorvectorpair(name, value=None, python_value=None, julia_value=None):587 a = arg(name, value, python_value, julia_value,588 "std::vector<" + ns + "::vectorpair> &", "int **", True)589 api_name = "api_" + name + "_"590 api_name_n = api_name + "n_"591 api_name_nn = api_name + "nn_"592 a.c_pre = " std::vector<" + ns + "::vectorpair >" + api_name + ";\n"593 a.c_arg = api_name594 a.c_post = (" vectorvectorpair2intptrptr(" + api_name + ", " + name +595 ", " + name + "_n, " + name + "_nn);\n")596 a.c = "int *** " + name + ", size_t ** " + name + "_n, size_t *" + name + "_nn"597 a.cwrap_pre = "int **" + api_name + "; size_t *" + api_name_n + ", " + api_name_nn + ";\n"598 a.cwrap_arg = "&" + api_name + ", " + "&" + api_name_n + ", " + "&" + api_name_nn599 a.cwrap_post = (name + ".resize(" + api_name_nn + "); " +600 "for(size_t i = 0; i < " + api_name_nn + "; ++i){ " +601 name + "[i].resize(" + api_name_n + "[i] / 2); " +602 "for(size_t j = 0; j < " + api_name_n + "[i] / 2; ++j){ " +603 name + "[i][j].first = " + api_name + "[i][j * 2 + 0]; " +604 name + "[i][j].second = " + api_name + "[i][j * 2 + 1]; } " +605 ns + "Free(" + api_name + "[i]); } " +606 ns + "Free(" + api_name + "); " + ns + "Free(" + api_name_n + ");\n")607 a.python_pre = (api_name + ", " + api_name_n + ", " + api_name_nn +608 " = POINTER(POINTER(c_int))(), POINTER(c_size_t)(), c_size_t()")609 a.python_arg = ("byref(" + api_name + "), byref(" + api_name_n + "), byref(" +610 api_name_nn + ")")611 a.python_return = ("_ovectorvectorpair(" + api_name + ", " + api_name_n + ", " +612 api_name_nn + ")")613 a.julia_ctype = "Ptr{Ptr{Ptr{Cint}}}, Ptr{Ptr{Csize_t}}, Ptr{Csize_t}"614 a.julia_pre = (api_name + " = Ref{Ptr{Ptr{Cint}}}()\n " +615 api_name_n + " = Ref{Ptr{Csize_t}}()\n " +616 api_name_nn + " = Ref{Csize_t}()")617 a.julia_arg = api_name + ", " + api_name_n + ", " + api_name_nn618 a.julia_post = ("tmp_" + api_name + " = unsafe_wrap(Array, " + api_name + "[], " +619 api_name_nn + "[], own=true)\n " +620 "tmp_" + api_name_n + " = unsafe_wrap(Array, " + api_name_n + "[], " +621 api_name_nn + "[], own=true)\n " +622 name + " = Vector{Tuple{Cint,Cint}}[]\n " +623 "resize!(" + name + ", " + api_name_nn + "[])\n " +624 "for i in 1:" + api_name_nn + "[]\n " +625 " tmp = unsafe_wrap(Array, tmp_" + api_name + "[i], tmp_" +626 api_name_n + "[i], own=true)\n " +627 " " + name + "[i] = [(tmp[i], tmp[i+1]) for i in 1:2:length(tmp)]\n " +628 "end")629 return a630def argcargv():631 a = arg("", None, None, None, "", "", False)632 a.cpp = "int argc = 0, char ** argv = 0"633 a.c_arg = "argc, argv"634 a.c = "int argc, char ** argv"635 a.c_pre = ""636 a.c_post = ""637 a.cwrap_arg = "argc, argv"638 a.name = "argv"639 a.python_value = "[]"640 a.julia_value = "Vector{String}()"641 a.python_arg = "api_argc_, api_argv_"642 a.python_pre = "api_argc_, api_argv_ = _iargcargv(argv)"643 a.julia_ctype = "Cint, Ptr{Ptr{Cchar}}"644 a.julia_arg = "length(argv), argv"645 return a646class Module:647 def __init__(self, name, doc):648 self.name = name649 self.doc = doc650 self.fs = []651 self.submodules = []652 def add(self, name, doc, rtype, *args):653 self.fs.append((rtype, name, args, doc, []))654 def add_special(self, name, doc, special, rtype, *args):655 self.fs.append((rtype, name, args, doc, special))656 def add_module(self, name, doc):657 module = Module(name, doc)658 self.submodules.append(module)659 return module660cpp_header="""// {0}661//662// See the LICENSE.txt file for license information. Please report all663// issues on {1}664#ifndef {2}_H665#define {2}_H666// This file defines the {3} C++ API (v{4}.{5}).667//668// Do not edit it directly: it is automatically generated by `api/gen.py'.669//670// By design, the {3} C++ API is purely functional, and only uses elementary671// types from the standard library. See `demos/api' for examples.672#if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)673#define _USE_MATH_DEFINES674#endif675#include <cmath>676#include <vector>677#include <string>678#include <utility>679#define {2}_API_VERSION "{4}.{5}"680#define {2}_API_VERSION_MAJOR {4}681#define {2}_API_VERSION_MINOR {5}682#if defined({2}_DLL)683#if defined({2}_DLL_EXPORT)684#define {2}_API __declspec(dllexport)685#else686#define {2}_API __declspec(dllimport)687#endif688#else689#define {2}_API690#endif691namespace {6} {{692 // A geometrical entity in the {3} API is represented by two integers: its693 // dimension (dim = 0, 1, 2 or 3) and its tag (its unique, strictly positive694 // identifier). When dealing with multiple geometrical entities of possibly695 // different dimensions, the entities are packed as a vector of (dim, tag)696 // integer pairs.697 typedef std::vector<std::pair<int, int> > vectorpair;698}}699"""700cpp_footer="""#endif701"""702c_header="""/*703 * {0}704 *705 * See the LICENSE.txt file for license information. Please report all706 * issues on {1}707 */708#ifndef {2}C_H709#define {2}C_H710/*711 * This file defines the {3} C API (v{4}.{5}).712 *713 * Do not edit it directly: it is automatically generated by `api/gen.py'.714 *715 * By design, the {3} C API is purely functional, and only uses elementary716 * types. See `demos/api' for examples.717 */718#include <stddef.h>719#define {2}_API_VERSION "{4}.{5}"720#define {2}_API_VERSION_MAJOR {4}721#define {2}_API_VERSION_MINOR {5}722#if defined({2}_DLL)723#if defined({2}_DLL_EXPORT)724#define {2}_API __declspec(dllexport)725#else726#define {2}_API __declspec(dllimport)727#endif728#else729#define {2}_API730#endif731{2}_API void {6}Free(void *p);732{2}_API void *{6}Malloc(size_t n);733"""734c_footer="""735#endif736"""737c_cpp_header="""// {0}738//739// See the LICENSE.txt file for license information. Please report all740// issues on {1}741#include <string.h>742#include <stdlib.h>743#include "{2}.h"744extern \"C\" {{745 #include "{2}c.h"746}}747{3}_API void *{2}Malloc(size_t n)748{{749 return malloc(n);750}}751{3}_API void {2}Free(void *p)752{{753 if(p) free(p);754}}755"""756c_cpp_utils="""757void vectorvectorpair2intptrptr(const std::vector<{0}::vectorpair > &v, int ***p, size_t **size, size_t *sizeSize)758{{759 *p = (int**){0}Malloc(sizeof(int*) * v.size());760 *size = (size_t*){0}Malloc(sizeof(size_t) * v.size());761 for(size_t i = 0; i < v.size(); ++i)762 vectorpair2intptr(v[i], &(*p)[i], &((*size)[i]));763 *sizeSize = v.size();764}}765"""766cwrap_header="""// {0}767//768// See the LICENSE.txt file for license information. Please report all769// issues on {1}770#ifndef {2}_H771#define {2}_H772// This file redefines the {3} C++ API in terms of the C API (v{4}.{5}).773//774// This is provided as a convenience for users of the binary {3} SDK whose C++775// compiler ABI is not compatible with the ABI of the C++ compiler used to create776// the SDK (and who can thus not directly use the C++ API defined in `{6}.h').777//778// To use this header file in your C++ code, simply rename it as `{6}.h'.779//780// Note that using this header file will lead to (slightly) reduced performance781// compared to using the native {3} C++ API from the original `{6}.h', as it782// entails additional data copies between this C++ wrapper, the C API and the783// native C++ code.784//785// Do not edit this file directly: it is automatically generated by `api/gen.py'.786#if defined(_MSC_VER) && !defined(_USE_MATH_DEFINES)787#define _USE_MATH_DEFINES788#endif789#include <cmath>790#include <vector>791#include <string>792#include <utility>793#include <string.h>794extern \"C\" {{795 #include "{6}c.h"796}}797namespace {6} {{798 // A geometrical entity in the {3} API is represented by two integers: its799 // dimension (dim = 0, 1, 2 or 3) and its tag (its unique, strictly positive800 // identifier). When dealing with multiple geometrical entities of possibly801 // different dimensions, the entities are packed as a vector of (dim, tag)802 // integer pairs.803 typedef std::vector<std::pair<int, int> > vectorpair;804}}805"""806cwrap_utils="""807template<typename t>808{1}void vector2ptr(const std::vector<t> &v, t **p, size_t *size)809{{810 *p = (t*){0}Malloc(sizeof(t) * v.size());811 for(size_t i = 0; i < v.size(); ++i){{812 (*p)[i] = v[i];813 }}814 *size = v.size();815}}816{1}void vectorpair2intptr(const {0}::vectorpair &v, int **p, size_t *size)817{{818 *p = (int*){0}Malloc(sizeof(int) * v.size() * 2);819 for(size_t i = 0; i < v.size(); ++i){{820 (*p)[i * 2 + 0] = v[i].first;821 (*p)[i * 2 + 1] = v[i].second;822 }}823 *size = v.size() * 2;824}}825{1}void vectorstring2charptrptr(const std::vector<std::string> &v, char ***p, size_t *size)826{{827 *p = (char**){0}Malloc(sizeof(char*) * v.size());828 for(size_t i = 0; i < v.size(); ++i){{829 (*p)[i] = strdup(v[i].c_str());830 }}831 *size = v.size();832}}833template<typename t>834{1}void vectorvector2ptrptr(const std::vector<std::vector<t> > &v, t ***p, size_t **size, size_t *sizeSize)835{{836 *p = (t**){0}Malloc(sizeof(t*) * v.size());837 *size = (size_t*){0}Malloc(sizeof(size_t) * v.size());838 for(size_t i = 0; i < v.size(); ++i)839 vector2ptr(v[i], &((*p)[i]), &((*size)[i]));840 *sizeSize = v.size();841}}842"""843cwrap_footer="""#endif844"""845python_header = """# {0}846#847# See the LICENSE.txt file for license information. Please report all848# issues on {1}849# This file defines the {2} Python API (v{3}.{4}).850#851# Do not edit it directly: it is automatically generated by `api/gen.py'.852#853# By design, the {2} Python API is purely functional, and only uses elementary854# types (as well as `numpy' arrays if `numpy' is avaiable). See `demos/api' for855# examples.856from ctypes import *857from ctypes.util import find_library858import signal859import os860import platform861from math import pi862{5}_API_VERSION = "{3}.{4}"863{5}_API_VERSION_MAJOR = {3}864{5}_API_VERSION_MINOR = {4}865__version__ = {5}_API_VERSION866signal.signal(signal.SIGINT, signal.SIG_DFL)867libdir = os.path.dirname(os.path.realpath(__file__))868if platform.system() == "Windows":869 libpath = os.path.join(libdir, "{6}-{3}.{4}.dll")870elif platform.system() == "Darwin":871 libpath = os.path.join(libdir, "lib{6}.dylib")872else:873 libpath = os.path.join(libdir, "lib{6}.so")874if not os.path.exists(libpath):875 libpath = find_library("{6}")876lib = CDLL(libpath)877use_numpy = False878try:879 import numpy880 try:881 from weakref import finalize as weakreffinalize882 except:883 from backports.weakref import finalize as weakreffinalize884 use_numpy = True885except:886 pass887# Utility functions, not part of the Gmsh Python API888def _ostring(s):889 sp = s.value.decode("utf-8")890 lib.{6}Free(s)891 return sp892def _ovectorpair(ptr, size):893 v = list((ptr[i * 2], ptr[i * 2 + 1]) for i in range(size//2))894 lib.{6}Free(ptr)895 return v896def _ovectorint(ptr, size):897 if use_numpy:898 v = numpy.ctypeslib.as_array(ptr, (size, ))899 weakreffinalize(v, lib.{6}Free, ptr)900 else:901 v = list(ptr[i] for i in range(size))902 lib.{6}Free(ptr)903 return v904def _ovectorsize(ptr, size):905 if use_numpy:906 v = numpy.ctypeslib.as_array(ptr, (size, ))907 weakreffinalize(v, lib.{6}Free, ptr)908 else:909 v = list(ptr[i] for i in range(size))910 lib.{6}Free(ptr)911 return v912def _ovectordouble(ptr, size):913 if use_numpy:914 v = numpy.ctypeslib.as_array(ptr, (size, ))915 weakreffinalize(v, lib.{6}Free, ptr)916 else:917 v = list(ptr[i] for i in range(size))918 lib.{6}Free(ptr)919 return v920def _ovectorstring(ptr, size):921 v = list(_ostring(cast(ptr[i], c_char_p)) for i in range(size))922 lib.{6}Free(ptr)923 return v924def _ovectorvectorint(ptr, size, n):925 v = [_ovectorint(pointer(ptr[i].contents), size[i]) for i in range(n.value)]926 lib.{6}Free(size)927 lib.{6}Free(ptr)928 return v929def _ovectorvectorsize(ptr, size, n):930 v = [_ovectorsize(pointer(ptr[i].contents), size[i]) for i in range(n.value)]931 lib.{6}Free(size)932 lib.{6}Free(ptr)933 return v934def _ovectorvectordouble(ptr, size, n):935 v = [_ovectordouble(pointer(ptr[i].contents), size[i]) for i in range(n.value)]936 lib.{6}Free(size)937 lib.{6}Free(ptr)938 return v939def _ovectorvectorpair(ptr, size, n):940 v = [_ovectorpair(pointer(ptr[i].contents), size[i]) for i in range(n.value)]941 lib.{6}Free(size)942 lib.{6}Free(ptr)943 return v944def _ivectorint(o):945 if use_numpy:946 return numpy.ascontiguousarray(o, numpy.int32).ctypes, c_size_t(len(o))947 else:948 return (c_int * len(o))(*o), c_size_t(len(o))949def _ivectorsize(o):950 if use_numpy:951 return numpy.ascontiguousarray(o, numpy.uintp).ctypes, c_size_t(len(o))952 else:953 return (c_size_t * len(o))(*o), c_size_t(len(o))954def _ivectordouble(o):955 if use_numpy:956 array = numpy.ascontiguousarray(o, numpy.float64)957 ct = array.ctypes958 ct.array = array959 return ct, c_size_t(len(o))960 else:961 return (c_double * len(o))(*o), c_size_t(len(o))962def _ivectorpair(o):963 if use_numpy:964 array = numpy.ascontiguousarray(o, numpy.int32)965 ct = array.ctypes966 ct.array = array967 return ct, c_size_t(len(o) * 2)968 else:969 return ((c_int * 2) * len(o))(*o), c_size_t(len(o) * 2)970def _ivectorstring(o):971 return (c_char_p * len(o))(*(s.encode() for s in o)), c_size_t(len(o))972def _ivectorvectorint(os):973 n = len(os)974 parrays = [_ivectorint(o) for o in os]975 sizes = (c_size_t * n)(*(a[1] for a in parrays))976 arrays = (POINTER(c_int) * n)(*(cast(a[0], POINTER(c_int)) for a in parrays))977 arrays.ref = [a[0] for a in parrays]978 size = c_size_t(n)979 return arrays, sizes, size980def _ivectorvectorsize(os):981 n = len(os)982 parrays = [_ivectorsize(o) for o in os]983 sizes = (c_size_t * n)(*(a[1] for a in parrays))984 arrays = (POINTER(c_size_t) * n)(*(cast(a[0], POINTER(c_size_t)) for a in parrays))985 arrays.ref = [a[0] for a in parrays]986 size = c_size_t(n)987 return arrays, sizes, size988def _ivectorvectordouble(os):989 n = len(os)990 parrays = [_ivectordouble(o) for o in os]991 sizes = (c_size_t * n)(*(a[1] for a in parrays))992 arrays = (POINTER(c_double) * n)(*(cast(a[0], POINTER(c_double)) for a in parrays))993 arrays.ref = [a[0] for a in parrays]994 size = c_size_t(n)995 return arrays, sizes, size996def _iargcargv(o):997 return c_int(len(o)), (c_char_p * len(o))(*(s.encode() for s in o))998# Gmsh Python API begins here999"""1000julia_header = """# {0}1001#1002# See the LICENSE.txt file for license information. Please report all1003# issues on {1}1004# This file defines the {2} Julia API (v{3}.{4}).1005#1006# Do not edit it directly: it is automatically generated by `api/gen.py'.1007#1008# By design, the {2} Julia API is purely functional, and only uses elementary1009# types. See `demos/api' for examples.1010"""1011def capi(s): return s[:1].upper() + s[1:]1012class API:1013 def __init__(self, version_major, version_minor, namespace="gmsh", code="Gmsh",1014 copyright="Gmsh - Copyright (C) 1997-2019 C. Geuzaine, J.-F. Remacle",1015 issues="https://gitlab.onelab.info/gmsh/gmsh/issues."):1016 self.version_major = version_major1017 self.version_minor = version_minor1018 global ns1019 ns = namespace1020 self.code = code1021 self.copyright = copyright1022 self.issues = issues1023 self.modules = []1024 def add_module(self, name, doc):1025 module = Module(name, doc)1026 self.modules.append(module)1027 return module1028 def write_cpp(self):1029 def write_module(module, indent):1030 f.write(indent + "namespace " + module.name + " { // " +1031 capi(module.doc) + "\n\n")1032 indent += " "1033 for rtype, name, args, doc, special in module.fs:1034 f.write(indent + "// " + ("\n" + indent + "// ").join(1035 textwrap.wrap(doc, 80-len(indent))) + "\n")1036 rt = rtype.rcpp_type if rtype else "void"1037 fnameapi = indent + ns.upper() + "_API " + rt + " " + name + "(";1038 f.write(fnameapi)1039 if args:1040 f.write((",\n" + ' ' * len(fnameapi)).join(a.cpp for a in args))1041 f.write(");\n\n")1042 for m in module.submodules:1043 write_module(m, indent)1044 f.write(indent[:-2] + "} // namespace " + module.name + "\n\n")1045 with open(ns + ".h", "w") as f:1046 f.write(cpp_header.format(self.copyright, self.issues, ns.upper(), self.code,1047 self.version_major, self.version_minor, ns))1048 for m in self.modules:1049 write_module(m, "")1050 f.write(cpp_footer)1051 def write_c(self):1052 def write_module(module, c_namespace, cpp_namespace, indent):1053 cpp_namespace += module.name + "::"1054 if c_namespace:1055 c_namespace += module.name[0].upper() + module.name[1:]1056 else:1057 c_namespace = module.name1058 fcwrap.write(indent + "namespace " + module.name + " { // " +1059 capi(module.doc) + "\n\n")1060 indent += " "1061 for rtype, name, args, doc, special in module.fs:1062 # *c.h1063 fname = c_namespace + name[0].upper() + name[1:]1064 f.write("\n/* " + "\n * ".join(textwrap.wrap(doc, 75)) + " */\n")1065 fnameapi = ns.upper() + "_API " + (rtype.rc_type if rtype else "void") + " " + fname + "("1066 f.write(fnameapi1067 + (",\n" + ' ' * len(fnameapi)).join(1068 list((a.c for a in args + (oint("ierr"), ))))1069 + ");\n")1070 if "rawc" not in special:1071 # *c.cpp1072 fc.write(ns.upper() + "_API " + (rtype.rc_type if rtype else "void"))1073 fc.write(" " + fname + "(" +1074 ", ".join(list((a.c for a in args + (oint("ierr"), )))) +1075 ")\n{\n")1076 if rtype:1077 fc.write(" " + rtype.rc_type + " result_api_ = 0;\n")1078 fc.write(" if(ierr) *ierr = 0;\n");1079 fc.write(" try {\n");1080 fc.write("".join((a.c_pre for a in args)))1081 fc.write(" ")1082 if rtype:1083 fc.write("result_api_ = ")1084 fc.write(cpp_namespace + name + "(" + ", ".join(1085 list((a.c_arg for a in args))) +1086 ");\n")1087 fc.write("".join((a.c_post for a in args)))1088 fc.write(" }\n catch(int api_ierr_){\n " +1089 "if(ierr) *ierr = api_ierr_;\n }\n");1090 if rtype:1091 fc.write(" return result_api_;\n");1092 fc.write("}\n\n")1093 # *.h_cwrap1094 fcwrap.write(indent + "// " + ("\n" + indent + "// ").join1095 (textwrap.wrap(doc, 80-len(indent))) + "\n")1096 rt = rtype.rcpp_type if rtype else "void"1097 fnameapi = indent + "inline " + rt + " " + name + "(";1098 fcwrap.write(fnameapi)1099 if args:1100 fcwrap.write((",\n" + ' ' * len(fnameapi)).join(a.cpp for a in args))1101 fcwrap.write(")\n" + indent + "{\n" + indent + " int ierr = 0;\n")1102 for a in args:1103 if a.cwrap_pre:1104 fcwrap.write(indent + " " + a.cwrap_pre)1105 fcwrap.write(indent + " ")1106 if rtype:1107 fcwrap.write(rt + " result_api_ = ")1108 fcwrap.write(fname + "(" + ", ".join((a.cwrap_arg for a in args)))1109 if args:1110 fcwrap.write(", &ierr);\n")1111 else:1112 fcwrap.write("&ierr);\n")1113 fcwrap.write(indent + " " + "if(ierr) throw ierr;\n");1114 for a in args:1115 if a.cwrap_post:1116 fcwrap.write(indent + " " + a.cwrap_post)1117 if rtype:1118 fcwrap.write(indent + " " + "return result_api_;\n")1119 fcwrap.write(indent + "}\n\n")1120 for m in module.submodules:1121 write_module(m, c_namespace, cpp_namespace, indent)1122 fcwrap.write(indent[:-2] + "} // namespace " + module.name + "\n\n")1123 with open(ns + "c.h", "w") as f:1124 with open(ns + "c.cpp", "w") as fc:1125 with open(ns + ".h_cwrap", "w") as fcwrap:1126 f.write(c_header.format(self.copyright, self.issues, ns.upper(),1127 self.code, self.version_major,1128 self.version_minor, ns))1129 fc.write(c_cpp_header.format(self.copyright, self.issues, ns,1130 ns.upper()))1131 fc.write(cwrap_utils.format(ns, ""))1132 fc.write(c_cpp_utils.format(ns))1133 fc.write("\n")1134 fcwrap.write(cwrap_header.format(self.copyright, self.issues,1135 ns.upper(), self.code,1136 self.version_major,1137 self.version_minor, ns))1138 fcwrap.write("namespace " + ns + " {\n")1139 s = cwrap_utils.format(ns, "inline ").split('\n')1140 for line in s:1141 fcwrap.write(" " + line + "\n")1142 fcwrap.write("}\n\n")1143 for module in self.modules:1144 write_module(module, "", "", "")1145 f.write(c_footer)1146 fcwrap.write(cwrap_footer)1147 def write_python(self):1148 def parg(a):1149 return a.name + (("=" + a.python_value) if a.python_value else "")1150 def write_function(f, fun, modulepath, indent):1151 (rtype, name, args, doc, special) = fun1152 if "onlycc++" in special: return1153 iargs = list(a for a in args if not a.out)1154 oargs = list(a for a in args if a.out)1155 f.write("\n")1156 if modulepath != ns:1157 f.write(indent + "@staticmethod\n")1158 f.write(indent + "def " + name + "("1159 + ", ".join((parg(a) for a in iargs))1160 + "):\n")1161 indent += " "1162 f.write(indent + '"""\n')1163 f.write(indent + ("\n" + indent).join(textwrap.wrap(doc, 75)) + "\n")1164 if rtype or oargs:1165 f.write("\n" + indent + "Return " + ", ".join(1166 ([("an " if rtype.rtexi_type == "integer value" else "a ") +1167 rtype.rtexi_type] if rtype else[])1168 + [("`" + a.name + "'") for a in oargs])1169 + ".\n")1170 f.write(indent + '"""\n')1171 for a in args:1172 if a.python_pre: f.write(indent + a.python_pre + "\n")1173 f.write(indent + "ierr = c_int()\n")1174 f.write(indent + "api__result__ = " if ((rtype is oint) or (rtype is odouble)) else (indent))1175 c_name = modulepath + name[0].upper() + name[1:]1176 f.write("lib." + c_name + "(\n " + indent +1177 (",\n" + indent + " ").join(1178 tuple((a.python_arg for a in args)) + ("byref(ierr)", )) +1179 ")\n")1180 f.write(indent + "if ierr.value != 0:\n")1181 f.write(indent + " raise ValueError(\n")1182 f.write(indent + ' "' + c_name + ' returned non-zero error code: ",\n')1183 f.write(indent + " ierr.value)\n")1184 r = (["api__result__"]) if rtype else []1185 r += list((o.python_return for o in oargs))1186 if len(r) != 0:1187 if len(r) == 1:1188 f.write(indent + "return " + r[0] + "\n")1189 else:1190 f.write(indent + "return (\n" + indent + " " +1191 (",\n" + indent + " ").join(r) + ")\n")1192 def write_module(f, m, modulepath, indent):1193 if modulepath:1194 modulepath += m.name[0].upper() + m.name[1:]1195 else:1196 modulepath = m.name1197 for fun in m.fs:1198 write_function(f, fun, modulepath, indent)1199 for module in m.submodules:1200 f.write("\n\n" + indent + "class " + module.name + ":\n")1201 indentm = indent + " "1202 f.write(indentm + '"""\n')1203 f.write(indentm + ("\n" + indentm).join1204 (textwrap.wrap(capi(module.doc), 75)) + "\n")1205 f.write(indentm + '"""\n')1206 write_module(f, module, modulepath, indentm)1207 with open(ns + ".py", "w") as f:1208 f.write(python_header.format(self.copyright, self.issues, self.code,1209 self.version_major, self.version_minor,1210 ns.upper(), ns))1211 for module in self.modules:1212 write_module(f, module, "", "")1213 def write_julia(self):1214 def parg(a):1215 return a.name + ((" = " + a.julia_value) if a.julia_value else "")1216 def write_function(f, fun, c_mpath, jl_mpath):1217 (rtype, name, args, doc, special) = fun1218 if "onlycc++" in special: return1219 iargs = list(a for a in args if not a.out)1220 oargs = list(a for a in args if a.out)1221 f.write('\n"""\n ')1222 f.write(jl_mpath + name + "(" + ", ".join(parg(a) for a in iargs) + ")\n\n")1223 f.write("\n".join(textwrap.wrap(doc, 80)).replace("'", "`") + "\n")1224 if rtype or oargs:1225 f.write("\nReturn " + ", ".join(1226 ([("an " if rtype.rtexi_type == "integer value" else "a ") +1227 rtype.rtexi_type] if rtype else[])1228 + [("`" + a.name + "`") for a in oargs])1229 + ".\n")1230 f.write('"""\n')1231 f.write("function " + name + "("1232 + ", ".join((parg(a) for a in iargs))1233 + ")\n")1234 for a in args:1235 if a.julia_pre: f.write(" " + a.julia_pre + "\n")1236 f.write(" ierr = Ref{Cint}()\n ")1237 f.write("api__result__ = " if ((rtype is oint) or (rtype is odouble)) else "")1238 c_name = c_mpath + name[0].upper() + name[1:]1239 f.write("ccall((:" + c_name + ", " +1240 ("" if c_mpath == ns else ns + ".") + "lib), " +1241 ("Cvoid" if rtype is None else rtype.rjulia_type) + ",\n" +1242 " " * 10 + "(" + ", ".join(1243 (tuple(a.julia_ctype for a in args) + ("Ptr{Cint}",))) +1244 ("," if not len(args) else "") + "),\n" +1245 " " * 10 + ", ".join(1246 tuple(a.julia_arg for a in args) + ("ierr",)) + ")\n")1247 f.write(' ierr[] != 0 && error("' + c_name +1248 ' returned non-zero error code: $(ierr[])")\n')1249 for a in args:1250 if a.julia_post: f.write(" " + a.julia_post + "\n")1251 r = (["api__result__"]) if rtype else []1252 r += list((o.julia_return for o in oargs))1253 f.write(" return ")1254 if len(r) == 0:1255 f.write("nothing")1256 else:1257 f.write(", ".join(r))1258 f.write("\nend\n")1259 def write_module(f, m, c_mpath, jl_mpath, level):1260 f.write('\n"""\n ')1261 f.write("module " + jl_mpath + m.name + "\n\n")1262 f.write("\n".join(textwrap.wrap(capi(m.doc), 80)) + "\n")1263 f.write('"""\n')1264 f.write("module " + m.name + "\n\n")1265 if level == 1:1266 f.write('const {0}_API_VERSION = "{1}.{2}"\n'.1267 format(ns.upper(), self.version_major, self.version_minor))1268 f.write('const {0}_API_VERSION_MAJOR = {1}\n'.1269 format(ns.upper(), self.version_major))1270 f.write('const {0}_API_VERSION_MINOR = {1}\n'.1271 format(ns.upper(), self.version_minor))1272 f.write('const libdir = dirname(@__FILE__)\n')1273 f.write('const libname = Sys.iswindows() ? "' + ns +1274 '-{0}.{1}'.format(self.version_major, self.version_minor) +1275 '" : "lib' + ns + '"\n')1276 f.write('import Libdl\n')1277 f.write('const lib = Libdl.find_library([libname], [libdir])\n')1278 else:1279 f.write("import " + ("." * level) + ns + "\n")1280 if c_mpath:1281 c_mpath += m.name[0].upper() + m.name[1:]1282 jl_mpath += m.name + "."1283 else:1284 c_mpath = m.name1285 jl_mpath = m.name + "."1286 for fun in m.fs:1287 write_function(f, fun, c_mpath, jl_mpath)1288 for module in m.submodules:1289 write_module(f, module, c_mpath, jl_mpath, level + 1)1290 f.write("\nend # end of module " + m.name + "\n")1291 with open(ns + ".jl", "w") as f:1292 f.write(julia_header.format(self.copyright, self.issues, self.code,1293 self.version_major, self.version_minor))1294 for module in self.modules:1295 write_module(f, module, "", "", 1)1296 def write_texi(self):1297 def write_module(module, path, node, node_next, node_prev):1298 f.write("@node " + node + ", " + node_next + ", " + node_prev + ", Gmsh API\n");1299 f.write("@section Namespace @code{" + path + "}: " + module.doc + "\n\n");1300 f.write("@ftable @code\n");1301 for rtype, name, args, doc, special in module.fs:1302 f.write("@item " + name + "\n");1303 tdoc = doc.replace("`", "@code{").replace("'", "}")1304 f.write("\n".join(textwrap.wrap(tdoc, 80)) + "\n\n")1305 f.write("@table @asis\n");1306 iargs = list(a for a in args if not a.out)1307 oargs = list(a for a in args if a.out)1308 f.write("@item " + "Input:\n" +1309 (", ".join(("@code{" + iarg.name + "}") for iarg in iargs)1310 if len(iargs) else "-") + "\n")1311 f.write("@item " + "Output:\n" +1312 (", ".join(("@code{" + oarg.name + "}") for oarg in oargs)1313 if len(oargs) else "-") + "\n")1314 f.write("@item " + "Return:\n" +1315 (rtype.rtexi_type if rtype else "-") + "\n")1316 f.write("@end table\n\n");1317 f.write("@end ftable\n\n");1318 with open("api.texi", "w") as f:1319 f.write("@c This file was generated by api/gen.py: do not edit manually!\n\n")1320 def flatten_module(flat, module, path):1321 p = path + ("/" if len(path) else "") + module.name1322 flat.append((module, p))1323 for m in module.submodules:1324 flatten_module(flat, m, p)1325 def node_name(n):1326 return "Namespace " + n[1]1327 flat = []1328 for m in self.modules:1329 flatten_module(flat, m, "")1330 N = len(flat)1331 f.write("@menu\n")1332 for i in range(N):1333 f.write("* " + node_name(flat[i]) + "::\n")1334 f.write("@end menu\n\n")1335 for i in range(N):1336 write_module(flat[i][0], flat[i][1], node_name(flat[i]),1337 "" if i == N - 1 else node_name(flat[i+1]),...
test_app.py
Source:test_app.py
1"""2This file (test_app.py) contains the functional tests for checking if the3response format is proper. Run tests/unit/test_crud.py before running this.4"""5import json6import re7import uuid8import pytest9from hydra_python_core.doc_writer import HydraLink, DocUrl10from hydrus.tests.conftest import gen_dummy_object11from hydrus.utils import get_doc12# specify common fixture for all tests13@pytest.mark.usefixtures('init_db_for_app_tests')14class TestApp():15 def test_Index(self, test_app_client, constants):16 """Test for the Index."""17 HYDRUS_SERVER_URL = constants['HYDRUS_SERVER_URL']18 API_NAME = constants['API_NAME']19 response_get = test_app_client.get(f'/{API_NAME}')20 endpoints = json.loads(response_get.data.decode('utf-8'))21 response_post = test_app_client.post(f'/{API_NAME}', data=dict(foo='bar'))22 response_put = test_app_client.put(f'/{API_NAME}', data=dict(foo='bar'))23 response_delete = test_app_client.delete(f'/{API_NAME}')24 assert '@context' in endpoints25 assert endpoints['@id'] == f'{HYDRUS_SERVER_URL}{API_NAME}'26 assert endpoints['@type'] == 'EntryPoint'27 assert response_get.status_code == 20028 assert response_post.status_code == 40529 assert response_put.status_code == 40530 assert response_delete.status_code == 40531 def test_EntryPoint_context(self, test_app_client, constants):32 """Test for the EntryPoint context."""33 API_NAME = constants['API_NAME']34 response_get = test_app_client.get(f'/{API_NAME}/contexts/EntryPoint.jsonld')35 response_get_data = json.loads(response_get.data.decode('utf-8'))36 response_post = test_app_client.post(f'/{API_NAME}/contexts/EntryPoint.jsonld', data={})37 response_delete = test_app_client.delete(f'/{API_NAME}/contexts/EntryPoint.jsonld')38 assert response_get.status_code == 20039 assert '@context' in response_get_data40 assert response_post.status_code == 40541 assert response_delete.status_code == 40542 def test_Vocab(self, test_app_client, constants):43 """Test the vocab."""44 API_NAME = constants['API_NAME']45 HYDRUS_SERVER_URL = constants['HYDRUS_SERVER_URL']46 vocab_route = get_doc().doc_name47 response_get = test_app_client.get(f'/{API_NAME}/{vocab_route}#')48 response_get_data = json.loads(response_get.data.decode('utf-8'))49 assert '@context' in response_get_data50 assert response_get_data['@type'] == 'ApiDocumentation'51 assert response_get_data['@id'] == f'{HYDRUS_SERVER_URL}{API_NAME}/{vocab_route}'52 assert response_get.status_code == 20053 response_delete = test_app_client.delete(f'/{API_NAME}/{vocab_route}#')54 assert response_delete.status_code == 40555 response_put = test_app_client.put(56 f'/{API_NAME}/{vocab_route}#', data=json.dumps(dict(foo='bar')))57 assert response_put.status_code == 40558 response_post = test_app_client.post(f'/{API_NAME}/{vocab_route}#',59 data=json.dumps(dict(foo='bar')))60 assert response_post.status_code == 40561 def test_Collections_GET(self, test_app_client, constants, doc, init_db_for_app_tests):62 """Test GET on collection endpoints."""63 API_NAME = constants['API_NAME']64 index = test_app_client.get(f'/{API_NAME}')65 assert index.status_code == 20066 endpoints = json.loads(index.data.decode('utf-8'))67 for endpoint in endpoints['collections']:68 response_get = test_app_client.get(endpoint['@id'])69 assert response_get.status_code == 20070 response_get_data = json.loads(response_get.data.decode('utf-8'))71 assert '@context' in response_get_data72 assert '@id' in response_get_data73 assert '@type' in response_get_data74 assert 'members' in response_get_data75 # Check the item URI has the valid format, so it can be dereferenced76 if len(response_get_data['members']) > 0:77 for item in response_get_data['members']:78 class_type = item['@type']79 if class_type in doc.parsed_classes:80 class_ = doc.parsed_classes[class_type]['class']81 class_methods = [82 x.method for x in class_.supportedOperation]83 if 'GET' in class_methods:84 item_response = test_app_client.get(85 response_get_data['members'][0]['@id'])86 assert item_response.status_code == 20087 def test_pagination(self, test_app_client, constants, doc):88 """Test basic pagination"""89 API_NAME = constants['API_NAME']90 index = test_app_client.get(f'/{API_NAME}')91 assert index.status_code == 20092 endpoints = json.loads(index.data.decode('utf-8'))93 for endpoint in endpoints['collections']:94 response_get = test_app_client.get(endpoint['@id'])95 assert response_get.status_code == 20096 response_get_data = json.loads(97 response_get.data.decode('utf-8'))98 assert 'hydra:view' in response_get_data99 assert 'hydra:first' in response_get_data['hydra:view']100 assert 'hydra:last' in response_get_data['hydra:view']101 if 'hydra:next' in response_get_data['hydra:view']:102 response_next = test_app_client.get(103 response_get_data['hydra:view']['hydra:next'])104 assert response_next.status_code == 200105 response_next_data = json.loads(response_next.data.decode('utf-8'))106 assert 'hydra:previous' in response_next_data['hydra:view']107 break108 def test_Collections_PUT(self, test_app_client, constants, doc):109 """Test insert data to the collection."""110 API_NAME = constants['API_NAME']111 index = test_app_client.get(f'/{API_NAME}')112 assert index.status_code == 200113 endpoints = json.loads(index.data.decode('utf-8'))114 for endpoint in endpoints['collections']:115 collection_name = '/'.join(endpoint['@id'].split(f'/{API_NAME}/')[1:])116 collection = doc.collections[collection_name]['collection']117 collection_methods = [x.method for x in collection.supportedOperation]118 if 'PUT' in collection_methods:119 dummy_object = gen_dummy_object(collection.name, doc)120 good_response_put = test_app_client.put(endpoint['@id'],121 data=json.dumps(dummy_object))122 assert good_response_put.status_code == 201123 def test_collection_object_GET(self, test_app_client, constants, doc):124 """Test GET of a given collection object using ID."""125 API_NAME = constants['API_NAME']126 index = test_app_client.get(f'/{API_NAME}')127 assert index.status_code == 200128 endpoints = json.loads(index.data.decode('utf-8'))129 for endpoint in endpoints['collections']:130 collection_name = '/'.join(endpoint['@id'].split(f'/{API_NAME}/')[1:])131 collection = doc.collections[collection_name]['collection']132 collection_methods = [x.method for x in collection.supportedOperation]133 if 'PUT' in collection_methods:134 dummy_object = gen_dummy_object(collection.name, doc)135 initial_put_response = test_app_client.put(136 endpoint['@id'], data=json.dumps(dummy_object))137 assert initial_put_response.status_code == 201138 response = json.loads(initial_put_response.data.decode('utf-8'))139 regex = r'(.*)ID (.{36})* (.*)'140 matchObj = re.match(regex, response['description'])141 assert matchObj is not None142 id_ = matchObj.group(2)143 if 'GET' in collection_methods:144 get_response = test_app_client.get(f'{endpoint["@id"]}/{id_}')145 assert get_response.status_code == 200146 def test_collection_object_PUT(self, test_app_client, constants, doc):147 """Test PUT of a given collection object using ID."""148 API_NAME = constants['API_NAME']149 index = test_app_client.get(f'/{API_NAME}')150 assert index.status_code == 200151 endpoints = json.loads(index.data.decode('utf-8'))152 for endpoint in endpoints['collections']:153 collection_name = '/'.join(endpoint['@id'].split(f'/{API_NAME}/')[1:])154 collection = doc.collections[collection_name]['collection']155 collection_methods = [x.method for x in collection.supportedOperation]156 if 'PUT' in collection_methods:157 dummy_object = gen_dummy_object(collection.name, doc)158 initial_put_response = test_app_client.put(159 endpoint['@id'], data=json.dumps(dummy_object))160 assert initial_put_response.status_code == 201161 def test_collection_object_POST(self, test_app_client, constants, doc, socketio):162 """Test POST of a given collection object using ID."""163 API_NAME = constants['API_NAME']164 index = test_app_client.get(f'/{API_NAME}')165 assert index.status_code == 200166 endpoints = json.loads(index.data.decode('utf-8'))167 for endpoint in endpoints['collections']:168 collection_name = '/'.join(endpoint['@id'].split(f'/{API_NAME}/')[1:])169 collection = doc.collections[collection_name]['collection']170 collection_methods = [x.method for x in collection.supportedOperation]171 dummy_object = gen_dummy_object(collection.name, doc)172 initial_put_response = test_app_client.put(173 endpoint['@id'], data=json.dumps(dummy_object))174 assert initial_put_response.status_code == 201175 response = json.loads(initial_put_response.data.decode('utf-8'))176 regex = r'(.*)ID (.{36})* (.*)'177 matchObj = re.match(regex, response['description'])178 assert matchObj is not None179 id_ = matchObj.group(2)180 if 'POST' in collection_methods:181 # members attribute should be writeable for POSTs182 if collection.supportedProperty[0].write:183 dummy_object = gen_dummy_object(collection.name, doc)184 post_replace_response = test_app_client.post(f'{endpoint["@id"]}/{id_}',185 data=json.dumps(dummy_object))186 assert post_replace_response.status_code == 200187 def test_collection_object_DELETE(self, test_app_client, constants, doc):188 """Test DELETE of a given collection object using ID."""189 API_NAME = constants['API_NAME']190 index = test_app_client.get(f'/{API_NAME}')191 assert index.status_code == 200192 endpoints = json.loads(index.data.decode('utf-8'))193 for endpoint in endpoints['collections']:194 collection_name = '/'.join(195 endpoint["@id"].split(f'/{API_NAME}/')[1:])196 collection = doc.collections[collection_name]['collection']197 collection_methods = [198 x.method for x in collection.supportedOperation]199 dummy_object = gen_dummy_object(collection.name, doc)200 initial_put_response = test_app_client.put(endpoint["@id"],201 data=json.dumps(dummy_object))202 assert initial_put_response.status_code == 201203 response = json.loads(initial_put_response.data.decode('utf-8'))204 regex = r'(.*)ID (.{36})* (.*)'205 matchObj = re.match(regex, response['description'])206 assert matchObj is not None207 id_ = matchObj.group(2)208 if 'DELETE' in collection_methods:209 delete_response = test_app_client.delete(210 f'{endpoint["@id"]}/{id_}')211 assert delete_response.status_code == 200212 def test_object_PUT_at_id(self, test_app_client, constants, doc):213 """Create object in collection using PUT at specific ID."""214 API_NAME = constants['API_NAME']215 index = test_app_client.get(f'/{API_NAME}')216 assert index.status_code == 200217 endpoints = json.loads(index.data.decode('utf-8'))218 for endpoint in endpoints['collections']:219 collection_name = '/'.join(220 endpoint["@id"].split(f'/{API_NAME}/')[1:])221 collection = doc.collections[collection_name]['collection']222 collection_methods = [223 x.method for x in collection.supportedOperation]224 dummy_object = gen_dummy_object(collection.name, doc)225 if 'PUT' in collection_methods:226 dummy_object = gen_dummy_object(collection.name, doc)227 put_response = test_app_client.put(f'{endpoint["@id"]}/{uuid.uuid4()}',228 data=json.dumps(dummy_object))229 assert put_response.status_code == 201230 def test_object_PUT_at_ids(self, test_app_client, constants, doc):231 API_NAME = constants['API_NAME']232 index = test_app_client.get(f'/{API_NAME}')233 assert index.status_code == 200234 endpoints = json.loads(index.data.decode('utf-8'))235 for endpoint in endpoints:236 if endpoint not in ['@context', '@id', '@type', 'collections']:237 class_name = '/'.join(endpoints[endpoint].split(f'/{API_NAME}/')[1:])238 if class_name not in doc.collections:239 class_ = doc.parsed_classes[class_name]['class']240 class_methods = [x.method for x in class_.supportedOperation]241 data_ = {'data': list()}242 objects = list()243 ids = ''244 for index in range(3):245 objects.append(gen_dummy_object(class_.title, doc))246 ids = f'{uuid.uuid4()},'247 data_['data'] = objects248 if 'PUT' in class_methods:249 put_response = test_app_client.put(f'{endpoints[endpoint]}/add/{ids}',250 data=json.dumps(data_))251 assert put_response.status_code == 201252 def test_endpointClass_PUT(self, test_app_client, constants, doc):253 """Check non collection Class PUT."""254 API_NAME = constants['API_NAME']255 index = test_app_client.get(f'/{API_NAME}')256 assert index.status_code == 200257 endpoints = json.loads(index.data.decode('utf-8'))258 for endpoint in endpoints:259 if endpoint not in ['@context', '@id', '@type', 'collections']:260 class_name = '/'.join(261 endpoints[endpoint].split(f'/{API_NAME}/')[1:])262 if class_name not in doc.collections:263 class_ = doc.parsed_classes[class_name]['class']264 class_methods = [265 x.method for x in class_.supportedOperation]266 if 'PUT' in class_methods:267 dummy_object = gen_dummy_object(class_.title, doc)268 put_response = test_app_client.put(endpoints[endpoint],269 data=json.dumps(dummy_object))270 assert put_response.status_code == 201271 def test_endpointClass_POST(self, test_app_client, constants, doc):272 """Check non collection Class POST."""273 API_NAME = constants['API_NAME']274 index = test_app_client.get(f'/{API_NAME}')275 assert index.status_code == 200276 endpoints = json.loads(index.data.decode('utf-8'))277 for endpoint in endpoints:278 if endpoint not in ['@context', '@id', '@type', 'collections']:279 class_name = '/'.join(endpoints[endpoint].split(f'/{API_NAME}/')[1:])280 if class_name not in doc.collections:281 class_ = doc.parsed_classes[class_name]['class']282 class_methods = [x.method for x in class_.supportedOperation]283 if 'PUT' in class_methods:284 # first insert a object which we will update later285 dummy_object = gen_dummy_object(class_.title, doc)286 initial_put_response = test_app_client.put(endpoints[endpoint],287 data=json.dumps(dummy_object))288 response = json.loads(289 initial_put_response.data.decode('utf-8'))290 regex = r'(.*)ID (.{36})* (.*)'291 matchObj = re.match(regex, response['description'])292 id_ = matchObj.group(2)293 if 'POST' in class_methods:294 dummy_object = gen_dummy_object(class_.title, doc)295 post_response = test_app_client.post(f'{endpoints[endpoint]}/{id_}',296 data=json.dumps(dummy_object))297 assert post_response.status_code == 200298 def test_endpointClass_DELETE(self, test_app_client, constants, doc):299 """Check non collection Class DELETE."""300 API_NAME = constants['API_NAME']301 index = test_app_client.get(f'/{API_NAME}')302 assert index.status_code == 200303 endpoints = json.loads(index.data.decode('utf-8'))304 for endpoint in endpoints:305 if endpoint not in ['@context', '@id', '@type', 'collections']:306 class_name = '/'.join(307 endpoints[endpoint].split(f'/{API_NAME}/')[1:])308 if class_name not in doc.collections:309 class_ = doc.parsed_classes[class_name]['class']310 class_methods = [x.method for x in class_.supportedOperation]311 if 'PUT' in class_methods:312 # first insert a object which we will update later313 dummy_object = gen_dummy_object(class_.title, doc)314 initial_put_response = test_app_client.put(endpoints[endpoint],315 data=json.dumps(dummy_object))316 response = json.loads(317 initial_put_response.data.decode('utf-8'))318 regex = r'(.*)ID (.{36})* (.*)'319 matchObj = re.match(regex, response['description'])320 id_ = matchObj.group(2)321 if 'DELETE' in class_methods:322 delete_response = test_app_client.delete(323 f'{endpoints[endpoint]}/{id_}')324 assert delete_response.status_code == 200325 def test_endpointClass_GET(self, test_app_client, constants, doc):326 """Check non collection Class GET."""327 API_NAME = constants['API_NAME']328 index = test_app_client.get(f'/{API_NAME}')329 assert index.status_code == 200330 endpoints = json.loads(index.data.decode('utf-8'))331 for endpoint in endpoints:332 if endpoint not in ['@context', '@id', '@type', 'collections']:333 class_name = '/'.join(endpoints[endpoint].split(f'/{API_NAME}/')[1:])334 if class_name not in doc.collections:335 class_ = doc.parsed_classes[class_name]['class']336 class_methods = [x.method for x in class_.supportedOperation]337 if 'GET' in class_methods:338 response_get = test_app_client.get(endpoints[endpoint])339 assert response_get.status_code == 405340 def test_IriTemplate(self, test_app_client, constants, doc):341 """Test structure of IriTemplates attached to parsed classes"""342 API_NAME = constants['API_NAME']343 index = test_app_client.get(f'/{API_NAME}')344 assert index.status_code == 200345 endpoints = json.loads(index.data.decode('utf-8'))346 expanded_base_url = DocUrl.doc_url347 for endpoint in endpoints['collections']:348 collection_name = '/'.join(endpoint["@id"].split(f'/{API_NAME}/')[1:])349 collection = doc.collections[collection_name]['collection']350 class_name = collection.manages["object"].split(expanded_base_url)[1]351 response_get = test_app_client.get(endpoint["@id"])352 assert response_get.status_code == 200353 response_get_data = json.loads(response_get.data.decode('utf-8'))354 assert 'search' in response_get_data355 assert 'hydra:mapping' in response_get_data['search']356 class_ = doc.parsed_classes[class_name]['class']357 class_props = [x.prop for x in class_.supportedProperty]358 for mapping in response_get_data['search']['hydra:mapping']:359 prop = mapping['hydra:property']360 prop_name = mapping['hydra:variable']361 is_valid_class_prop = prop not in ['limit', 'offset', 'pageIndex']362 # check if IRI property is for searching through a nested_class363 # and not this class_364 is_nested_class_prop = "[" in prop_name and "]" in prop_name365 if is_valid_class_prop and not is_nested_class_prop:366 assert prop in class_props367 def test_client_controlled_pagination(self, test_app_client, constants, doc):368 """Test pagination controlled by test_app_client with help of pageIndex,369 offset and limit parameters."""370 API_NAME = constants['API_NAME']371 index = test_app_client.get(f'/{API_NAME}')372 assert index.status_code == 200373 endpoints = json.loads(index.data.decode('utf-8'))374 for endpoint in endpoints['collections']:375 response_get = test_app_client.get(endpoint["@id"])376 assert response_get.status_code == 200377 response_get_data = json.loads(response_get.data.decode('utf-8'))378 assert 'search' in response_get_data379 assert 'hydra:mapping' in response_get_data['search']380 # Test with pageIndex and limit381 params = {'pageIndex': 1, 'limit': 2}382 response_for_page_param = test_app_client.get(383 endpoint["@id"], query_string=params)384 assert response_for_page_param.status_code == 200385 response_for_page_param_data = json.loads(386 response_for_page_param.data.decode('utf-8'))387 assert 'hydra:first' in response_for_page_param_data['hydra:view']388 assert 'hydra:last' in response_for_page_param_data['hydra:view']389 if 'hydra:next' in response_for_page_param_data['hydra:view']:390 hydra_next = response_for_page_param_data['hydra:view']['hydra:next']391 assert 'pageIndex=2' in hydra_next392 next_response = test_app_client.get(393 response_for_page_param_data['hydra:view']['hydra:next'])394 assert next_response.status_code == 200395 next_response_data = json.loads(396 next_response.data.decode('utf-8'))397 assert 'hydra:previous' in next_response_data['hydra:view']398 data = next_response_data['hydra:view']['hydra:previous']399 assert 'pageIndex=1' in data400 # Test with offset and limit401 params = {'offset': 1, 'limit': 2}402 response_for_offset_param = test_app_client.get(endpoint["@id"],403 query_string=params)404 assert response_for_offset_param.status_code == 200405 response_for_offset_param_data = json.loads(406 response_for_offset_param.data.decode('utf-8'))407 data = response_for_offset_param_data['hydra:view']408 assert 'hydra:first' in data409 assert 'hydra:last' in data410 if 'hydra:next' in data:411 assert 'offset=3' in data['hydra:next']412 next_response = test_app_client.get(data['hydra:next'])413 assert next_response.status_code == 200414 next_response_data = json.loads(next_response.data.decode('utf-8'))415 assert 'hydra:previous' in next_response_data['hydra:view']416 assert 'offset=1' in next_response_data['hydra:view']['hydra:previous']417 def test_GET_for_nested_class(self, test_app_client, constants, doc):418 API_NAME = constants['API_NAME']419 index = test_app_client.get(f'/{API_NAME}')420 assert index.status_code == 200421 endpoints = json.loads(index.data.decode('utf-8'))422 for endpoint in endpoints['collections']:423 collection_name = '/'.join(endpoint["@id"].split(f'/{API_NAME}/')[1:])424 collection = doc.collections[collection_name]['collection']425 class_methods = [x.method for x in collection.supportedOperation]426 if 'GET' in class_methods:427 response_get = test_app_client.get(endpoint["@id"])428 assert response_get.status_code == 200429 instance = response_get.json['members'][0]['@id']430 instance_type = instance.split('/')[-2]431 instance_class = doc.parsed_classes[instance_type]['class']432 instance_methods = [x.method for x in instance_class.supportedOperation]433 if 'GET' in instance_methods:434 response_get_data = test_app_client.get(instance).json435 assert '@context' in response_get_data436 assert '@id' in response_get_data437 assert '@type' in response_get_data438 class_props = [x for x in collection.supportedProperty]439 expanded_base_url = DocUrl.doc_url440 for prop_name in class_props:441 if not isinstance(prop_name.prop, HydraLink):442 if expanded_base_url in prop_name.prop:443 assert '@type' in response_get_data[prop_name.title]444 def test_required_props(self, test_app_client, constants, doc):445 API_NAME = constants['API_NAME']446 index = test_app_client.get(f'/{API_NAME}')447 assert index.status_code == 200448 endpoints = json.loads(index.data.decode('utf-8'))449 for endpoint in endpoints:450 if endpoint not in ['@context', '@id', '@type', 'collections']:451 class_name = '/'.join(endpoints[endpoint].split(f'/{API_NAME}/')[1:])452 if class_name not in doc.collections:453 class_ = doc.parsed_classes[class_name]['class']454 class_methods = [x.method for x in class_.supportedOperation]455 if 'PUT' in class_methods:456 dummy_object = gen_dummy_object(class_.title, doc)457 required_prop = ''458 for prop in class_.supportedProperty:459 if prop.required:460 required_prop = prop.title461 break462 if required_prop:463 del dummy_object[required_prop]464 put_response = test_app_client.put(465 endpoints[endpoint], data=json.dumps(dummy_object))466 assert put_response.status_code == 400467 def test_writeable_props(self, test_app_client, constants, doc):468 API_NAME = constants['API_NAME']469 index = test_app_client.get(f'/{API_NAME}')470 assert index.status_code == 200471 endpoints = json.loads(index.data.decode('utf-8'))472 for endpoint in endpoints:473 if endpoint not in ['@context', '@id', '@type', 'collections']:474 class_name = '/'.join(endpoints[endpoint].split(f'/{API_NAME}/')[1:])475 if class_name not in doc.collections:476 class_ = doc.parsed_classes[class_name]['class']477 class_methods = [x.method for x in class_.supportedOperation]478 if 'PUT' in class_methods:479 # first insert a object which we will update later480 dummy_object = gen_dummy_object(class_.title, doc)481 initial_put_response = test_app_client.put(endpoints[endpoint],482 data=json.dumps(dummy_object))483 response = json.loads(initial_put_response.data.decode('utf-8'))484 regex = r'(.*)ID (.{36})* (.*)'485 matchObj = re.match(regex, response['description'])486 id_ = matchObj.group(2)487 if 'POST' in class_methods:488 dummy_object = gen_dummy_object(class_.title, doc)489 # Test for writeable properties490 post_response = test_app_client.post(491 f'{endpoints[endpoint]}/{id_}', data=json.dumps(dummy_object))492 assert post_response.status_code == 200493 # Test for properties with writeable=False494 non_writeable_prop = ''495 for prop in class_.supportedProperty:496 if prop.write is False:497 non_writeable_prop = prop.title498 break499 if non_writeable_prop != '':500 dummy_object[non_writeable_prop] = 'xyz'501 post_response = test_app_client.post(502 endpoints[endpoint], data=json.dumps(dummy_object))503 assert post_response.status_code == 405504 def test_readable_props(self, test_app_client, constants, doc):505 API_NAME = constants['API_NAME']506 index = test_app_client.get(f'/{API_NAME}')507 assert index.status_code == 200508 endpoints = json.loads(index.data.decode('utf-8'))509 for endpoint in endpoints:510 if endpoint not in ['@context', '@id', '@type', 'collections']:511 class_name = '/'.join(512 endpoints[endpoint].split(f'/{API_NAME}/')[1:])513 if class_name not in doc.collections:514 class_ = doc.parsed_classes[class_name]['class']515 class_methods = [516 x.method for x in class_.supportedOperation]517 if 'GET' in class_methods:518 not_readable_prop = ''519 for prop in class_.supportedProperty:520 if prop.read is False:521 not_readable_prop = prop.title522 break523 if not_readable_prop:524 get_response = test_app_client.get(525 endpoints[endpoint])526 get_response_data = json.loads(527 get_response.data.decode('utf-8'))528 assert not_readable_prop not in get_response_data529 def test_bad_objects(self, test_app_client, constants, doc):530 """Checks if bad objects are added or not."""531 API_NAME = constants['API_NAME']532 index = test_app_client.get(f'/{API_NAME}')533 assert index.status_code == 200534 endpoints = json.loads(index.data.decode('utf-8'))535 for endpoint in endpoints:536 if endpoint not in ['@context', '@id', '@type', 'collections']:537 class_name = '/'.join(538 endpoints[endpoint].split(f'/{API_NAME}/')[1:])539 if class_name in doc.parsed_classes:540 class_ = doc.parsed_classes[class_name]['class']541 class_methods = [542 x.method for x in class_.supportedOperation]543 if 'PUT' in class_methods:544 bad_response_put = test_app_client.put(545 endpoints[endpoint],546 data=json.dumps(dict(foo='bar')))547 assert bad_response_put.status_code == 400548 def test_bad_requests(self, test_app_client, constants, doc):549 """Checks if bad requests are handled or not."""550 API_NAME = constants['API_NAME']551 index = test_app_client.get(f'/{API_NAME}')552 assert index.status_code == 200553 endpoints = json.loads(index.data.decode('utf-8'))554 for endpoint in endpoints:555 if endpoint not in ['@context', '@id', '@type', 'collections']:556 class_name = '/'.join(endpoints[endpoint].split(f'/{API_NAME}/')[1:])557 if class_name not in doc.collections:558 class_ = doc.parsed_classes[class_name]['class']559 class_methods = [x.method for x in class_.supportedOperation]560 dummy_object = gen_dummy_object(class_.title, doc)561 if 'PUT' in class_methods:562 initial_put_response = test_app_client.put(563 endpoints[endpoint], data=json.dumps(dummy_object))564 assert initial_put_response.status_code == 201565 response = json.loads(initial_put_response.data.decode('utf-8'))566 regex = r'(.*)ID (.{36})* (.*)'567 matchObj = re.match(regex, response['description'])568 assert matchObj is not None569 id_ = matchObj.group(2)570 if 'POST' not in class_methods:571 dummy_object = gen_dummy_object(class_.title, doc)572 post_replace_response = test_app_client.post(573 f'{endpoints[endpoint]}/{id_}', data=json.dumps(dummy_object))574 assert post_replace_response.status_code == 405575 if 'DELETE' not in class_methods:576 delete_response = test_app_client.delete(577 f'{endpoints[endpoint]}/{id_}')578 assert delete_response.status_code == 405579 def test_Endpoints_Contexts(self, test_app_client, constants, doc):580 """Test all endpoints contexts are generated properly."""581 API_NAME = constants['API_NAME']582 index = test_app_client.get(f'/{API_NAME}')583 assert index.status_code == 200584 endpoints = json.loads(index.data.decode('utf-8'))585 for endpoint in endpoints['collections']:586 response_get = test_app_client.get(endpoints['@id'])587 assert response_get.status_code == 200588 context = json.loads(response_get.data.decode('utf-8'))['@context']589 response_context = test_app_client.get(context)590 response_context_data = json.loads(591 response_context.data.decode('utf-8'))592 assert response_context.status_code == 200...
test_genericVendor.py
Source:test_genericVendor.py
1from ctypes import CDLL, cdll, create_string_buffer2import pytest3import RP1210, os, configparser4from utilities import RP1210ConfigTestUtility5API_NAMES = ["PEAKRP32", "DLAUSB32", "DGDPA5MA", "NULN2R32", "CMNSI632", "CIL7R32", "DrewLinQ", "DTKRP32"]6INVALID_API_NAMES = ["empty_api", "invalid_api", "extra_empty_api", "invalid_pd_api"]7# These tests are meant to be run with cwd @ repository's highest-level directory8CWD = os.getcwd()9TEST_FILES_DIRECTORY = CWD + ".\\Test\\test-files"10INI_DIRECTORY = TEST_FILES_DIRECTORY + "\\ini-files"11DLL_DIRECTORY = TEST_FILES_DIRECTORY + "\\dlls"12RP121032_PATH = TEST_FILES_DIRECTORY + "\\RP121032.ini"13# try to get Windows Server to load DLLs w/ GitHub Actions14os.add_dll_directory(DLL_DIRECTORY)15os.add_dll_directory(os.getcwd())16os.environ['PATH'] += os.pathsep + DLL_DIRECTORY17for d in os.environ['path'].split(';'): # overboard18 if os.path.isdir(d):19 os.add_dll_directory(d)20invalid_apis = [] + INVALID_API_NAMES21# Check which APIs are missing dependencies so they can be skipped22for api_name in API_NAMES:23 valid = True24 try:25 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"26 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"27 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)28 if api_name not in invalid_apis:29 valid = rp1210.getAPI().isValid()30 except Exception:31 valid = False32 if not valid:33 invalid_apis.append(api_name)34def test_cwd():35 """Make sure cwd isn't in Test folder."""36 cwd = os.getcwd()37 assert "RP1210" in cwd38 assert "Test" not in cwd39@pytest.mark.parametrize("api_name", argvalues=API_NAMES)40def test_api_files_exist(api_name : str):41 """Makes sure all the relevant API files are in test-files directory."""42 assert os.path.exists(TEST_FILES_DIRECTORY)43 assert os.path.exists(INI_DIRECTORY)44 assert os.path.exists(DLL_DIRECTORY)45 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"46 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"47 assert os.path.isfile(ini_path)48 assert os.path.isfile(RP121032_PATH)49 if not api_name in invalid_apis:50 assert os.path.isfile(dll_path)51 assert cdll.LoadLibrary(dll_path) != None52def test_getAPINames():53 """54 Test the getAPINames() function with a custom directory.55 56 Also calls getAPINames() with no argument to make sure there isn't an exception.57 """58 RP1210.getAPINames()59 for name in RP1210.getAPINames(RP121032_PATH):60 assert name in API_NAMES61@pytest.mark.parametrize("rp121032_path", ["bork", "bork.ini", 1234, "RP121032", RP121032_PATH + "x"])62def test_getAPINames_invalid(rp121032_path):63 """64 Makes sure we get an exception if we provide an invalid path for getAPINames().65 """66 with pytest.raises(FileNotFoundError):67 RP1210.getAPINames(rp121032_path)68@pytest.mark.parametrize("api_name", argvalues=API_NAMES + INVALID_API_NAMES)69def test_RP1210Config(api_name : str):70 """71 Tests RP1210Config class with all sample files provided in test-files folder.72 """73 config = configparser.ConfigParser()74 utility = RP1210ConfigTestUtility(config)75 config.read(INI_DIRECTORY + "\\" + api_name + ".ini")76 rp1210 = RP1210.RP1210Config(api_name, DLL_DIRECTORY, INI_DIRECTORY)77 assert rp1210.isValid() == True or api_name in INVALID_API_NAMES78 assert rp1210.getAPIName() == api_name == rp1210.api.getAPIName()79 utility.verifydata(rp1210.getName, "VendorInformation", "Name", fallback="(Vendor Name Missing)")80 utility.verifydata(rp1210.getAddress1, "VendorInformation", "Address1")81 utility.verifydata(rp1210.getAddress2, "VendorInformation", "Address2")82 utility.verifydata(rp1210.getCity, "VendorInformation", "City")83 utility.verifydata(rp1210.getState, "VendorInformation", "State")84 utility.verifydata(rp1210.getCountry, "VendorInformation", "Country")85 utility.verifydata(rp1210.getPostal, "VendorInformation", "Postal")86 utility.verifydata(rp1210.getTelephone, "VendorInformation", "Telephone")87 utility.verifydata(rp1210.getFax, "VendorInformation", "Fax")88 utility.verifydata(rp1210.getVendorURL, "VendorInformation", "VendorURL")89 utility.verifydata(rp1210.getVersion, "VendorInformation", "Version")90 utility.verifydata(rp1210.autoDetectCapable, "VendorInformation", "AutoDetectCapable", fallback=False)91 utility.verifydata(rp1210.getAutoDetectCapable, "VendorInformation", "AutoDetectCapable", fallback=False)92 utility.verifydata(rp1210.getTimeStampWeight, "VendorInformation", "TimeStampWeight", fallback=1.0)93 utility.verifydata(rp1210.getMessageString, "VendorInformation", "MessageString")94 utility.verifydata(rp1210.getErrorString, "VendorInformation", "ErrorString")95 utility.verifydata(rp1210.getRP1210Version, "VendorInformation", "RP1210")96 utility.verifydata(rp1210.getDebugLevel, "VendorInformation", "DebugLevel", fallback=-1)97 utility.verifydata(rp1210.getDebugFile, "VendorInformation", "DebugFile")98 utility.verifydata(rp1210.getDebugMode, "VendorInformation", "DebugMode", fallback=-1)99 utility.verifydata(rp1210.getDebugFileSize, "VendorInformation", "DebugFileSize", fallback=1024)100 utility.verifydata(rp1210.getNumberOfSessions, "VendorInformation", "NumberOfRTSCTSSessions", fallback=1)101 utility.verifydata(rp1210.getCANAutoBaud, "VendorInformation", "CANAutoBaud", fallback=False)102 utility.verifydata(rp1210.getCANFormatsSupported, "VendorInformation", "CANFormatsSupported")103 utility.verifydata(rp1210.getJ1939FormatsSupported, "VendorInformation", "J1939FormatsSupported")104 utility.verifydata(rp1210.getDeviceIDs, "VendorInformation", "Devices")105 utility.verifydata(rp1210.getProtocolIDs, "VendorInformation", "Protocols")106 assert rp1210.getName() == rp1210.getDescription()107 assert rp1210.getName() in str(rp1210)108 assert rp1210.getCANAutoBaud() == rp1210.autoBaudEnabled()109 assert rp1210.getProtocol() == rp1210.getProtocol("J1939")110@pytest.mark.parametrize("api_name", argvalues=API_NAMES + INVALID_API_NAMES)111def test_RP1210Config_forceempty(api_name : str):112 """113 Test behavior after RP1210Config is forcibly cleared.114 115 This is here to test for cases where RP1210Config is missing sections.116 I was hoping this would cover the exceptions in RP1210Config, but it doesn't :(117 """118 rp1210 = RP1210.RP1210Config(api_name, DLL_DIRECTORY, INI_DIRECTORY)119 rp1210.clear()120 assert rp1210.getDevices() == []121 assert rp1210.getProtocols() == []122 assert rp1210.getProtocolNames() == []123 assert rp1210.getProtocolIDs() == []124@pytest.mark.parametrize("api_name", argvalues=API_NAMES + INVALID_API_NAMES)125def test_Devices(api_name : str):126 config = configparser.ConfigParser()127 utility = RP1210ConfigTestUtility(config)128 config.read(INI_DIRECTORY + "\\" + api_name + ".ini")129 rp1210 = RP1210.RP1210Config(api_name, DLL_DIRECTORY, INI_DIRECTORY)130 deviceIDs = rp1210.getDeviceIDs()131 for id in deviceIDs:132 device = rp1210.getDevice(id)133 utility.verifydevicedata(device.getID, id, "DeviceID", fallback=-1)134 utility.verifydevicedata(device.getDescription, id, "DeviceDescription")135 utility.verifydevicedata(device.getName, id, "DeviceName")136 utility.verifydevicedata(device.getParams, id, "DeviceParams")137 utility.verifydevicedata(device.getMultiJ1939Channels, id, "MultiJ1939Channels", fallback=0)138 utility.verifydevicedata(device.getMultiCANChannels, id, "MultiCANChannels", fallback=0)139 if device.getID() == -1:140 assert "(Invalid Device)" in str(device)141 else:142 assert str(device) == str(device.getID()) + " - " + device.getDescription()143 assert device in rp1210.getDevices()144 with pytest.raises(TypeError):145 assert device != "dingus"146@pytest.mark.parametrize("api_name", argvalues=API_NAMES + INVALID_API_NAMES)147def test_Protocols(api_name : str):148 config = configparser.ConfigParser()149 utility = RP1210ConfigTestUtility(config)150 rp1210 = RP1210.RP1210Config(api_name, DLL_DIRECTORY, INI_DIRECTORY)151 config.read(INI_DIRECTORY + "\\" + api_name + ".ini")152 protocolIDs = rp1210.getProtocolIDs()153 assert rp1210.getProtocol("test protocol name") is None154 assert rp1210.getProtocol([]) is None155 for name in rp1210.getProtocolNames():156 assert rp1210.getProtocol(name).getString() == name157 assert not rp1210.getProtocol("dinglebop protocol")158 assert not rp1210.getProtocol(b"this is bytes, not int or str")159 if not api_name in invalid_apis:160 assert rp1210.getProtocolNames()161 if not api_name in INVALID_API_NAMES:162 assert protocolIDs163 if api_name in INVALID_API_NAMES and api_name != "invalid_pd_api":164 assert rp1210.getProtocols() == []165 for id in protocolIDs:166 protocol = rp1210.getProtocol(id)167 name = protocol.getString()168 protocolFromString = rp1210.getProtocol(name)169 assert protocolFromString.getString() == name170 assert name in rp1210.getProtocolNames()171 assert rp1210.getProtocol(name).getString() == name172 utility.verifyprotocoldata(protocol.getDescription, id, "ProtocolDescription")173 utility.verifyprotocoldata(protocol.getString, id, "ProtocolString")174 utility.verifyprotocoldata(protocol.getParams, id, "ProtocolParams")175 utility.verifyprotocoldata(protocol.getDevices, id, "Devices")176 utility.verifyprotocoldata(protocol.getSpeed, id, "ProtocolSpeed")177 assert protocol in rp1210.getProtocols()178 with pytest.raises(TypeError):179 assert protocol != "dingus"180@pytest.mark.parametrize("api_name", argvalues=API_NAMES)181def test_load_DLL(api_name : str):182 """Loads an API's DLL and checks for validity."""183 if api_name in invalid_apis:184 pytest.skip(f"Skipping {api_name} due to missing dependencies.")185 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"186 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"187 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)188 # try to load it twice, to make sure they don't collide or something189 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)190 assert rp1210.getAPI().isValid()191 assert rp1210.api.getDLL() != None192 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)193 assert rp1210.api.loadDLL() != None194 # make sure that RP1210API is invalid if DLL is set to None195 rp1210.api.setDLL(None)196 assert not rp1210.api._api_valid197@pytest.mark.parametrize("api_name", argvalues=API_NAMES)198def test_conformsToRP1210C(api_name : str):199 """Tests conformsToRP1210C function."""200 if api_name in invalid_apis:201 pytest.skip(f"Skipping {api_name} due to missing dependencies.")202 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"203 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"204 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)205 if not rp1210.api.isValid():206 assert not rp1210.api.conformsToRP1210C()207 if rp1210.api.isValid():208 assert rp1210.api.conformsToRP1210C() == rp1210.api._conforms_to_rp1210c209@pytest.mark.parametrize("api_name", argvalues=API_NAMES)210def test_disconnected_ClientConnect(api_name : str):211 """Tests whether ClientConnect follows expected behavior when disconnected from device."""212 if api_name in invalid_apis:213 pytest.skip(f"Skipping {api_name} due to missing dependencies.")214 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"215 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"216 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)217 deviceID = rp1210.getProtocol("J1939").getDevices()[0]218 clientID = rp1210.api.ClientConnect(deviceID, b"J1939:Baud=Auto")219 assert RP1210.translateErrorCode(clientID) in RP1210.RP1210_ERRORS.values()220@pytest.mark.parametrize("api_name", argvalues=API_NAMES)221def test_disconnected_ClientDisconnect(api_name : str):222 """Tests whether ClientDisconnect follows expected behavior when disconnected from device."""223 if api_name in invalid_apis:224 pytest.skip(f"Skipping {api_name} due to missing dependencies.")225 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"226 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"227 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)228 code = rp1210.api.ClientDisconnect(0)229 if code < 0:230 code += 65536231 if api_name == "NULN2R32": # Nexiq drivers can trick computer into thinking it's connected232 assert code == 0 or code >= 128233 return234 assert code >= 128235@pytest.mark.parametrize("api_name", argvalues=API_NAMES)236def test_disconnected_ReadVersion(api_name : str):237 """Test RP1210_ReadVersion while adapter is disconnected."""238 if api_name in invalid_apis:239 pytest.skip(f"Skipping ReadVersion test for {api_name} due to missing dependencies.")240 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"241 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"242 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)243 buff1 = create_string_buffer(16)244 buff2 = create_string_buffer(16)245 buff3 = create_string_buffer(16)246 buff4 = create_string_buffer(16)247 rp1210.api.ReadVersion(buff1, buff2, buff3, buff4)248 assert str(buff1) + str(buff2) + str(buff3) + str(buff4) != ""249@pytest.mark.parametrize("api_name", argvalues=API_NAMES)250def test_disconnected_ReadVersionDirect(api_name : str):251 """Test ReadVersionDirect while adapter is disconnected."""252 if api_name in invalid_apis:253 pytest.skip(f"Skipping ReadVersionDirect test for {api_name} due to missing dependencies.")254 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"255 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"256 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)257 dll_ver, api_ver = rp1210.api.ReadVersionDirect()258 assert dll_ver != ""259 assert api_ver != ""260 assert dll_ver == rp1210.api.ReadDLLVersion()261 assert api_ver == rp1210.api.ReadAPIVersion()262@pytest.mark.parametrize("api_name", argvalues=API_NAMES)263def test_disconnected_ReadDetailedVersion(api_name : str):264 """Test ReadDetailedVersion while adapter is disconnected."""265 if api_name in invalid_apis:266 pytest.skip(f"Skipping ReadDetailedVersion test for {api_name} due to missing dependencies.")267 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"268 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"269 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)270 buff1 = create_string_buffer(17)271 buff2 = create_string_buffer(17)272 buff3 = create_string_buffer(17)273 ret_val = rp1210.api.ReadDetailedVersion(0, buff1, buff2, buff3)274 assert RP1210.translateErrorCode(ret_val) in ["ERR_DLL_NOT_INITIALIZED", "ERR_HARDWARE_NOT_RESPONDING", "ERR_INVALID_CLIENT_ID"]275 assert rp1210.api.ReadDetailedVersionDirect(0)276@pytest.mark.parametrize("api_name", argvalues=API_NAMES)277def test_disconnected_GetErrorMsg(api_name : str):278 """Test GetErrorMsg while adapter is disconnected."""279 if api_name in invalid_apis:280 pytest.skip(f"Skipping GetErrorMsg test for {api_name} due to missing dependencies.")281 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"282 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"283 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)284 for code in RP1210.RP1210_ERRORS.keys():285 msg = rp1210.api.GetErrorMsg(code)286 if not api_name == "DrewLinQ": # DrewLinQ fails this, but that's their problem287 assert msg != ""288@pytest.mark.parametrize("api_name", argvalues=API_NAMES)289def test_disconnected_SendCommand(api_name : str):290 """Test SendCommand while adapter is disconnected."""291 if api_name in invalid_apis:292 pytest.skip(f"Skipping SendCommand test for {api_name} due to missing dependencies.")293 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"294 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"295 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)296 for command in RP1210.RP1210_COMMANDS:297 assert RP1210.translateErrorCode(rp1210.api.SendCommand(command, 0)) in RP1210.RP1210_ERRORS.values()298@pytest.mark.parametrize("api_name", argvalues=API_NAMES)299def test_disconnected_GetHardwareStatus(api_name : str):300 """Test GetHardwareStatus while adapter is disconnected."""301 if api_name in invalid_apis:302 pytest.skip(f"Skipping GetHardwareStatus test for {api_name} due to missing dependencies.")303 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"304 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"305 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)306 buffer = create_string_buffer(64)307 ret_val = rp1210.api.GetHardwareStatus(0, buffer, 64)308 if ret_val < 0:309 ret_val += 65536310 assert not buffer.value311 assert ret_val in RP1210.RP1210_ERRORS312@pytest.mark.parametrize("api_name", argvalues=API_NAMES)313def test_disconnected_GetHardwareStatusDirect(api_name : str):314 """Test GetHardwareStatusDirect while adapter is disconnected."""315 if api_name in invalid_apis:316 pytest.skip(f"Skipping GetHardwareStatusDirect test for {api_name} due to missing dependencies.")317 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"318 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"319 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)320 assert not int.from_bytes(rp1210.api.GetHardwareStatusDirect(0), 'big')321@pytest.mark.parametrize("api_name", argvalues=API_NAMES)322def test_disconnected_SendMessage(api_name : str):323 if api_name in invalid_apis:324 pytest.skip(f"Skipping SendMessage test for {api_name} due to missing dependencies.")325 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"326 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"327 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)328 for val in ["blargle", "", 0, 324234, b'blargle', b'']:329 ret_val = rp1210.api.SendMessage(0, val) # set size automatically330 assert RP1210.translateErrorCode(ret_val) in RP1210.RP1210_ERRORS.values()331 if not isinstance(val, int):332 ret_val = rp1210.api.SendMessage(0, val, len(val)) # specify size333 assert RP1210.translateErrorCode(ret_val) in RP1210.RP1210_ERRORS.values()334@pytest.mark.parametrize("api_name", argvalues=API_NAMES)335def test_disconnected_Read(api_name : str):336 """Test ReadMessage and ReadDirect."""337 if api_name in invalid_apis:338 pytest.skip(f"Skipping 'Remaining Functions' test for {api_name} due to missing dependencies.")339 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"340 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"341 rp1210 = RP1210.RP1210Config(api_name, dll_path, ini_path)342 read_array_in = create_string_buffer(256)343 assert rp1210.api.ReadMessage(128, read_array_in, len(read_array_in)) <= 0344 assert not read_array_in.value345 read_array_in = create_string_buffer(64)346 assert rp1210.api.ReadMessage(0, read_array_in) <= 0347 assert not read_array_in.value348 assert not rp1210.api.ReadDirect(0)349@pytest.mark.parametrize("api_name", argvalues=API_NAMES)350def test_RP1210API_magic_methods(api_name : str):351 """Test __bool__ and __str__ in RP1210API."""352 if api_name in invalid_apis:353 pytest.skip(f"Skipping 'Remaining Functions' test for {api_name} due to missing dependencies.")354 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"355 api = RP1210.RP1210API(api_name, dll_path)356 assert bool(api) == api.isValid()357 assert str(api) == api.getAPIName()358@pytest.mark.parametrize("api_name", argvalues=INVALID_API_NAMES)359def test_RP1210API_magic_methods_with_invalid_api(api_name : str):360 """Test __bool__ and __str__ in RP1210API with invalid API names."""361 api = RP1210.RP1210API(api_name)362 assert bool(api) == api.isValid()363 assert str(api) == api.getAPIName()364@pytest.mark.parametrize("api_name", argvalues=API_NAMES)365def test_RP1210Config_magic_methods(api_name : str):366 """Test __bool__ in RP1210Config."""367 if api_name in invalid_apis:368 pytest.skip(f"Skipping 'Remaining Functions' test for {api_name} due to missing dependencies.")369 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"370 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"371 config = RP1210.RP1210Config(api_name, dll_path, ini_path)372 config2 = RP1210.RP1210Config(api_name, dll_path, ini_path)373 assert bool(config) == config.isValid()374 assert config == config2375 if api_name != "NULN2R32":376 assert config != RP1210.RP1210Config("NULN2R32", dll_path, ini_path)377@pytest.mark.parametrize("api_name", argvalues=INVALID_API_NAMES)378def test_RP1210Config_magic_methods_with_invalid_api(api_name : str):379 """Test __bool__ in RP1210Config with invalid API names."""380 config = RP1210.RP1210Config(api_name)381 config2 = RP1210.RP1210Config(api_name)382 assert bool(config) == config.isValid()383 assert config == config2384 assert config != RP1210.RP1210Config("dinglebop")385@pytest.mark.parametrize("api_name", argvalues=API_NAMES)386def test_RP1210VendorList_addVendor(api_name : str):387 """Tests addVendor function in RP1210VendorList"""388 vendors = RP1210.RP1210VendorList(RP121032_PATH, DLL_DIRECTORY, INI_DIRECTORY)389 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"390 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"391 config = RP1210.RP1210Config(api_name, dll_path, ini_path)392 assert config in vendors393 assert RP1210.RP1210Config("dinglebop") not in vendors394 # add by name395 length = len(vendors)396 vendors.addVendor(api_name)397 assert len(vendors) == length + 1398 assert vendors[length] == config399 # add by RP1210Config object400 vendors.addVendor(config)401 assert len(vendors) == length + 2402 assert vendors[length + 1] == config403 # add random api name404 vendors.addVendor("dinglebop")405 assert len(vendors) == length + 3406 assert vendors[length + 2] != config407 assert not vendors[length + 2].isValid() # should be invalid408 # add invalid type409 with pytest.raises(TypeError):410 vendors.addVendor(4)411@pytest.mark.parametrize("api_name", argvalues=API_NAMES)412def test_RP1210VendorList_setVendorByName(api_name : str):413 """Tests setVendor function in RP1210VendorList"""414 vendors = RP1210.RP1210VendorList(RP121032_PATH, DLL_DIRECTORY, INI_DIRECTORY)415 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"416 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"417 config = RP1210.RP1210Config(api_name, dll_path, ini_path)418 vendors.setVendor(api_name)419 assert vendors.getAPIName() == api_name420 assert vendors.getVendorIndex() == vendors.getVendorIndex(api_name)421 assert vendors.vendor == config422@pytest.mark.parametrize("api_name", argvalues=API_NAMES)423def test_RP1210VendorList_setVendorByVendor(api_name : str):424 """Tests setVendor function in RP1210VendorList"""425 vendors = RP1210.RP1210VendorList(RP121032_PATH, DLL_DIRECTORY, INI_DIRECTORY)426 ini_path = INI_DIRECTORY + "\\" + api_name + ".ini"427 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"428 config = RP1210.RP1210Config(api_name, dll_path, ini_path)429 vendors.setVendor(config)430 assert vendors.getAPIName() == api_name431 assert vendors.getVendorIndex() == vendors.getVendorIndex(api_name)432 assert vendors.vendor == config433@pytest.mark.parametrize("api_name", argvalues=API_NAMES)434def test_RP1210VendorList_accessAPI(api_name : str):435 """Access `api` property in RP1210VendorList."""436 vendors = RP1210.RP1210VendorList(RP121032_PATH, DLL_DIRECTORY, INI_DIRECTORY)437 dll_path = DLL_DIRECTORY + "\\" + api_name + ".dll"438 api = RP1210.RP1210API(api_name, dll_path)439 vendors.setVendor(api_name)440 assert vendors.api == api == api_name441 assert vendors.getAPIName() == vendors.api.getAPIName()442 # setter should raise exception443 with pytest.raises(AttributeError):...
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!