@@ -351,6 +351,9 @@ def __init__(
351351 self ._data = []
352352 self ._reporter = rep .Reporter (os .path .join (os .getcwd (), "unitTests-{}.log" .format (tool )))
353353
354+ # List to store tested packages, used for coverage report
355+ self ._packages = []
356+
354357 # By default, include export of FMUs.
355358 self ._include_fmu_test = True
356359
@@ -589,6 +592,7 @@ def getModelicaCommand(self):
589592 elif self ._modelica_tool != 'dymola' :
590593 return 'jm_ipython.sh'
591594 else :
595+ return "C://Program Files//Dymola 2023x//bin64//Dymola"
592596 return self ._modelica_tool
593597
594598 def isExecutable (self , program ):
@@ -771,11 +775,12 @@ def setSinglePackage(self, packageName):
771775
772776 # Set data dictionary as it may have been generated earlier for the whole library.
773777 self ._data = []
774-
778+ self . _packages = []
775779 for pac in packages :
776780 pacSep = pac .find ('.' )
777781 pacPat = pac [pacSep + 1 :]
778782 pacPat = pacPat .replace ('.' , os .sep )
783+ self ._packages .append (pacPat )
779784 rooPat = os .path .join (self ._libHome , 'Resources' , 'Scripts' , 'Dymola' , pacPat )
780785 # Verify that the directory indeed exists
781786 if not os .path .isdir (rooPat ):
@@ -4288,3 +4293,114 @@ def _model_from_mo(self, mo_file):
42884293 model = '.' .join (splt [root :])
42894294 # remove the '.mo' at the end
42904295 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