
    רiL                    $   d Z ddlmZ ddlZddlmc mZ ddl	Z	ddl
Z
ddlZddlZddlZddlZddlmZ ddlZdZeej&                  vrej&                  j)                  de       ddlmc mZ ddlmZmZmZmZmZ ddlmZ dddZ dd	Z! ejD                  d
      d        Z# ejD                         d        Z$ G d d      Z% G d d      Z& G d d      Z' G d d      Z(e)dk(  r*ddlZ ejT                   ejV                  e,ddg             yy)uC  
Story 7.05 — Registry Integration Tests
=========================================
Comprehensive black-box and white-box tests for MODULE 7: Platform Registry.

Test summary (11 tests):
  BB  test_all_builtins_registered        — 10 platforms present at import
  BB  test_register_and_get               — register → get → same config
  BB  test_list_platforms                 — register 3 → list returns correct names
  BB  test_unknown_platform               — returns None for unknown name
  BB  test_case_insensitive               — "HubSpot" lookup == "hubspot"
  BB  test_custom_yaml_overrides_builtin  — YAML config overwrites existing entry
  BB  test_load_from_yaml                 — valid YAML → platform registered
  BB  test_invalid_yaml_skipped           — bad YAML syntax → skipped, warning logged
  BB  test_missing_required_field         — YAML without 'name' → skipped
  WB  test_platform_names_lowercase       — all built-in keys are lower-case
  WB  test_config_immutability            — mutating returned config doesn't change registry
    )annotationsN)Optionalz/mnt/e/genesis-system)PLATFORM_REGISTRYget_platformlist_platformsload_custom_platformsregister_platform)PlatformConfigc                ^    t        | j                         | j                         d|  d      S )z1Create a minimal PlatformConfig for use in tests.zhttps://docs.z.example.comnamedisplay_namedocs_base_url)r
   lowertitle)r   s    >/mnt/e/genesis-system/tests/kb/test_m7_registry_integration.py_make_platformr   6   s-    ZZ\ZZ\%dV<8     c                    t         j                  j                  | |      }t        |dd      5 }|j	                  |       ddd       |S # 1 sw Y   |S xY w)zFWrite *content* to *filename* inside *directory* and return full path.wzutf-8)encodingN)ospathjoinopenwrite)	directoryfilenamecontentr   fhs        r   _write_yamlr!   ?   sJ    77<<	8,D	dC'	* b
KKs   AAT)autousec               #     K   t        j                  t              } d t        j                          t        j                  |        yw)z
    Snapshot the registry before each test and restore it afterwards.
    This keeps tests isolated without paying the cost of a full module reload.
    N)copydeepcopyr   clearupdate)snapshots    r   _restore_registryr)   K   s4      }}./H	X&s   AA
c                    t        |       S )z<Return a temporary directory suitable for YAML config files.)str)tmp_paths    r   tmp_config_dirr-   W   s     x=r   c                  N    e Zd ZdZh dZh dZeez  Zd Zd Zd Z	d Z
d Zd	 Zy
)TestBuiltinRegistrationuD   7.01 / 7.02 / 7.03 — Built-in platforms auto-registered at import.>   xerostripetelnyxhubspotgohighlevel>   aroflofergussimprotradify	servicem8c                   t        t                     }| j                  }|j                  } ||      }|st	        j
                  d| j                  |z
         dz   dt        j                         v st	        j                  |       rt	        j                  |       ndt	        j                  |      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }t        t	        j                  |            dx}x}}y)uA   BB — 10 built-in platforms must be present after module import.zMissing built-ins: zm
>assert %(py7)s
{%(py7)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.ALL_BUILTIN
}.issubset
}(%(py5)s)
}self
registered)py0py2py4py5py7N)setr   ALL_BUILTINissubset
@pytest_ar_format_assertmsg@py_builtinslocals_should_repr_global_name	_safereprAssertionError_format_explanation)r;   r<   @py_assert1@py_assert3@py_assert6@py_format8s         r   test_all_builtins_registeredz4TestBuiltinRegistration.test_all_builtins_registeredi   s&   )*
 	
(( 	
(4 	
4 	
  "$"2"2Z"?!@A	
 	
	6	
 	
   	
 	
 		  	
 	
 		   	
 	
 		 ) 	
 	
	6	
 	
  *4 	
 	
 		 *4 	
 	
 		 5 	
 	
 	
 	
 	
 	
r   c           	        | j                   D ]  }t        |      }d}||u}|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d| d      dz   d	|iz  }t        t        j                  |            dx}}|j                  }|j                  }d
} ||      }	|	st        j                  d| d|j                         dz   dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |	      dz  }
t        t        j                  |
            dx}x}x}}	 y)u?   BB — Each of the Core-5 platforms is individually accessible.Nis notz%(py0)s is not %(py3)scfgr=   py3zCore platform '' not found in registry
>assert %(py5)sr@   http
Platform '' has invalid docs_base_url: q
>assert %(py8)s
{%(py8)s = %(py4)s
{%(py4)s = %(py2)s
{%(py2)s = %(py0)s.docs_base_url
}.startswith
}(%(py6)s)
}r=   r>   r?   py6py8)
CORE_NAMESr   rE   _call_reprcomparerG   rH   rI   rJ   rF   rK   rL   r   
startswithr;   r   rV   @py_assert2rM   @py_format4@py_format6rN   @py_assert5@py_assert7@py_format9s              r   test_core_5_presentz+TestBuiltinRegistration.test_core_5_presentp   s   OO 	Dt$C"S3d?SSS3dSSSSSS3SSS3SSSdSSSodV;R$SSSSSSS$$ $//  /7 7   TF"?@Q@Q?RS v     I   I %  I 0  I 17  I 8      	r   c           	        | j                   D ]  }t        |      }d}||u}|st        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d| d      dz   d	|iz  }t        t        j                  |            dx}}|j                  }|j                  }d
} ||      }	|	st        j                  d| d|j                         dz   dt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      t        j                  |      t        j                  |	      dz  }
t        t        j                  |
            dx}x}x}}	 y)uD   BB — Each of the AU-Trades-5 platforms is individually accessible.NrS   rU   rV   rW   zAU trades platform 'rY   rZ   r@   r[   r\   r]   r^   r_   )AU_TRADE_NAMESr   rE   rc   rG   rH   rI   rJ   rF   rK   rL   r   rd   re   s              r   test_au_trades_5_presentz0TestBuiltinRegistration.test_au_trades_5_presenty   s   '' 	Dt$C"X3d?XXX3dXXXXXX3XXX3XXXdXXX&:4&@W$XXXXXXX$$ $//  /7 7   TF"?@Q@Q?RS v     I   I %  I 0  I 17  I 8      	r   c                   t        d      }d}||u}|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|j                  }d}||u}|st        j                  d|fd	||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}x}}d}	|j                  }|j                  }
 |
       }|	|v }|st        j                  d|fd|	|f      t        j                  |	      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |
      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}	x}x}x}
}y)u/   BB — HubSpot built-in includes a sitemap URL.r3   NrS   rU   rV   rW   assert %(py5)sr@   z7%(py2)s
{%(py2)s = %(py0)s.sitemap_url
} is not %(py5)sr=   r>   r@   assert %(py7)srA   sitemapin)ze%(py1)s in %(py9)s
{%(py9)s = %(py7)s
{%(py7)s = %(py5)s
{%(py5)s = %(py3)s.sitemap_url
}.lower
}()
})py1rX   r@   rA   py9zassert %(py11)spy11)r   rE   rc   rG   rH   rI   rJ   rK   rL   sitemap_urlr   )r;   rV   rf   rM   rg   rh   @py_assert4rN   rP   @py_assert0rO   @py_assert8@py_format10@py_format12s                 r   test_hubspot_has_sitemapz0TestBuiltinRegistration.test_hubspot_has_sitemap   so   9%s$s$ss$*d*d****d******s***s******d*******3COO3O113133y33333y3333y333333C333C333O3331333333333333r   c                   t        d      }d}||u}|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|j                  }d}||u}|st        j                  d|fd	||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}x}}y)u.   BB — Stripe built-in includes a sitemap URL.r1   NrS   rU   rV   rW   rq   r@   rr   rs   rt   rA   
r   rE   rc   rG   rH   rI   rJ   rK   rL   r{   	r;   rV   rf   rM   rg   rh   r|   rN   rP   s	            r   test_stripe_has_sitemapz/TestBuiltinRegistration.test_stripe_has_sitemap       8$s$s$ss$*d*d****d******s***s******d*******r   c                   t        d      }d}||u}|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|j                  }d}||u}|st        j                  d|fd	||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      t        j                  |      d
z  }dd|iz  }t        t        j                  |            dx}x}}y)u.   BB — Telnyx built-in includes a sitemap URL.r2   NrS   rU   rV   rW   rq   r@   rr   rs   rt   rA   r   r   s	            r   test_telnyx_has_sitemapz/TestBuiltinRegistration.test_telnyx_has_sitemap   r   r   N)__name__
__module____qualname____doc__rb   rn   rC   rQ   rl   ro   r   r   r    r   r   r/   r/   a   s:    N HJKN~-K
4++r   r/   c                  4    e Zd ZdZd Zd Zd Zd Zd Zd Z	y)	TestRegistryOperationsu=   7.01 — Register, get, list, and unknown-platform behaviour.c                l   t        d      }t        |       t        d      }d}||u}|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|j                  }d}||k(  }|st        j                  d	|fd
||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }dd|iz  }	t        t        j                  |	            dx}x}}|j                  }|j                  }
||
k(  }|st        j                  d	|fd||
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}}
|j                  }|j                  }
||
k(  }|st        j                  d	|fd||
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}}
y)u>   BB — Registered config can be retrieved with correct values.acmeplatformNrS   rU   	retrievedrW   rq   r@   ==)z,%(py2)s
{%(py2)s = %(py0)s.name
} == %(py5)srs   rt   rA   )zV%(py2)s
{%(py2)s = %(py0)s.display_name
} == %(py6)s
{%(py6)s = %(py4)s.display_name
}rV   r=   r>   r?   r`   zassert %(py8)sra   )zX%(py2)s
{%(py2)s = %(py0)s.docs_base_url
} == %(py6)s
{%(py6)s = %(py4)s.docs_base_url
})r   r	   r   rE   rc   rG   rH   rI   rJ   rK   rL   r   r   r   )r;   rV   r   rf   rM   rg   rh   r|   rN   rP   ri   @py_format7rk   s                r   test_register_and_getz,TestRegistryOperations.test_register_and_get   s   ^,# 0	 $$y$$$$y$$$$$$y$$$y$$$$$$$$$$~~//~////~//////y///y///~//////////%%9)9)99%)99999%)9999999y999y999%999999999999)99999999&&;#*;*;;&*;;;;;&*;;;;;;;y;;;y;;;&;;;;;;#;;;#;;;*;;;;;;;;r   c                n   t        t        d             t        t        d             t        t        d             t               }d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }dd	|iz  }t        t        j                  |            d
x}}d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }dd	|iz  }t        t        j                  |            d
x}}d}||v }|st        j                  d|fd||f      t        j
                  |      dt        j                         v st        j                  |      rt        j
                  |      nddz  }dd	|iz  }t        t        j                  |            d
x}}y
)uH   BB — list_platforms() returns all registered names including new ones.alphabetagammarv   z%(py1)s in %(py3)snamesrx   rX   rq   r@   N)r	   r   r   rE   rc   rJ   rG   rH   rI   rK   rL   )r;   r   r}   rf   rg   rh   s         r   test_list_platformsz*TestRegistryOperations.test_list_platforms   s;   .12.01.12 w%w%w%%vvvw%w%w%%r   c                   t               }t        |      }||k(  }|s9t        j                  d|fd||f      dt	        j
                         v st        j                  |      rt        j                  |      nddt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  |      rt        j                  |      ndt        j                  |      dz  }t        j                  d      dz   d|iz  }t        t        j                  |            d	x}}y	)
u.   BB — list_platforms() returns a sorted list.r   )z0%(py0)s == %(py5)s
{%(py5)s = %(py2)s(%(py3)s)
}r   sorted)r=   r>   rX   r@   z,list_platforms() should return a sorted listz
>assert %(py7)srA   N)r   r   rE   rc   rG   rH   rI   rJ   rF   rK   rL   )r;   r   r|   rM   rh   rP   s         r   test_list_platforms_is_sortedz4TestRegistryOperations.test_list_platforms_is_sorted   s     uUu%UUUuUUUUUUuUUUuUUUUUUUUUUUUUUUuUUUuUUUUUU'UUUUUUUr   c                d   t        d      }d}||u }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}y)	u>   BB — get_platform returns None for an unknown platform name.this_does_not_exist_xyzNis)z%(py0)s is %(py3)sresultrW   rq   r@   )	r   rE   rc   rG   rH   rI   rJ   rK   rL   )r;   r   rf   rM   rg   rh   s         r   "test_unknown_platform_returns_nonez9TestRegistryOperations.test_unknown_platform_returns_none   se    78v~vvvr   c                f   t        ddd      }t        |       d}t        |      }d}||u}|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}x}}d}t        |      }d}||u}|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}x}}d}t        |      }d}||u}|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}x}}d}t        |      }d}||u}|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      t        j                  |      d	z  }d
d|iz  }t        t        j                  |            dx}x}x}}y)u@   BB — Registry lookup is case-insensitive for registered names.HubSpotzhttps://knowledge.hubspot.comr   r3   NrS   z4%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} is not %(py7)sr   r=   r>   r?   rA   assert %(py9)sry   HUBSPOThUbSpOt)r
   r	   r   rE   rc   rG   rH   rI   rJ   rK   rL   )r;   rV   rM   rN   rO   ri   rP   r   s           r   test_case_insensitive_getz0TestRegistryOperations.test_case_insensitive_get   s%   "9

 	# &2|I&2d2&d2222&d222222|222|222I222&222d2222222%2|I&2d2&d2222&d222222|222|222I222&222d2222222%2|I&2d2&d2222&d222222|222|222I222&222d2222222%2|I&2d2&d2222&d222222|222|222I222&222d2222222r   c                   t        t        ddd             t        t        ddd             t        d      }d}||u}|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|j                  }d}||k(  }|st        j                  d|fd||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}|j                  }d}||k(  }|st        j                  d|fd||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)uD   BB — Registering a platform with same name replaces the old entry.
myplatformOldzhttps://old.example.comr   Newzhttps://new.example.comNrS   rU   rV   rW   rq   r@   r   z4%(py2)s
{%(py2)s = %(py0)s.display_name
} == %(py5)srs   rt   rA   z5%(py2)s
{%(py2)s = %(py0)s.docs_base_url
} == %(py5)s)r	   r
   r   rE   rc   rG   rH   rI   rJ   rK   rL   r   r   r   s	            r   !test_register_overwrites_existingz8TestRegistryOperations.test_register_overwrites_existing   s~   .EAZ
 	 	.EAZ
 	 <(s$s$ss$(5(5((((5((((((s(((s((((((5(((((((  =$== $===== $=======s===s=== ===$========r   N)
r   r   r   r   r   r   r   r   r   r   r   r   r   r   r      s$    G	<	 V

3>r   r   c                  L    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
d	 Zd
 Zd Zy)TestYamlLoadingu+   7.04 — load_custom_platforms() behaviour.c                J	   t        j                  d      }t        |d|       t        |      }d}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}}t        d      }d
}||u}|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}}|j                  }d}	||	k(  }
|
st	        j
                  d|
fd||	f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |	      dz  }dd|iz  }t        t	        j                  |            d
x}x}
}	|j                  }d}	||	k(  }
|
st	        j
                  d|
fd||	f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |	      dz  }dd|iz  }t        t	        j                  |            d
x}x}
}	|j                  }d}	||	k(  }
|
st	        j
                  d|
fd||	f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |	      dz  }dd|iz  }t        t	        j                  |            d
x}x}
}	|j                   }d}	||	k(  }
|
st	        j
                  d|
fd||	f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |	      dz  }dd|iz  }t        t	        j                  |            d
x}x}
}	y
)u8   BB — Valid YAML file results in a registered platform.z            name: acmecorp
            display_name: Acme Corp
            docs_base_url: https://docs.acmecorp.example.com
            sitemap_url: https://docs.acmecorp.example.com/sitemap.xml
            max_pages: 100
        zacmecorp.yaml   r   z%(py0)s == %(py3)scountrW   rq   r@   NacmecorprS   rU   rV   z	Acme Corpr   rs   rt   rA   z!https://docs.acmecorp.example.comr   z-https://docs.acmecorp.example.com/sitemap.xml)z3%(py2)s
{%(py2)s = %(py0)s.sitemap_url
} == %(py5)sd   z1%(py2)s
{%(py2)s = %(py0)s.max_pages
} == %(py5)s)textwrapdedentr!   r   rE   rc   rG   rH   rI   rJ   rK   rL   r   r   r   r{   	max_pagesr;   r-   yaml_contentr   rf   rM   rg   rh   rV   r|   rN   rP   s               r   test_load_from_yamlz#TestYamlLoading.test_load_from_yaml   s    (  	NO\B%n5uzuuu:&s$s$ss$.;.;....;......s...s......;.......  G$GG $GGGGG $GGGGGGGsGGGsGGG GGG$GGGGGGGGQ"QQ"QQQQQ"QQQQQQQsQQQsQQQQQQ"QQQQQQQQ}}##}####}######s###s###}##########r   c                *   t        j                  d      }t        |d|       t        |      }d}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}}t        d      }d
}||u}|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}}|j                  }d}	||	k(  }
|
st	        j
                  d|
fd||	f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |	      dz  }dd|iz  }t        t	        j                  |            d
x}x}
}	|j                  }d}	||	k(  }
|
st	        j
                  d|
fd||	f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      t	        j                  |	      dz  }dd|iz  }t        t	        j                  |            d
x}x}
}	y
)uF   BB — YAML config with same name as a built-in replaces the built-in.z            name: hubspot
            display_name: HubSpot Custom
            docs_base_url: https://custom.hubspot.example.com
        zhubspot_custom.yamlr   r   r   r   rW   rq   r@   Nr3   rS   rU   rV   zHubSpot Customr   rs   rt   rA   z"https://custom.hubspot.example.comr   )r   r   r!   r   rE   rc   rG   rH   rI   rJ   rK   rL   r   r   r   r   s               r   "test_custom_yaml_overrides_builtinz2TestYamlLoading.test_custom_yaml_overrides_builtin   s      ( 
 	N$9<H%n5uzuuu9%s$s$ss$3#33#33333#3333333s333s333333#33333333  H$HH $HHHHH $HHHHHHHsHHHsHHH HHH$HHHHHHHHr   c                   d}t        |d|       ddl}|j                  |j                  d      5  t	        |      }ddd       d}|k(  }|st        j                  d|fd||f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
z  }dd|iz  }	t        t        j                  |	            dx}}d}t        |      }
d}|
|u }|st        j                  d|fd|
|f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |
      t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}
x}}y# 1 sw Y   xY w)u<   BB — Syntactically invalid YAML is skipped with a warning.z/name: bad
  - this: is: invalid: yaml:
   :::::zbad.yamlr   Ncore.kb.platform_registryloggerr   r   r   rW   rq   r@   badr   )z0%(py4)s
{%(py4)s = %(py0)s(%(py2)s)
} is %(py7)sr   r   r   ry   )r!   loggingat_levelWARNINGr   rE   rc   rG   rH   rI   rJ   rK   rL   r   )r;   r-   caplogbad_yamlr   r   rf   rM   rg   rh   rN   rO   ri   rP   r   s                  r   test_invalid_yaml_skippedz)TestYamlLoading.test_invalid_yaml_skipped   s%   FNJ9__W__5P_Q 	:).9E	: uzuuu!*|E"*d*"d****"d******|***|***E***"***d*******	: 	:s   GGc                   t        j                  d      }t        |d|       ddl}|j	                  |j
                  d      5  t        |      }ddd       d}|k(  }|st        j                  d|fd||f      d	t        j                         v st        j                  |      rt        j                  |      nd	t        j                  |      d
z  }dd|iz  }	t        t        j                  |	            dx}}y# 1 sw Y   xY w)u;   BB — YAML missing 'name' field is skipped with a warning.zi            display_name: No Name Platform
            docs_base_url: https://noname.example.com
        znoname.yamlr   Nr   r   r   r   r   rW   rq   r@   )r   r   r!   r   r   r   r   rE   rc   rG   rH   rI   rJ   rK   rL   )
r;   r-   r   r   r   r   rf   rM   rg   rh   s
             r   #test_missing_required_field_skippedz3TestYamlLoading.test_missing_required_field_skipped  s     (  	NM<@__W__5P_Q 	:).9E	: uzuuu	: 	:s   C??Dc                   t        j                  d      }t        |d|       t        |      }d}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}}y
)u4   BB — YAML missing 'display_name' field is skipped.z]            name: nodisplay
            docs_base_url: https://nodisplay.example.com
        znodisplay.yamlr   r   r   r   rW   rq   r@   Nr   r   r!   r   rE   rc   rG   rH   rI   rJ   rK   rL   r;   r-   r   r   rf   rM   rg   rh   s           r   !test_missing_display_name_skippedz1TestYamlLoading.test_missing_display_name_skipped       (  	N$4lC%n5uzuuur   c                   t        j                  d      }t        |d|       t        |      }d}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}}y
)u5   BB — YAML missing 'docs_base_url' field is skipped.zJ            name: nodocsurl
            display_name: No Docs URL
        znodocsurl.yamlr   r   r   r   rW   rq   r@   Nr   r   s           r   "test_missing_docs_base_url_skippedz2TestYamlLoading.test_missing_docs_base_url_skipped%  r   r   c                f   t        |      }d}||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}y)	u'   BB — Empty directory returns count 0.r   r   r   r   rW   rq   r@   N)	r   rE   rc   rG   rH   rI   rJ   rK   rL   )r;   r-   r   rf   rM   rg   rh   s          r   !test_empty_directory_returns_zeroz1TestYamlLoading.test_empty_directory_returns_zero/  sd    %n5uzuuur   c           
        t        d      D ]2  }t        j                  d| d| d| d      }t        |d| d|       4 t	        |      }d}||k(  }|st        j                  d|fd	||f      d
t        j                         v st        j                  |      rt        j                  |      nd
t        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}t        d      D ]  }d| }t        |      }	d}
|	|
u}|st        j                  d|fd|	|
f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |	      t        j                  |
      dz  }dd|iz  }t        t        j                  |            dx}x}	x}}
 y)u4   BB — Multiple valid YAML files all get registered.   z                name: platformz(
                display_name: Platform z5
                docs_base_url: https://docs.platformz.example.com
            platformz.yamlr   r   r   rW   rq   r@   NrS   r   r   r   r   ry   )ranger   r   r!   r   rE   rc   rG   rH   rI   rJ   rK   rL   r   )r;   r-   ir   r   rf   rM   rg   rh   rN   rO   ri   rP   r   s                 r   test_multiple_yaml_filesz(TestYamlLoading.test_multiple_yaml_files4  sb   q 	KA#?? 0 c "(()s +556C 8, L
 (1#U(;\J	K &n5uzuuuq 	<A"*1#;</;t;/t;;;;/t;;;;;;<;;;<;;;;;;/;;;t;;;;;;;	<r   c                v   t        j                  d      }t        |d|       t        |      }d}||k(  }|st	        j
                  d|fd||f      dt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }dd	|iz  }t        t	        j                  |            d
x}}d}t        |      }d
}	||	u}
|
st	        j
                  d|
fd||	f      dt        j                         v st	        j                  t              rt	        j                  t              ndt	        j                  |      t	        j                  |      t	        j                  |	      dz  }dd|iz  }t        t	        j                  |            d
x}x}x}
}	y
)u=   BB — Files with .yml extension (not just .yaml) are loaded.z            name: ymlplatform
            display_name: YML Platform
            docs_base_url: https://docs.ymlplatform.example.com
        zymlplatform.ymlr   r   r   r   rW   rq   r@   NymlplatformrS   r   r   r   r   ry   )r   r   r!   r   rE   rc   rG   rH   rI   rJ   rK   rL   r   )r;   r-   r   r   rf   rM   rg   rh   rN   rO   ri   rP   r   s                r   test_yml_extension_loadedz)TestYamlLoading.test_yml_extension_loadedC  s    ( 
 	N$5|D%n5uzuuu)6|M*6$6*$6666*$666666|666|666M666*666$6666666r   c                *   t        j                  d      }t        |d|       t        |       d}t	        |      }d}||u}|st        j                  d|fd||f      dt        j                         v st        j                  t              rt        j                  t              ndt        j                  |      t        j                  |      t        j                  |      dz  }d	d
|iz  }t        t        j                  |            dx}x}x}}y)u6   BB — YAML names are lower-cased during registration.z            name: MyMixedCase
            display_name: My Mixed Case
            docs_base_url: https://docs.mixedcase.example.com
        zmixedcase.yamlmymixedcaseNrS   r   r   r   r   ry   )r   r   r!   r   r   rE   rc   rG   rH   rI   rJ   rK   rL   )	r;   r-   r   rM   rN   rO   ri   rP   r   s	            r   &test_yaml_name_normalized_to_lowercasez6TestYamlLoading.test_yaml_name_normalized_to_lowercaseO  s     ( 
 	N$4lCn-)6|M*6$6*$6666*$666666|666|666M666*666$6666666r   N)r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r      s8    5$*I$+
<
7
7r   r   c                  :    e Zd ZdZd Zd Zd Zd Zd Zd Z	d Z
y	)
TestWhiteBoxz/Internal structure and immutability guarantees.c                   t        j                         D ],  }|j                  } |       }||k(  }|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |      dz  }t        j                  d| d      dz   d|iz  }t        t        j                  |            d	x}x}}/ y	)
u<   WB — All keys in PLATFORM_REGISTRY are lower-case strings.r   )zD%(py0)s == %(py6)s
{%(py6)s = %(py4)s
{%(py4)s = %(py2)s.lower
}()
}keyr   zRegistry key 'z' is not lower-casez
>assert %(py8)sra   N)r   keysr   rE   rc   rG   rH   rI   rJ   rF   rK   rL   )r;   r   rN   ri   rM   r   rk   s          r   test_platform_names_lowercasez*TestWhiteBox.test_platform_names_lowercasec  s    $))+ 	C)) )+ 3+%   3+  v     I   v     I   I $  I &    !%89     	r   c                   t        d      }d}||u}|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|j                  }d	|_	        |j                  j                  d
       t        d      }d}||u}|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}}|j                  }||k(  }|st        j                  d|fd||f      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dt        j                         v st        j
                  |      rt        j                  |      nddz  }	dd|	iz  }
t        t        j                  |
            dx}}d
}|j                  }||v}|st        j                  d|fd||f      t        j                  |      dt        j                         v st        j
                  |      rt        j                  |      ndt        j                  |      dz  }dd|iz  }t        t        j                  |            dx}x}}y)uA   WB — Mutating the returned config does not affect the registry.r3   NrS   rU   cfg_originalrW   rq   r@   zhttps://mutated.example.comzhttps://injected.example.com/*	cfg_freshr   )z5%(py2)s
{%(py2)s = %(py0)s.docs_base_url
} == %(py4)soriginal_url)r=   r>   r?   zassert %(py6)sr`   not in)z8%(py1)s not in %(py5)s
{%(py5)s = %(py3)s.url_patterns
})rx   rX   r@   rt   rA   )r   rE   rc   rG   rH   rI   rJ   rK   rL   r   url_patternsappend)r;   r   rf   rM   rg   rh   r   r   rN   @py_format5r   r}   r|   rP   s                 r   test_config_immutabilityz%TestWhiteBox.test_config_immutabilityj  s   #I.#''|4''''|4''''''|'''|'''4'''''''#11 &C"!!(()IJ !+	 $$y$$$$y$$$$$$y$$$y$$$$$$$$$$&&6&,6666&,666666y666y666&666666,666,6666666/My7M7MM/7MMMMM/7MMMM/MMMMMMyMMMyMMM7MMMMMMMMr   c                
   t        ddd      }t        |       d}|t        v }|st        j                  d|fd|t        f      t        j
                  |      dt        j                         v st        j                  t              rt        j
                  t              ndd	z  }d
d|iz  }t        t        j                  |            dx}}d}|t        v}|st        j                  d|fd|t        f      t        j
                  |      dt        j                         v st        j                  t              rt        j
                  t              ndd	z  }d
d|iz  }t        t        j                  |            dx}}y)uE   WB — register_platform() stores the entry under the lower-case key.UpperCasePlatformzUpper Case Platformzhttps://upper.example.comr   uppercaseplatformrv   r   r   r   rq   r@   Nr   )z%(py1)s not in %(py3)s)r
   r	   r   rE   rc   rJ   rG   rH   rI   rK   rL   )r;   rV   r}   rf   rg   rh   s         r   %test_register_stores_by_lowercase_keyz2TestWhiteBox.test_register_stores_by_lowercase_keyz  s    $.5

 	#"7"&77777"&7777"777777&7777&77777777";"*;;;;;"*;;;;";;;;;;*;;;;*;;;;;;;;r   c                d   t         j                  }t        |t              }|s'ddt	        j
                         v st        j                  t              rt        j                  t              nddt	        j
                         v st        j                  t               rt        j                  t               ndt        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              ndt        j                  |      dz  }t        t        j                  |            dx}}t        d      t         j                  d<   d}|t        v }|st        j                  d	|fd
|t        f      t        j                  |      dt	        j
                         v st        j                  t              rt        j                  t              nddz  }dd|iz  }t        t        j                  |            dx}}t         j                  d= y)uB   WB — PLATFORM_REGISTRY is the actual dict exposed by the module.z\assert %(py6)s
{%(py6)s = %(py0)s(%(py3)s
{%(py3)s = %(py1)s.PLATFORM_REGISTRY
}, %(py4)s)
}
isinstancereg_moddict)r=   rx   rX   r?   r`   Nsentinel_sentinel_test_keyrv   r   r   r   rq   r@   )r  r   r   r  rG   rH   rE   rI   rJ   rK   rL   r   rc   )r;   rf   ri   r   r}   rg   rh   s          r   +test_platform_registry_is_module_level_dictz8TestWhiteBox.test_platform_registry_is_module_level_dict  s'   !33:z3T::::::::z:::z::::::':::':::3::::::T:::T:::::::::::H:T!!"67#8#'88888#'8888#888888'8888'88888888%%&:;r   c                   t        j                  d      }t        d      }||u}|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      nddt        j                         v st        j                  |      rt        j                  |      nddz  }t        j                  d      dz   d	|iz  }t        t        j                  |            d
}y
)uJ   WB — get_platform() never returns the same object as the registry entry.r3   rS   )z%(py0)s is not %(py2)sr   	raw_entry)r=   r>   zCget_platform() must return a copy, not the original registry objectz
>assert %(py4)sr?   N)r   getr   rE   rc   rG   rH   rI   rJ   rF   rK   rL   )r;   r  r   rM   @py_format3r   s         r   )test_get_returns_deepcopy_not_same_objectz6TestWhiteBox.test_get_returns_deepcopy_not_same_object  s    %)))4	 +		) 	
 	
y	 	
 	
	6	
 	
   	
 	
 		  	
 	
	6	
 	
  !* 	
 	
 		 !* 	
 	
  R	
 	
 	
 	
 	
r   c                   t        t                     }t        t        d             t        t                     }d}||v }|st	        j
                  d|fd||f      t	        j                  |      dt        j                         v st	        j                  |      rt	        j                  |      nddz  }dd|iz  }t        t	        j                  |            dx}}||z
  }dh}||k(  }|st	        j
                  d	|fd
||f      dt        j                         v st	        j                  |      rt	        j                  |      nddt        j                         v st	        j                  |      rt	        j                  |      ndt	        j                  |      dz  }dd|iz  }	t        t	        j                  |	            dx}x}}y)u7   WB — list_platforms() reflects additions immediately.newentry999rv   r   afterr   rq   r@   Nr   )z(%(py0)s - %(py1)s) == %(py5)sbefore)r=   rx   r@   rt   rA   )rB   r   r	   r   rE   rc   rJ   rG   rH   rI   rK   rL   )
r;   r  r  r}   rf   rg   rh   r|   rN   rP   s
             r   .test_list_platforms_reflects_new_registrationsz;TestWhiteBox.test_list_platforms_reflects_new_registrations  s   ^%&.78N$%%}%%%%}%%%}%%%%%%%%%%%%%%%%v~0-0~0000~000000u000u000000v000v0000000000r   c                Z   t        j                  d      }t        j                  j	                  t        |      d      }t        |d      5 }|j                  |       ddd       t        t        |             t        d      }d}||u}|st        j                  d|fd||f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      d	z  }d
d|iz  }	t!        t        j"                  |	            dx}}|j$                  }d}
||
k(  }|st        j                  d|fd||
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |
      dz  }	dd|	iz  }t!        t        j"                  |            dx}x}}
|j&                  }d}
||
k(  }|st        j                  d|fd||
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |
      dz  }	dd|	iz  }t!        t        j"                  |            dx}x}}
|j(                  }d}
||
k(  }|st        j                  d|fd||
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |
      dz  }	dd|	iz  }t!        t        j"                  |            dx}x}}
|j*                  }d}
||
k(  }|st        j                  d|fd||
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |
      dz  }	dd|	iz  }t!        t        j"                  |            dx}x}}
|j,                  }d}
||
k(  }|st        j                  d|fd||
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |
      dz  }	dd|	iz  }t!        t        j"                  |            dx}x}}
|j.                  }d}
||
u }|st        j                  d|fd||
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |
      dz  }	dd|	iz  }t!        t        j"                  |            dx}x}}
|j0                  }d}
||
u }|st        j                  d|fd||
f      dt        j                         v st        j                  |      rt        j                  |      ndt        j                  |      t        j                  |
      dz  }	dd|	iz  }t!        t        j"                  |            dx}x}}
y# 1 sw Y   ExY w)uA   WB — YAML without optional fields uses PlatformConfig defaults.z            name: minimalplatform
            display_name: Minimal Platform
            docs_base_url: https://minimal.example.com
        zminimal.yamlr   NminimalplatformrS   rU   rV   rW   rq   r@   i  r   )z2%(py2)s
{%(py2)s = %(py0)s.chunk_size
} == %(py5)srs   rt   rA      )z5%(py2)s
{%(py2)s = %(py0)s.chunk_overlap
} == %(py5)si  r      )z5%(py2)s
{%(py2)s = %(py0)s.refresh_hours
} == %(py5)snone)z1%(py2)s
{%(py2)s = %(py0)s.auth_type
} == %(py5)sFr   )z7%(py2)s
{%(py2)s = %(py0)s.use_browserless
} is %(py5)s)z3%(py2)s
{%(py2)s = %(py0)s.sitemap_url
} is %(py5)s)r   r   r   r   r   r+   r   r   r   r   rE   rc   rG   rH   rI   rJ   rK   rL   
chunk_sizechunk_overlapr   refresh_hours	auth_typeuse_browserlessr{   )r;   r,   r   r   r    rV   rf   rM   rg   rh   r|   rN   rP   s                r   'test_yaml_optional_fields_have_defaultsz4TestWhiteBox.test_yaml_optional_fields_have_defaults  s    ( 
 ww||CM>:$_ 	#HH\"	# 	c(m,,-s$s$ss$~~%%~%%%%~%%%%%%s%%%s%%%~%%%%%%%%%%  'C' C'''' C''''''s'''s''' '''C'''''''}}$$}$$$$}$$$$$$s$$$s$$$}$$$$$$$$$$  'C' C'''' C''''''s'''s''' '''C'''''''}}&&}&&&&}&&&&&&s&&&s&&&}&&&&&&&&&&""+e+"e++++"e++++++s+++s+++"+++e+++++++&$&$&&&&$&&&&&&s&&&s&&&&&&$&&&&&&&	# 	#s   Z  Z*N)r   r   r   r   r   r   r   r  r
  r  r  r   r   r   r   r   `  s)    9N 	<<
1'r   r   __main__z-vz
--tb=short)testplatform)r   r+   returnr
   )r   r+   r   r+   r   r+   r  r+   )-r   
__future__r   builtinsrG   _pytest.assertion.rewrite	assertionrewriterE   r$   	importlibr   systempfiler   typingr   pytest_PROJECT_ROOTr   insertcore.kb.platform_registrykbplatform_registryr  r   r   r   r   r	   core.kb.contractsr
   r   r!   fixturer)   r-   r/   r   r   r   r   exitmain__file__r   r   r   <module>r2     s  & #     	 
     ( HHOOA}% , +  - ' '  2+ 2+j=> =>@C7 C7TR' R'r zCHH[V[[(D,789 r   