1from math import inf, nan, pi 2from typing import Any 3 4from pytest import raises 5 6from graphql.error import GraphQLError 7from graphql.language import parse_value as parse_value_to_ast 8from graphql.pyutils import Undefined 9from graphql.type import ( 10 GraphQLInt, 11 GraphQLFloat, 12 GraphQLString, 13 GraphQLBoolean, 14 GraphQLID, 15) 16 17 18def describe_type_system_specified_scalar_types(): 19 def describe_graphql_int(): 20 def parse_value(): 21 _parse_value = GraphQLInt.parse_value 22 23 def _parse_value_raises(s: Any, message: str): 24 with raises(GraphQLError) as exc_info: 25 _parse_value(s) 26 assert str(exc_info.value) == message 27 28 assert _parse_value(1) == 1 29 assert _parse_value(0) == 0 30 assert _parse_value(-1) == -1 31 32 _parse_value_raises( 33 9876504321, 34 "Int cannot represent non 32-bit signed integer value: 9876504321", 35 ) 36 _parse_value_raises( 37 -9876504321, 38 "Int cannot represent non 32-bit signed integer value: -9876504321", 39 ) 40 _parse_value_raises(0.1, "Int cannot represent non-integer value: 0.1") 41 _parse_value_raises(nan, "Int cannot represent non-integer value: nan") 42 _parse_value_raises(inf, "Int cannot represent non-integer value: inf") 43 _parse_value_raises( 44 Undefined, "Int cannot represent non-integer value: Undefined" 45 ) 46 _parse_value_raises(None, "Int cannot represent non-integer value: None") 47 _parse_value_raises("", "Int cannot represent non-integer value: ''") 48 _parse_value_raises("123", "Int cannot represent non-integer value: '123'") 49 _parse_value_raises(False, "Int cannot represent non-integer value: False") 50 _parse_value_raises(True, "Int cannot represent non-integer value: True") 51 _parse_value_raises([1], "Int cannot represent non-integer value: [1]") 52 _parse_value_raises( 53 {"value": 1}, "Int cannot represent non-integer value: {'value': 1}" 54 ) 55 56 def parse_literal(): 57 def _parse_literal(s: str): 58 return GraphQLInt.parse_literal(parse_value_to_ast(s)) 59 60 def _parse_literal_raises(s: str, message: str): 61 with raises(GraphQLError) as exc_info: 62 _parse_literal(s) 63 assert str(exc_info.value).startswith(message + "\n") 64 65 assert _parse_literal("1") == 1 66 assert _parse_literal("0") == 0 67 assert _parse_literal("-1") == -1 68 69 _parse_literal_raises( 70 "9876504321", 71 "Int cannot represent non 32-bit signed integer value: 9876504321", 72 ) 73 _parse_literal_raises( 74 "-9876504321", 75 "Int cannot represent non 32-bit signed integer value: -9876504321", 76 ) 77 _parse_literal_raises("1.0", "Int cannot represent non-integer value: 1.0") 78 _parse_literal_raises( 79 "null", "Int cannot represent non-integer value: null" 80 ) 81 _parse_literal_raises( 82 "None", "Int cannot represent non-integer value: None" 83 ) 84 _parse_literal_raises('""', 'Int cannot represent non-integer value: ""') 85 _parse_literal_raises( 86 '"123"', 'Int cannot represent non-integer value: "123"' 87 ) 88 _parse_literal_raises( 89 "false", "Int cannot represent non-integer value: false" 90 ) 91 _parse_literal_raises( 92 "False", "Int cannot represent non-integer value: False" 93 ) 94 _parse_literal_raises("[1]", "Int cannot represent non-integer value: [1]") 95 _parse_literal_raises( 96 "{value: 1}", "Int cannot represent non-integer value: {value: 1}" 97 ) 98 _parse_literal_raises( 99 "ENUM_VALUE", "Int cannot represent non-integer value: ENUM_VALUE" 100 ) 101 _parse_literal_raises( 102 "$var", "Int cannot represent non-integer value: $var" 103 ) 104 105 def serializes(): 106 serialize = GraphQLInt.serialize 107 108 assert serialize(1) == 1 109 assert serialize("123") == 123 110 assert serialize(0) == 0 111 assert serialize(-1) == -1 112 assert serialize(1e5) == 100000 113 assert serialize(False) == 0 114 assert serialize(True) == 1 115 assert serialize(type("Int", (int,), {})(5)) == 5 116 117 # The GraphQL specification does not allow serializing non-integer 118 # values as Int to avoid accidental data loss. 119 with raises(GraphQLError) as exc_info: 120 serialize(0.1) 121 assert str(exc_info.value) == "Int cannot represent non-integer value: 0.1" 122 with raises(GraphQLError) as exc_info: 123 serialize(1.1) 124 assert str(exc_info.value) == "Int cannot represent non-integer value: 1.1" 125 with raises(GraphQLError) as exc_info: 126 serialize(-1.1) 127 assert str(exc_info.value) == "Int cannot represent non-integer value: -1.1" 128 with raises(GraphQLError) as exc_info: 129 serialize("-1.1") 130 assert ( 131 str(exc_info.value) == "Int cannot represent non-integer value: '-1.1'" 132 ) 133 # Maybe a safe JavaScript int, but bigger than 2^32, so not 134 # representable as a GraphQL Int 135 with raises(GraphQLError) as exc_info: 136 serialize(9876504321) 137 assert str(exc_info.value) == ( 138 "Int cannot represent non 32-bit signed integer value: 9876504321" 139 ) 140 with raises(GraphQLError) as exc_info: 141 serialize(-9876504321) 142 assert str(exc_info.value) == ( 143 "Int cannot represent non 32-bit signed integer value: -9876504321" 144 ) 145 # Too big to represent as an Int in JavaScript or GraphQL 146 with raises(GraphQLError) as exc_info: 147 serialize(1e100) 148 assert str(exc_info.value) == ( 149 "Int cannot represent non 32-bit signed integer value: 1e+100" 150 ) 151 with raises(GraphQLError) as exc_info: 152 serialize(-1e100) 153 assert str(exc_info.value) == ( 154 "Int cannot represent non 32-bit signed integer value: -1e+100" 155 ) 156 with raises(GraphQLError) as exc_info: 157 serialize("one") 158 assert ( 159 str(exc_info.value) == "Int cannot represent non-integer value: 'one'" 160 ) 161 # Doesn't represent number 162 with raises(GraphQLError) as exc_info: 163 serialize("") 164 assert str(exc_info.value) == "Int cannot represent non-integer value: ''" 165 with raises(GraphQLError) as exc_info: 166 serialize(nan) 167 assert str(exc_info.value) == "Int cannot represent non-integer value: nan" 168 with raises(GraphQLError) as exc_info: 169 serialize(inf) 170 assert str(exc_info.value) == "Int cannot represent non-integer value: inf" 171 with raises(GraphQLError) as exc_info: 172 serialize([5]) 173 assert str(exc_info.value) == "Int cannot represent non-integer value: [5]" 174 175 def describe_graphql_float(): 176 def parse_value(): 177 _parse_value = GraphQLFloat.parse_value 178 179 def _parse_value_raises(s: Any, message: str): 180 with raises(GraphQLError) as exc_info: 181 _parse_value(s) 182 assert str(exc_info.value) == message 183 184 assert _parse_value(1) == 1 185 assert _parse_value(0) == 0 186 assert _parse_value(-1) == -1 187 assert _parse_value(0.1) == 0.1 188 assert _parse_value(pi) == pi 189 190 _parse_value_raises(nan, "Float cannot represent non numeric value: nan") 191 _parse_value_raises(inf, "Float cannot represent non numeric value: inf") 192 _parse_value_raises("", "Float cannot represent non numeric value: ''") 193 _parse_value_raises( 194 "123", "Float cannot represent non numeric value: '123'" 195 ) 196 _parse_value_raises( 197 "123.5", "Float cannot represent non numeric value: '123.5'" 198 ) 199 _parse_value_raises( 200 False, "Float cannot represent non numeric value: False" 201 ) 202 _parse_value_raises(True, "Float cannot represent non numeric value: True") 203 _parse_value_raises( 204 [0.1], "Float cannot represent non numeric value: [0.1]" 205 ) 206 _parse_value_raises( 207 {"value": 0.1}, 208 "Float cannot represent non numeric value: {'value': 0.1}", 209 ) 210 211 def parse_literal(): 212 def _parse_literal(s: str): 213 return GraphQLFloat.parse_literal(parse_value_to_ast(s)) 214 215 def _parse_literal_raises(s: str, message: str): 216 with raises(GraphQLError) as exc_info: 217 _parse_literal(s) 218 assert str(exc_info.value).startswith(message + "\n") 219 220 assert _parse_literal("1") == 1 221 assert _parse_literal("0") == 0 222 assert _parse_literal("-1") == -1 223 assert _parse_literal("0.1") == 0.1 224 assert _parse_literal(str(pi)) == pi 225 226 _parse_literal_raises( 227 "null", "Float cannot represent non numeric value: null" 228 ) 229 _parse_literal_raises( 230 "None", "Float cannot represent non numeric value: None" 231 ) 232 _parse_literal_raises('""', 'Float cannot represent non numeric value: ""') 233 _parse_literal_raises( 234 '"123"', 'Float cannot represent non numeric value: "123"' 235 ) 236 _parse_literal_raises( 237 '"123.5"', 'Float cannot represent non numeric value: "123.5"' 238 ) 239 _parse_literal_raises( 240 "false", "Float cannot represent non numeric value: false" 241 ) 242 _parse_literal_raises( 243 "False", "Float cannot represent non numeric value: False" 244 ) 245 _parse_literal_raises( 246 "[0.1]", "Float cannot represent non numeric value: [0.1]" 247 ) 248 _parse_literal_raises( 249 "{value: 0.1}", "Float cannot represent non numeric value: {value: 0.1}" 250 ) 251 _parse_literal_raises( 252 "ENUM_VALUE", "Float cannot represent non numeric value: ENUM_VALUE" 253 ) 254 _parse_literal_raises( 255 "$var", "Float cannot represent non numeric value: $var" 256 ) 257 258 def serializes(): 259 serialize = GraphQLFloat.serialize 260 261 assert serialize(1) == 1.0 262 assert serialize(0) == 0.0 263 assert serialize("123.5") == 123.5 264 assert serialize(-1) == -1.0 265 assert serialize(0.1) == 0.1 266 assert serialize(1.1) == 1.1 267 assert serialize(-1.1) == -1.1 268 assert serialize("-1.1") == -1.1 269 assert serialize(False) == 0 270 assert serialize(True) == 1 271 assert serialize(type("Float", (float,), {})(5.5)) == 5.5 272 273 with raises(GraphQLError) as exc_info: 274 serialize(nan) 275 assert ( 276 str(exc_info.value) == "Float cannot represent non numeric value: nan" 277 ) 278 with raises(GraphQLError) as exc_info: 279 serialize(inf) 280 assert ( 281 str(exc_info.value) == "Float cannot represent non numeric value: inf" 282 ) 283 with raises(GraphQLError) as exc_info: 284 serialize("one") 285 assert str(exc_info.value) == ( 286 "Float cannot represent non numeric value: 'one'" 287 ) 288 with raises(GraphQLError) as exc_info: 289 serialize("") 290 assert str(exc_info.value) == "Float cannot represent non numeric value: ''" 291 with raises(GraphQLError) as exc_info: 292 serialize([5]) 293 assert ( 294 str(exc_info.value) == "Float cannot represent non numeric value: [5]" 295 ) 296 297 def describe_graphql_string(): 298 def parse_value(): 299 _parse_value = GraphQLString.parse_value 300 301 def _parse_value_raises(s: Any, message: str): 302 with raises(GraphQLError) as exc_info: 303 _parse_value(s) 304 assert str(exc_info.value) == message 305 306 assert _parse_value("foo") == "foo" 307 308 _parse_value_raises( 309 Undefined, "String cannot represent a non string value: Undefined" 310 ) 311 _parse_value_raises( 312 None, "String cannot represent a non string value: None" 313 ) 314 _parse_value_raises(1, "String cannot represent a non string value: 1") 315 _parse_value_raises(nan, "String cannot represent a non string value: nan") 316 _parse_value_raises( 317 False, "String cannot represent a non string value: False" 318 ) 319 _parse_value_raises( 320 ["foo"], "String cannot represent a non string value: ['foo']" 321 ) 322 _parse_value_raises( 323 {"value": "foo"}, 324 "String cannot represent a non string value: {'value': 'foo'}", 325 ) 326 327 def parse_literal(): 328 def _parse_literal(s: str): 329 return GraphQLString.parse_literal(parse_value_to_ast(s)) 330 331 def _parse_literal_raises(s: str, message: str): 332 with raises(GraphQLError) as exc_info: 333 _parse_literal(s) 334 assert str(exc_info.value).startswith(message + "\n") 335 336 assert _parse_literal('"foo"') == "foo" 337 assert _parse_literal('"""bar"""') == "bar" 338 339 _parse_literal_raises( 340 "null", "String cannot represent a non string value: null" 341 ) 342 _parse_literal_raises( 343 "None", "String cannot represent a non string value: None" 344 ) 345 _parse_literal_raises("1", "String cannot represent a non string value: 1") 346 _parse_literal_raises( 347 "0.1", "String cannot represent a non string value: 0.1" 348 ) 349 _parse_literal_raises( 350 "false", "String cannot represent a non string value: false" 351 ) 352 _parse_literal_raises( 353 "False", "String cannot represent a non string value: False" 354 ) 355 _parse_literal_raises( 356 '["foo"]', 'String cannot represent a non string value: ["foo"]' 357 ) 358 _parse_literal_raises( 359 '{value: "foo"}', 360 'String cannot represent a non string value: {value: "foo"}', 361 ) 362 _parse_literal_raises( 363 "ENUM_VALUE", "String cannot represent a non string value: ENUM_VALUE" 364 ) 365 _parse_literal_raises( 366 "$var", "String cannot represent a non string value: $var" 367 ) 368 369 def serializes(): 370 serialize = GraphQLString.serialize 371 372 assert serialize("string") == "string" 373 assert serialize(1) == "1" 374 assert serialize(-1.1) == "-1.1" 375 assert serialize(True) == "true" 376 assert serialize(False) == "false" 377 378 class StringableObjValue: 379 def __str__(self): 380 return "something useful" 381 382 assert serialize(StringableObjValue()) == "something useful" 383 384 with raises(GraphQLError) as exc_info: 385 serialize(nan) 386 assert str(exc_info.value) == "String cannot represent value: nan" 387 388 with raises(GraphQLError) as exc_info: 389 serialize([1]) 390 assert str(exc_info.value) == "String cannot represent value: [1]" 391 392 with raises(GraphQLError) as exc_info: 393 serialize({}) 394 assert str(exc_info.value) == "String cannot represent value: {}" 395 396 with raises(GraphQLError) as exc_info: 397 serialize({"value_of": "value_of string"}) 398 assert ( 399 str(exc_info.value) == "String cannot represent value:" 400 " {'value_of': 'value_of string'}" 401 ) 402 403 def describe_graphql_boolean(): 404 def parse_value(): 405 _parse_value = GraphQLBoolean.parse_value 406 407 def _parse_value_raises(s: Any, message: str): 408 with raises(GraphQLError) as exc_info: 409 _parse_value(s) 410 assert str(exc_info.value) == message 411 412 assert _parse_value(True) is True 413 assert _parse_value(False) is False 414 415 _parse_value_raises( 416 Undefined, "Boolean cannot represent a non boolean value: Undefined" 417 ) 418 _parse_value_raises( 419 None, "Boolean cannot represent a non boolean value: None" 420 ) 421 _parse_value_raises(0, "Boolean cannot represent a non boolean value: 0") 422 _parse_value_raises(1, "Boolean cannot represent a non boolean value: 1") 423 _parse_value_raises( 424 nan, "Boolean cannot represent a non boolean value: nan" 425 ) 426 _parse_value_raises("", "Boolean cannot represent a non boolean value: ''") 427 _parse_value_raises( 428 "false", "Boolean cannot represent a non boolean value: 'false'" 429 ) 430 _parse_value_raises( 431 "False", "Boolean cannot represent a non boolean value: 'False'" 432 ) 433 _parse_value_raises( 434 [False], "Boolean cannot represent a non boolean value: [False]" 435 ) 436 _parse_value_raises( 437 {"value": False}, 438 "Boolean cannot represent a non boolean value: {'value': False}", 439 ) 440 441 def parse_literal(): 442 def _parse_literal(s: str): 443 return GraphQLBoolean.parse_literal(parse_value_to_ast(s)) 444 445 def _parse_literal_raises(s: str, message: str): 446 with raises(GraphQLError) as exc_info: 447 _parse_literal(s) 448 assert str(exc_info.value).startswith(message + "\n") 449 450 assert _parse_literal("true") is True 451 assert _parse_literal("false") is False 452 453 _parse_literal_raises( 454 "True", "Boolean cannot represent a non boolean value: True" 455 ) 456 _parse_literal_raises( 457 "False", "Boolean cannot represent a non boolean value: False" 458 ) 459 _parse_literal_raises( 460 "null", "Boolean cannot represent a non boolean value: null" 461 ) 462 _parse_literal_raises( 463 "None", "Boolean cannot represent a non boolean value: None" 464 ) 465 _parse_literal_raises( 466 "0", "Boolean cannot represent a non boolean value: 0" 467 ) 468 _parse_literal_raises( 469 "1", "Boolean cannot represent a non boolean value: 1" 470 ) 471 _parse_literal_raises( 472 "0.1", "Boolean cannot represent a non boolean value: 0.1" 473 ) 474 _parse_literal_raises( 475 '""', 'Boolean cannot represent a non boolean value: ""' 476 ) 477 _parse_literal_raises( 478 '"false"', 'Boolean cannot represent a non boolean value: "false"' 479 ) 480 _parse_literal_raises( 481 '"False"', 'Boolean cannot represent a non boolean value: "False"' 482 ) 483 _parse_literal_raises( 484 "[false]", "Boolean cannot represent a non boolean value: [false]" 485 ) 486 _parse_literal_raises( 487 "[False]", "Boolean cannot represent a non boolean value: [False]" 488 ) 489 _parse_literal_raises( 490 "{value: false}", 491 "Boolean cannot represent a non boolean value: {value: false}", 492 ) 493 _parse_literal_raises( 494 "{value: False}", 495 "Boolean cannot represent a non boolean value: {value: False}", 496 ) 497 _parse_literal_raises( 498 "ENUM_VALUE", "Boolean cannot represent a non boolean value: ENUM_VALUE" 499 ) 500 _parse_literal_raises( 501 "$var", "Boolean cannot represent a non boolean value: $var" 502 ) 503 504 def serializes(): 505 serialize = GraphQLBoolean.serialize 506 507 assert serialize(1) is True 508 assert serialize(0) is False 509 assert serialize(True) is True 510 assert serialize(False) is False 511 with raises(TypeError, match="not an acceptable base type"): 512 # you can't subclass bool in Python 513 assert serialize(type("Boolean", (bool,), {})(True)) is True 514 515 with raises(GraphQLError) as exc_info: 516 serialize(nan) 517 assert str(exc_info.value) == ( 518 "Boolean cannot represent a non boolean value: nan" 519 ) 520 521 with raises(GraphQLError) as exc_info: 522 serialize("") 523 assert str(exc_info.value) == ( 524 "Boolean cannot represent a non boolean value: ''" 525 ) 526 527 with raises(GraphQLError) as exc_info: 528 serialize("True") 529 assert str(exc_info.value) == ( 530 "Boolean cannot represent a non boolean value: 'True'" 531 ) 532 533 with raises(GraphQLError) as exc_info: 534 serialize([False]) 535 assert str(exc_info.value) == ( 536 "Boolean cannot represent a non boolean value: [False]" 537 ) 538 539 with raises(GraphQLError) as exc_info: 540 serialize({}) 541 assert str(exc_info.value) == ( 542 "Boolean cannot represent a non boolean value: {}" 543 ) 544 545 def describe_graphql_id(): 546 def parse_value(): 547 _parse_value = GraphQLID.parse_value 548 549 def _parse_value_raises(s: Any, message: str): 550 with raises(GraphQLError) as exc_info: 551 _parse_value(s) 552 assert str(exc_info.value) == message 553 554 assert _parse_value("") == "" 555 assert _parse_value("1") == "1" 556 assert _parse_value("foo") == "foo" 557 assert _parse_value(1) == "1" 558 assert _parse_value(0) == "0" 559 assert _parse_value(-1) == "-1" 560 561 # Maximum and minimum safe numbers in JS 562 assert _parse_value(9007199254740991) == "9007199254740991" 563 assert _parse_value(-9007199254740991) == "-9007199254740991" 564 565 _parse_value_raises(Undefined, "ID cannot represent value: Undefined") 566 _parse_value_raises(None, "ID cannot represent value: None") 567 _parse_value_raises(0.1, "ID cannot represent value: 0.1") 568 _parse_value_raises(nan, "ID cannot represent value: nan") 569 _parse_value_raises(inf, "ID cannot represent value: inf") 570 _parse_value_raises(False, "ID cannot represent value: False") 571 _parse_value_raises(["1"], "ID cannot represent value: ['1']") 572 _parse_value_raises( 573 {"value": "1"}, "ID cannot represent value: {'value': '1'}" 574 ) 575 576 def parse_literal(): 577 def _parse_literal(s: str): 578 return GraphQLID.parse_literal(parse_value_to_ast(s)) 579 580 def _parse_literal_raises(s: str, message: str): 581 with raises(GraphQLError) as exc_info: 582 _parse_literal(s) 583 assert str(exc_info.value).startswith(message + "\n") 584 585 assert _parse_literal('""') == "" 586 assert _parse_literal('"1"') == "1" 587 assert _parse_literal('"foo"') == "foo" 588 assert _parse_literal('"""foo"""') == "foo" 589 assert _parse_literal("1") == "1" 590 assert _parse_literal("0") == "0" 591 assert _parse_literal("-1") == "-1" 592 593 # Support arbitrary long numbers even if they can't be represented in JS 594 assert _parse_literal("90071992547409910") == "90071992547409910" 595 assert _parse_literal("-90071992547409910") == "-90071992547409910" 596 597 _parse_literal_raises( 598 "null", "ID cannot represent a non-string and non-integer value: null" 599 ) 600 _parse_literal_raises( 601 "None", "ID cannot represent a non-string and non-integer value: None" 602 ) 603 _parse_literal_raises( 604 "0.1", "ID cannot represent a non-string and non-integer value: 0.1" 605 ) 606 _parse_literal_raises( 607 "false", "ID cannot represent a non-string and non-integer value: false" 608 ) 609 _parse_literal_raises( 610 "False", "ID cannot represent a non-string and non-integer value: False" 611 ) 612 _parse_literal_raises( 613 '["1"]', 'ID cannot represent a non-string and non-integer value: ["1"]' 614 ) 615 _parse_literal_raises( 616 '{value: "1"}', 617 "ID cannot represent a non-string and non-integer value:" 618 ' {value: "1"}', 619 ) 620 _parse_literal_raises( 621 "ENUM_VALUE", 622 "ID cannot represent a non-string and non-integer value: ENUM_VALUE", 623 ) 624 _parse_literal_raises( 625 "$var", "ID cannot represent a non-string and non-integer value: $var" 626 ) 627 628 def serializes(): 629 serialize = GraphQLID.serialize 630 631 assert serialize("string") == "string" 632 assert serialize("false") == "false" 633 assert serialize("") == "" 634 assert serialize(123) == "123" 635 assert serialize(0) == "0" 636 assert serialize(-1) == "-1" 637 638 class ObjValue: 639 def __init__(self, value): 640 self._id = value 641 642 def __str__(self): 643 return str(self._id) 644 645 obj_value = ObjValue(123) 646 assert serialize(obj_value) == "123" 647 648 with raises(GraphQLError) as exc_info: 649 serialize(True) 650 assert str(exc_info.value) == "ID cannot represent value: True" 651 652 with raises(GraphQLError) as exc_info: 653 serialize(3.14) 654 assert str(exc_info.value) == "ID cannot represent value: 3.14" 655 656 with raises(GraphQLError) as exc_info: 657 serialize({}) 658 assert str(exc_info.value) == "ID cannot represent value: {}" 659 660 with raises(GraphQLError) as exc_info: 661 serialize(["abc"]) 662 assert str(exc_info.value) == "ID cannot represent value: ['abc']" 663