@@ -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,114 @@ 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
+ Example:
4312
+ >>> from buildingspy.development.regressiontest import Tester
4313
+ >>> import os
4314
+ >>> ut = Tester(tool='dymola')
4315
+ >>> myMoLib = os.path.join("buildingspy", "tests", "MyModelicaLibrary")
4316
+ >>> ut.setLibraryRoot(myMoLib)
4317
+ >>> ut.setSinglePackage('Examples')
4318
+ >>> coverage_result = ut.getCoverage()
4319
+ """
4320
+ # first lines copy and paste from run function
4321
+ if self .get_number_of_tests () == 0 :
4322
+ self .setDataDictionary (self ._rootPackage )
4323
+
4324
+ # Remove all data that do not require a simulation or an FMU export.
4325
+ # Otherwise, some processes may have no simulation to run and then
4326
+ # the json output file would have an invalid syntax
4327
+
4328
+ # now we got clean _data to compare
4329
+ # next step get all examples in the package (whether whole library or
4330
+ # single package)
4331
+ if self ._packages :
4332
+ packages = self ._packages
4333
+ else :
4334
+ packages = list (dict .fromkeys (
4335
+ [pac ['ScriptFile' ].split (os .sep )[0 ] for pac in self ._data ])
4336
+ )
4337
+
4338
+ all_examples = []
4339
+ for package in packages :
4340
+ package_path = os .path .join (self ._libHome , package )
4341
+ for dirpath , dirnames , filenames in os .walk (package_path ):
4342
+ for filename in filenames :
4343
+ filepath = os .path .abspath (os .path .join (dirpath , filename ))
4344
+ if any (
4345
+ xs in filepath for xs in ['Examples' , 'Validation' ]
4346
+ ) and not filepath .endswith (('package.mo' , '.order' )):
4347
+ all_examples .append (filepath )
4348
+
4349
+ n_tested_examples = len (temp_data )
4350
+ n_examples = len (all_examples )
4351
+ if n_examples > 0 :
4352
+ coverage = round (n_tested_examples / n_examples , 2 ) * 100
4353
+ else :
4354
+ coverage = 100
4355
+
4356
+ tested_model_names = [
4357
+ nam ['ScriptFile' ].split (os .sep )[- 1 ][:- 1 ] for nam in self ._data
4358
+ ]
4359
+
4360
+ missing_examples = [
4361
+ i for i in all_examples if not any (
4362
+ xs in i for xs in tested_model_names )
4363
+ ]
4364
+
4365
+ return coverage , n_tested_examples , n_examples , missing_examples , packages
4366
+
4367
+ def printCoverage (
4368
+ self ,
4369
+ coverage : float ,
4370
+ n_tested_examples : int ,
4371
+ n_examples : int ,
4372
+ missing_examples : list ,
4373
+ packages : list ,
4374
+ printer : callable = None
4375
+ ) -> None :
4376
+ """
4377
+ Print the output of getCoverage to inform about
4378
+ coverage rate and missing models.
4379
+ The default printer is the ``reporter.writeOutput``.
4380
+ If another printing method is required, e.g. ``print`` or
4381
+ ``logging.info``, it may be passed via the ``printer`` argument.
4382
+
4383
+ Example:
4384
+ >>> from buildingspy.development.regressiontest import Tester
4385
+ >>> import os
4386
+ >>> ut = Tester(tool='dymola')
4387
+ >>> myMoLib = os.path.join("buildingspy", "tests", "MyModelicaLibrary")
4388
+ >>> ut.setLibraryRoot(myMoLib)
4389
+ >>> ut.setSinglePackage('Examples')
4390
+ >>> coverage_result = ut.getCoverage()
4391
+ >>> ut.printCoverage(*coverage_result, printer=print)
4392
+ """
4393
+ if printer is None :
4394
+ printer = self ._reporter .writeOutput
4395
+ printer (f'***\n Model Coverage: { int (coverage )} %' )
4396
+ printer (
4397
+ f'***\n You are testing: { n_tested_examples } '
4398
+ f'out of { n_examples } examples in package{ "s" if len (packages ) > 1 else "" } :' ,
4399
+ )
4400
+ for package in packages :
4401
+ printer (package )
4402
+
4403
+ if missing_examples :
4404
+ print ('***\n The following examples are not tested\n ' )
4405
+ for i in missing_examples :
4406
+ print (i .split (self ._libHome )[1 ])
0 commit comments