hspec не удается импортировать (частную) зависимость кода, несмотря на переопределение CPP
Допустим, у меня есть файл src примерно так:
{-# LANGUAGE CPP #-}
module Alphabet (
#ifdef TEST
alphabet
#endif
) where
alphabet :: [Char]
alphabet = "abcdefghijklmnopqrstuvwxyz"
.cabal
файл вроде так:
name: Alphabet
version: 0.1.0.0
library
build-depends: base >=4.8 && <4.9, containers >=0.5 && <0.6, split >=0.2 && <0.3
hs-source-dirs: src
Exposed-modules: Alphabet
default-language: Haskell2010
test-suite alphabet-test
ghc-options: -Wall -Werror
cpp-options: -DTEST
default-extensions: OverloadedStrings
type: exitcode-stdio-1.0
main-is: Spec.hs
hs-source-dirs: tests
build-depends: Alphabet, base >= 4.8 && < 4.9, containers >= 0.5 && <0.6, split >= 0.2 && < 0.3, hspec, QuickCheck
default-language: Haskell2010
Главный тестовый файл выглядит так:
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
и тестовый файл как:
module AphabetSpec (spec) where
import Test.Hspec
import Alphabet (alphabet)
spec :: Spec
spec = do
describe "Alphabet.alphabet" $ do
it "returns the alphabet" $ do
alphabet `shouldBe` "abcdefghijklmnopqrstuvwxyz"
now running `cabal test`:
cabal test
Preprocessing library Alphabet-0.1.0.0...
In-place registering Alphabet-0.1.0.0...
Preprocessing test suite 'alphabet-test' for Alphabet-0.1.0.0...
[1 of 1] Compiling Main ( tests/AlphabetSpec.hs, dist/build/alphabet-test/alphabet-test-tmp/AlphabetSpec.o )
tests/AlphabetSpec.hs:4:27:
Module ‘Alphabet’ does not export ‘alphabet’
Почему мой CPP не работает, как ожидалось? Как я могу это исправить?
2 ответа
Почему мой CPP не работает, как ожидалось?
Двухступенчатое здание. Поскольку ваши тесты зависят от библиотеки, она сначала собирается. В библиотеке не установлены параметры CPP, поэтому alphabet
не экспортируется.
Когда тесты собраны, ваша библиотека уже скомпилирована, и alphabet
не экспортируется. Это разделение проблем.
Как я могу это исправить?
Есть несколько приемов для работы со "скрытыми" (например, неэкспортированными) функциями. Например, вы можете поместить их всех в .Internal
модуль. Таким образом, пользователи, которые хотят использовать скрытые биты, могут сделать это довольно легко, но случайный пользователь не имеет слишком много инструментов под рукой.
Другой способ справиться с этим - сбросить зависимость в тесте и вместо этого добавить src
каталог к тестам:
hs-source-dirs: tests, src
Однако это также означает, что вам нужно перестроить всю библиотеку для тестов, но это позволит использовать CPP.
Третий вариант - не проверять alphabet
, но вместо этого наблюдаемое поведение экспортируемых функций, которые зависят от него. Так что вместо тестирования alphabet
, вы бы проверить filterAlpha
:
filterAlpha :: String -> String
filterAlpha = filter (`elem` alphabet)
Вы должны проверить filterAlpha
тем не мение. Если есть много функций, которые используют alphabet
, вероятно, у вас будет какой-то тест, который заметит регрессию, если вы случайно измените ее.
Проблема была просто синтаксической ошибкой. #ifdef
неправильно, #ifndef
правильно