Re-use tests between packages in Stack - haskell

I'm curious if it's possible to expose test folder of one package, so another package in multi-package Stack setup could re-use test functions & instances:
second-package-test -> dependsOn -> first-package-test
The first package has the following lines in package.yaml:
tests:
first-package-test:
main: Spec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- first-package
- hspec
- QuickCheck
- quickcheck-instances
- quickcheck-classes
And the second package that should rely on the first one has the following setup:
stack.yaml contains:
extra-deps:
- ../first-package <-- it seems that it imports only library, not the tests
package.yaml contains:
tests:
second-package-test:
main: Spec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- second-package
- hspec
- QuickCheck
- quickcheck-instances
- quickcheck-classes
The root aggregation of them looks simple. stack.yaml:
packages:
- first-package
- second-package
I think, in theory, it's possible to create a third package with tests only that are exposed as a library, but wonder if there is a bit more elegant way to achieve the same thing.

Related

How to get a graph of dependencies of Haskell project

I have a several executable targets in the project, like:
...
app/
other_app/
src/
package.yaml
stack.yaml
...
so, I have obviously different .hs files in app/, other_app/, src/. If I build it with stack tool then it build apps and other_apps executables from their dependencies, ie, if some .hs file changed in src/ - the result executable will be rebuild. Otherwise - no. stack knows a graph of dependencies like GNU make does it. How to list/print this graph? For example, for C I have makedepend tool which is able to extract dependencies recursively from .c files. Is it possible to be done for Haskell files? With stack tool itself? Maybe with a cabal tool? I tried, for example, v2-freeze of the cabal tool, but it is not related to the problem.
UPDATE:
package.yaml looks like:
.............
executables:
app1-exe:
main: Main.hs
source-dirs: app1
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- app1
app2-exe:
main: Main.hs
source-dirs: app2
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- app1
............
and now I want to list recursively dependencies (in Makefile-style, not dependencies on packages, like stack dot does it!), for instance for app2's Main.hs, something like:
src/Component1/Types.hs
src/Component1/Utils.hs
src/CoolLibrary/CoolUtility.hs
...

Building multiple executables in the default Haskell Stack project

I used the default stack new to setup a project that has a server and a client as separate executables. I altered the package.yaml file in what seems like the right way (As of April 21, 2020 "There is no user guide") and added a new file to my app directory called Client.hs.
I got an error saying "Enabling workaround for Main module 'Main' listed in 'other-modules' illegally!"
How do I have stack build both the client and the server?
When I ran stack build I got:
[... clip ...]
Building executable 'ObjectServer' for ObjectServer-0.1.0.1..
[4 of 4] Compiling Client
Linking .stack-work\dist\29cc6475\build\ObjectServer\ObjectServer.exe ...
Warning: Enabling workaround for Main module 'Main' listed in 'other-modules'
illegally!
Preprocessing executable 'Client' for ObjectServer-0.1.0.1..
Building executable 'Client' for ObjectServer-0.1.0.1..
[3 of 3] Compiling Client
<no location info>: error:
output was redirected with -o, but no output will be generated
because there is no Main module.
-- While building package ObjectServer-0.1.0.1 using:
D:\HaskellStack\setup-exe-cache\x86_64-windows\Cabal-simple_Z6RU0evB_3.0.1.0_ghc-8.8.3.exe --builddir=.stack-work\dist\29cc6475 build lib:ObjectServer exe:Client exe:ObjectServer --ghc-options " -fdiagnostics-color=always"
Process exited with code: ExitFailure 1
The relevant portion of package.yaml looks like this:
executables:
ObjectServer:
main: Main.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- ObjectServer
Client:
main: Client.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- ObjectServer
There are two problems here. First, the default value for other-modules in hpack is "all modules in source-dirs except main and modules mentioned in a when clause". If you look at the generated .cabal file, you'll see that as a result of this default, each executable has incorrectly included the other executable's module in its other-modules list. Second, the main setting gives the source file that contains the main module, but doesn't change the name of the module expected by GHC from Main to anything else. Therefore, that module still needs to be named module Main where ..., not module Client where..., unless you also, separately add a -main-is Client GHC option.
So, I would advise modifying Client.hs to make it the Main module:
-- in Client.hs
module Main where
...
and then specifying other-modules: [] explicitly for both executables:
executables:
ObjectServer:
main: Main.hs
other-modules: []
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- ObjectServer
Client:
main: Client.hs
other-modules: []
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- ObjectServer
That seems to work in my testing.

Unable to add classy-prelude dependency

I am trying to add classy-prelude dependency to my stack project as follows:
name: FooService
version: 0.1.0.0
github: "githubuser/FooService"
license: BSD3
author: "Author name here"
maintainer: "example#example.com"
copyright: "2019 Author name here"
extra-source-files:
- README.md
- ChangeLog.md
# Metadata used when publishing your package
# synopsis: Short description of your package
# category: Web
# To avoid duplicated efforts in documentation and dealing with the
# complications of embedding Haddock markup inside cabal files, it is
# common to point users to the README.md file.
description: Please see the README on GitHub at <https://github.com/githubuser/FooService#readme>
dependencies:
- base >= 4.7 && < 5
- classy-prelude
default-extesion:
- NoImplicitPrelude
- OverloadedStrings
library:
source-dirs: src
executables:
FooService-exe:
main: Main.hs
source-dirs: app
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- FooService
tests:
FooService-test:
main: Spec.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
dependencies:
- FooService
when call the interactive environment I've got the error message:
Using main module: 1. Package `FooService' component FooService:exe:FooService-exe with main-is file: /home/developer/haskell/FooService/app/Main.hs Cabal file info not found for classy-prelude-1.5.0#sha256:ed1a607f688745bc263be0b2ed2492729a62fd4c9821b68c2bfacbd7a9d9293d,1928, updating Selected mirror https://s3.amazonaws.com/hackage.fpcomplete.com/ Downloading timestamp No package index update available, but didn't update cache last time, running now Calculating hashes to check for hackage-security rebases or filesystem changes Updating preexisting cache, should be quick Populating cache from file size 640326144, hash bb56d41c70c9e6cdd625a6c3c7de5f56823e92cc6fe880f8056259ab31d3e0d5 Populating package index cache ... Failed populating package index cache
Error: BadChecksum 0
Warning: Build failed, but trying to launch GHCi anyway The following GHC options are incompatible with GHCi and have not been passed to it:
-threaded Configuring GHCi with the following packages: FooService GHCi, version 8.6.5: http://www.haskell.org/ghc/ :? for help <command line>: cannot satisfy -package classy-prelude-1.5.0
What is missing?

How does one have multiple libraries using hpack?

I'd like to organize my project into different libraries, since eventually I may be splitting some out to external repositories.
In a .cabal file I can have multiple libraries (one unnamed, and multiple named, I believe):
library
import: servant-deps
exposed-modules:
App
other-modules:
Paths_cow_streamer
hs-source-dirs:
src
build-depends:
servant-server >= 0.15
library sxapi
import: servant-deps
exposed-modules:
SxClient
other-modules:
Paths_cow_streamer
hs-source-dirs:
sxapi
build-depends:
http-client
Initially I tried like this in my hpack package.yaml:
library:
bar:
source-dirs:
- src
dependencies:
- servant-server >= 0.14
- wai
- warp
foo:
source-dirs:
- sxapi
dependencies:
- servant-server >= 0.14
- wai
- warp
But in this case, none of the entries seemed to be interpreted correctly, since e.g. source-dirs weren't present in the generated cabal file.
I also tried this, but unsurprisingly, one of the library definitions was overwritten:
library:
source-dirs:
- src
dependencies:
- servant-server >= 0.14
- wai
- warp
library:
source-dirs:
- sxapi
dependencies:
- servant-server >= 0.14
- wai
- warp
As per the documentation of hpack (https://github.com/sol/hpack#top-level-fields) you use the internal-libraries header for your internal (named) libraries.

Not in scope: type constructor or class ‘Test.Framework.TestSuite’ when trying to create unit tests

I'm writing a small library in Haskell, and want to have tests to accompany it. For testing I intend to use HFT, and the project as a whole is managed by stack. stack test fails for some reason with the following output:
[1 of 2] Compiling Main ( test/Ini.hs, .stack-work/dist/x86_64-linux-tinfo6/Cabal-2.0.1.0/build/ini-tests/ini-tests-tmp/Main.o ) │····························
[2 of 2] Compiling Paths_schemer ( .stack-work/dist/x86_64-linux-tinfo6/Cabal-2.0.1.0/build/ini-tests/autogen/Paths_schemer.hs, .stack-work/dist/x86_64-linux-tinfo6/Cabal-2.0.1.0/build/ini-tests/ini-tests-tm│····························
p/Paths_schemer.o ) │····························
│····························
/stuff/projects/schemer/.stack-work/dist/x86_64-linux-tinfo6/Cabal-2.0.1.0/build/ini-tests/autogen/Paths_schemer.hs:54:39: error: │····························
Not in scope: type constructor or class ‘Test.Framework.TestSuite’ │····························
No module named ‘Test.Framework’ is imported. │····························
│····························
/stuff/projects/schemer/.stack-work/dist/x86_64-linux-tinfo6/Cabal-2.0.1.0/build/ini-tests/autogen/Paths_schemer.hs:55:38: error: │····························
Not in scope: ‘Test.Framework.makeTestSuite’ │····························
No module named ‘Test.Framework’ is imported. │····························
My Ini.hs file that will later contain the tests is very bare-bone, just
import Test.Framework
main :: IO ()
main = htfMain htf_thisModulesTests
My package.yaml is
name: schemer
version: 0.1.0.0
github: "mpevnev/schemer"
license: BSD3
author: "Michail Pevnev"
maintainer: "mpevnev#gmail.com"
copyright: ""
extra-source-files: []
# Metadata used when publishing your package
# synopsis: Short description of your package
# category: Web
# To avoid duplicated efforts in documentation and dealing with the
# complications of embedding Haddock markup inside cabal files, it is
# common to point users to the README.md file.
description: Please see the README on GitHub at <https://github.com/mpevnev/schemer#readme>
dependencies:
- attoparsec
- base >= 4.7 && < 5
- text
library:
source-dirs: src
tests:
ini-tests:
main: Ini.hs
source-dirs: test
ghc-options:
- -threaded
- -rtsopts
- -with-rtsopts=-N
- -F
- -pgmF htfpp
dependencies:
- schemer
- text
- HTF
Here's the autogenerated schemer.cabal:
-- This file has been generated from package.yaml by hpack version 0.28.2.
--
-- see: https://github.com/sol/hpack
--
-- hash: 17ae623236b8f5b101f56373c975656e898efa7506acb143db7375f229509a79
name: schemer
version: 0.1.0.0
description: Please see the README on GitHub at <https://github.com/mpevnev/schemer#readme>
homepage: https://github.com/mpevnev/schemer#readme
bug-reports: https://github.com/mpevnev/schemer/issues
author: Michail Pevnev
maintainer: mpevnev#gmail.com
license: BSD3
license-file: LICENSE
build-type: Simple
cabal-version: >= 1.10
source-repository head
type: git
location: https://github.com/mpevnev/schemer
library
exposed-modules:
Control.Scheme.Ini
Control.Schemer
other-modules:
Paths_schemer
hs-source-dirs:
src
build-depends:
attoparsec
, base >=4.7 && <5
, text
default-language: Haskell2010
test-suite ini-tests
type: exitcode-stdio-1.0
main-is: Ini.hs
other-modules:
Paths_schemer
hs-source-dirs:
test
ghc-options: -threaded -rtsopts -with-rtsopts=-N -F -pgmF htfpp
build-depends:
HTF
, attoparsec
, base >=4.7 && <5
, schemer
, text
default-language: Haskell2010
I'm not sure what's wrong and what is this Paths_schemer thing. Help is appreciated.
The options -F -pgmF htfpp are switched on globally. This applies the HTF preprocessor to all the files of the test suite, including the autogenerated Paths_schemer.
The more scalable solution is to enable the preprocessor only on files that import Test.Framework, using the OPTIONS_GHC pragma in each one:
{-# OPTIONS_GHC -F -pgmF htfpp #-}
Another way is to set other-modules: [] in the test-suite section in package.yaml to avoid generating Paths_schemer, although that only solves the problem for this one module.

Resources