1- // Copyright (c) 2025 SIL International
1+ // Copyright (c) 2025 SIL International
22// This software is licensed under the LGPL, version 2.1 or later
33// (http://www.gnu.org/licenses/lgpl-2.1.html)
44
@@ -21,6 +21,7 @@ namespace SIL.FieldWorks.Build.Tasks.FwBuildTasksTests
2121 public sealed class RegFreeCreatorTests
2222 {
2323 private const string AsmNamespace = "urn:schemas-microsoft-com:asm.v1" ;
24+ private const string RemovedManagedLgIcuCollatorClsid = "{e771361c-ff54-4120-9525-98a0b7a9accf}" ;
2425
2526 [ Test ]
2627 public void ProcessManagedAssembly_PlacesClrClassAsChildOfAssembly ( )
@@ -65,6 +66,76 @@ public void ProcessManagedAssembly_PlacesClrClassAsChildOfAssembly()
6566 }
6667 }
6768
69+ [ Test ]
70+ public void ProcessManagedAssembly_TargetComVisibleFalseClass_DoesNotEmitClrClass ( )
71+ {
72+ var tempDir = Path . Combine ( Path . GetTempPath ( ) , Guid . NewGuid ( ) . ToString ( "N" ) ) ;
73+ Directory . CreateDirectory ( tempDir ) ;
74+ var assemblyPath = Path . Combine ( tempDir , "SampleComVisibleFalseClass.dll" ) ;
75+
76+ try
77+ {
78+ const string source = @"using System.Runtime.InteropServices;
79+ [assembly: ComVisible(true)]
80+ [assembly: Guid(""3D757DD4-8985-4CA6-B2C4-FA2B950C9F6D"")]
81+ namespace RegFreeCreatorTestAssembly
82+ {
83+ [ComVisible(false)]
84+ [Guid(""e771361c-ff54-4120-9525-98a0b7a9accf"")]
85+ public class SampleComVisibleFalseClass
86+ {
87+ }
88+ }" ;
89+ CompileAssembly ( assemblyPath , source ) ;
90+
91+ var doc = new XmlDocument ( ) ;
92+ var root = doc . CreateElement ( "assembly" , AsmNamespace ) ;
93+ doc . AppendChild ( root ) ;
94+ var logger = new TaskLoggingHelper ( new TestBuildEngine ( ) , nameof ( RegFreeCreatorTests ) ) ;
95+ var creator = new RegFreeCreator ( doc , logger ) ;
96+
97+ var foundClrClass = creator . ProcessManagedAssembly ( root , assemblyPath ) ;
98+ Assert . That ( foundClrClass , Is . False , "Assembly with only ComVisible(false) class should not produce clrClass entries." ) ;
99+
100+ var ns = new XmlNamespaceManager ( doc . NameTable ) ;
101+ ns . AddNamespace ( "asmv1" , AsmNamespace ) ;
102+ var clrClassUnderAssembly = root . SelectSingleNode ( "asmv1:clrClass" , ns ) ;
103+ Assert . That ( clrClassUnderAssembly , Is . Null , "clrClass must NOT be produced for ComVisible(false) class." ) ;
104+ var removedClrClass = root . SelectSingleNode ( "asmv1:clrClass[@clsid='" + RemovedManagedLgIcuCollatorClsid + "']" , ns ) ;
105+ Assert . That ( removedClrClass , Is . Null , "Removed ManagedLgIcuCollator CLSID must not appear in generated clrClass entries." ) ;
106+ Assert . That ( root . OuterXml , Does . Not . Contain ( RemovedManagedLgIcuCollatorClsid ) ) ;
107+ }
108+ finally
109+ {
110+ if ( Directory . Exists ( tempDir ) )
111+ {
112+ Directory . Delete ( tempDir , true ) ;
113+ }
114+ }
115+ }
116+
117+ [ Test ]
118+ public void AddExcludedClsids_NormalizesClsidValues ( )
119+ {
120+ var doc = new XmlDocument ( ) ;
121+ var root = doc . CreateElement ( "assembly" , AsmNamespace ) ;
122+ doc . AppendChild ( root ) ;
123+ var logger = new TaskLoggingHelper ( new TestBuildEngine ( ) , nameof ( RegFreeCreatorTests ) ) ;
124+ var creator = new RegFreeCreator ( doc , logger ) ;
125+
126+ creator . AddExcludedClsids ( new [ ] { "e771361c-ff54-4120-9525-98a0b7a9accf" , "{3fb0fcd2-ac55-42a8-b580-73b89a2b6215}" } ) ;
127+
128+ // Use reflection to verify the private field _excludedClsids was populated and normalized
129+ var field = typeof ( RegFreeCreator ) . GetField ( "_excludedClsids" , System . Reflection . BindingFlags . NonPublic | System . Reflection . BindingFlags . Instance ) ;
130+ Assert . That ( field , Is . Not . Null , "Should find the private _excludedClsids field." ) ;
131+
132+ var excludedHashSet = ( System . Collections . Generic . HashSet < string > ) field . GetValue ( creator ) ;
133+ Assert . That ( excludedHashSet , Is . Not . Null ) ;
134+ Assert . That ( excludedHashSet . Count , Is . EqualTo ( 2 ) ) ;
135+ Assert . That ( excludedHashSet . Contains ( RemovedManagedLgIcuCollatorClsid ) , Is . True , "Should normalize Clsid without braces." ) ;
136+ Assert . That ( excludedHashSet . Contains ( "{3fb0fcd2-ac55-42a8-b580-73b89a2b6215}" ) , Is . True , "Should preserve Clsid with braces." ) ;
137+ }
138+
68139 private static void CompileComVisibleAssembly ( string outputPath )
69140 {
70141 const string source = @"using System.Runtime.InteropServices;
@@ -79,7 +150,11 @@ public class SampleComClass
79150 {
80151 }
81152}" ;
153+ CompileAssembly ( outputPath , source ) ;
154+ }
82155
156+ private static void CompileAssembly ( string outputPath , string source )
157+ {
83158 var provider = new CSharpCodeProvider ( ) ;
84159 var parameters = new CompilerParameters
85160 {
@@ -94,7 +169,7 @@ public class SampleComClass
94169 if ( results . Errors . HasErrors )
95170 {
96171 var message = string . Join ( Environment . NewLine , results . Errors . Cast < CompilerError > ( ) . Select ( e => e . ToString ( ) ) ) ;
97- throw new InvalidOperationException ( $ "Failed to compile COM-visible test assembly:{ Environment . NewLine } { message } ") ;
172+ throw new InvalidOperationException ( $ "Failed to compile test assembly:{ Environment . NewLine } { message } ") ;
98173 }
99174 }
100175 }
0 commit comments