1212import pytest
1313import requests
1414from pytest_bdd import given , parsers , then , when
15+ from typing_extensions import TypeGuard
1516from yarl import URL
1617
1718from pact .v3 import Pact
19+ from pact .v3 .error import (
20+ BodyMismatch ,
21+ BodyTypeMismatch ,
22+ HeaderMismatch ,
23+ MetadataMismatch ,
24+ Mismatch ,
25+ MissingRequest ,
26+ PathMismatch ,
27+ QueryMismatch ,
28+ RequestMismatch ,
29+ RequestNotFound ,
30+ StatusMismatch ,
31+ )
1832from tests .v3 .compatibility_suite .util import (
1933 FIXTURES_ROOT ,
2034 PactInteractionTuple ,
3549
3650logger = logging .getLogger (__name__ )
3751
52+
53+ MISMATCH_MAP : dict [str , type [Mismatch ]] = {
54+ "query" : QueryMismatch ,
55+ "header" : HeaderMismatch ,
56+ "body" : BodyMismatch ,
57+ "body-content-type" : BodyTypeMismatch ,
58+ }
59+
60+
61+ def _mismatch_with_path (
62+ mismatch : Mismatch ,
63+ ) -> TypeGuard [MissingRequest | RequestNotFound | RequestMismatch | BodyMismatch ]:
64+ """
65+ Check if a mismatch has a `path` attribute.
66+
67+ This function is used to check if the mismatch in question is one of the
68+ variants that have a `path` attribute. This has little purpose at runtime,
69+ but is useful for type checking.
70+ """
71+ return isinstance (
72+ mismatch , (MissingRequest , RequestNotFound , RequestMismatch , BodyMismatch )
73+ )
74+
75+
76+ def _mismatch_with_mismatch (
77+ mismatch : Mismatch ,
78+ ) -> TypeGuard [
79+ PathMismatch
80+ | StatusMismatch
81+ | QueryMismatch
82+ | HeaderMismatch
83+ | BodyTypeMismatch
84+ | BodyMismatch
85+ | MetadataMismatch
86+ ]:
87+ """
88+ Check if a mismatch has a `mismatch` attribute.
89+
90+ This function is used to check if the mismatch in question is one of the
91+ variants that have a `mismatch` attribute. This has little purpose at runtime,
92+ but is useful for type checking.
93+ """
94+ return isinstance (
95+ mismatch ,
96+ (
97+ PathMismatch ,
98+ StatusMismatch ,
99+ QueryMismatch ,
100+ HeaderMismatch ,
101+ BodyTypeMismatch ,
102+ BodyMismatch ,
103+ MetadataMismatch ,
104+ ),
105+ )
106+
107+
38108################################################################################
39109## Given
40110################################################################################
@@ -285,7 +355,11 @@ def _(
285355 indent = 2 ,
286356 ),
287357 )
288- logger .info ("Mismatches:\n %s" , json .dumps (srv .mismatches , indent = 2 ))
358+ msg = "\n " .join ([
359+ "Mismatches:" ,
360+ * (f" ({ i + 1 } ) { m } " for i , m in enumerate (srv .mismatches )),
361+ ])
362+ logger .info (msg )
289363 assert response .status_code == code
290364
291365
@@ -363,9 +437,9 @@ def _(
363437
364438 for mismatch in srv .mismatches :
365439 if (
366- mismatch [ "method" ] == interaction_definitions [ n ]. method
367- and mismatch [ "path" ] == interaction_definitions [n ].path
368- and mismatch [ "type" ] == "missing-request"
440+ isinstance ( mismatch , MissingRequest )
441+ and mismatch . method == interaction_definitions [n ].method
442+ and mismatch . path == interaction_definitions [ n ]. path
369443 ):
370444 return
371445 pytest .fail ("Expected mismatch not found" )
@@ -397,10 +471,10 @@ def _(
397471
398472 for mismatch in srv .mismatches :
399473 if (
400- mismatch [ "method" ] == interaction_definitions [ n ]. method
401- and mismatch [ "request" ][ " method" ] == method
402- and mismatch [ "path" ] == interaction_definitions [ n ]. path
403- and mismatch [ "type" ] == "request-not-found"
474+ isinstance ( mismatch , RequestNotFound )
475+ and mismatch . method == interaction_definitions [ n ]. method
476+ and mismatch . method == method
477+ and mismatch . path == interaction_definitions [ n ]. path
404478 ):
405479 return
406480 pytest .fail ("Expected mismatch not found" )
@@ -431,9 +505,9 @@ def _(
431505
432506 for mismatch in srv .mismatches :
433507 if (
434- mismatch [ "request" ][ "method" ] == method
435- and mismatch [ "path" ] == path
436- and mismatch [ "type" ] == "request-not-found"
508+ isinstance ( mismatch , RequestNotFound )
509+ and mismatch . method == method
510+ and mismatch . path == path
437511 ):
438512 return
439513 pytest .fail ("Expected mismatch not found" )
@@ -470,27 +544,17 @@ def _(
470544 """
471545 The mismatches will contain a mismatch with the error.
472546 """
473- if mismatch_type == "query" :
474- mismatch_type = "QueryMismatch"
475- elif mismatch_type == "header" :
476- mismatch_type = "HeaderMismatch"
477- elif mismatch_type == "body" :
478- mismatch_type = "BodyMismatch"
479- elif mismatch_type == "body-content-type" :
480- mismatch_type = "BodyTypeMismatch"
481- else :
482- msg = f"Unexpected mismatch type: { mismatch_type } "
483- raise ValueError (msg )
484-
485547 logger .info ("Expecting mismatch: %s" , mismatch_type )
486548 logger .info ("With error: %s" , error )
487549 for mismatch in srv .mismatches :
488- for sub_mismatch in mismatch ["mismatches" ]:
489- if (
490- error in sub_mismatch ["mismatch" ]
491- and sub_mismatch ["type" ] == mismatch_type
492- ):
493- return
550+ if isinstance (mismatch , RequestMismatch ):
551+ for sub_mismatch in mismatch .mismatches :
552+ if (
553+ isinstance (sub_mismatch , MISMATCH_MAP [mismatch_type ])
554+ and _mismatch_with_mismatch (sub_mismatch )
555+ and error in sub_mismatch .mismatch
556+ ):
557+ return
494558 pytest .fail ("Expected mismatch not found" )
495559
496560
@@ -514,13 +578,15 @@ def _(
514578 """
515579 The mismatches will contain a mismatch with the error.
516580 """
517- mismatch_type = "BodyMismatch" if mismatch_type == "body" else mismatch_type
518581 for mismatch in srv .mismatches :
519- for sub_mismatch in mismatch ["mismatches" ]:
582+ assert isinstance (mismatch , RequestMismatch )
583+ for sub_mismatch in mismatch .mismatches :
520584 if (
521- sub_mismatch ["mismatch" ] == error
522- and sub_mismatch ["type" ] == mismatch_type
523- and sub_mismatch ["path" ] == path
585+ isinstance (sub_mismatch , MISMATCH_MAP [mismatch_type ])
586+ and _mismatch_with_mismatch (sub_mismatch )
587+ and sub_mismatch .mismatch == error
588+ and _mismatch_with_path (sub_mismatch )
589+ and sub_mismatch .path == path
524590 ):
525591 return
526592 pytest .fail ("Expected mismatch not found" )
0 commit comments