Using HSpec with Stack - haskell

I have the following architecture :
backend
├── Chat.hs
├── Main.hs
└── Message.hs
test
├── backendSpec
│ └── MessageSpec.hs
└── Spec.hs
My .cabal file contains the following
test-suite spec
build-depends: base, hspec == 2.*,
snap >= 0.14.0.6,
containers,
aeson,
text,
transformers,
stm,
snap-core,
snap-server,
socket-io,
engine-io-snap,
snap-cors,
bytestring
hs-source-dirs: test
main-is: Spec.hs
Type: exitcode-stdio-1.0
but when I do
stack test
HSpec cannot find my test int MessageSpec.hs.
Finished in 0.0002 seconds
0 examples, 0 failures
Spec.hs is the correct input : {-# OPTIONS_GHC -F -pgmF hspec-discover #-}
and my MessageSpec module is exposing : module MessageSpec (main, spec).
Could you help me find a way to make my stack project doing all my tests.
Thank you,

Your path to your spec must follow the module name convention. backendSpec.MessageSpec is not a valid module name, since it starts with a lowercase letter.
Furthermore, the module name of your spec should only differ by the additional suffix Spec from your original module. Your modules in backendSpec wouldn't follow this:
module Message where ...
-- vs
module BackendSpec.MessageSpec where ...
So to fix this, make sure that all directories in your test directory start with an uppercase letter. But even better, make sure that the test directory has the same structure as your src directory, as this will result in better module names during your tests:
-- If file is test/BackendSpec/MessageSpec.hs
BackendSpec.Message:
<someDescription>
<some assertion>
<some assertion>
<some assertion>
vs
-- If file is test/MessageSpec.hs
Message:
<someDescription>
<some assertion>
<some assertion>
<some assertion>
(The relevant code for this behaviour can be found in hspec/Run.hs of hspec-discover)

Related

stack build works as expected but stack runghc can't find local modules

So I have a Haskell project (managed using stack) structured like this:
.
├── Main.hs
├── Other1.hs
├── subfolder
   └── Other2.hs
where the Main module imports both Other1 and Other2, as simply as
import Other1
import Other2
My .cabal file says:
name: (...)
executable Main
hs-source-dirs:
.,
subfolder
main-is: Main.hs
other-modules:
Other1
Other2
Now, if I run stack build everything works great, all modules are compiled and it looks like nothing can go wrong. But then if I try to execute my program with stack runghc Main, module Other2 (the one in the subfolder) is not found.
Why is that the case? How can I execute my code?

How can I have GHCi reload include changes in the local dependent library?

Full reproducible project here: https://github.com/chrissound/215
I have the following simple cabal file which defines:
a library (source under src-lib)
executable (source under src) in the same project (which depends on the above local library)
cabal-version: 1.12
name: HaskellNixCabalStarter
version: 0.1.0.0
author: HaskellNixCabalStarter
maintainer: HaskellNixCabalStarter
license: MIT
build-type: Simple
library
exposed-modules:
Hello
other-modules:
Paths_HaskellNixCabalStarter
hs-source-dirs:
src-lib
build-depends:
base >=4.12 && <4.13
default-language: Haskell2010
executable app
main-is: Main.hs
other-modules:
Paths_HaskellNixCabalStarter
hs-source-dirs:
src
build-depends:
HaskellNixCabalStarter
, base >=4.12 && <4.13
default-language: Haskell2010
I can open a GHCi repl with:
cabal v2-repl app
However, upon GHCi reloading (:r), it will only reload changes in the app executable, and disregard any changes in the library.
This seems like very limiting / incorrect behavior. How can I fix this / workaround this?
There is a workaround, you either
run cabal repl and then :load src/Main.hs, or
with cabal repl app you'd need to :load src/Main.hs src-lib/Hello.hs.
Now :reload also reloads changes from dependencies.
In the first case it's the :load that somehow also starts loading/following the dependencies. (Not sure why cabal repl app isn't doing exactly the same.)
On the second case you need to explicitly name the modules you want to follow. Also, you need to have the module in who's namespace you want to be in, first. So :load src/Main.hs ..others...
See this on reddit. It appears that cabal can only have one "unit" loaded, but loading other sources with :load seems to subvert that.
I don't think it can be done (yet?). Evidence:
jeff#jbb-dell:cabal-experim$ tree
.
├── cabal.project
├── P1
│   ├── app
│   │   ├── Lib.hs
│   │   └── Main.hs
│   └── P1.cabal
└── P2
├── P2.cabal
└── src
└── MyLib.hs
jeff#jbb-dell:cabal-experim$ cabal repl P1 P2
cabal: Cannot open a repl for multiple components at once. The targets 'P1'
and 'P2' refer to different components.
The reason for this limitation is that current versions of ghci do not support
loading multiple components as source. Load just one component and when you
make changes to a dependent component then quit and reload.

Importing a haskell module from the parent directory

Given the following directory structure:
root
├── scripts
│   └── script1.hs
└── source
   ├── librarymodule.hs
   └── libraryconfig.txt
Where "librarymodule.hs" would be a library exporting multiple functions, where the output is influenced by the contents of the libraryconfig.txt file in his directory.
script1.hs is the file needing to use the functions declared in librarymodule.hs.
I can't find a solution on the internet for a structure as given above and hoped someone could help out.
GHC has a -i option. Under root/scripts/, this will add root/source/ to the search path:
ghc -i../source script1.hs
Also consider packaging your library using cabal so you can install it and use it anywhere without worrying about paths.
Here is a minimal example of a library with data-files:
source/
├── mylibrary.cabal
├── LibraryModule.hs
└── libraryconfig.txt
mylibrary.cabal
name: mylibrary
version: 0.0.1
build-type: Simple
cabal-version: >= 1.10
data-files: libraryconfig.txt
library
exposed-modules: LibraryModule
other-modules: Paths_mylibrary
build-depends: base
default-language: Haskell2010
LibraryModule.hs
module LibraryModule where
import Paths_mylibrary -- This module will be generated by cabal
-- Some function that uses the data-file
printConfig :: IO ()
printConfig = do
n <- getDataFileName "libraryconfig.txt"
-- Paths_mylibrary.getDataFileName resolves paths for files associated with mylibrary
c <- readFile n
print c
See this link for information about the Paths_* module: https://www.haskell.org/cabal/users-guide/developing-packages.html#accessing-data-files-from-package-code
Now running cabal install should install mylibrary.
Then, under scripts/script1.hs, you can just run ghc script1.hs, using the library you installed.

Idiomatic way to run test-suites in stack

Haskell beginner here.
I am struggling to find a nice way to run my test-suites that I have defined in my .cabal file. Given that you add test-suite sections in the .cabal file I would expect that you can run all of them with a single command like stack runtests.
The best answer I found is this one:
Haskell Stack Ghci test-suite suggesting that you have to run
stack ghci --test module:test:libtests
However, there are two things that irritate me and I think that there must be a better way doing it.
It is cumbersome to call stack ghci --test module:test:libtests explicitly. I don't want to do that if I have more test-suites when projects get larger.
Even worse, I end up in an interactive session and have to call main myself. This does not scale.
Isn't there a better way to run your test-suites for a project in stack? Of course I could do some shell scripting, but hey stack should know how to run my tests, I specified everything in the .cabal file.
I tried stack runghc --test but that doesn't help.
Project setup:
.
├── app
│   └── Main.hs
├── LICENSE
├── README.md
├── Setup.hs
├── src
│   ├── Lib.hs
│   └── WordNumber.hs
├── stack.yaml
├── test
│   └── Spec.hs
└── WordNumber.cabal
WordNumber.cabal
name: WordNumber
version: 0.1.0.0
-- synopsis:
-- description:
homepage: https://github.com/githubuser/WordNumber#readme
license: BSD3
license-file: LICENSE
author: Author name here
maintainer: example#example.com
copyright: 2017 Author name here
category: Web
build-type: Simple
extra-source-files: README.md
cabal-version: >=1.10
library
hs-source-dirs: src
exposed-modules: Lib, WordNumber
build-depends: base >= 4.7 && < 5
default-language: Haskell2010
executable wordnumber
hs-source-dirs: app
main-is: Main.hs
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends: base
, WordNumber
default-language: Haskell2010
test-suite wordnumber-test
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: Spec.hs
build-depends: base
, WordNumber
, hspec
ghc-options: -threaded -rtsopts -with-rtsopts=-N
default-language: Haskell2010
Update:
Actually I feel a bit stupid for not finding the answer myself. It is either stack test or stack build --test and also documented.
However, for people following the HaskellBook it might not be that obvious. For some reason all tests in the testing chapter are executed in the cumbersome way and running tests with stack test is never mentioned.
stack test runs tests located in a .cabal file. It runs stack build if required, so you don't need to build manually before testing.
See further: https://docs.haskellstack.org/en/stable/GUIDE/#stack-test

How am I meant to split code between src/Lib.hs and app/Main.hs in a new stack project?

I was following the stack guide and I got a new project setup (yay!).
It generated the following file layout:
.
├── app
│   ├── Main.hs
├── .gitignore
├── LICENSE
├── helloworld.cabal
├── Setup.hs
├── src
│   └── Lib.hs
├── stack.yaml
└── test
└── Spec.hs
According to the "Files in helloworld" section of the guide:
The app/Main.hs, src/Lib.hs, and test/Spec.hs files are all Haskell source files that compose the actual functionality of our project (we won't dwell on them here).
I really wish they had dwelled on that for a second, because I have no idea what the distinction between app/Main.hs and src/Lib.hs should be. Which code should I put where?
In what ways am I supposed to divide code between app/, src/, app/Main.hs and src/Lib.hs?
If I'm just writing an application or just writing a library, do I need both files/directories?
This separation of modules into folders can be any way you want. The naive idea is that you put almost all logic into the Lib folder. Main.hs then just
imports required parts from Lib,
reads command-line arguments, and
runs stuff.
You can rename app into executables and change the corresponding lines in .cabal file. Actually, you can come up with an arbitrary file hierarchy.
In our company project, we use another but also very popular approach. And our file hierarchy looks like this:
.
|-- bench
|-- src
|-- exec1
|-- Main.hs
|-- exec2
|-- Main.hs
|-- SuperCoolLibrary
|-- LibModule1.hs
|-- LibModule2.hs
|-- test
|-- Setup.hs
Other stack.yaml, .cabal, etc. files are not shown here.
Actually, if you are writing an application, you can just create one Main.hs file and put all logic inside the main function. You won't believe it but as a Haskell lecturer I saw such code from my students :(
Though I don't suggest you write code that way.
If you are writing a library then you don't need Main.hs files and the main function at all. You can look at a simple example like this library (it allows you to automatically generate command-line options from data types): optparse-generic
I hope I helped clearing up your confusion.
The main reason it's typically set up like this even for an application is for writing tests. Say you create a default stack project called foo, the test suite foo-test will depend on the foo library, as will the foo-exe. If you were to put all your functions into app/Main.hs, then those functions cannot be tested from the foo-test test suite.
If you're just playing around and don't care about having a test suite, you could base your stack project on the simple template:
$ stack new foo simple
If you'd like to set up testing, I like tasty. You'd modify your .cabal file something like this:
test-suite foo-test
type: exitcode-stdio-1.0
hs-source-dirs: test
main-is: Spec.hs
build-depends: base
, foo
, tasty
, tasty-hunit
, tasty-quickcheck
ghc-options: -threaded -rtsopts -with-rtsopts=-N
default-language: Haskell2010
Then take a look at the example.

Resources