1# -*- coding: utf-8 -*- 2 3# This program is free software; you can redistribute it and/or modify it under 4# the terms of the (LGPL) GNU Lesser General Public License as published by the 5# Free Software Foundation; either version 3 of the License, or (at your 6# option) any later version. 7# 8# This program is distributed in the hope that it will be useful, but WITHOUT 9# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 10# FOR A PARTICULAR PURPOSE. See the GNU Library Lesser General Public License 11# for more details at ( http://www.gnu.org/licenses/lgpl.html ). 12# 13# You should have received a copy of the GNU Lesser General Public License 14# along with this program; if not, write to the Free Software Foundation, Inc., 15# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 16# written by: Jurko Gospodnetić ( jurko.gospodnetic@pke.hr ) 17 18""" 19Suds library's built-in XSD type handling unit tests. 20 21Implemented using the 'pytest' testing framework. 22 23""" 24 25import testutils 26if __name__ == "__main__": 27 testutils.run_using_pytest(globals()) 28 29import suds.client 30import suds.sax.date 31from suds.xsd.sxbuiltin import (Factory, XAny, XBoolean, XBuiltin, XDate, 32 XDateTime, XDecimal, XFloat, XInteger, XLong, XString, XTime) 33from testutils.compare_sax import CompareSAX 34 35import pytest 36 37import datetime 38import decimal 39import re 40import sys 41 42if sys.version_info >= (2, 6): 43 import fractions 44if sys.version_info >= (3,): 45 long = int 46 47 48class _Dummy: 49 """Class for testing unknown object class handling.""" 50 pass 51 52 53# Define mock MockXType classes (e.g. MockXDate, MockXInteger & MockXString) 54# used to test translate() methods in different XSD data type model classes 55# such as XDate, XInteger & XString. 56def _def_mock_xsd_class(x_class_name): 57 """ 58 Define a mock XType class and reference it globally as MockXType. 59 60 XType classes (e.g. XDate, XInteger & XString), represent built-in XSD 61 types. Their mock counterparts created here (e.g. MockXDate, MockXInteger & 62 MockXString) may be used to test their translate() methods without having 63 to connect them to an actual XSD schema. 64 65 This is achieved by having their constructor call take no parameters and 66 not call the parent class __init__() method. 67 68 Rationale why these mock classes are used instead of actual XType classes: 69 * XType instances need to be connected to an actual XSD schema element 70 which would unnecessarily complicate our test code. 71 * XType translate() implementations are not affected by whether the 72 instance they have been called on has been connected to an actual XSD 73 schema element. 74 * XType translate() functions can not be called as unbound methods, e.g. 75 XDate.translate(...). Such an implementation would fail if those 76 methods are not defined exactly in the specified XType class but in one 77 of its parent classes. 78 79 """ 80 x_class = getattr(suds.xsd.sxbuiltin, x_class_name) 81 assert issubclass(x_class, XBuiltin) 82 mock_class_name = "Mock" + x_class_name 83 mock_class = type(mock_class_name, (x_class,), { 84 "__doc__": "Mock %s not connected to an XSD schema." % (x_class_name,), 85 "__init__": lambda self: None}) 86 globals()[mock_class_name] = mock_class 87 88for x in ("XAny", "XBoolean", "XDate", "XDateTime", "XDecimal", "XFloat", 89 "XInteger", "XLong", "XString", "XTime"): 90 _def_mock_xsd_class(x) 91 92 93# Built-in XSD data types as defined in 'XML Schema Part 2: Datatypes Second 94# Edition' (http://www.w3.org/TR/2004/REC-xmlschema-2-20041028). Each is paired 95# with its respective suds library XSD type modeling class. 96builtins = { 97 "anySimpleType": XString, 98 "anyType": XAny, 99 "anyURI": XString, 100 "base64Binary": XString, 101 "boolean": XBoolean, 102 "byte": XInteger, 103 "date": XDate, 104 "dateTime": XDateTime, 105 "decimal": XDecimal, 106 "double": XFloat, 107 "duration": XString, 108 "ENTITIES": XString, 109 "ENTITY": XString, 110 "float": XFloat, 111 "gDay": XString, 112 "gMonth": XString, 113 "gMonthDay": XString, 114 "gYear": XString, 115 "gYearMonth": XString, 116 "hexBinary": XString, 117 "ID": XString, 118 "IDREF": XString, 119 "IDREFS": XString, 120 "int": XInteger, 121 "integer": XInteger, 122 "language": XString, 123 "long": XLong, 124 "Name": XString, 125 "NCName": XString, 126 "negativeInteger": XInteger, 127 "NMTOKEN": XString, 128 "NMTOKENS": XString, 129 "nonNegativeInteger": XInteger, 130 "nonPositiveInteger": XInteger, 131 "normalizedString": XString, 132 "NOTATION": XString, 133 "positiveInteger": XInteger, 134 "QName": XString, 135 "short": XInteger, 136 "string": XString, 137 "time": XTime, 138 "token": XString, 139 "unsignedByte": XInteger, 140 "unsignedInt": XInteger, 141 "unsignedLong": XLong, 142 "unsignedShort": XInteger} 143 144# XML namespaces where all the built-in type names live, as defined in 'XML 145# Schema Part 2: Datatypes Second Edition' 146# (http://www.w3.org/TR/2004/REC-xmlschema-2-20041028). 147builtin_namespaces = [ 148 "http://www.w3.org/2001/XMLSchema", 149 "http://www.w3.org/2001/XMLSchema-datatypes"] 150 151 152class TestXBoolean: 153 """suds.xsd.sxbuiltin.XBoolean.translate() tests.""" 154 155 @pytest.mark.parametrize(("source", "expected"), ( 156 (0, "false"), 157 (1, "true"), 158 (False, "false"), 159 (True, "true"))) 160 def test_from_python_object(self, source, expected): 161 translated = MockXBoolean().translate(source, topython=False) 162 assert translated.__class__ is str 163 assert translated == expected 164 165 @pytest.mark.parametrize("source", ( 166 None, 167 pytest.mark.skipif(sys.version_info >= (3,), 168 reason="int == long since Python 3.0")(long(0)), 169 pytest.mark.skipif(sys.version_info >= (3,), 170 reason="int == long since Python 3.0")(long(1)), 171 "x", 172 "True", 173 "False", 174 object(), 175 _Dummy(), 176 datetime.date(2101, 1, 1))) 177 def test_from_python_object__invalid(self, source): 178 assert MockXBoolean().translate(source, topython=False) is source 179 180 @pytest.mark.parametrize("source", (-1, 2, 5, 100)) 181 def test_from_python_object__invalid_integer(self, source): 182 #TODO: See if this special integer handling is really desired. 183 assert MockXBoolean().translate(source, topython=False) is None 184 185 @pytest.mark.parametrize(("source", "expected"), ( 186 ("0", False), 187 ("1", True), 188 ("false", False), 189 ("true", True))) 190 def test_to_python_object(self, source, expected): 191 assert MockXBoolean().translate(source) is expected 192 193 @pytest.mark.parametrize("source", 194 (0, 1, "", "True", "False", "2", "Z", "-1", "00", "x", "poppycock")) 195 def test_to_python_object__invalid(self, source): 196 assert MockXBoolean().translate(source) is None 197 198 199class TestXDate: 200 """ 201 suds.xsd.sxbuiltin.XDate.translate() tests. 202 203 Related Python object <--> string conversion details are tested in a 204 separate date/time related test module. These tests are only concerned with 205 basic translate() functionality. 206 207 """ 208 209 def test_from_python_object__date(self): 210 date = datetime.date(2013, 7, 24) 211 translated = MockXDate().translate(date, topython=False) 212 assert translated.__class__ is suds.sax.date.Date 213 assert str(translated) == "2013-07-24" 214 215 def test_from_python_object__datetime(self): 216 dt = datetime.datetime(2013, 7, 24, 11, 59, 4) 217 translated = MockXDate().translate(dt, topython=False) 218 assert translated.__class__ is suds.sax.date.Date 219 assert str(translated) == "2013-07-24" 220 221 @pytest.mark.parametrize("source", ( 222 None, 223 object(), 224 _Dummy(), 225 datetime.time())) 226 def test_from_python_object__invalid(self, source): 227 assert MockXDate().translate(source, topython=False) is source 228 229 def test_to_python_object(self): 230 assert MockXDate().translate("1941-12-7") == datetime.date(1941, 12, 7) 231 232 def test_to_python_object__empty_string(self): 233 assert MockXDate().translate("") == None 234 235 236class TestXDateTime: 237 """ 238 suds.xsd.sxbuiltin.XDateTime.translate() tests. 239 240 Related Python object <--> string conversion details are tested in a 241 separate date/time related test module. These tests are only concerned with 242 basic translate() functionality. 243 244 """ 245 246 def test_from_python_object(self): 247 dt = datetime.datetime(2021, 12, 31, 11, 25) 248 translated = MockXDateTime().translate(dt, topython=False) 249 assert translated.__class__ is suds.sax.date.DateTime 250 assert str(translated) == "2021-12-31T11:25:00" 251 252 @pytest.mark.parametrize("source", ( 253 None, 254 object(), 255 _Dummy(), 256 datetime.time(22, 47, 9, 981), 257 datetime.date(2101, 1, 1))) 258 def test_from_python_object__invalid(self, source): 259 assert MockXDateTime().translate(source, topython=False) is source 260 261 def test_to_python_object(self): 262 dt = datetime.datetime(1941, 12, 7, 10, 30, 22, 454000) 263 assert MockXDateTime().translate("1941-12-7T10:30:22.454") == dt 264 265 def test_to_python_object__empty_string(self): 266 assert MockXDateTime().translate("") == None 267 268 269class TestXDecimal: 270 """suds.xsd.sxbuiltin.XDecimal.translate() tests.""" 271 272 @pytest.mark.parametrize(("source", "expected"), ( 273 # Zeros. 274 (decimal.Decimal("0"), "0"), 275 (decimal.Decimal("-0"), "-0"), 276 # Positive integral. 277 (decimal.Decimal("1"), "1"), 278 (decimal.Decimal("1000"), "1000"), 279 (decimal.Decimal("1E500"), "1" + "0" * 500), 280 # Negative integral. 281 (decimal.Decimal("-1"), "-1"), 282 (decimal.Decimal("-1000"), "-1000"), 283 (decimal.Decimal("-1E500"), "-1" + "0" * 500), 284 # Simple fractional. 285 (decimal.Decimal("0.1"), "0.1"), 286 (decimal.Decimal("-0.1"), "-0.1"), 287 (decimal.Decimal("0." + "0123456789" * 9), "0." + "0123456789" * 9), 288 (decimal.Decimal("-0." + "0123456789" * 9), "-0." + "0123456789" * 9), 289 # Zero with extra fractional digits. 290 (decimal.Decimal("0.0000"), "0"), 291 (decimal.Decimal("-0.0000"), "-0"), 292 # Only 0s as fractional digits. 293 (decimal.Decimal("5.000000000000000000"), "5"), 294 (decimal.Decimal("-5.000000000000000000"), "-5"), 295 # Trailing fractional 0 digits. 296 (decimal.Decimal("5.000000123000000000000"), "5.000000123"), 297 (decimal.Decimal("-5.000000123000000000000"), "-5.000000123"), 298 # Very small fractional part. 299 (decimal.Decimal("9E-100"), "0." + "0" * 99 + "9"), 300 (decimal.Decimal("-9E-100"), "-0." + "0" * 99 + "9"))) 301 def test_decimal_to_xsd_value_representation(self, source, expected): 302 assert source.__class__ is decimal.Decimal 303 string = MockXDecimal()._decimal_to_xsd_format(source) 304 assert string.__class__ is str 305 assert string == expected 306 307 @pytest.mark.parametrize("source", ( 308 decimal.Decimal(0), 309 decimal.Decimal("0.1") + decimal.Decimal("0.2"), 310 decimal.Decimal("5.781963"))) 311 def test_from_python_object(self, source): 312 assert source.__class__ is decimal.Decimal, "bad test data" 313 translated = MockXDecimal().translate(source, topython=False) 314 expected = MockXDecimal()._decimal_to_xsd_format(source) 315 assert translated.__class__ is str 316 assert translated == expected 317 318 extra_test_data = () 319 if sys.version_info >= (2, 6): 320 extra_test_data = ( 321 # fraction.Fraction 322 fractions.Fraction(10, 4), 323 fractions.Fraction(1, 3)) 324 @pytest.mark.parametrize("source", ( 325 None, 326 # bool 327 True, 328 False, 329 # float 330 -50.2, 331 1.9623e-26, 332 0.1 + 0.2, 333 0.7, 334 1.0, 335 50.99999, 336 # int 337 0, 338 1, 339 -55566, 340 # str 341 "0.1", 342 "0.2", 343 "x", 344 # other 345 object(), 346 _Dummy(), 347 datetime.date(2101, 1, 1)) + extra_test_data) 348 def test_from_python_object__no_translation(self, source): 349 assert MockXDecimal().translate(source, topython=False) is source 350 351 @pytest.mark.parametrize("source", ( 352 "-500.0", 353 "0", 354 "0.0", 355 "0.00000000000000000000001", 356 "000", 357 "1.78123875", 358 "-1.78123875", 359 "1", 360 "01", 361 "100")) 362 def test_to_python_object(self, source): 363 translated = MockXDecimal().translate(source) 364 assert translated.__class__ is decimal.Decimal 365 assert translated == decimal.Decimal(source) 366 367 @pytest.mark.parametrize("source", 368 ("", 0, 1, 1.5, True, False, 500, _Dummy(), object())) 369 def test_to_python_object__invalid_class_or_empty_string(self, source): 370 assert MockXDecimal().translate(source) is None 371 372 @pytest.mark.parametrize("src", (" ", "0,0", "0-0", "x", "poppycock")) 373 def test_to_python_object__invalid_string(self, src): 374 """ 375 Suds raises raw Python exceptions when it fails to convert received 376 response element data to its mapped Python decimal.Decimal data type, 377 according to the used WSDL schema. 378 379 """ 380 pytest.raises(decimal.InvalidOperation, MockXDecimal().translate, src) 381 382 383class TestXFloat: 384 """suds.xsd.sxbuiltin.XFloat.translate() tests.""" 385 386 extra_test_data = () 387 if sys.version_info >= (2, 6): 388 extra_test_data = ( 389 # fraction.Fraction 390 fractions.Fraction(10, 4), 391 fractions.Fraction(1, 3)) 392 @pytest.mark.parametrize("source", ( 393 None, 394 # bool 395 True, 396 False, 397 # decimal.Decimal 398 decimal.Decimal(0), 399 decimal.Decimal("0.1") + decimal.Decimal("0.2"), 400 decimal.Decimal("5.781963"), 401 # float 402 -50.2, 403 0.1 + 0.2, 404 0.7, 405 1.0, 406 50.99999, 407 # int 408 0, 409 1, 410 -55566, 411 # str 412 "0.1", 413 "0.2", 414 "x", 415 # other 416 object(), 417 _Dummy(), 418 datetime.date(2101, 1, 1)) + extra_test_data) 419 def test_from_python_object(self, source): 420 assert MockXFloat().translate(source, topython=False) is source 421 422 @pytest.mark.parametrize("source", ( 423 "-500.0", 424 "0", 425 "0.0", 426 "0.00000000000000000000001", 427 "000", 428 "1.78123875", 429 "-1.78123875", 430 "1", 431 "01", 432 "100")) 433 def test_to_python_object(self, source): 434 translated = MockXFloat().translate(source) 435 assert translated.__class__ is float 436 assert translated == float(source) 437 438 @pytest.mark.parametrize("source", 439 ("", 0, 1, 1.5, True, False, 500, _Dummy(), object())) 440 def test_to_python_object__invalid_class_or_empty_string(self, source): 441 assert MockXFloat().translate(source) is None 442 443 @pytest.mark.parametrize("source", (" ", "0,0", "0-0", "x", "poppycock")) 444 def test_to_python_object__invalid_string(self, source, monkeypatch): 445 """ 446 Suds raises raw Python exceptions when it fails to convert received 447 response element data to its mapped Python float data type, according 448 to the used WSDL schema. 449 450 """ 451 monkeypatch.delitem(locals(), "e", False) 452 e = pytest.raises(ValueError, MockXFloat().translate, source).value 453 try: 454 # Using different Python interpreter versions and different source 455 # strings results in different exception messages here. 456 try: 457 float(source) 458 pytest.fail("Bad test data.") 459 except ValueError: 460 assert str(e) == str(sys.exc_info()[1]) 461 finally: 462 del e # explicitly break circular reference chain in Python 3 463 464 465class TestXInteger: 466 """suds.xsd.sxbuiltin.XInteger.translate() tests.""" 467 468 @pytest.mark.parametrize("source", ( 469 None, 470 # bool 471 False, 472 True, 473 # int 474 -50, 475 0, 476 1, 477 50, 478 # long 479 long(-50), 480 long(0), 481 long(1), 482 long(50), 483 # str 484 "x", 485 # other 486 object(), 487 _Dummy(), 488 datetime.date(2101, 1, 1))) 489 def test_from_python_object(self, source): 490 assert MockXInteger().translate(source, topython=False) is source 491 492 @pytest.mark.parametrize("source", ("-500", "0", "000", "1", "01", "100")) 493 def test_to_python_object(self, source): 494 translated = MockXInteger().translate(source) 495 assert translated.__class__ is int 496 assert translated == int(source) 497 498 @pytest.mark.parametrize("source", 499 ("", 0, 1, True, False, 500, _Dummy(), object())) 500 def test_to_python_object__invalid_class_or_empty_string(self, source): 501 assert MockXInteger().translate(source) is None 502 503 @pytest.mark.parametrize("source", (" ", "0-0", "x", "poppycock")) 504 def test_to_python_object__invalid_string(self, source, monkeypatch): 505 """ 506 Suds raises raw Python exceptions when it fails to convert received 507 response element data to its mapped Python integer data type, according 508 to the used WSDL schema. 509 510 """ 511 monkeypatch.delitem(locals(), "e", False) 512 e = pytest.raises(ValueError, MockXInteger().translate, source).value 513 try: 514 # Using different Python interpreter versions and different source 515 # strings results in different exception messages here. 516 try: 517 int(source) 518 pytest.fail("Bad test data.") 519 except ValueError: 520 assert str(e) == str(sys.exc_info()[1]) 521 finally: 522 del e # explicitly break circular reference chain in Python 3 523 524 525class TestXLong: 526 """suds.xsd.sxbuiltin.XLong.translate() tests.""" 527 528 @pytest.mark.parametrize("source", ( 529 None, 530 # bool 531 False, 532 True, 533 # int 534 -50, 535 0, 536 1, 537 50, 538 # long 539 long(-50), 540 long(0), 541 long(1), 542 long(50), 543 # str 544 "x", 545 # other 546 object(), 547 _Dummy(), 548 datetime.date(2101, 1, 1))) 549 def test_from_python_object(self, source): 550 assert MockXLong().translate(source, topython=False) is source 551 552 @pytest.mark.parametrize(("source", "expected"), ( 553 ("-500", -500), 554 ("0", 0), 555 ("000", 0), 556 ("1", 1), 557 ("01", 1), 558 ("100", 100))) 559 def test_to_python_object(self, source, expected): 560 translated = MockXLong().translate(source) 561 assert translated.__class__ is long 562 assert translated == expected 563 564 @pytest.mark.parametrize("source", 565 ("", 0, 1, True, False, 500, _Dummy(), object())) 566 def test_to_python_object__invalid_class_or_empty_string(self, source): 567 assert MockXLong().translate(source) is None 568 569 @pytest.mark.parametrize("source", (" ", "0-0", "x", "poppycock")) 570 def test_to_python_object__invalid_string(self, source, monkeypatch): 571 """ 572 Suds raises raw Python exceptions when it fails to convert received 573 response element data to its mapped Python long data type, according to 574 the used WSDL schema. 575 576 """ 577 monkeypatch.delitem(locals(), "e", False) 578 e = pytest.raises(ValueError, MockXLong().translate, source).value 579 try: 580 # Using different Python interpreter versions and different source 581 # strings results in different exception messages here. 582 try: 583 long(source) 584 pytest.fail("Bad test data.") 585 except ValueError: 586 assert str(e) == str(sys.exc_info()[1]) 587 finally: 588 del e # explicitly break circular reference chain in Python 3 589 590 591class TestXTime: 592 """ 593 suds.xsd.sxbuiltin.XTime.translate() tests. 594 595 Related Python object <--> string conversion details are tested in a 596 separate date/time related test module. These tests are only concerned with 597 basic translate() functionality. 598 599 """ 600 601 def test_from_python_object(self): 602 time = datetime.time(16, 53, 12) 603 translated = MockXTime().translate(time, topython=False) 604 assert translated.__class__ is suds.sax.date.Time 605 assert str(translated) == "16:53:12" 606 607 @pytest.mark.parametrize("source", ( 608 None, 609 object(), 610 _Dummy(), 611 datetime.date(2101, 1, 1), 612 datetime.datetime(2101, 1, 1, 22, 47, 9, 981))) 613 def test_from_python_object__invalid(self, source): 614 assert MockXTime().translate(source, topython=False) is source 615 616 def test_to_python_object(self): 617 assert MockXTime().translate("10:30:22") == datetime.time(10, 30, 22) 618 619 def test_to_python_object__empty_string(self): 620 assert MockXTime().translate("") == None 621 622 623@pytest.mark.parametrize(("xsd_type_name", "xsd_type"), 624 sorted(builtins.items()) + # See 'Project implementation note #1'. 625 [("...unknown...", XBuiltin)]) 626def test_create_builtin_type_schema_objects(xsd_type_name, xsd_type): 627 schema = _create_dummy_schema() 628 xsd_object = Factory.create(schema, xsd_type_name) 629 assert xsd_object.__class__ is xsd_type 630 assert xsd_object.name == xsd_type_name 631 assert xsd_object.schema is schema 632 633 634@pytest.mark.parametrize("xsd_type_name", ("tonkica-polonkica", "integer")) 635def test_create_custom_mapped_builtin_type_schema_objects(xsd_type_name, 636 monkeypatch): 637 """User code can add or update built-in XSD type registrations.""" 638 _monkeypatch_builtin_XSD_type_registry(monkeypatch) 639 class MockType: 640 def __init__(self, schema, name): 641 self.schema = schema 642 self.name = name 643 schema = _Dummy() 644 Factory.maptag(xsd_type_name, MockType) 645 xsd_object = Factory.create(schema, xsd_type_name) 646 assert xsd_object.__class__ is MockType 647 assert xsd_object.name == xsd_type_name 648 assert xsd_object.schema is schema 649 650 651# See 'Project implementation note #1'. 652@pytest.mark.parametrize("name", sorted(builtins.keys())) 653@pytest.mark.parametrize("namespace", builtin_namespaces) 654def test_recognize_builtin_types(name, namespace): 655 schema = _create_dummy_schema() 656 assert schema.builtin((name, namespace)) 657 658 659# See 'Project implementation note #1'. 660@pytest.mark.parametrize("name", sorted(builtins.keys())) 661@pytest.mark.parametrize("namespace", ("", " ", "some-dummy-namespace")) 662def test_recognize_builtin_types_in_unknown_namespace(name, namespace): 663 schema = _create_dummy_schema() 664 assert not schema.builtin((name, namespace)) 665 666 667@pytest.mark.parametrize("name", ("", " ", "x", "xyz")) 668@pytest.mark.parametrize("namespace", builtin_namespaces + 669 ["", " ", "some-dummy-namespace"]) 670def test_recognize_non_builtin_types(name, namespace): 671 schema = _create_dummy_schema() 672 assert not schema.builtin((name, namespace)) 673 674 675def test_recognize_custom_mapped_builtins(monkeypatch): 676 """User code can register additional XSD built-ins.""" 677 _monkeypatch_builtin_XSD_type_registry(monkeypatch) 678 schema = _create_dummy_schema() 679 name = "trla-baba-lan" 680 for ns in builtin_namespaces: 681 assert not schema.builtin((name, ns)) 682 Factory.maptag(name, _Dummy) 683 for ns in builtin_namespaces: 684 assert schema.builtin((name, ns)) 685 686 687def test_resolving_builtin_types(monkeypatch): 688 _monkeypatch_builtin_XSD_type_registry(monkeypatch) 689 class MockXInteger(XInteger): 690 pass 691 Factory.maptag("osama", MockXInteger) 692 693 wsdl = testutils.wsdl('<xsd:element name="wu" type="xsd:osama"/>', 694 input="wu") 695 client = testutils.client_from_wsdl(wsdl) 696 697 element, schema_object = client.sd[0].params[0] 698 assert element.name == "wu" 699 assert element.type == ("osama", "http://www.w3.org/2001/XMLSchema") 700 assert schema_object.__class__ is MockXInteger 701 assert schema_object.name == "osama" 702 assert schema_object.schema is client.wsdl.schema 703 704 705def test_translation(monkeypatch): 706 """Python <--> XML representation translation on marshall/unmarshall.""" 707 anObject = _Dummy() 708 class MockType(XBuiltin): 709 def __init__(self, *args, **kwargs): 710 self._mock_translate_log = [] 711 super(MockType, self).__init__(*args, **kwargs) 712 def translate(self, value, topython=True): 713 self._mock_translate_log.append((value, topython)) 714 if topython: 715 return anObject 716 return "'ollywood" 717 _monkeypatch_builtin_XSD_type_registry(monkeypatch) 718 Factory.maptag("woof", MockType) 719 720 namespace = "I'm a little tea pot, short and stout..." 721 wsdl = testutils.wsdl("""\ 722 <xsd:element name="wi" type="xsd:woof"/> 723 <xsd:element name="wo" type="xsd:woof"/>""", input="wi", output="wo", 724 xsd_target_namespace=namespace, operation_name="f") 725 client = testutils.client_from_wsdl(wsdl, nosend=True, prettyxml=True) 726 727 # Check suds library's XSD schema input parameter information. 728 schema = client.wsdl.schema 729 element_in = schema.elements["wi", namespace] 730 assert element_in.name == "wi" 731 element_out = schema.elements["wo", namespace] 732 assert element_out.name == "wo" 733 schema_object_in = element_in.resolve() 734 schema_object_out = element_out.resolve() 735 assert element_in is client.sd[0].params[0][0] 736 assert schema_object_in is client.sd[0].params[0][1] 737 assert schema_object_in.__class__ is MockType 738 assert schema_object_in._mock_translate_log == [] 739 assert schema_object_out.__class__ is MockType 740 assert schema_object_out._mock_translate_log == [] 741 742 # Construct operation invocation request - test marshalling. 743 request = client.service.f(55) 744 assert schema_object_in._mock_translate_log == [(55, False)] 745 assert schema_object_out._mock_translate_log == [] 746 CompareSAX.data2data(request.envelope, """\ 747<?xml version="1.0" encoding="UTF-8"?> 748<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"> 749 <Header/> 750 <Body> 751 <wi xmlns="%s">'ollywood</wi> 752 </Body> 753</Envelope>""" % (namespace,)) 754 755 # Process operation response - test unmarshalling. 756 response = client.service.f(__inject=dict(reply=suds.byte_str("""\ 757<?xml version="1.0"?> 758<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/"> 759 <Body> 760 <wo xmlns="%s">fri-fru</wo> 761 </Body> 762</Envelope>""" % (namespace,)))) 763 assert response is anObject 764 assert schema_object_in._mock_translate_log == [(55, False)] 765 assert schema_object_out._mock_translate_log == [("fri-fru", True)] 766 767 768def _create_dummy_schema(): 769 """Constructs a new dummy XSD schema instance.""" 770 #TODO: Find out how to construct this XSD schema object directly without 771 # first having to construct a suds.client.Client from a complete WSDL 772 # schema. 773 wsdl = testutils.wsdl('<xsd:element name="dummy"/>', input="dummy") 774 client = testutils.client_from_wsdl(wsdl) 775 return client.wsdl.schema 776 777 778def _monkeypatch_builtin_XSD_type_registry(monkeypatch): 779 """ 780 Monkeypatches the global suds built-in XSD type dictionary. 781 782 After calling this function, a test is free to mess around with suds 783 library's built-in XSD type register (register new ones, change classes 784 registered for a particular XSD type, remove registrations, and such) and 785 any such changes will be automatically undone at the end of the test. 786 787 If a test does not call this function, any such modifications will be left 788 valid in the current global application state and may affect tests run 789 afterwards. 790 791 """ 792 tags = Factory.tags 793 assert tags.__class__ is dict 794 monkeypatch.setattr(Factory, "tags", dict(tags)) 795