packages feed

HaskellAnalysisProgram-0.1.0: src/Analyse.hs

{-|
Module      : Analyse
Description : Main test module for program analysis
Copyright   : Copyright (C) 2019 S. Kamps
License     : -- This file is distributed under the  terms of the Apache License 2.0.
              For more information, see the file "LICENSE", which is included in the distribution.
Stability   : experimental
-}
module Analyse
    (analyse
    ) where

import qualified Control.Monad              as Monad
import           CsvData
import qualified Data.Set                   as Set
import           FileOperation
import qualified MetaHS.DataModel.MetaModel as MetaModel
import           MetaHS.EDSL
import           MetaHS.Extensions.CBO
import           MetaHS.Extensions.LCOM
import           MetaHS.Extensions.LOC
import qualified ModuleLevelAnalysis        as ModuleLevel
import qualified ProgramLevelAnalysis       as ProgramLevel
import           Settings
import           System.Directory           (createDirectory,
                                             doesDirectoryExist, doesFileExist,
                                             removeDirectoryRecursive,
                                             removeFile)
import           System.FilePath.Posix      ((</>))
import           Text.Printf

-- | Start analysis based on the type of required information.
-- | Type of analysis is either Evolution or Distribution.
-- | Type of metric is either LCOM, LOC or CBO
analyse :: Settings  -- ^ The settings required for the Implementation Under Test.
        -> IO ()
analyse settings@(Settings  _ _ _ Evolution LCOM) = do
  setupOutputDirectory settings
  metaModel <- generate settings
  let metaModelCompl = lcomAggregator metaModel
  analyseEvo settings metaModelCompl
analyse settings@(Settings  _ _ _ Evolution CBO) = do
  setupOutputDirectory settings
  metaModel <- generate settings
  let metaModelCompl = cboAggregator metaModel
  analyseEvo settings metaModelCompl
analyse settings@(Settings  _ _ _ Evolution LOC) = do
  setupOutputDirectory settings
  metaModel <- generate settings
  let metaModelCompl = locAggregator metaModel
  analyseEvo settings metaModelCompl

analyse settings@(Settings  _ _ _ Distribution LCOM) = do
  setupOutputDirectory settings
  metaModel <- generate settings
  let metaModelCompl = lcomAggregator metaModel
  analyseDist settings metaModelCompl
analyse settings@(Settings  _ _ _ Distribution CBO) = do
  setupOutputDirectory settings
  metaModel <- generate settings
  let metaModelCompl = cboAggregator metaModel
  analyseDist settings metaModelCompl
analyse settings@(Settings  _ _ _ Distribution LOC) = do
  setupOutputDirectory settings
  metaModel <- generate settings
  let metaModelCompl = locAggregator metaModel
  analyseDist settings metaModelCompl

-- | Analysis for information on program level. For instance to plot package evolution.
analyseEvo :: Settings  -- ^ The settings required for the Implementation Under Test.
           -> MetaModel.MetaModel -- ^ Metamodel complemented with specific metric
           -> IO ()
analyseEvo settings mm = do
  let iutName = programName settings
  let metricName = show $ metricType settings
  let id = versionHashId settings

  let avg =     ProgramLevel.calculateAverage id metricName mm
  let median =  ProgramLevel.calculateMedian id metricName mm
  let gini =    ProgramLevel.calculateGiniCoefficient id metricName mm
  let cg =      ProgramLevel.calculateCG id metricName mm
  let ivd =     ProgramLevel.calculateIvd id (metricType settings) mm
  let cgTimesIvd = ivd * cg
  let metricDetailInfo = ModuleLevel.extractMetricData id metricName mm

  appendItemToFile settings ((iutName ++ "_" ++ metricName) ++ "_Detailinfo") metricDetailInfo
  appendItemToFile settings ((iutName ++ "_" ++ metricName) ++ "_Average") [avg]
  appendItemToFile settings ((iutName ++ "_" ++ metricName) ++ "_Median") [median]
  appendItemToFile settings ((iutName ++ "_" ++ metricName) ++ "_Gini") [gini]
  appendItemToFile settings ((iutName ++ "_" ++ metricName) ++ "_CG") [cg]
  appendItemToFile settings ((iutName ++ "_" ++ metricName) ++ "_IVD") [ivd]
  appendItemToFile settings ((iutName ++ "_" ++ metricName) ++ "_CgTimesIvd") [cgTimesIvd]

  printf "Analysis output located in  %s\n" $ show $ outputDirectory settings
  return ()

-- | Analysis for information about metric's module distribution.
analyseDist :: Settings  -- ^ The settings required for the Implementation Under Test.
           -> MetaModel.MetaModel -- ^ Metamodel complemented with specific metric
           -> IO ()
analyseDist settings mm = do
  setupOutputDirectory settings

  let metricName = show $ metricType settings
  printf "Analysing %s.\n" metricName
  printf "\n"
  writeMetaModeltoFile settings mm
  let distList = ProgramLevel.calculateDistribution (commitHash settings) metricName mm
  let popList = ProgramLevel.calculatePopulation (commitHash settings) metricName mm
  mapM_ (f settings) distList
  mapM_ (g settings) popList
  printf "Analysis output located in  %s\n" $ show $ outputDirectory settings
  return ()

-- | helper for writing distribution to .csv file.
f :: Settings -> (Int,Int) -> IO ()
f s x = do
  let z = DistPair x
  appendDistToFile s ("Distribution " ++ show (metricType s)) z

  -- | helper for writing population to .csv file.
g :: Settings -> Int -> IO ()
g s x = do
  appendPopToFile s ("population " ++ show (metricType s)) x

-- | Generates the MetaModel based on the provided Settings.
generate :: Settings                -- ^ The settings required for the Implementation Under Test.
         -> IO MetaModel.MetaModel  -- ^ The generated MetaModel.
generate settings = generateMetaModel pn sd pef
  where
    pn = programName settings
    sd = sourcesDirectory settings
    pef = parseErrorsFile settings

versionHashId :: Settings -> String
versionHashId s = version s ++ "," ++ commitHash s