6
6
using System ;
7
7
using System . Collections . Generic ;
8
8
using System . IO ;
9
+ using System . Linq ;
9
10
using System . Text . RegularExpressions ;
10
11
using Microsoft . VisualStudio . TestTools . UnitTesting ;
11
12
using Mono . Cecil ;
@@ -60,6 +61,8 @@ public class StubsGenerationTests
60
61
"static void NativeMethodWithReferenceParameters( uint8_t& param0, uint16_t& param1, HRESULT &hr );" ;
61
62
62
63
private string _stubsPath ;
64
+ private List < string > _nfTestLibTypeToIncludeInLookupTable = new List < string > ( ) ;
65
+ private List < string > _nfTestLibTypeToIncludeInHeader = new List < string > ( ) ;
63
66
64
67
[ TestMethod ]
65
68
public void GeneratingStubsFromNFAppTest ( )
@@ -212,6 +215,49 @@ public void BackingFieldsAbsentTests()
212
215
Assert . IsFalse ( Regex . IsMatch ( generatedAssemblyHeaderFile , @"(?<!')<\w+>k__BackingField(?!')" ) , "Found a name with BackingField pattern, when it shouldn't" ) ;
213
216
}
214
217
218
+ [ TestMethod ]
219
+ public void StubsAndDeclarationMatchTests ( )
220
+ {
221
+ string generatedAssemblyHeaderFile = File . ReadAllText ( $ "{ _stubsPath } \\ TestNFClassLibrary.h") ;
222
+ string generatedAssemblyLookupFile = File . ReadAllText ( $ "{ _stubsPath } \\ TestNFClassLibrary.cpp") ;
223
+
224
+ // extract all type definitions from the header file
225
+ MatchCollection typeDefinitionsInHeader = Regex . Matches ( generatedAssemblyHeaderFile , @"struct\s{1}(\w+_\w+_\w+_\w+)\b" , RegexOptions . IgnoreCase | RegexOptions . Multiline ) ;
226
+
227
+ // extract all type definitions from the lookup file
228
+ List < Match > typeDefinitionsInLookupTable = Regex . Matches ( generatedAssemblyLookupFile , @"^\s{4}(\w+_\w+_\w+_\w+)::" , RegexOptions . IgnoreCase | RegexOptions . Multiline )
229
+ . Cast < Match > ( )
230
+ . GroupBy ( m => m . Groups [ 1 ] . Value )
231
+ . Select ( g => g . First ( ) )
232
+ . ToList ( ) ;
233
+
234
+ // check if all entries in lookup table are present in the header
235
+ foreach ( Match typeDefinition in typeDefinitionsInLookupTable )
236
+ {
237
+ string typeName = typeDefinition . Groups [ 1 ] . Value ;
238
+ bool found = typeDefinitionsInHeader . Cast < Match > ( ) . Any ( md => md . Groups [ 1 ] . Value == typeName ) ;
239
+ Assert . IsTrue ( found , $ "Type definition { typeName } not found in header file") ;
240
+ }
241
+
242
+ // check if all expected types are present in the lookup table
243
+ Assert . AreEqual ( _nfTestLibTypeToIncludeInLookupTable . Count , typeDefinitionsInLookupTable . Count , "Number of type definitions don't match" ) ;
244
+
245
+ foreach ( string typeName in _nfTestLibTypeToIncludeInLookupTable )
246
+ {
247
+ bool found = typeDefinitionsInLookupTable . Any ( md => md . Groups [ 1 ] . Value == typeName ) ;
248
+ Assert . IsTrue ( found , $ "Type definition { typeName } not found in lookup table") ;
249
+ }
250
+
251
+ // check if all expected types are present in the header file
252
+ Assert . AreEqual ( _nfTestLibTypeToIncludeInHeader . Count , typeDefinitionsInHeader . Count , "Number of type definitions don't match" ) ;
253
+
254
+ foreach ( string typeName in _nfTestLibTypeToIncludeInHeader )
255
+ {
256
+ bool found = typeDefinitionsInHeader . Cast < Match > ( ) . Any ( md => md . Groups [ 1 ] . Value == typeName ) ;
257
+ Assert . IsTrue ( found , $ "Type definition { typeName } not found in header file") ;
258
+ }
259
+ }
260
+
215
261
[ TestInitialize ]
216
262
public void GenerateStubs ( )
217
263
{
@@ -256,6 +302,16 @@ public void GenerateStubs()
256
302
257
303
assemblyBuilder . Minimize ( ) ;
258
304
305
+ // recompile
306
+ using ( FileStream stream = File . Open (
307
+ Path . ChangeExtension ( stubsGenerationFileToCompile , "tmp" ) ,
308
+ FileMode . Create ,
309
+ FileAccess . ReadWrite ) )
310
+ using ( BinaryWriter writer = new BinaryWriter ( stream ) )
311
+ {
312
+ assemblyBuilder . Write ( GetBinaryWriter ( writer ) ) ;
313
+ }
314
+
259
315
nanoTablesContext tablesContext = assemblyBuilder . TablesContext ;
260
316
261
317
var skeletonGenerator = new nanoSkeletonGenerator (
@@ -296,6 +352,17 @@ public void GenerateStubs()
296
352
297
353
assemblyBuilder . Minimize ( ) ;
298
354
355
+ // recompile
356
+ using ( FileStream stream = File . Open (
357
+ Path . ChangeExtension ( nfLibFileToCompile , "tmp" ) ,
358
+ FileMode . Create ,
359
+ FileAccess . ReadWrite ) )
360
+
361
+ using ( BinaryWriter writer = new BinaryWriter ( stream ) )
362
+ {
363
+ assemblyBuilder . Write ( GetBinaryWriter ( writer ) ) ;
364
+ }
365
+
299
366
tablesContext = assemblyBuilder . TablesContext ;
300
367
301
368
skeletonGenerator = new nanoSkeletonGenerator (
@@ -307,6 +374,39 @@ public void GenerateStubs()
307
374
true ) ;
308
375
309
376
skeletonGenerator . GenerateSkeleton ( ) ;
377
+
378
+ // save types that are to be included from assembly lookup declaration
379
+ foreach ( TypeDefinition c in tablesContext . TypeDefinitionTable . Items )
380
+ {
381
+ if ( c . HasMethods && nanoSkeletonGenerator . ShouldIncludeType ( c ) )
382
+ {
383
+ foreach ( MethodDefinition m in nanoTablesContext . GetOrderedMethods ( c . Methods ) )
384
+ {
385
+ ushort rva = tablesContext . ByteCodeTable . GetMethodRva ( m ) ;
386
+
387
+ // check method inclusion
388
+ // method is not a native implementation (RVA 0xFFFF) and is not abstract
389
+ if ( rva == 0xFFFF && ! m . IsAbstract )
390
+ {
391
+ _nfTestLibTypeToIncludeInLookupTable . Add ( $ "Library_{ skeletonGenerator . SafeProjectName } _{ NativeMethodsCrc . GetClassName ( c ) } ") ;
392
+
393
+ // only need to add the type once
394
+ break ;
395
+ }
396
+ }
397
+ }
398
+ }
399
+
400
+ // save types that are to be included in assembly header
401
+ foreach ( TypeDefinition c in tablesContext . TypeDefinitionTable . Items )
402
+ {
403
+ if ( nanoSkeletonGenerator . ShouldIncludeType ( c )
404
+ && c . HasMethods
405
+ && c . HasFields )
406
+ {
407
+ _nfTestLibTypeToIncludeInHeader . Add ( $ "Library_{ skeletonGenerator . SafeProjectName } _{ NativeMethodsCrc . GetClassName ( c ) } ") ;
408
+ }
409
+ }
310
410
}
311
411
312
412
[ TestCleanup ]
0 commit comments