2016-01-16 4 views
1

Disons que j'ai un fichier src comme ceci:hspec ne pas importer la dépendance de code (privé) malgré override RPC

{-# LANGUAGE CPP #-} 
module Alphabet (
#ifdef TEST 
    alphabet 
#endif 
) where 
    alphabet :: [Char] 
    alphabet = "abcdefghijklmnopqrstuvwxyz" 

un fichier .cabal comme ceci:

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 

Un fichier de test maître comme si:

{-# OPTIONS_GHC -F -pgmF hspec-discover #-} 

et un fichier de test comme:

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’ 

Pourquoi mon CPP ne fonctionne-t-il pas comme prévu? Comment puis-je le réparer?

+1

Le moyen suggéré semble être d'utiliser des drapeaux (comme [cette question asker] (http://stackoverflow.com/questions/31821952/flags-in-cabal-files)) –

Répondre

3

Pourquoi mon CPP ne fonctionne-t-il pas comme prévu?

Construction en deux étapes. Comme vos tests dépendent de la bibliothèque, elle est générée en premier. La bibliothèque ne possède aucune option CPP définie, par conséquent, alphabet n'est pas exportée.

Lorsque les tests sont compilés, votre bibliothèque est déjà compilée et alphabet n'est pas exportée. C'est une séparation des préoccupations.

Comment puis-je résoudre ce problème?

Il existe plusieurs astuces pour travailler avec des fonctions "cachées" (par exemple non exportées). Pour un, vous pouvez les mettre tous dans un module .Internal. De cette façon, les utilisateurs qui veulent utiliser les bits cachés peuvent le faire assez facilement, mais l'utilisateur occasionnel n'a pas trop d'outils à portée de main.

Une autre façon de gérer cela est de laisser tomber la dépendance dans le test et ajouter à la place du répertoire src aux tests:

hs-source-dirs:  tests, src 

Cependant, cela signifie également que vous devez reconstruire l'ensemble des tests, mais cela permettra d'utiliser le CPP.

Une troisième option consiste à ne pas tester alphabet, mais plutôt le comportement observable des fonctions exportées qui en dépendent. Ainsi, au lieu des tests alphabet, vous tester filterAlpha:

filterAlpha :: String -> String 
filterAlpha = filter (`elem` alphabet) 

Vous devez tester filterAlpha de toute façon. S'il y a beaucoup de fonctions qui utilisent alphabet, il est probable que vous aurez un test qui remarquera une régression si vous le changez accidentellement.

+0

Vous êtes une rockstar ....Je vous jure que vous avez fait plus pour mon Haskell dans les dernières 24 heures que les heures de blogs/bricolage ont fait au cours des dernières semaines :) Merci –

0

Le problème était simplement une erreur de syntaxe. #ifdef est faux, #ifndef est correct

+1

Ne faites-vous pas le contraire de qu'est-ce que tu voulais, cependant? '# ifndef' signifie" si ce n'est pas défini "donc vous rendez la fonction' alphabet' toujours publique, sauf quand 'TEST' est défini. –

+0

:(vous avez raison –