@@ -607,6 +607,91 @@ mod tests {
607607 }
608608 }
609609
610+ /// #674 end to end through the real lanes: the hosted rewrite, then the
611+ /// takeover's per-pin `restore_upstream` and vendored wiring for each
612+ /// package in turn, then a revert in either order.
613+ #[ tokio:: test]
614+ async fn takeover_through_hosted_unwind_reverts_byte_exact ( ) {
615+ use crate :: patch:: redirect:: upstream:: { restore_upstream, HostedPin , RestoreOptions } ;
616+ let original = "[build-system]\n requires = [\" hatchling\" ]\n build-backend = \" hatchling.build\" \n \n [project]\n name = \" app\" \n version = \" 0.1.0\" \n dependencies = [\" six==1.16.0\" , \" toml==0.10.2\" ]\n " ;
617+ let packages = [
618+ ( "six" , "1.16.0" , UUID ) ,
619+ ( "toml" , "0.10.2" , "a0f74f9a-ce65-4451-ab60-025159b4d410" ) ,
620+ ] ;
621+ let deps: Vec < crate :: patch:: redirect:: DepOverride > = packages
622+ . iter ( )
623+ . map ( |( name, version, uuid) | {
624+ serde_json:: from_value ( json ! ( {
625+ "ecosystem" : "pypi" , "name" : name, "version" : version,
626+ "token" : "11111111-1111-1111-1111-111111111111" ,
627+ "patchUuid" : uuid,
628+ "artifactUrl" : format!(
629+ "https://patch.socket.dev/patch/pypi/{name}/{version}/11111111-1111-1111-1111-111111111111/{uuid}/{name}-{version}-py3-none-any.whl"
630+ ) ,
631+ "integrity" : { "sha256" : "d" . repeat( 64 ) }
632+ } ) )
633+ . unwrap ( )
634+ } )
635+ . collect ( ) ;
636+ let input = BTreeMap :: from ( [ ( "pyproject.toml" . to_owned ( ) , original. to_owned ( ) ) ] ) ;
637+ let hosted = crate :: patch:: redirect:: rewrite_registry_redirect_with_pipenv_version (
638+ & input,
639+ & deps,
640+ & BTreeMap :: new ( ) ,
641+ None ,
642+ false ,
643+ ) ;
644+ let hosted = & hosted. files [ "pyproject.toml" ] ;
645+ assert ! (
646+ hosted. contains( "allow-direct-references = true" ) ,
647+ "{hosted}"
648+ ) ;
649+ for order in [ [ 0 , 1 ] , [ 1 , 0 ] ] {
650+ let temp = tempfile:: tempdir ( ) . unwrap ( ) ;
651+ let root = temp. path ( ) ;
652+ tokio:: fs:: write ( root. join ( "pyproject.toml" ) , hosted)
653+ . await
654+ . unwrap ( ) ;
655+ let pins = HostedPin :: all ( & crate :: vex:: discover_patched_refs ( root) . await ) ;
656+ assert_eq ! ( pins. len( ) , 2 , "{pins:?}" ) ;
657+ let mut state = VendorState :: default ( ) ;
658+ let mut entries = Vec :: new ( ) ;
659+ for ( name, version, uuid) in packages {
660+ let pin = pins. iter ( ) . find ( |pin| pin. uuid == uuid) . unwrap ( ) ;
661+ let restore = restore_upstream (
662+ root,
663+ std:: slice:: from_ref ( pin) ,
664+ & RestoreOptions {
665+ offline : true ,
666+ ..RestoreOptions :: default ( )
667+ } ,
668+ )
669+ . await ;
670+ assert_eq ! ( restore. refused( ) . count( ) , 0 , "{name}" ) ;
671+ let project = load ( root, name, version, uuid) . await . unwrap ( ) ;
672+ let wheel = format ! ( ".socket/vendor/pypi/{uuid}/{name}-{version}-py3-none-any.whl" ) ;
673+ let wiring = wire ( & project, root, name, version, & wheel, & "0" . repeat ( 64 ) )
674+ . await
675+ . unwrap ( ) ;
676+ let entry = entry ( uuid, name, & wheel, & "0" . repeat ( 64 ) , wiring) ;
677+ state. entries . insert ( name. into ( ) , entry. clone ( ) ) ;
678+ entries. push ( entry) ;
679+ save_state ( root, & state) . await . unwrap ( ) ;
680+ }
681+ for index in order {
682+ let outcome = revert ( & entries[ index] , root, false ) . await ;
683+ assert ! ( outcome. success, "{:?}" , outcome. error) ;
684+ }
685+ assert_eq ! (
686+ tokio:: fs:: read_to_string( root. join( "pyproject.toml" ) )
687+ . await
688+ . unwrap( ) ,
689+ original,
690+ "order {order:?}"
691+ ) ;
692+ }
693+ }
694+
610695 /// The #674 drop only applies to a permission recorded while
611696 /// non-vendored direct references were live. A permission the user set
612697 /// is restored verbatim after two vendored packages are reverted, inline
0 commit comments