@@ -38,13 +38,16 @@ use jj_lib::backend::Commit;
3838use jj_lib:: backend:: CommitId ;
3939use jj_lib:: backend:: Conflict ;
4040use jj_lib:: backend:: ConflictId ;
41+ use jj_lib:: backend:: CopyHistory ;
42+ use jj_lib:: backend:: CopyId ;
4143use jj_lib:: backend:: CopyRecord ;
4244use jj_lib:: backend:: FileId ;
4345use jj_lib:: backend:: SecureSig ;
4446use jj_lib:: backend:: SigningFn ;
4547use jj_lib:: backend:: SymlinkId ;
4648use jj_lib:: backend:: Tree ;
4749use jj_lib:: backend:: TreeId ;
50+ use jj_lib:: dag_walk:: topo_order_forward;
4851use jj_lib:: index:: Index ;
4952use jj_lib:: object_id:: ObjectId as _;
5053use jj_lib:: repo_path:: RepoPath ;
@@ -68,6 +71,7 @@ pub struct TestBackendData {
6871 files : HashMap < RepoPathBuf , HashMap < FileId , Vec < u8 > > > ,
6972 symlinks : HashMap < RepoPathBuf , HashMap < SymlinkId , String > > ,
7073 conflicts : HashMap < RepoPathBuf , HashMap < ConflictId , Conflict > > ,
74+ copies : HashMap < CopyId , CopyHistory > ,
7175}
7276
7377#[ derive( Clone , Default ) ]
@@ -249,6 +253,47 @@ impl Backend for TestBackend {
249253 Ok ( id)
250254 }
251255
256+ async fn read_copy ( & self , id : & CopyId ) -> BackendResult < CopyHistory > {
257+ let copy = self . locked_data ( ) . copies . get ( id) . cloned ( ) . ok_or_else ( || {
258+ BackendError :: ObjectNotFound {
259+ object_type : "copy" . to_string ( ) ,
260+ hash : id. hex ( ) ,
261+ source : "" . into ( ) ,
262+ }
263+ } ) ?;
264+ Ok ( copy)
265+ }
266+
267+ async fn write_copy ( & self , contents : & CopyHistory ) -> BackendResult < CopyId > {
268+ let id = CopyId :: new ( get_hash ( contents) ) ;
269+ self . locked_data ( )
270+ . copies
271+ . insert ( id. clone ( ) , contents. clone ( ) ) ;
272+ Ok ( id)
273+ }
274+
275+ async fn get_related_copies ( & self , copy_id : & CopyId ) -> BackendResult < Vec < CopyHistory > > {
276+ let copies = & self . locked_data ( ) . copies ;
277+ if !copies. contains_key ( copy_id) {
278+ return Err ( BackendError :: ObjectNotFound {
279+ object_type : "copy history" . to_string ( ) ,
280+ hash : copy_id. hex ( ) ,
281+ source : "" . into ( ) ,
282+ } ) ;
283+ }
284+ // Return all copy histories to test that the caller correctly ignores histories
285+ // that are not relevant to the trees they're working with.
286+ let mut histories = vec ! [ ] ;
287+ for id in topo_order_forward (
288+ copies. keys ( ) ,
289+ |id| * id,
290+ |id| copies. get ( * id) . unwrap ( ) . parents . iter ( ) ,
291+ ) {
292+ histories. push ( copies. get ( id) . unwrap ( ) . clone ( ) ) ;
293+ }
294+ Ok ( histories)
295+ }
296+
252297 async fn read_tree ( & self , path : & RepoPath , id : & TreeId ) -> BackendResult < Tree > {
253298 if id == & self . empty_tree_id {
254299 return Ok ( Tree :: default ( ) ) ;
@@ -356,3 +401,46 @@ impl Backend for TestBackend {
356401 Ok ( ( ) )
357402 }
358403}
404+
405+ #[ cfg( test) ]
406+ mod tests {
407+
408+ use pollster:: FutureExt as _;
409+
410+ use super :: * ;
411+ use crate :: repo_path_buf;
412+
413+ fn copy_history ( path : & str , parents : & [ CopyId ] ) -> CopyHistory {
414+ CopyHistory {
415+ current_path : repo_path_buf ( path) ,
416+ parents : parents. to_vec ( ) ,
417+ salt : vec ! [ ] ,
418+ }
419+ }
420+
421+ #[ test]
422+ fn get_related_copies ( ) {
423+ let backend = TestBackend :: with_data ( Arc :: new ( Mutex :: new ( TestBackendData :: default ( ) ) ) ) ;
424+
425+ // Test with a single chain so the resulting order is deterministic
426+ let copy1 = copy_history ( "foo1" , & [ ] ) ;
427+ let copy1_id = backend. write_copy ( & copy1) . block_on ( ) . unwrap ( ) ;
428+ let copy2 = copy_history ( "foo2" , & [ copy1_id. clone ( ) ] ) ;
429+ let copy2_id = backend. write_copy ( & copy2) . block_on ( ) . unwrap ( ) ;
430+ let copy3 = copy_history ( "foo3" , & [ copy2_id. clone ( ) ] ) ;
431+ let copy3_id = backend. write_copy ( & copy3) . block_on ( ) . unwrap ( ) ;
432+
433+ // Error when looking up by non-existent id
434+ assert ! ( backend
435+ . get_related_copies( & CopyId :: from_hex( "abcd" ) )
436+ . block_on( )
437+ . is_err( ) ) ;
438+
439+ // Looking up by any id returns the related copies in the same order (children
440+ // before parents)
441+ let related = backend. get_related_copies ( & copy1_id) . block_on ( ) . unwrap ( ) ;
442+ assert_eq ! ( related, vec![ copy3. clone( ) , copy2. clone( ) , copy1. clone( ) ] ) ;
443+ let related: Vec < CopyHistory > = backend. get_related_copies ( & copy3_id) . block_on ( ) . unwrap ( ) ;
444+ assert_eq ! ( related, vec![ copy3. clone( ) , copy2. clone( ) , copy1. clone( ) ] ) ;
445+ }
446+ }
0 commit comments