0

My Main.hs file takes in commandline arguments:

module Main (toLowerStr, Result(..), grade, main) where

...

grade :: [String] -> String -> String -> (Bool, Result, [Highlight])
    grade dictWords correctAnswer studentAnswer =
            ...

...

main :: IO ()
main = do
        args <- getArgs
        dict <- readFile $ args !! 0
        ...

Which works fine, except when I try to test. My testing file is

module Testing where

import Main
import Test.Hspec

main :: IO ()
main = do
        dict <- readFile "dict.txt"
        let dictWords = map toLowerStr $ lines dict
        hspec $ do
        describe "Validate passing answers" $ do
                it "Match should be verified exactly" $ do
                        grade dictWords "house" "house"
                              `shouldBe` (True, Perfect, [])

Yet when I run cabal test it still gives me

Preprocessing test suite 'tests' for grade-0.1.0.0...
[2 of 2] Compiling Testing          ( src/HSpecTests.hs, dist/build/tests/tests-tmp/Testing.o )
Linking dist/build/tests/tests ...
Running 1 test suites...
Test suite tests: RUNNING...
tests: Prelude.(!!): index too large

Test suite tests: FAIL

I'm pretty sure it's failing because of the calls to args in Main.main, because the executable itself works fine, and I don't see !! being used anywhere else.

How do I get tests to run?

EDIT: Used pattern matching in Main.hs:

main :: IO ()
main = do
        [filename, correctString, studentString] <- getArgs
        ...

and the error is now

[1 of 2] Compiling Main             ( src/Main.hs, dist/build/tests/tests-tmp/Main.o )
Linking dist/build/tests/tests ...
Running 1 test suites...
Test suite tests: RUNNING...
tests: user error (Pattern match failure in do expression at src/Main.hs:141:9-48)
Test suite tests: FAIL

EDIT 2: My entire grade.cabal file

-- Initial grade.cabal generated by cabal init.  For further documentation,
--  see http://haskell.org/cabal/users-guide/

name:                grade
version:             0.1.0.0
-- synopsis:            
-- description:         
license-file:        LICENSE
author:              Amos Ng <amosng@cmu.edu>
maintainer:          Amos Ng <amosng@cmu.edu>
-- copyright:           
category:            Language
build-type:          Simple
cabal-version:       >=1.8

executable grade
  main-is:             Main.hs
  -- other-modules:       
  build-depends:       base, split ==0.2.*
  hs-source-dirs:      src

test-suite tests
  ghc-options:         -Wall
  type: exitcode-stdio-1.0
  main-is:             HSpecTests.hs
  other-modules:       Main
  build-depends:       base, split ==0.2.*, hspec ==1.11.*
  hs-source-dirs:      src
wrongusername
  • 18,564
  • 40
  • 130
  • 214
  • What is below the "..."? Can you add the .cabal file (maybe you use the wrong src/main) – Random Dev Sep 12 '14 at 09:55
  • 1
    1: Using `!! 0` is the same as just calling `head`. 2: try using pattern matching (and emitting a sensible error message) instead of doing either of those. – MathematicalOrchid Sep 12 '14 at 09:56
  • BTW: you should consider using the neat discovery feature of HSpec: https://hspec.github.io/hspec-discover.html – Random Dev Sep 12 '14 at 09:57
  • @CarstenKönig I don't have the file with me right now but there's only two .hs files in `src`: Main.hs and HSpecTest.spec, and both use different module names. I don't think it'll be confused? – wrongusername Sep 12 '14 at 15:16
  • @MathematicalOrchid ok, I updated the main file to use pattern matching. It's the culprit for sure. Any ideas? – wrongusername Sep 13 '14 at 07:33
  • It's just the same as before - your test seems to call the original Main.hs where you do your patternmatching now - obvious you don't want this (now you even need 3 arguments btw - not only 1) - you can easily test this by `cabal test --test-option="dict.txt"` - but as I said now you need 3 options because of your pattern-matching so give more) – Random Dev Sep 13 '14 at 08:13
  • If you could show us your `.cabal` file I could tell you why it takes the *wrong* main-method/module for your test – Random Dev Sep 13 '14 at 08:14
  • @CarstenKönig I've put my entire .cabal file there, does anything jump out at you? – wrongusername Sep 14 '14 at 04:21
  • @CarstenKönig adding `--test-option="dict.txt house house"` doesn't solve it (even though `grade dict.txt house house` works just fine after I do `cabal install`) – wrongusername Sep 14 '14 at 04:23
  • @CarstenKönig also i've put the entire testing file there – wrongusername Sep 14 '14 at 04:40
  • GHC will always use as the entry point the function named `main` out of the module named `Main`. Since `HSpecTests.hs` is the `Testing` module, not the `Main` module, its `main` is completely ignored, instead favoring the `main` from the `Main` module. You should break your logic out of the `Main` module, leaving the `Main` module as a command-line stub. Then you’ll want to exclude that from the test build, and change `module Testing` to `module Main` in `HSpecTests.hs`. – icktoofay Sep 14 '14 at 04:43
  • @icktoofay Ahhhh finally fixed it! Thanks so much, can you put that as an answer please? – wrongusername Sep 14 '14 at 04:49

1 Answers1

1

GHC will always use as the entry point the function named main out of the module named Main. Since HSpecTests.hs is the Testing module, not the Main module, its main is completely ignored, instead favoring the main from the Main module. You should break your logic out of the Main module, leaving the Main module as a command-line stub. Then you’ll want to exclude that from the test build, and change module Testing to module Main in HSpecTests.hs.

icktoofay
  • 126,289
  • 21
  • 250
  • 231
  • @wrongusername there are other ways to do this - the file your `Main`-Module is in has not to be called `Main.hs` and you can use different folders (for example `/src` and `/test`) to setup a sensible project structure - have a look at this Wiki article: http://www.haskell.org/haskellwiki/Structure_of_a_Haskell_project (this is a link from the above document but maybe you don't see it: http://www.haskell.org/haskellwiki/How_to_write_a_Haskell_program) – Random Dev Sep 14 '14 at 06:40
  • @CarstenKönig I see, thanks a lot for the information! It is quite useful – wrongusername Sep 14 '14 at 07:31
  • @wrongusername @CarstenKönig I tend to put the main module for a program in a separate directory `driver`, see branch [`testing-a-programm`](https://github.com/sol/hspec-example/tree/testing-a-programm) of `sol/hspec-example` on GitHub. – Simon Hengel Nov 01 '14 at 05:44