@@ -351,6 +351,9 @@ def __init__(
351
351
self ._data = []
352
352
self ._reporter = rep .Reporter (os .path .join (os .getcwd (), "unitTests-{}.log" .format (tool )))
353
353
354
+ # List to store tested packages, used for coverage report
355
+ self ._packages = []
356
+
354
357
# By default, include export of FMUs.
355
358
self ._include_fmu_test = True
356
359
@@ -589,6 +592,7 @@ def getModelicaCommand(self):
589
592
elif self ._modelica_tool != 'dymola' :
590
593
return 'jm_ipython.sh'
591
594
else :
595
+ return "C://Program Files//Dymola 2023x//bin64//Dymola"
592
596
return self ._modelica_tool
593
597
594
598
def isExecutable (self , program ):
@@ -771,11 +775,12 @@ def setSinglePackage(self, packageName):
771
775
772
776
# Set data dictionary as it may have been generated earlier for the whole library.
773
777
self ._data = []
774
-
778
+ self . _packages = []
775
779
for pac in packages :
776
780
pacSep = pac .find ('.' )
777
781
pacPat = pac [pacSep + 1 :]
778
782
pacPat = pacPat .replace ('.' , os .sep )
783
+ self ._packages .append (pacPat )
779
784
rooPat = os .path .join (self ._libHome , 'Resources' , 'Scripts' , 'Dymola' , pacPat )
780
785
# Verify that the directory indeed exists
781
786
if not os .path .isdir (rooPat ):
@@ -4288,3 +4293,104 @@ def _model_from_mo(self, mo_file):
4288
4293
model = '.' .join (splt [root :])
4289
4294
# remove the '.mo' at the end
4290
4295
return model [:- 3 ]
4296
+
4297
+ def getCoverage (self ):
4298
+ """
4299
+ Analyse how many examples are tested.
4300
+ If ``setSinglePackage`` is called before this function,
4301
+ only packages set will be included. Else, the whole library
4302
+ will be checked.
4303
+
4304
+ Returns:
4305
+ - The coverage rate in percent as float
4306
+ - The number of examples tested as int
4307
+ - The total number of examples as int
4308
+ - The list of models not tested as List[str]
4309
+ - The list of packages included in the analysis as List[str]
4310
+ """
4311
+ # first lines copy and paste from run function
4312
+ if self .get_number_of_tests () == 0 :
4313
+ self .setDataDictionary (self ._rootPackage )
4314
+
4315
+ # Remove all data that do not require a simulation or an FMU export.
4316
+ # Otherwise, some processes may have no simulation to run and then
4317
+ # the json output file would have an invalid syntax
4318
+
4319
+ # to not interact with other code here, we use the temp_data list
4320
+
4321
+ temp_data = [
4322
+ element for element in self ._data [:]
4323
+ if element ['mustSimulate' ] or element ['mustExportFMU' ]
4324
+ ]
4325
+
4326
+ # now we got clean _data to compare
4327
+ # next step get all examples in the package (whether whole library or
4328
+ # single package)
4329
+ if self ._packages :
4330
+ packages = self ._packages
4331
+ else :
4332
+ packages = list (dict .fromkeys (
4333
+ [pac ['ScriptFile' ].split (os .sep )[0 ] for pac in self ._data ])
4334
+ )
4335
+
4336
+ all_examples = []
4337
+ for package in packages :
4338
+ package_path = os .path .join (self ._libHome , package )
4339
+ for dirpath , dirnames , filenames in os .walk (package_path ):
4340
+ for filename in filenames :
4341
+ if any (
4342
+ xs in filename for xs in ['Examples' , 'Validation' ]
4343
+ ) and not filename .endswith (('package.mo' , '.order' )):
4344
+ all_examples .append (os .path .abspath (
4345
+ os .path .join (dirpath , filename ))
4346
+ )
4347
+
4348
+ coverage = round (len (temp_data ) / len (all_examples ), 2 ) * 100
4349
+
4350
+ tested_model_names = [
4351
+ nam ['ScriptFile' ].split (os .sep )[- 1 ][:- 1 ] for nam in temp_data
4352
+ ]
4353
+
4354
+ missing_examples = [
4355
+ i for i in all_examples if not any (
4356
+ xs in i for xs in tested_model_names )
4357
+ ]
4358
+
4359
+ n_tested_examples = len (temp_data )
4360
+ n_examples = len (all_examples )
4361
+ return coverage , n_tested_examples , n_examples , missing_examples , packages
4362
+
4363
+ def printCoverage (
4364
+ self ,
4365
+ coverage : float ,
4366
+ n_tested_examples : int ,
4367
+ n_examples : int ,
4368
+ missing_examples : list ,
4369
+ packages : list ,
4370
+ printer : callable = None
4371
+ ) -> None :
4372
+ """
4373
+ Print the output of getCoverage to inform about
4374
+ coverage rate and missing models.
4375
+ The default printer is the ``reporter.writeOutput``.
4376
+ If another printing method is required, e.g. ``print`` or
4377
+ ``logging.info``, it may be passed via the ``printer`` argument.
4378
+ """
4379
+ if printer is None :
4380
+ printer = self ._reporter .writeOutput
4381
+ printer ('***\n \n Model Coverage: ' , str (int (coverage )) + '%' )
4382
+ printer (
4383
+ '***\n \n You are testing : ' ,
4384
+ n_tested_examples ,
4385
+ ' out of ' ,
4386
+ n_examples ,
4387
+ 'total examples in '
4388
+ )
4389
+ for package in packages :
4390
+ printer (package )
4391
+ printer ('\n ' )
4392
+
4393
+ if missing_examples :
4394
+ print ('***\n \n The following examples are not tested\n ' )
4395
+ for i in missing_examples :
4396
+ print (i .split (self ._libHome )[1 ])
0 commit comments