Entry point for test suite with multiple files in Cabal project? - haskell

New to Cabal, so sorry if this is obvious, but I obviously want to have more than one file in my Cabal project's test suite, yet the .cabal file is insisting on being given an entrypoint. What do I put for this?
For example, if I have two modules in my library and want to test each in their own test file. One is no more important than the other, so how do I go about making one of the files an entrypoint?

You could make two test suites.
test-suite A
main-is: test-module-A.hs
test-suite B
main-is: test-module-B.hs
Or you could make a single suite that imports both test modules.
test-suite both
main-is: test-both.hs
other-modules: TestA, TestB

Related

Exposing internal modules to tests in Cabal

I'm contributing to an open source project which defines its project setup in a cabal file that looks like this (omitting lots of properties that are not relevant for this problem):
library
hs-source-dirs: src
build-depends:
base >= 4.9 && < 5,
some-other-deps
exposed-modules:
Data.Foo.Bar,
Data.Foo.Baz
other-modules:
Data.Foo.Bar.Internal
test-suite test
hs-source-dirs:
tests
build-depends:
foo-library
other-modules:
Foo.Bar.Tests,
Foo.Baz.Tests
Now, in order to test the feature I'm adding, I want the tests to have access to the Data.Foo.Bar.Internal module, but since it's hidden in the library, I can't access it from the tests.
I looked at the cabal docs which suggested adding a third component - an internal library (unfortunately not linkable, but search for "internal libraries"). If I understand the documentation correctly, I should be able to do something like this:
library foo-internal
hs-source-dirs: src
build-depends:
base,
some-other-deps
exposed-modules:
Data.Foo.Bar.Internal
library
hs-source-dirs: src
build-depends:
base >= 4.9 && < 5,
foo-internal,
some-other-deps
exposed-modules:
Data.Foo.Bar,
Data.Foo.Baz
test-suite test
hs-source-dirs:
tests
build-depends:
foo-library,
foo-internal
other-modules:
Foo.Bar.Tests,
Foo.Baz.Tests
but running stack build here gives me warnings that Data.Foo.Bar.Internal "should be added to exposed-modules or other-modules in ./foo.cabal", and then a build error in the test that seems to be caused by failed unification (it points to a function argument for a function defined in the library, says that its type must be Data.Foo.Bar.Internal.Qux defined in package foo, and that the type foo:Data.Foo.Bar.Internal.Qux don't match).
How can I expose internal modules to the test suite, without exposing them also to consumers of the library?
As mentioned in the comments, different components (internal libraries, executables) should have modules under different roots.
This is a recurrent point of confusion. For another example: https://stackoverflow.com/a/6711739/6863749
There is an open ticket on Cabal's issue tracker about clarifying this with a suitable warning; it's apparently non-trivial to detect this situation reliably because it overlaps with legitimate use cases: https://github.com/haskell/cabal/issues/5335

Do I have to repeat all dependencies in the test configuration?

This bugs me time and again, basically if I create a test-suite in the cabal configuration I add the projects src folder to the test suites hs-source-dirs section and repeat all dependencies in build-depends. A typical project might look like:
-- in file "foo.cabal"
library
build-depends: a, b, c
exposed-modules: Foo, Bar
hs-source-dirs: src
test-suite tests
build-depends: foo, a, b, c
hs-source-dirs: test
The other option is to include src in the test suites hs-source-dirs as well.
Both of them require me to specify all build dependencies in the test case, as far as I know. Is there a way around this?
It should work as is but there is a reported bug when you use it with cabal repl
Overall it seems work with cabal test but if you try to load the test-file into cabal repl you might get an error like this:
Could not find module ‘XYZ’
It is a member of the hidden package ‘XZY-[ver]’.
Perhaps you need to add ‘XYZ’ to the build-depends in your .cabal file.
Use -v to see a list of the files searched for.
So right now it might be a good idea to indeed copy the dependencies but hopefully this will get resolved shortly

cabal doesn't find Source.hs

My project structure is as follows:
~/.../project_name
project_name.cabal
Setup.hs
src/
Main.hs
Data/
...
test/
MainTestSuite
...
I have (amongst others) the following lines in my project.cabal:
build-type: Simple
...
executable project_name
main-is: Main.hs
...
hs-source-dirs: src
When I cabal configure (works fine) and then cabal build I get the error message:
cabal: can't find source for Setup in src, dist/build/autogen
It works when I put Source.hs in src but this seems messy to me and I haven't seen this in other projects, where Source.hs is always in the project root. How do I get cabal to find Source.hs?
As an aside: What's the purpose of Source.hs anyways?
The problem was caused by accidently adding the Source file as a dependency in other-modules in the cabal-file of the project ... that caused all the trouble.
hs-source-dirs: ., src comes to mind as a fast fix.
That's what my projects use, and I generate my cabal files automatically (so I suppose that's the default).

Shared cabal "build-depends" (Haskell) [duplicate]

Here's a .cabal file:
Name: myprogram
Version: 0.1
-- blah blah blah
Cabal-version: >=1.9.2
Executable myprogram
HS-source-dirs: src
Main-is: Main.hs
Build-depends: attoparsec == 0.10.*,
base == 4.3.*,
-- long long list of packages
Test-Suite test
HS-source-dirs: test, src
Type: exitcode-stdio-1.0
Main-is: Main.hs
Build-depends: attoparsec == 0.10.*,
base == 4.3.*,
-- long long list of packages
QuickCheck == 2.4.*
Is there any way I can replace the long list of build-depends packages for the test suite with "same as for the executable, plus QuickCheck"?
Edit: version information.
cabal-dev 0.9
cabal-install 0.10.2
Cabal library 1.10.2.0
GHC 7.0.4
Haskell Platform 2011.4.0.0
NOTE: superseded by phadej's answer suggesting common stanzas.
Is there any way I can replace the long list of build-depends packages for the test suite with "same as for the executable, plus QuickCheck"?
Not that I know of. However, there is a way to only mention the list of build-depends packages once, by structuring your project into three targets:
a library that contains all your code, and needs the long build-depends list.
an executable that consists of only one file, and depends on base and the library from above.
a test-suite that depends on the library from above, and the testing packages you are using.
Maybe this approach is what indygemma's answer proposes, but the Cabal file proposed there will not quite achieve it, as Norman Ramsey points out in a comment. Here's the main points of what you need in a Cabal file. For a full example that works for me, you can look at this Cabal file.
name: my-program
version: ...
library
hs-source-dirs: src-lib
build-depends: base, containers, ...
exposed-modules: My.Program.Main, ...
executable my-program
hs-source-dirs: src-exec
main-is: my-program.hs
Build-depends: base, my-program
test-suite tests
type: exitcode-stdio-1.0
hs-source-dirs: src-test
main-is: tests.hs
other-modules: ...
build-depends: base, my-program, test-framework, ...
Important points:
There are three separate source directories for the three targets. This is necessary to stop GHC from recompiling library files when building the other targets.
All of the application code is in the library. The executable is just a wrapper, like this:
import My.Program.Main (realMain)
main = realMain
The library exposes all modules that are necessary for testing.
The last point highlights the drawback of this approach: You end up having to expose internal modules. The main benefit of this approach is that you have less duplication in the Cabal file, and maybe more importantly, less duplication in the build process: The library code will be built only once, and then linked into both the executable and the test-suite.
Since version 2.2 Cabal supports common stanzas, to dedup build info fields:
https://cabal.readthedocs.io/en/latest/developing-packages.html#common-stanzas
cabal-version: 2.2
name: myprogram
version: 0.1
-- blah blah blah
common deps
build-depends: base ^>= 4.11,
-- long long list of packages
ghc-options: -Wall
library
import: deps
exposed-modules: Foo
test-suite tests
import: deps
type: exitcode-stdio-1.0
main-is: Tests.hs
build-depends: foo
You could also consider using hpack instead of writing the .cabal file by hand:
In hpack's package.yaml format, you can specify a common dependencies field whose entries are added to every components' build-depends field when generating the .cabal file.
For example, see hpack's own package.yaml and the generated hpack.cabal.
To start using hpack with an existing package, you can use hpack-convert which will generate the package.yaml from an existing .cabal file.
To create a new package that uses hpack, you can use stack's simple-hpack template like so: stack new mypkg simple-hpack.
If you use stack for development, you don't have to call hpack manually to regenerate the .cabal file from an updated package.yaml – stack will do that automatically.
No easy way:
you can use m4 and specify your dependencies once, but then you will need to reprocess your Cabal file through m4 whenever you change it.
you can move the code you are testing out to a library, and then specify the library in your Build-depends for the test. That requires you to install a library even just to run the test.
You can just not put the test in the cabal file at all. Build it with ghc --make, which will pull in dependencies. But then you lose cabal integration.
There is an optional library section for .cabal files, which solves your problem.
name: myprogram
version: 0.1
-- blah blah blah
cabal-version: >=1.9.2
library
build-depends: attoparsec == 0.10.*
, base == 4.3.*
-- long long list of packages
executable myprogram
hs-source-dirs: src
main-is: Main.hs
test-suite test
hs-source-dirs: test, src
type: exitcode-stdio-1.0
main-is: Main.hs
build-depends: QuickCheck == 2.4.*

Testing Haskell code defined in the Main module

I'm looking for help regarding how to write tests for Haskell code that is defined in the Main module.
The project I want to test is a cabal package in which I've defined multiple executables.
Each executable code is declared only made of a single file (one for each project euler problem), and I usually run them individually with the cabal run command.
I have tried to write a test, also in the Main module, but when compiling, the function I'm trying to test is not found ("Not in scope" error).
What is the right way to write tests in this case?
For information, below is the directory layout of my project:
pe/ # root
pe.cabal
src/
Util.hs
Problem001.hs # "module Main where" and declares a main function
Problem002.hs # "module Main where" and declares a main function
(...)
test/
TestProblem001.hs # "module Main where" and declares a main function
Below is an extract from pe.cabal:
test-suite test-all
hs-source-dirs: test
type: exitcode-stdio-1.0
main-is: TestProblem001.hs
build-depends: base, HUnit, Cabal >= 1.9.2
executable problem-001
hs-source-dirs: src
main-is: Problem001.hs
build-depends: base
ghc-options: -Wall -Werror -O2
[edit]
As I couldn't find any resource for this exact requirement, I opted for a project architecture which is easier to test: problems are defined as library and not individual executables anymore.
I do so
test1 = ...
test2 = ...
main = do
args <- getArgs
case args of
... -> check test1
... -> check test2

Resources