55using System ;
66using System . Globalization ;
77using System . Linq ;
8+ using System . Text . RegularExpressions ;
89using System . Threading ;
910using System . Threading . Tasks ;
1011using Microsoft . CodeAnalysis . CSharp ;
@@ -25,8 +26,8 @@ public class EnableNullableTests
2526 var project = solution . GetRequiredProject ( projectId ) ;
2627 var document = project . Documents . First ( ) ;
2728
28- // Only the input solution contains '#nullable enable'
29- if ( ! document . GetTextSynchronously ( CancellationToken . None ) . ToString ( ) . Contains ( "#nullable enable" ) )
29+ // Only the input solution contains '#nullable enable' or '#nullable enable' in the first document
30+ if ( ! Regex . IsMatch ( document . GetTextSynchronously ( CancellationToken . None ) . ToString ( ) , "#nullable ? enable" ) )
3031 {
3132 var compilationOptions = ( CSharpCompilationOptions ) solution . GetRequiredProject ( projectId ) . CompilationOptions ! ;
3233 solution = solution . WithProjectCompilationOptions ( projectId , compilationOptions . WithNullableContextOptions ( NullableContextOptions . Enable ) ) ;
@@ -35,16 +36,43 @@ public class EnableNullableTests
3536 return solution ;
3637 } ;
3738
38- [ Fact ]
39- public async Task EnabledOnNullableEnable ( )
39+ private static readonly Func < Solution , ProjectId , Solution > s_enableNullableInFixedSolutionFromRestoreKeyword =
40+ ( solution , projectId ) =>
41+ {
42+ var project = solution . GetRequiredProject ( projectId ) ;
43+ var document = project . Documents . First ( ) ;
44+
45+ // Only the input solution contains '#nullable restore' or '#nullable restore' in the first document
46+ if ( ! Regex . IsMatch ( document . GetTextSynchronously ( CancellationToken . None ) . ToString ( ) , "#nullable ?restore" ) )
47+ {
48+ var compilationOptions = ( CSharpCompilationOptions ) solution . GetRequiredProject ( projectId ) . CompilationOptions ! ;
49+ solution = solution . WithProjectCompilationOptions ( projectId , compilationOptions . WithNullableContextOptions ( NullableContextOptions . Enable ) ) ;
50+ }
51+
52+ return solution ;
53+ } ;
54+
55+ private static readonly Func < Solution , ProjectId , Solution > s_enableNullableInFixedSolutionFromDisableKeyword =
56+ s_enableNullableInFixedSolutionFromRestoreKeyword ;
57+
58+ [ Theory ]
59+ [ InlineData ( "$$#nullable enable" ) ]
60+ [ InlineData ( "#$$nullable enable" ) ]
61+ [ InlineData ( "#null$$able enable" ) ]
62+ [ InlineData ( "#nullable$$ enable" ) ]
63+ [ InlineData ( "#nullable $$ enable" ) ]
64+ [ InlineData ( "#nullable $$enable" ) ]
65+ [ InlineData ( "#nullable ena$$ble" ) ]
66+ [ InlineData ( "#nullable enable$$" ) ]
67+ public async Task EnabledOnNullableEnable ( string directive )
4068 {
41- var code1 = @"
42- #nullable enable$$
69+ var code1 = $ @ "
70+ { directive }
4371
4472class Example
45- {
73+ {{
4674 string? value;
47- }
75+ }}
4876" ;
4977 var code2 = @"
5078class Example2
@@ -573,17 +601,217 @@ public async Task DisabledForUnsupportedLanguageVersion(LanguageVersion language
573601 } . RunAsync ( ) ;
574602 }
575603
576- [ Fact ]
577- public async Task DisabledOnNullableDisable ( )
604+ [ Theory ]
605+ [ InlineData ( "$$#nullable restore" ) ]
606+ [ InlineData ( "#$$nullable restore" ) ]
607+ [ InlineData ( "#null$$able restore" ) ]
608+ [ InlineData ( "#nullable$$ restore" ) ]
609+ [ InlineData ( "#nullable $$ restore" ) ]
610+ [ InlineData ( "#nullable $$restore" ) ]
611+ [ InlineData ( "#nullable res$$tore" ) ]
612+ [ InlineData ( "#nullable restore$$" ) ]
613+ public async Task EnabledOnNullableRestore ( string directive )
578614 {
579- var code = @"
580- #nullable disable$$
615+ var code1 = $@ "
616+ { directive }
617+
618+ class Example
619+ {{
620+ string value;
621+ }}
622+ " ;
623+ var code2 = @"
624+ class Example2
625+ {
626+ string value;
627+ }
628+ " ;
629+ var code3 = @"
630+ class Example3
631+ {
632+ #nullable enable
633+ string? value;
634+ #nullable restore
635+ }
636+ " ;
637+ var code4 = @"
638+ #nullable disable
639+
640+ class Example4
641+ {
642+ string value;
643+ }
644+ " ;
645+
646+ var fixedDirective = directive . Replace ( "$$" , "" ) . Replace ( "restore" , "disable" ) ;
647+
648+ var fixedCode1 = $@ "
649+ { fixedDirective }
650+
651+ class Example
652+ {{
653+ string value;
654+ }}
655+ " ;
656+ var fixedCode2 = @"
657+ #nullable disable
658+
659+ class Example2
660+ {
661+ string value;
662+ }
663+ " ;
664+ var fixedCode3 = @"
665+ #nullable disable
666+
667+ class Example3
668+ {
669+ #nullable restore
670+ string? value;
671+ #nullable disable
672+ }
673+ " ;
674+ var fixedCode4 = @"
675+ #nullable disable
676+
677+ class Example4
678+ {
679+ string value;
680+ }
581681" ;
582682
583683 await new VerifyCS . Test
584684 {
585- TestCode = code ,
586- FixedCode = code ,
685+ TestState =
686+ {
687+ Sources =
688+ {
689+ code1 ,
690+ code2 ,
691+ code3 ,
692+ code4 ,
693+ } ,
694+ } ,
695+ FixedState =
696+ {
697+ Sources =
698+ {
699+ fixedCode1 ,
700+ fixedCode2 ,
701+ fixedCode3 ,
702+ fixedCode4 ,
703+ } ,
704+ } ,
705+ SolutionTransforms = { s_enableNullableInFixedSolutionFromRestoreKeyword } ,
706+ } . RunAsync ( ) ;
707+ }
708+
709+ [ Theory ]
710+ [ InlineData ( "$$#nullable disable" ) ]
711+ [ InlineData ( "#$$nullable disable" ) ]
712+ [ InlineData ( "#null$$able disable" ) ]
713+ [ InlineData ( "#nullable$$ disable" ) ]
714+ [ InlineData ( "#nullable $$ disable" ) ]
715+ [ InlineData ( "#nullable $$disable" ) ]
716+ [ InlineData ( "#nullable dis$$able" ) ]
717+ [ InlineData ( "#nullable disable$$" ) ]
718+ public async Task EnabledOnNullableDisable ( string directive )
719+ {
720+ var code1 = $@ "
721+ { directive }
722+
723+ class Example
724+ {{
725+ string value;
726+ }}
727+
728+ #nullable restore
729+ " ;
730+ var code2 = @"
731+ class Example2
732+ {
733+ string value;
734+ }
735+ " ;
736+ var code3 = @"
737+ class Example3
738+ {
739+ #nullable enable
740+ string? value;
741+ #nullable restore
742+ }
743+ " ;
744+ var code4 = @"
745+ #nullable disable
746+
747+ class Example4
748+ {
749+ string value;
750+ }
751+ " ;
752+
753+ var fixedDirective = directive . Replace ( "$$" , "" ) ;
754+
755+ var fixedCode1 = $@ "
756+ { fixedDirective }
757+
758+ class Example
759+ {{
760+ string value;
761+ }}
762+
763+ #nullable disable
764+ " ;
765+ var fixedCode2 = @"
766+ #nullable disable
767+
768+ class Example2
769+ {
770+ string value;
771+ }
772+ " ;
773+ var fixedCode3 = @"
774+ #nullable disable
775+
776+ class Example3
777+ {
778+ #nullable restore
779+ string? value;
780+ #nullable disable
781+ }
782+ " ;
783+ var fixedCode4 = @"
784+ #nullable disable
785+
786+ class Example4
787+ {
788+ string value;
789+ }
790+ " ;
791+
792+ await new VerifyCS . Test
793+ {
794+ TestState =
795+ {
796+ Sources =
797+ {
798+ code1 ,
799+ code2 ,
800+ code3 ,
801+ code4 ,
802+ } ,
803+ } ,
804+ FixedState =
805+ {
806+ Sources =
807+ {
808+ fixedCode1 ,
809+ fixedCode2 ,
810+ fixedCode3 ,
811+ fixedCode4 ,
812+ } ,
813+ } ,
814+ SolutionTransforms = { s_enableNullableInFixedSolutionFromDisableKeyword } ,
587815 } . RunAsync ( ) ;
588816 }
589817 }
0 commit comments