Help setting up Cabal project with HUnit tests

Hi,

In order to learn Haskell, my plan is to do some of the problems in the Project Euler.

So I created a Cabal project and I want to do unit tests to validate the problems with HUnit in order to have a structure to work with.

This is the file structure :

haskell
├── cabal.project.local
├── cabal.project.local~
├── project-euler.cabal
├── Setup.hs
├── src
│   └── Problem_1.hs
└── test
    └── Tests.hs
  • First question : as I want to do this for multiple languages, the root folder is named haskell. Is it an issue to have a cabal project that is named differently than the parent folder?

So I set up tests like this in the project-euler.cabal file :

Test-Suite test
    type: exitcode-stdio-1.0
    ghc-options: -Wall
    hs-source-dirs: test
    main-is:    Tests.hs
    build-depends: base, HUnit
    default-language: Haskell2010

And in my Test.hs file :

import Test.HUnit

test1 :: Test
test1 = TestCase (assertEqual "test" 0 1)

tests :: Test
tests = TestList [TestLabel "test1" test1]

main :: IO Counts
main = do
  runTestTT tests
  • Second question : if I run cabal test, it says :
Build profile: -w ghc-8.8.3 -O1
In order, the following will be built (use -v for more details):
 - project-euler-0.1.0.0 (test:test) (ephemeral targets)
Preprocessing test suite 'test' for project-euler-0.1.0.0..
Building test suite 'test' for project-euler-0.1.0.0..
Running 1 test suites...
Test suite test: RUNNING...
Test suite test: PASS
Test suite logged to:
/home/josephhenry/git/project-euler/src/haskell/dist-newstyle/build/x86_64-linux/ghc-8.8.3/project-euler-0.1.0.0/t/test/test/project-euler-0.1.0.0-test.log
1 of 1 test suites (1 of 1 test cases) passed.

but the test1 should not pass, what is wrong here?

If I now run cabal run test, it’s working fine :

Build profile: -w ghc-8.8.3 -O1
In order, the following will be built (use -v for more details):
 - project-euler-0.1.0.0 (test:test) (additional components to build)
Preprocessing test suite 'test' for project-euler-0.1.0.0..
Building test suite 'test' for project-euler-0.1.0.0..
### Failure in: 0:test1                   
test/Tests.hs:4
test
expected: 0
 but got: 1
Cases: 1  Tried: 1  Errors: 0  Failures: 1

So what is the difference here?

  • Last question : In my src folder, I will have multiple .hs files, one for each problem with one function to test each time like :
-- src/Problem_1.hs                                                                         
problem_1 = sum [x | x <- init [0..1000], (x `mod` 3 == 0) || (x `mod` 5 == 0)]

Now how can I import it inside my Test.hs file? Is it the best way to do this or should I put a test file for each of the problems?

Any suggestions is greatly appreciated! :wink:

To import your problems into your test you can either add the project to the build-depends of the test suite like

build-depends: base, HUnit, project-euler

or you can add the src directory to hs-source-dirs of your test suite.

As to why cabal test and cabal run test are different I don’t know since I don’t use HUnit, but maybe this comment is relevant https://gist.github.com/23Skidoo/8019225#gistcomment-1480191

1 Like

Hi @eddiemundo,

Thanks for the answer!

If I add project-euler as a dependency of the test suite, this is what I get :

$ cabal run test

cabal: Cannot run the test suite 'test' because the solver did not find a plan
that included the test suites for project-euler-0.1.0.0. It is probably worth
trying again with test suites explicitly enabled in the configuration in the
cabal.project{.local} file. This will ask the solver to find a plan with the
test suites available. It will either fail with an explanation or find a
different plan that uses different versions of some other packages. Use the
'--dry-run' flag to see package versions and check that you are happy with the
choices.

I don’t quite understand this message :thinking:

But it works fine with hs-source-dirs and the gist link you sent so thank you :wink:

Oh I thought in your .cabal file you also had either a library or executable stanza and not just the test-suite stanza. Something like this:

library
  hs-source-dirs: src
  build-depends: ...
  exposed-modules:
    Problem_1
  other-modules:
  default-extensions:
  default-language: Haskell2010

will make the error go away. However, in your case I think doing what you’ve already done and not adding a library or executable stanza is probably better.

1 Like

For a while, I struggled with project-setup details like this. A resource that has helped improve that experience a lot, is the stack project templates (https://github.com/commercialhaskell/stack-templates). Try them out, I think they speak for themselves. For example, there is an hspec template even (https://github.com/commercialhaskell/stack-templates/blob/master/hspec.hsfiles). You can access it with stack like so:

$ stack new explore-hspec hspec
$ cd explore-hspec
$ stack build --test

In the end, you should see some output like:

image

The directory layout and details of .cabal/etc files are all there for exploration and learning. But it comes working out of the box, so very approachable and a nice foundation to start a project on. I use the rio, simple, and yesodweb/minimal templates a lot :slight_smile:

YMMV!

1 Like