@@ -517,6 +517,95 @@ public void RemoveMultiple()
517517 """ ) ) ;
518518 }
519519
520+ /// <summary>
521+ /// Verifies that files without UTF-8 BOM don't get one added when saved.
522+ /// This is critical for shebang (#!) scripts on Unix-like systems.
523+ /// <see href="https://github.com/dotnet/sdk/issues/52054"/>
524+ /// </summary>
525+ [ Fact ]
526+ public void PreservesNoBomEncoding ( )
527+ {
528+ var testInstance = _testAssetsManager . CreateTestDirectory ( ) ;
529+ var tempFile = Path . Join ( testInstance . Path , "test.cs" ) ;
530+
531+ // Create a file without BOM
532+ var content = "#!/usr/bin/env dotnet run\n Console.WriteLine();" ;
533+ File . WriteAllText ( tempFile , content , new UTF8Encoding ( encoderShouldEmitUTF8Identifier : false ) ) ;
534+
535+ // Load, modify, and save
536+ var sourceFile = SourceFile . Load ( tempFile ) ;
537+ var editor = FileBasedAppSourceEditor . Load ( sourceFile ) ;
538+ editor . Add ( new CSharpDirective . Package ( default ) { Name = "MyPackage" , Version = "1.0.0" } ) ;
539+ editor . SourceFile . Save ( ) ;
540+
541+ // Verify no BOM was added
542+ var bytes = File . ReadAllBytes ( tempFile ) ;
543+ Assert . True ( bytes is not [ 0xEF , 0xBB , 0xBF , ..] ,
544+ "File should not have UTF-8 BOM" ) ;
545+
546+ // Verify the complete file content is correct
547+ var savedContent = File . ReadAllText ( tempFile ) ;
548+ var expectedContent = "#!/usr/bin/env dotnet run\n \n #:package [email protected] \n \n Console.WriteLine();" ; 549+ Assert . Equal ( expectedContent , savedContent ) ;
550+ }
551+
552+ /// <summary>
553+ /// Verifies that files with UTF-8 BOM preserve it when saved.
554+ /// <see href="https://github.com/dotnet/sdk/issues/52054"/>
555+ /// </summary>
556+ [ Fact ]
557+ public void PreservesBomEncoding ( )
558+ {
559+ var testInstance = _testAssetsManager . CreateTestDirectory ( ) ;
560+ var tempFile = Path . Join ( testInstance . Path , "test.cs" ) ;
561+
562+ // Create a file with BOM
563+ var content = "Console.WriteLine();" ;
564+ File . WriteAllText ( tempFile , content , new UTF8Encoding ( encoderShouldEmitUTF8Identifier : true ) ) ;
565+
566+ // Load, modify, and save
567+ var sourceFile = SourceFile . Load ( tempFile ) ;
568+ var editor = FileBasedAppSourceEditor . Load ( sourceFile ) ;
569+ editor . Add ( new CSharpDirective . Package ( default ) { Name = "MyPackage" , Version = "1.0.0" } ) ;
570+ editor . SourceFile . Save ( ) ;
571+
572+ // Verify BOM is still present
573+ var bytes = File . ReadAllBytes ( tempFile ) ;
574+ Assert . True ( bytes is [ 0xEF , 0xBB , 0xBF , ..] ,
575+ "File should have UTF-8 BOM" ) ;
576+ }
577+
578+ /// <summary>
579+ /// Verifies that files with non-UTF-8 encodings (like UTF-16) preserve their encoding when saved.
580+ /// <see href="https://github.com/dotnet/sdk/issues/52054"/>
581+ /// </summary>
582+ [ Fact ]
583+ public void PreservesNonUtf8Encoding ( )
584+ {
585+ var testInstance = _testAssetsManager . CreateTestDirectory ( ) ;
586+ var tempFile = Path . Join ( testInstance . Path , "test.cs" ) ;
587+
588+ // Create a file with UTF-16 encoding (includes BOM by default)
589+ var content = "Console.WriteLine(\" UTF-16 test\" );" ;
590+ File . WriteAllText ( tempFile , content , Encoding . Unicode ) ;
591+
592+ // Load, modify, and save
593+ var sourceFile = SourceFile . Load ( tempFile ) ;
594+ var editor = FileBasedAppSourceEditor . Load ( sourceFile ) ;
595+ editor . Add ( new CSharpDirective . Package ( default ) { Name = "MyPackage" , Version = "1.0.0" } ) ;
596+ editor . SourceFile . Save ( ) ;
597+
598+ // Verify UTF-16 BOM is still present (0xFF 0xFE for UTF-16 LE)
599+ var bytes = File . ReadAllBytes ( tempFile ) ;
600+ Assert . True ( bytes is [ 0xFF , 0xFE , ..] ,
601+ "File should have UTF-16 LE BOM" ) ;
602+
603+ // Verify content is still readable as UTF-16
604+ var savedContent = File . ReadAllText ( tempFile , Encoding . Unicode ) ;
605+ Assert . Contains ( "#:package [email protected] " , savedContent ) ; 606+ Assert . Contains ( "Console.WriteLine" , savedContent ) ;
607+ }
608+
520609 private void Verify (
521610 string input ,
522611 params ReadOnlySpan < ( Action < FileBasedAppSourceEditor > action , string expectedOutput ) > verify )
0 commit comments