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 правильно

Другие вопросы по тегам