@@ -486,8 +486,6 @@ async def test_download_files_default_location(
486486
487487class TestGetManifestAsync :
488488 """Integration tests for DownloadList.get_manifest_async.
489-
490- - test_get_manifest_with_custom_csv_descriptor: tab-separated descriptor produces TSV
491489 """
492490
493491 async def test_get_manifest_with_custom_csv_descriptor (
@@ -498,8 +496,19 @@ async def test_get_manifest_with_custom_csv_descriptor(
498496 scheduled_for_cart_removal : list ,
499497 ) -> None :
500498 """get_manifest_async() respects a custom CsvTableDescriptor."""
501- # GIVEN a cart containing one of our files
502- file = await _create_test_file (project , syn , schedule_for_cleanup )
499+ # GIVEN a cart containing a file whose name contains the quote
500+ # character, so the writer must emit the escape character
501+ path = utils .make_bogus_uuid_file ()
502+ schedule_for_cleanup (path )
503+ uuid_suffix = str (uuid .uuid4 ())
504+ file_name = f"it's_{ uuid_suffix } "
505+ file = File (
506+ parent_id = project ["id" ],
507+ path = path ,
508+ name = file_name ,
509+ )
510+ await file .store_async (synapse_client = syn )
511+ schedule_for_cleanup (file .id )
503512 await _add_to_cart (file , syn , scheduled_for_cart_removal )
504513
505514 # WHEN I request a manifest with all non-default descriptor options
@@ -516,24 +525,36 @@ async def test_get_manifest_with_custom_csv_descriptor(
516525 )
517526 schedule_for_cleanup (manifest_path )
518527
519- # THEN the downloaded file uses the custom descriptor settings
520528 with open (manifest_path , newline = "" ) as f :
521529 content = f .read ()
522530
523- # AND tab separator is used
531+ # THEN tab separator is used
524532 assert "\t " in content , "Expected tab separators in manifest"
525533
526- # AND lines end with \n (not \r\n or other)
527- lines = content .split ("\n " )
528- lines = [line for line in lines if line ]
534+ # AND the escape character was used for the embedded quote in the file name
535+ assert "/'" in content , (
536+ f"Expected escape sequence /' in manifest (from escaping ' in file name), "
537+ f"got: { content !r} "
538+ )
539+
540+ # AND line endings are LF only (no CR)
541+ assert "\r " not in content , "Expected LF-only line endings; found CR"
529542
530- # AND our file appears in the raw content (no header row)
531- assert len (lines ) >= 1 , "Expected at least one row in the manifest"
532- assert any (
533- file .id in line for line in lines
534- ), f"Expected { file .id } in manifest content"
543+ # AND there is no header row -- the first non-empty line is the data row
544+ lines = [line for line in content .split ("\n " ) if line ]
545+ assert lines , "Expected at least one row in the manifest"
546+ assert file .id in lines [0 ], (
547+ f"Expected first line to be the data row containing { file .id } "
548+ f"(no header), got: { lines [0 ]!r} "
549+ )
535550
536- # AND the single-quote character is used for quoting
537- assert (
538- '"' not in content
539- ), "Expected single-quote quoting, but found double quotes in manifest"
551+ # AND the name field is wrapped in single quotes (the writer quoted it
552+ # because it contains the quote character)
553+ fields = lines [0 ].split ("\t " )
554+ name_field = next ((f for f in fields if uuid_suffix in f ), None )
555+ assert name_field is not None , (
556+ f"Name field containing { uuid_suffix !r} not found in { lines [0 ]!r} "
557+ )
558+ assert name_field .startswith ("'" ) and name_field .endswith ("'" ), (
559+ f"Expected name field wrapped in single quotes, got: { name_field !r} "
560+ )
0 commit comments