1import pytest 2from urllib.parse import SplitResult 3 4from yarl import URL 5 6 7def test_inheritance(): 8 with pytest.raises(TypeError) as ctx: 9 10 class MyURL(URL): # type: ignore[misc] 11 pass 12 13 assert ( 14 "Inheriting a class " 15 "<class 'test_url.test_inheritance.<locals>.MyURL'> " 16 "from URL is forbidden" == str(ctx.value) 17 ) 18 19 20def test_str_subclass(): 21 class S(str): 22 pass 23 24 assert str(URL(S("http://example.com"))) == "http://example.com" 25 26 27def test_is(): 28 u1 = URL("http://example.com") 29 u2 = URL(u1) 30 assert u1 is u2 31 32 33def test_bool(): 34 assert URL("http://example.com") 35 assert not URL() 36 assert not URL("") 37 38 39def test_absolute_url_without_host(): 40 with pytest.raises(ValueError): 41 URL("http://:8080/") 42 43 44def test_url_is_not_str(): 45 url = URL("http://example.com") 46 assert not isinstance(url, str) 47 48 49def test_str(): 50 url = URL("http://example.com:8888/path/to?a=1&b=2") 51 assert str(url) == "http://example.com:8888/path/to?a=1&b=2" 52 53 54def test_repr(): 55 url = URL("http://example.com") 56 assert "URL('http://example.com')" == repr(url) 57 58 59def test_origin(): 60 url = URL("http://user:password@example.com:8888/path/to?a=1&b=2") 61 assert URL("http://example.com:8888") == url.origin() 62 63 64def test_origin_nonascii(): 65 url = URL("http://user:password@историк.рф:8888/path/to?a=1&b=2") 66 assert str(url.origin()) == "http://xn--h1aagokeh.xn--p1ai:8888" 67 68 69def test_origin_ipv6(): 70 url = URL("http://user:password@[::1]:8888/path/to?a=1&b=2") 71 assert str(url.origin()) == "http://[::1]:8888" 72 73 74def test_origin_not_absolute_url(): 75 url = URL("/path/to?a=1&b=2") 76 with pytest.raises(ValueError): 77 url.origin() 78 79 80def test_origin_no_scheme(): 81 url = URL("//user:password@example.com:8888/path/to?a=1&b=2") 82 with pytest.raises(ValueError): 83 url.origin() 84 85 86def test_drop_dots(): 87 u = URL("http://example.com/path/../to") 88 assert str(u) == "http://example.com/to" 89 90 91def test_abs_cmp(): 92 assert URL("http://example.com:8888") == URL("http://example.com:8888") 93 assert URL("http://example.com:8888/") == URL("http://example.com:8888/") 94 assert URL("http://example.com:8888/") == URL("http://example.com:8888") 95 assert URL("http://example.com:8888") == URL("http://example.com:8888/") 96 97 98def test_abs_hash(): 99 url = URL("http://example.com:8888") 100 url_trailing = URL("http://example.com:8888/") 101 assert hash(url) == hash(url_trailing) 102 103 104# properties 105 106 107def test_scheme(): 108 url = URL("http://example.com") 109 assert "http" == url.scheme 110 111 112def test_raw_user(): 113 url = URL("http://user@example.com") 114 assert "user" == url.raw_user 115 116 117def test_raw_user_non_ascii(): 118 url = URL("http://вася@example.com") 119 assert "%D0%B2%D0%B0%D1%81%D1%8F" == url.raw_user 120 121 122def test_no_user(): 123 url = URL("http://example.com") 124 assert url.user is None 125 126 127def test_user_non_ascii(): 128 url = URL("http://вася@example.com") 129 assert "вася" == url.user 130 131 132def test_raw_password(): 133 url = URL("http://user:password@example.com") 134 assert "password" == url.raw_password 135 136 137def test_raw_password_non_ascii(): 138 url = URL("http://user:пароль@example.com") 139 assert "%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C" == url.raw_password 140 141 142def test_password_non_ascii(): 143 url = URL("http://user:пароль@example.com") 144 assert "пароль" == url.password 145 146 147def test_password_without_user(): 148 url = URL("http://:password@example.com") 149 assert url.user is None 150 assert "password" == url.password 151 152 153def test_user_empty_password(): 154 url = URL("http://user:@example.com") 155 assert "user" == url.user 156 assert "" == url.password 157 158 159def test_raw_host(): 160 url = URL("http://example.com") 161 assert "example.com" == url.raw_host 162 163 164def test_raw_host_non_ascii(): 165 url = URL("http://историк.рф") 166 assert "xn--h1aagokeh.xn--p1ai" == url.raw_host 167 168 169def test_host_non_ascii(): 170 url = URL("http://историк.рф") 171 assert "историк.рф" == url.host 172 173 174def test_localhost(): 175 url = URL("http://[::1]") 176 assert "::1" == url.host 177 178 179def test_host_with_underscore(): 180 url = URL("http://abc_def.com") 181 assert "abc_def.com" == url.host 182 183 184def test_raw_host_when_port_is_specified(): 185 url = URL("http://example.com:8888") 186 assert "example.com" == url.raw_host 187 188 189def test_raw_host_from_str_with_ipv4(): 190 url = URL("http://127.0.0.1:80") 191 assert url.raw_host == "127.0.0.1" 192 193 194def test_raw_host_from_str_with_ipv6(): 195 url = URL("http://[::1]:80") 196 assert url.raw_host == "::1" 197 198 199def test_authority_full() -> None: 200 url = URL("http://user:passwd@host.com:8080/path") 201 assert url.raw_authority == "user:passwd@host.com:8080" 202 assert url.authority == "user:passwd@host.com:8080" 203 204 205def test_authority_short() -> None: 206 url = URL("http://host.com/path") 207 assert url.raw_authority == "host.com" 208 209 210def test_authority_full_nonasci() -> None: 211 url = URL("http://ваня:пароль@айдеко.рф:8080/path") 212 assert url.raw_authority == ( 213 "%D0%B2%D0%B0%D0%BD%D1%8F:%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C@" 214 "xn--80aidohy.xn--p1ai:8080" 215 ) 216 assert url.authority == "ваня:пароль@айдеко.рф:8080" 217 218 219def test_lowercase(): 220 url = URL("http://gitHUB.com") 221 assert url.raw_host == "github.com" 222 assert url.host == url.raw_host 223 224 225def test_lowercase_nonascii(): 226 url = URL("http://Айдеко.Рф") 227 assert url.raw_host == "xn--80aidohy.xn--p1ai" 228 assert url.host == "айдеко.рф" 229 230 231def test_compressed_ipv6(): 232 url = URL("http://[1DEC:0:0:0::1]") 233 assert url.raw_host == "1dec::1" 234 assert url.host == url.raw_host 235 236 237def test_ipv6_zone(): 238 url = URL("http://[fe80::822a:a8ff:fe49:470c%тест%42]:123") 239 assert url.raw_host == "fe80::822a:a8ff:fe49:470c%тест%42" 240 assert url.host == url.raw_host 241 242 243def test_ipv4_zone(): 244 # I'm unsure if it is correct. 245 url = URL("http://1.2.3.4%тест%42:123") 246 assert url.raw_host == "1.2.3.4%тест%42" 247 assert url.host == url.raw_host 248 249 250def test_port_for_explicit_port(): 251 url = URL("http://example.com:8888") 252 assert 8888 == url.port 253 254 255def test_port_for_implicit_port(): 256 url = URL("http://example.com") 257 assert 80 == url.port 258 259 260def test_port_for_relative_url(): 261 url = URL("/path/to") 262 assert url.port is None 263 264 265def test_port_for_unknown_scheme(): 266 url = URL("unknown://example.com") 267 assert url.port is None 268 269 270def test_explicit_port_for_explicit_port(): 271 url = URL("http://example.com:8888") 272 assert 8888 == url.explicit_port 273 274 275def test_explicit_port_for_implicit_port(): 276 url = URL("http://example.com") 277 assert url.explicit_port is None 278 279 280def test_explicit_port_for_relative_url(): 281 url = URL("/path/to") 282 assert url.explicit_port is None 283 284 285def test_explicit_port_for_unknown_scheme(): 286 url = URL("unknown://example.com") 287 assert url.explicit_port is None 288 289 290def test_raw_path_string_empty(): 291 url = URL("http://example.com") 292 assert "/" == url.raw_path 293 294 295def test_raw_path(): 296 url = URL("http://example.com/path/to") 297 assert "/path/to" == url.raw_path 298 299 300def test_raw_path_non_ascii(): 301 url = URL("http://example.com/путь/сюда") 302 assert "/%D0%BF%D1%83%D1%82%D1%8C/%D1%81%D1%8E%D0%B4%D0%B0" == url.raw_path 303 304 305def test_path_non_ascii(): 306 url = URL("http://example.com/путь/сюда") 307 assert "/путь/сюда" == url.path 308 309 310def test_path_with_spaces(): 311 url = URL("http://example.com/a b/test") 312 assert "/a b/test" == url.path 313 314 url = URL("http://example.com/a b") 315 assert "/a b" == url.path 316 317 318def test_raw_path_for_empty_url(): 319 url = URL() 320 assert "" == url.raw_path 321 322 323def test_raw_path_for_colon_and_at(): 324 url = URL("http://example.com/path:abc@123") 325 assert url.raw_path == "/path:abc@123" 326 327 328def test_raw_query_string(): 329 url = URL("http://example.com?a=1&b=2") 330 assert url.raw_query_string == "a=1&b=2" 331 332 333def test_raw_query_string_non_ascii(): 334 url = URL("http://example.com?б=в&ю=к") 335 assert url.raw_query_string == "%D0%B1=%D0%B2&%D1%8E=%D0%BA" 336 337 338def test_query_string_non_ascii(): 339 url = URL("http://example.com?б=в&ю=к") 340 assert url.query_string == "б=в&ю=к" 341 342 343def test_path_qs(): 344 url = URL("http://example.com/") 345 assert url.path_qs == "/" 346 url = URL("http://example.com/?б=в&ю=к") 347 assert url.path_qs == "/?б=в&ю=к" 348 url = URL("http://example.com/path?б=в&ю=к") 349 assert url.path_qs == "/path?б=в&ю=к" 350 351 352def test_raw_path_qs(): 353 url = URL("http://example.com/") 354 assert url.raw_path_qs == "/" 355 url = URL("http://example.com/?б=в&ю=к") 356 assert url.raw_path_qs == "/?%D0%B1=%D0%B2&%D1%8E=%D0%BA" 357 url = URL("http://example.com/path?б=в&ю=к") 358 assert url.raw_path_qs == "/path?%D0%B1=%D0%B2&%D1%8E=%D0%BA" 359 url = URL("http://example.com/путь?a=1&b=2") 360 assert url.raw_path_qs == "/%D0%BF%D1%83%D1%82%D1%8C?a=1&b=2" 361 362 363def test_query_string_spaces(): 364 url = URL("http://example.com?a+b=c+d&e=f+g") 365 assert url.query_string == "a b=c d&e=f g" 366 367 368# raw fragment 369 370 371def test_raw_fragment_empty(): 372 url = URL("http://example.com") 373 assert "" == url.raw_fragment 374 375 376def test_raw_fragment(): 377 url = URL("http://example.com/path#anchor") 378 assert "anchor" == url.raw_fragment 379 380 381def test_raw_fragment_non_ascii(): 382 url = URL("http://example.com/path#якорь") 383 assert "%D1%8F%D0%BA%D0%BE%D1%80%D1%8C" == url.raw_fragment 384 385 386def test_raw_fragment_safe(): 387 url = URL("http://example.com/path#a?b/c:d@e") 388 assert "a?b/c:d@e" == url.raw_fragment 389 390 391def test_fragment_non_ascii(): 392 url = URL("http://example.com/path#якорь") 393 assert "якорь" == url.fragment 394 395 396def test_raw_parts_empty(): 397 url = URL("http://example.com") 398 assert ("/",) == url.raw_parts 399 400 401def test_raw_parts(): 402 url = URL("http://example.com/path/to") 403 assert ("/", "path", "to") == url.raw_parts 404 405 406def test_raw_parts_without_path(): 407 url = URL("http://example.com") 408 assert ("/",) == url.raw_parts 409 410 411def test_raw_path_parts_with_2F_in_path(): 412 url = URL("http://example.com/path%2Fto/three") 413 assert ("/", "path%2Fto", "three") == url.raw_parts 414 415 416def test_raw_path_parts_with_2f_in_path(): 417 url = URL("http://example.com/path%2fto/three") 418 assert ("/", "path%2Fto", "three") == url.raw_parts 419 420 421def test_raw_parts_for_relative_path(): 422 url = URL("path/to") 423 assert ("path", "to") == url.raw_parts 424 425 426def test_raw_parts_for_relative_path_starting_from_slash(): 427 url = URL("/path/to") 428 assert ("/", "path", "to") == url.raw_parts 429 430 431def test_raw_parts_for_relative_double_path(): 432 url = URL("path/to") 433 assert url.raw_parts == url.raw_parts 434 435 436def test_parts_for_empty_url(): 437 url = URL() 438 assert ("",) == url.raw_parts 439 440 441def test_raw_parts_non_ascii(): 442 url = URL("http://example.com/путь/сюда") 443 assert ( 444 "/", 445 "%D0%BF%D1%83%D1%82%D1%8C", 446 "%D1%81%D1%8E%D0%B4%D0%B0", 447 ) == url.raw_parts 448 449 450def test_parts_non_ascii(): 451 url = URL("http://example.com/путь/сюда") 452 assert ("/", "путь", "сюда") == url.parts 453 454 455def test_name_for_empty_url(): 456 url = URL() 457 assert "" == url.raw_name 458 459 460def test_raw_name(): 461 url = URL("http://example.com/path/to#frag") 462 assert "to" == url.raw_name 463 464 465def test_raw_name_root(): 466 url = URL("http://example.com/#frag") 467 assert "" == url.raw_name 468 469 470def test_raw_name_root2(): 471 url = URL("http://example.com") 472 assert "" == url.raw_name 473 474 475def test_raw_name_root3(): 476 url = URL("http://example.com/") 477 assert "" == url.raw_name 478 479 480def test_relative_raw_name(): 481 url = URL("path/to") 482 assert "to" == url.raw_name 483 484 485def test_relative_raw_name_starting_from_slash(): 486 url = URL("/path/to") 487 assert "to" == url.raw_name 488 489 490def test_relative_raw_name_slash(): 491 url = URL("/") 492 assert "" == url.raw_name 493 494 495def test_name_non_ascii(): 496 url = URL("http://example.com/путь") 497 assert url.name == "путь" 498 499 500def test_plus_in_path(): 501 url = URL("http://example.com/test/x+y%2Bz/:+%2B/") 502 assert "/test/x+y+z/:++/" == url.path 503 504 505def test_nonascii_in_qs(): 506 url = URL("http://example.com") 507 url2 = url.with_query({"f\xf8\xf8": "f\xf8\xf8"}) 508 assert "http://example.com/?f%C3%B8%C3%B8=f%C3%B8%C3%B8" == str(url2) 509 510 511def test_percent_encoded_in_qs(): 512 url = URL("http://example.com") 513 url2 = url.with_query({"k%cf%80": "v%cf%80"}) 514 assert str(url2) == "http://example.com/?k%25cf%2580=v%25cf%2580" 515 assert url2.raw_query_string == "k%25cf%2580=v%25cf%2580" 516 assert url2.query_string == "k%cf%80=v%cf%80" 517 assert url2.query == {"k%cf%80": "v%cf%80"} 518 519 520# modifiers 521 522 523def test_parent_raw_path(): 524 url = URL("http://example.com/path/to") 525 assert url.parent.raw_path == "/path" 526 527 528def test_parent_raw_parts(): 529 url = URL("http://example.com/path/to") 530 assert url.parent.raw_parts == ("/", "path") 531 532 533def test_double_parent_raw_path(): 534 url = URL("http://example.com/path/to") 535 assert url.parent.parent.raw_path == "/" 536 537 538def test_empty_parent_raw_path(): 539 url = URL("http://example.com/") 540 assert url.parent.parent.raw_path == "/" 541 542 543def test_empty_parent_raw_path2(): 544 url = URL("http://example.com") 545 assert url.parent.parent.raw_path == "/" 546 547 548def test_clear_fragment_on_getting_parent(): 549 url = URL("http://example.com/path/to#frag") 550 assert URL("http://example.com/path") == url.parent 551 552 553def test_clear_fragment_on_getting_parent_toplevel(): 554 url = URL("http://example.com/#frag") 555 assert URL("http://example.com/") == url.parent 556 557 558def test_clear_query_on_getting_parent(): 559 url = URL("http://example.com/path/to?a=b") 560 assert URL("http://example.com/path") == url.parent 561 562 563def test_clear_query_on_getting_parent_toplevel(): 564 url = URL("http://example.com/?a=b") 565 assert URL("http://example.com/") == url.parent 566 567 568# truediv 569 570 571def test_div_root(): 572 url = URL("http://example.com") 573 assert str(url / "path" / "to") == "http://example.com/path/to" 574 575 576def test_div_root_with_slash(): 577 url = URL("http://example.com/") 578 assert str(url / "path" / "to") == "http://example.com/path/to" 579 580 581def test_div(): 582 url = URL("http://example.com/path") 583 assert str(url / "to") == "http://example.com/path/to" 584 585 586def test_div_with_slash(): 587 url = URL("http://example.com/path/") 588 assert str(url / "to") == "http://example.com/path/to" 589 590 591def test_div_path_starting_from_slash_is_forbidden(): 592 url = URL("http://example.com/path/") 593 with pytest.raises(ValueError): 594 url / "/to/others" 595 596 597def test_div_cleanup_query_and_fragment(): 598 url = URL("http://example.com/path?a=1#frag") 599 assert str(url / "to") == "http://example.com/path/to" 600 601 602def test_div_for_empty_url(): 603 url = URL() / "a" 604 assert url.raw_parts == ("a",) 605 606 607def test_div_for_relative_url(): 608 url = URL("a") / "b" 609 assert url.raw_parts == ("a", "b") 610 611 612def test_div_for_relative_url_started_with_slash(): 613 url = URL("/a") / "b" 614 assert url.raw_parts == ("/", "a", "b") 615 616 617def test_div_non_ascii(): 618 url = URL("http://example.com/сюда") 619 url2 = url / "туда" 620 assert url2.path == "/сюда/туда" 621 assert url2.raw_path == "/%D1%81%D1%8E%D0%B4%D0%B0/%D1%82%D1%83%D0%B4%D0%B0" 622 assert url2.parts == ("/", "сюда", "туда") 623 assert url2.raw_parts == ( 624 "/", 625 "%D1%81%D1%8E%D0%B4%D0%B0", 626 "%D1%82%D1%83%D0%B4%D0%B0", 627 ) 628 629 630def test_div_percent_encoded(): 631 url = URL("http://example.com/path") 632 url2 = url / "%cf%80" 633 assert url2.path == "/path/%cf%80" 634 assert url2.raw_path == "/path/%25cf%2580" 635 assert url2.parts == ("/", "path", "%cf%80") 636 assert url2.raw_parts == ("/", "path", "%25cf%2580") 637 638 639def test_div_with_colon_and_at(): 640 url = URL("http://example.com/base") / "path:abc@123" 641 assert url.raw_path == "/base/path:abc@123" 642 643 644def test_div_with_dots(): 645 url = URL("http://example.com/base") / "../path/./to" 646 assert url.raw_path == "/path/to" 647 648 649# with_path 650 651 652def test_with_path(): 653 url = URL("http://example.com") 654 url2 = url.with_path("/test") 655 assert str(url2) == "http://example.com/test" 656 assert url2.raw_path == "/test" 657 assert url2.path == "/test" 658 659 660def test_with_path_nonascii(): 661 url = URL("http://example.com") 662 url2 = url.with_path("/π") 663 assert str(url2) == "http://example.com/%CF%80" 664 assert url2.raw_path == "/%CF%80" 665 assert url2.path == "/π" 666 667 668def test_with_path_percent_encoded(): 669 url = URL("http://example.com") 670 url2 = url.with_path("/%cf%80") 671 assert str(url2) == "http://example.com/%25cf%2580" 672 assert url2.raw_path == "/%25cf%2580" 673 assert url2.path == "/%cf%80" 674 675 676def test_with_path_encoded(): 677 url = URL("http://example.com") 678 url2 = url.with_path("/test", encoded=True) 679 assert str(url2) == "http://example.com/test" 680 assert url2.raw_path == "/test" 681 assert url2.path == "/test" 682 683 684def test_with_path_encoded_nonascii(): 685 url = URL("http://example.com") 686 url2 = url.with_path("/π", encoded=True) 687 assert str(url2) == "http://example.com/π" 688 assert url2.raw_path == "/π" 689 assert url2.path == "/π" 690 691 692def test_with_path_encoded_percent_encoded(): 693 url = URL("http://example.com") 694 url2 = url.with_path("/%cf%80", encoded=True) 695 assert str(url2) == "http://example.com/%cf%80" 696 assert url2.raw_path == "/%cf%80" 697 assert url2.path == "/π" 698 699 700def test_with_path_dots(): 701 url = URL("http://example.com") 702 assert str(url.with_path("/test/.")) == "http://example.com/test/" 703 704 705def test_with_path_relative(): 706 url = URL("/path") 707 assert str(url.with_path("/new")) == "/new" 708 709 710def test_with_path_query(): 711 url = URL("http://example.com?a=b") 712 assert str(url.with_path("/test")) == "http://example.com/test" 713 714 715def test_with_path_fragment(): 716 url = URL("http://example.com#frag") 717 assert str(url.with_path("/test")) == "http://example.com/test" 718 719 720def test_with_path_empty(): 721 url = URL("http://example.com/test") 722 assert str(url.with_path("")) == "http://example.com" 723 724 725def test_with_path_leading_slash(): 726 url = URL("http://example.com") 727 assert url.with_path("test").path == "/test" 728 729 730# with_fragment 731 732 733def test_with_fragment(): 734 url = URL("http://example.com") 735 url2 = url.with_fragment("frag") 736 assert str(url2) == "http://example.com/#frag" 737 assert url2.raw_fragment == "frag" 738 assert url2.fragment == "frag" 739 740 741def test_with_fragment_safe(): 742 url = URL("http://example.com") 743 u2 = url.with_fragment("a:b?c@d/e") 744 assert str(u2) == "http://example.com/#a:b?c@d/e" 745 746 747def test_with_fragment_non_ascii(): 748 url = URL("http://example.com") 749 url2 = url.with_fragment("фрагм") 750 assert url2.raw_fragment == "%D1%84%D1%80%D0%B0%D0%B3%D0%BC" 751 assert url2.fragment == "фрагм" 752 753 754def test_with_fragment_percent_encoded(): 755 url = URL("http://example.com") 756 url2 = url.with_fragment("%cf%80") 757 assert str(url2) == "http://example.com/#%25cf%2580" 758 assert url2.raw_fragment == "%25cf%2580" 759 assert url2.fragment == "%cf%80" 760 761 762def test_with_fragment_None(): 763 url = URL("http://example.com/path#frag") 764 url2 = url.with_fragment(None) 765 assert str(url2) == "http://example.com/path" 766 767 768def test_with_fragment_None_matching(): 769 url = URL("http://example.com/path") 770 url2 = url.with_fragment(None) 771 assert url is url2 772 773 774def test_with_fragment_matching(): 775 url = URL("http://example.com/path#frag") 776 url2 = url.with_fragment("frag") 777 assert url is url2 778 779 780def test_with_fragment_bad_type(): 781 url = URL("http://example.com") 782 with pytest.raises(TypeError): 783 url.with_fragment(123) 784 785 786# with_name 787 788 789def test_with_name(): 790 url = URL("http://example.com/a/b") 791 assert url.raw_parts == ("/", "a", "b") 792 url2 = url.with_name("c") 793 assert url2.raw_parts == ("/", "a", "c") 794 assert url2.parts == ("/", "a", "c") 795 assert url2.raw_path == "/a/c" 796 assert url2.path == "/a/c" 797 798 799def test_with_name_for_naked_path(): 800 url = URL("http://example.com") 801 url2 = url.with_name("a") 802 assert url2.raw_parts == ("/", "a") 803 804 805def test_with_name_for_relative_path(): 806 url = URL("a") 807 url2 = url.with_name("b") 808 assert url2.raw_parts == ("b",) 809 810 811def test_with_name_for_relative_path2(): 812 url = URL("a/b") 813 url2 = url.with_name("c") 814 assert url2.raw_parts == ("a", "c") 815 816 817def test_with_name_for_relative_path_starting_from_slash(): 818 url = URL("/a") 819 url2 = url.with_name("b") 820 assert url2.raw_parts == ("/", "b") 821 822 823def test_with_name_for_relative_path_starting_from_slash2(): 824 url = URL("/a/b") 825 url2 = url.with_name("c") 826 assert url2.raw_parts == ("/", "a", "c") 827 828 829def test_with_name_empty(): 830 url = URL("http://example.com/path/to").with_name("") 831 assert str(url) == "http://example.com/path/" 832 833 834def test_with_name_non_ascii(): 835 url = URL("http://example.com/path").with_name("путь") 836 assert url.path == "/путь" 837 assert url.raw_path == "/%D0%BF%D1%83%D1%82%D1%8C" 838 assert url.parts == ("/", "путь") 839 assert url.raw_parts == ("/", "%D0%BF%D1%83%D1%82%D1%8C") 840 841 842def test_with_name_percent_encoded(): 843 url = URL("http://example.com/path") 844 url2 = url.with_name("%cf%80") 845 assert url2.raw_parts == ("/", "%25cf%2580") 846 assert url2.parts == ("/", "%cf%80") 847 assert url2.raw_path == "/%25cf%2580" 848 assert url2.path == "/%cf%80" 849 850 851def test_with_name_with_slash(): 852 with pytest.raises(ValueError): 853 URL("http://example.com").with_name("a/b") 854 855 856def test_with_name_non_str(): 857 with pytest.raises(TypeError): 858 URL("http://example.com").with_name(123) 859 860 861def test_with_name_within_colon_and_at(): 862 url = URL("http://example.com/oldpath").with_name("path:abc@123") 863 assert url.raw_path == "/path:abc@123" 864 865 866def test_with_name_dot(): 867 with pytest.raises(ValueError): 868 URL("http://example.com").with_name(".") 869 870 871def test_with_name_double_dot(): 872 with pytest.raises(ValueError): 873 URL("http://example.com").with_name("..") 874 875 876# is_absolute 877 878 879def test_is_absolute_for_relative_url(): 880 url = URL("/path/to") 881 assert not url.is_absolute() 882 883 884def test_is_absolute_for_absolute_url(): 885 url = URL("http://example.com") 886 assert url.is_absolute() 887 888 889def test_is_non_absolute_for_empty_url(): 890 url = URL() 891 assert not url.is_absolute() 892 893 894def test_is_non_absolute_for_empty_url2(): 895 url = URL("") 896 assert not url.is_absolute() 897 898 899def test_is_absolute_path_starting_from_double_slash(): 900 url = URL("//www.python.org") 901 assert url.is_absolute() 902 903 904# is_default_port 905 906 907def test_is_default_port_for_relative_url(): 908 url = URL("/path/to") 909 assert not url.is_default_port() 910 911 912def test_is_default_port_for_absolute_url_without_port(): 913 url = URL("http://example.com") 914 assert url.is_default_port() 915 916 917def test_is_default_port_for_absolute_url_with_default_port(): 918 url = URL("http://example.com:80") 919 assert url.is_default_port() 920 921 922def test_is_default_port_for_absolute_url_with_nondefault_port(): 923 url = URL("http://example.com:8080") 924 assert not url.is_default_port() 925 926 927def test_is_default_port_for_unknown_scheme(): 928 url = URL("unknown://example.com:8080") 929 assert not url.is_default_port() 930 931 932# 933 934 935def test_no_scheme(): 936 url = URL("example.com") 937 assert url.raw_host is None 938 assert url.raw_path == "example.com" 939 assert str(url) == "example.com" 940 941 942def test_no_scheme2(): 943 url = URL("example.com/a/b") 944 assert url.raw_host is None 945 assert url.raw_path == "example.com/a/b" 946 assert str(url) == "example.com/a/b" 947 948 949def test_from_non_allowed(): 950 with pytest.raises(TypeError): 951 URL(1234) 952 953 954def test_from_idna(): 955 url = URL("http://xn--jxagkqfkduily1i.eu") 956 assert "http://xn--jxagkqfkduily1i.eu" == str(url) 957 url = URL("http://xn--einla-pqa.de/") # needs idna 2008 958 assert "http://xn--einla-pqa.de/" == str(url) 959 960 961def test_to_idna(): 962 url = URL("http://εμπορικόσήμα.eu") 963 assert "http://xn--jxagkqfkduily1i.eu" == str(url) 964 url = URL("http://einlaß.de/") 965 assert "http://xn--einla-pqa.de/" == str(url) 966 967 968def test_from_ascii_login(): 969 url = URL("http://" "%D0%B2%D0%B0%D1%81%D1%8F" "@host:1234/") 970 assert ("http://" "%D0%B2%D0%B0%D1%81%D1%8F" "@host:1234/") == str(url) 971 972 973def test_from_non_ascii_login(): 974 url = URL("http://вася@host:1234/") 975 assert ("http://" "%D0%B2%D0%B0%D1%81%D1%8F" "@host:1234/") == str(url) 976 977 978def test_from_ascii_login_and_password(): 979 url = URL( 980 "http://" 981 "%D0%B2%D0%B0%D1%81%D1%8F" 982 ":%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C" 983 "@host:1234/" 984 ) 985 assert ( 986 "http://" 987 "%D0%B2%D0%B0%D1%81%D1%8F" 988 ":%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C" 989 "@host:1234/" 990 ) == str(url) 991 992 993def test_from_non_ascii_login_and_password(): 994 url = URL("http://вася:пароль@host:1234/") 995 assert ( 996 "http://" 997 "%D0%B2%D0%B0%D1%81%D1%8F" 998 ":%D0%BF%D0%B0%D1%80%D0%BE%D0%BB%D1%8C" 999 "@host:1234/" 1000 ) == str(url) 1001 1002 1003def test_from_ascii_path(): 1004 url = URL("http://example.com/" "%D0%BF%D1%83%D1%82%D1%8C/%D1%82%D1%83%D0%B4%D0%B0") 1005 assert ( 1006 "http://example.com/" "%D0%BF%D1%83%D1%82%D1%8C/%D1%82%D1%83%D0%B4%D0%B0" 1007 ) == str(url) 1008 1009 1010def test_from_ascii_path_lower_case(): 1011 url = URL("http://example.com/" "%d0%bf%d1%83%d1%82%d1%8c/%d1%82%d1%83%d0%b4%d0%b0") 1012 assert ( 1013 "http://example.com/" "%D0%BF%D1%83%D1%82%D1%8C/%D1%82%D1%83%D0%B4%D0%B0" 1014 ) == str(url) 1015 1016 1017def test_from_non_ascii_path(): 1018 url = URL("http://example.com/путь/туда") 1019 assert ( 1020 "http://example.com/" "%D0%BF%D1%83%D1%82%D1%8C/%D1%82%D1%83%D0%B4%D0%B0" 1021 ) == str(url) 1022 1023 1024def test_bytes(): 1025 url = URL("http://example.com/путь/туда") 1026 assert ( 1027 b"http://example.com/%D0%BF%D1%83%D1%82%D1%8C/%D1%82%D1%83%D0%B4%D0%B0" 1028 == bytes(url) 1029 ) 1030 1031 1032def test_from_ascii_query_parts(): 1033 url = URL( 1034 "http://example.com/" 1035 "?%D0%BF%D0%B0%D1%80%D0%B0%D0%BC" 1036 "=%D0%B7%D0%BD%D0%B0%D1%87" 1037 ) 1038 assert ( 1039 "http://example.com/" 1040 "?%D0%BF%D0%B0%D1%80%D0%B0%D0%BC" 1041 "=%D0%B7%D0%BD%D0%B0%D1%87" 1042 ) == str(url) 1043 1044 1045def test_from_non_ascii_query_parts(): 1046 url = URL("http://example.com/?парам=знач") 1047 assert ( 1048 "http://example.com/" 1049 "?%D0%BF%D0%B0%D1%80%D0%B0%D0%BC" 1050 "=%D0%B7%D0%BD%D0%B0%D1%87" 1051 ) == str(url) 1052 1053 1054def test_from_non_ascii_query_parts2(): 1055 url = URL("http://example.com/?п=з&ю=б") 1056 assert "http://example.com/?%D0%BF=%D0%B7&%D1%8E=%D0%B1" == str(url) 1057 1058 1059def test_from_ascii_fragment(): 1060 url = URL("http://example.com/" "#%D1%84%D1%80%D0%B0%D0%B3%D0%BC%D0%B5%D0%BD%D1%82") 1061 assert ( 1062 "http://example.com/" "#%D1%84%D1%80%D0%B0%D0%B3%D0%BC%D0%B5%D0%BD%D1%82" 1063 ) == str(url) 1064 1065 1066def test_from_bytes_with_non_ascii_fragment(): 1067 url = URL("http://example.com/#фрагмент") 1068 assert ( 1069 "http://example.com/" "#%D1%84%D1%80%D0%B0%D0%B3%D0%BC%D0%B5%D0%BD%D1%82" 1070 ) == str(url) 1071 1072 1073def test_to_str(): 1074 url = URL("http://εμπορικόσήμα.eu/") 1075 assert "http://xn--jxagkqfkduily1i.eu/" == str(url) 1076 1077 1078def test_to_str_long(): 1079 url = URL( 1080 "https://host-12345678901234567890123456789012345678901234567890" "-name:8888/" 1081 ) 1082 expected = ( 1083 "https://host-" 1084 "12345678901234567890123456789012345678901234567890" 1085 "-name:8888/" 1086 ) 1087 assert expected == str(url) 1088 1089 1090def test_decoding_with_2F_in_path(): 1091 url = URL("http://example.com/path%2Fto") 1092 assert "http://example.com/path%2Fto" == str(url) 1093 assert url == URL(str(url)) 1094 1095 1096def test_decoding_with_26_and_3D_in_query(): 1097 url = URL("http://example.com/?%26=%3D") 1098 assert "http://example.com/?%26=%3D" == str(url) 1099 assert url == URL(str(url)) 1100 1101 1102def test_fragment_only_url(): 1103 url = URL("#frag") 1104 assert str(url) == "#frag" 1105 1106 1107def test_url_from_url(): 1108 url = URL("http://example.com") 1109 assert URL(url) == url 1110 assert URL(url).raw_parts == ("/",) 1111 1112 1113def test_lowercase_scheme(): 1114 url = URL("HTTP://example.com") 1115 assert str(url) == "http://example.com" 1116 1117 1118def test_str_for_empty_url(): 1119 url = URL() 1120 assert "" == str(url) 1121 1122 1123def test_parent_for_empty_url(): 1124 url = URL() 1125 assert url is url.parent 1126 1127 1128def test_empty_value_for_query(): 1129 url = URL("http://example.com/path").with_query({"a": ""}) 1130 assert str(url) == "http://example.com/path?a=" 1131 1132 1133def test_none_value_for_query(): 1134 with pytest.raises(TypeError): 1135 URL("http://example.com/path").with_query({"a": None}) 1136 1137 1138def test_decode_pct_in_path(): 1139 url = URL("http://www.python.org/%7Eguido") 1140 assert "http://www.python.org/~guido" == str(url) 1141 1142 1143def test_decode_pct_in_path_lower_case(): 1144 url = URL("http://www.python.org/%7eguido") 1145 assert "http://www.python.org/~guido" == str(url) 1146 1147 1148# join 1149 1150 1151def test_join(): 1152 base = URL("http://www.cwi.nl/%7Eguido/Python.html") 1153 url = URL("FAQ.html") 1154 url2 = base.join(url) 1155 assert str(url2) == "http://www.cwi.nl/~guido/FAQ.html" 1156 1157 1158def test_join_absolute(): 1159 base = URL("http://www.cwi.nl/%7Eguido/Python.html") 1160 url = URL("//www.python.org/%7Eguido") 1161 url2 = base.join(url) 1162 assert str(url2) == "http://www.python.org/~guido" 1163 1164 1165def test_join_non_url(): 1166 base = URL("http://example.com") 1167 with pytest.raises(TypeError): 1168 base.join("path/to") 1169 1170 1171NORMAL = [ 1172 ("g:h", "g:h"), 1173 ("g", "http://a/b/c/g"), 1174 ("./g", "http://a/b/c/g"), 1175 ("g/", "http://a/b/c/g/"), 1176 ("/g", "http://a/g"), 1177 ("//g", "http://g"), 1178 ("?y", "http://a/b/c/d;p?y"), 1179 ("g?y", "http://a/b/c/g?y"), 1180 ("#s", "http://a/b/c/d;p?q#s"), 1181 ("g#s", "http://a/b/c/g#s"), 1182 ("g?y#s", "http://a/b/c/g?y#s"), 1183 (";x", "http://a/b/c/;x"), 1184 ("g;x", "http://a/b/c/g;x"), 1185 ("g;x?y#s", "http://a/b/c/g;x?y#s"), 1186 ("", "http://a/b/c/d;p?q"), 1187 (".", "http://a/b/c/"), 1188 ("./", "http://a/b/c/"), 1189 ("..", "http://a/b/"), 1190 ("../", "http://a/b/"), 1191 ("../g", "http://a/b/g"), 1192 ("../..", "http://a/"), 1193 ("../../", "http://a/"), 1194 ("../../g", "http://a/g"), 1195] 1196 1197 1198@pytest.mark.parametrize("url,expected", NORMAL) 1199def test_join_from_rfc_3986_normal(url, expected): 1200 # test case from https://tools.ietf.org/html/rfc3986.html#section-5.4 1201 base = URL("http://a/b/c/d;p?q") 1202 url = URL(url) 1203 expected = URL(expected) 1204 assert base.join(url) == expected 1205 1206 1207ABNORMAL = [ 1208 ("../../../g", "http://a/g"), 1209 ("../../../../g", "http://a/g"), 1210 ("/./g", "http://a/g"), 1211 ("/../g", "http://a/g"), 1212 ("g.", "http://a/b/c/g."), 1213 (".g", "http://a/b/c/.g"), 1214 ("g..", "http://a/b/c/g.."), 1215 ("..g", "http://a/b/c/..g"), 1216 ("./../g", "http://a/b/g"), 1217 ("./g/.", "http://a/b/c/g/"), 1218 ("g/./h", "http://a/b/c/g/h"), 1219 ("g/../h", "http://a/b/c/h"), 1220 ("g;x=1/./y", "http://a/b/c/g;x=1/y"), 1221 ("g;x=1/../y", "http://a/b/c/y"), 1222 ("g?y/./x", "http://a/b/c/g?y/./x"), 1223 ("g?y/../x", "http://a/b/c/g?y/../x"), 1224 ("g#s/./x", "http://a/b/c/g#s/./x"), 1225 ("g#s/../x", "http://a/b/c/g#s/../x"), 1226] 1227 1228 1229@pytest.mark.parametrize("url,expected", ABNORMAL) 1230def test_join_from_rfc_3986_abnormal(url, expected): 1231 # test case from https://tools.ietf.org/html/rfc3986.html#section-5.4.2 1232 base = URL("http://a/b/c/d;p?q") 1233 url = URL(url) 1234 expected = URL(expected) 1235 assert base.join(url) == expected 1236 1237 1238def test_split_result_non_decoded(): 1239 with pytest.raises(ValueError): 1240 URL(SplitResult("http", "example.com", "path", "qs", "frag")) 1241 1242 1243def test_human_repr(): 1244 url = URL("http://вася:пароль@хост.домен:8080/путь/сюда?арг=вал#фраг") 1245 s = url.human_repr() 1246 assert URL(s) == url 1247 assert s == "http://вася:пароль@хост.домен:8080/путь/сюда?арг=вал#фраг" 1248 1249 1250def test_human_repr_defaults(): 1251 url = URL("путь") 1252 s = url.human_repr() 1253 assert s == "путь" 1254 1255 1256def test_human_repr_default_port(): 1257 url = URL("http://вася:пароль@хост.домен/путь/сюда?арг=вал#фраг") 1258 s = url.human_repr() 1259 assert URL(s) == url 1260 assert s == "http://вася:пароль@хост.домен/путь/сюда?арг=вал#фраг" 1261 1262 1263def test_human_repr_ipv6(): 1264 url = URL("http://[::1]:8080/path") 1265 s = url.human_repr() 1266 url2 = URL(s) 1267 assert url2 == url 1268 assert url2.host == "::1" 1269 assert s == "http://[::1]:8080/path" 1270 1271 1272def test_human_repr_delimiters(): 1273 url = URL.build( 1274 scheme="http", 1275 user=" !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", 1276 password=" !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", 1277 host="хост.домен", 1278 port=8080, 1279 path="/ !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", 1280 query={ 1281 " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~": " !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~" 1282 }, 1283 fragment=" !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~", 1284 ) 1285 s = url.human_repr() 1286 assert URL(s) == url 1287 assert ( 1288 s == "http:// !\"%23$%25&'()*+,-.%2F%3A;<=>%3F%40[\\]^_`{|}~" 1289 ": !\"%23$%25&'()*+,-.%2F%3A;<=>%3F%40[\\]^_`{|}~" 1290 "@хост.домен:8080" 1291 "/ !\"%23$%25&'()*+,-./:;<=>%3F@[\\]^_`{|}~" 1292 "? !\"%23$%25%26'()*%2B,-./:%3B<%3D>?@[\\]^_`{|}~" 1293 "= !\"%23$%25%26'()*%2B,-./:%3B<%3D>?@[\\]^_`{|}~" 1294 "# !\"#$%25&'()*+,-./:;<=>?@[\\]^_`{|}~" 1295 ) 1296 1297 1298def test_human_repr_non_printable(): 1299 url = URL.build( 1300 scheme="http", 1301 user="вася\n\xad\u200b", 1302 password="пароль\n\xad\u200b", 1303 host="хост.домен", 1304 port=8080, 1305 path="/путь\n\xad\u200b", 1306 query={"арг\n\xad\u200b": "вал\n\xad\u200b"}, 1307 fragment="фраг\n\xad\u200b", 1308 ) 1309 s = url.human_repr() 1310 assert URL(s) == url 1311 assert ( 1312 s == "http://вася%0A%C2%AD%E2%80%8B:пароль%0A%C2%AD%E2%80%8B" 1313 "@хост.домен:8080" 1314 "/путь%0A%C2%AD%E2%80%8B" 1315 "?арг%0A%C2%AD%E2%80%8B=вал%0A%C2%AD%E2%80%8B" 1316 "#фраг%0A%C2%AD%E2%80%8B" 1317 ) 1318 1319 1320# relative 1321 1322 1323def test_relative(): 1324 url = URL("http://user:pass@example.com:8080/path?a=b#frag") 1325 rel = url.relative() 1326 assert str(rel) == "/path?a=b#frag" 1327 1328 1329def test_relative_is_relative(): 1330 url = URL("http://user:pass@example.com:8080/path?a=b#frag") 1331 rel = url.relative() 1332 assert not rel.is_absolute() 1333 1334 1335def test_relative_abs_parts_are_removed(): 1336 url = URL("http://user:pass@example.com:8080/path?a=b#frag") 1337 rel = url.relative() 1338 assert not rel.scheme 1339 assert not rel.user 1340 assert not rel.password 1341 assert not rel.host 1342 assert not rel.port 1343 1344 1345def test_relative_fails_on_rel_url(): 1346 with pytest.raises(ValueError): 1347 URL("/path?a=b#frag").relative() 1348 1349 1350def test_slash_and_question_in_query(): 1351 u = URL("http://example.com/path?http://example.com/p?a#b") 1352 assert u.query_string == "http://example.com/p?a" 1353 1354 1355def test_slash_and_question_in_fragment(): 1356 u = URL("http://example.com/path#http://example.com/p?a") 1357 assert u.fragment == "http://example.com/p?a" 1358 1359 1360def test_requoting(): 1361 u = URL("http://127.0.0.1/?next=http%3A//example.com/") 1362 assert u.raw_query_string == "next=http://example.com/" 1363 assert str(u) == "http://127.0.0.1/?next=http://example.com/" 1364