1
\$\begingroup\$

I'm currently working in a model-based testing tool. I'm writing some integration tests for it, which require two kind of input:

  1. Model files: which contain models to be parsed and run by the tool.
  2. Command files: which contain commands to be input to the tool.

To reduce the boilerplate I've written two functions that build a the path to the model and command files depending on the type of tests. The solution I came up with is shown below. However I don't like the fact that I have to use a dummy parameter in my type-classes.

{-
TorXakis - Model Based Testing
Copyright (c) 2015-2017 TNO and Radboud University
See LICENSE at root directory of this repository.
-}
{-# LANGUAGE OverloadedStrings #-}
-- | Utilities for working with tests paths within 'sqatt'.
module Paths
    ( BenchTest (BenchTest)
    , IntegrationTest (IntegrationTest)
    , txsFilePath
    , txsCmdPath
    )
where

import           Data.Text
import           Filesystem.Path
import           Filesystem.Path.CurrentOS
import           Prelude                   hiding (FilePath)

-- | Types of tests supported by 'sqatt'.
class TestType a where
    -- | Directory that contains the model and command files that are used in
    -- the tests. This is relative to 'sqatt' root folder.
    dataDir :: a -> FilePath

-- | Test of the examples used in the benchmarks.
data BenchTest = BenchTest
instance TestType BenchTest where
    dataDir _ = "data" </> "bench"

-- | Integration test.
data IntegrationTest = IntegrationTest
instance TestType IntegrationTest where
    dataDir _ = "data" </> "integration-test"

-- | Make a TorXakis model file path. It appends the given directory to the
-- test data directory, and appends the '.txs extension to the given file path.
--
txsFilePath :: TestType a
            => a
            -> FilePath -- ^ Directory of the current example.
            -> Text     -- ^ File name of the current example.
            -> FilePath
txsFilePath tt currExampDir fp =
  dataDir tt </> currExampDir </> fromText fp <.> "txs"

-- | Make a TorXakis commands file path. It appends the given directory to the
-- test data directory, and appends the .txscmd extension to the given file
-- path.
txsCmdPath :: TestType a
           => a        -- ^ Test type. This will determine the location of the test data directory.
           -> FilePath -- ^ Directory of the current example.
           -> Text     -- ^ File name of the current example.
           -> FilePath
txsCmdPath tt currExampDir fp =
  dataDir tt </> currExampDir </> fromText fp <.> "txscmd"
\$\endgroup\$
  • \$\begingroup\$ You could use a dummy parameter of kind Symbol instead and use type application to pass it, that'll allow you not to have to declare a new datatype every time. \$\endgroup\$ – gallais Oct 16 '17 at 12:53
  • 1
    \$\begingroup\$ @gallais Please put all suggestions for improvements in answers. \$\endgroup\$ – 200_success Oct 16 '17 at 16:22
1
\$\begingroup\$

Your code is fine and contains documentation, so there's not much to say at that point. That being said, your TestType problem can be tackled by transforming the type class to a data type:

data TestType = BenchTest | IntegrationTest

dataDir :: TestType -> FilePath

However, that just removes the constraint and makes your program less flexible in the long run. So let us go back to the drawing board. The data directory is part of the test configuration. That sounds like a valid new data type:

data TestConfiguration = TestConfiguration
                       { dataDir :: FilePath
                       , ...
                       }

defaultConfiguration :: TestConfiguration
defaultConfiguration = TestConfiguration
                     { dataDir = "data" </> "test"
                     , ...
                     }

Your two functions can now use TestConfiguration as first parameter instead of a TestType. This lets your user define adhoc configurations easily:

myConfiguration = defaultConfiguration
                { dataDir = "data" </> "my" </> "tuesday"
                , verbosity = VerboseLow
                , logFormat = TimeStamps
                , ... -- you get it
                }

Whether you want to allow record syntax, lenses or setters is left to you.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.