content: import Data.List(partition)
  import System.IO
  import Distribution.Simple.BuildPaths(exeExtension)
  import System.Process(readProcess)
  import System.Directory(doesFileExist,getDirectoryContents)
  import System.FilePath((</>),(<.>),takeExtension)
  import System.Exit(exitSuccess,exitFailure)
  
  main = 
     do res <- walk "testsuite"
        let cnt = length res
            (good,bad) = partition ((=="OK").fst.snd) res
            ok = length good
            fail = ok<cnt
        putStrLn $ show ok++"/"++show cnt++ " passed/tests"
        let overview = "dist/test/gf-tests.html"
        writeFile overview (toHTML bad)
        if ok<cnt 
          then do putStrLn $ overview++" contains an overview of the failed tests"
                  exitFailure
          else exitSuccess
    where
      toHTML res =
          "<!DOCTYPE html>\n"
          ++ "<meta charset=\"UTF-8\">\n"
          ++ "<style>\n"
          ++ "pre { max-width: 600px; overflow: scroll; }\n"
          ++ "th,td { vertical-align: top; text-align: left; }\n"
          ++ "</style>\n"
          ++ "<table border=1>\n<tr><th>Result<th>Input<th>Gold<th>Output\n"
          ++ unlines (map testToHTML res)
          ++ "</table>\n"
  
      testToHTML (in_file,(res,(input,gold,output))) =
        "<tr>"++concatMap td [pre res,in_file++":\n"++pre input,pre gold,pre output]
      pre s = "<pre>"++s++"</pre>"
      td s = "<td>"++s
  
      walk path = fmap concat . mapM (walkFile . (path </>)) =<< ls path
  
      walkFile fpath = do
        exists <- doesFileExist fpath
        if exists
          then if takeExtension fpath == ".gfs"
                 then do let in_file   = fpath
                             gold_file = fpath <.> ".gold"
                             out_file  = fpath <.> ".out"
                         putStr $ in_file++": "; hFlush stdout
                         res <- runTest in_file out_file gold_file
                         putStrLn $ fst res
                         return [(in_file,res)]
                 else return []
          else walk fpath
  
      runTest in_file out_file gold_file = do
        input <- readFile in_file
        writeFile out_file =<< run_gf input
        exists <- doesFileExist gold_file
        if exists
          then do out <- compatReadFile out_file
                  gold <- compatReadFile gold_file
                  let info = (input,gold,out)
                  return $! if out == gold then ("OK",info) else ("FAIL",info)
          else do out <- compatReadFile out_file
                  return ("MISSING GOLD",(input,"",out))
      -- Avoid failures caused by Win32/Unix text file incompatibility
      compatReadFile path =
        do h <- openFile path ReadMode
           hSetNewlineMode h universalNewlineMode
           hGetContents h
  
  -- Should consult the Cabal configuration!
  run_gf = readProcess default_gf ["-run","-gf-lib-path="++gf_lib_path]
  default_gf = "dist/build/gf/gf"<.>exeExtension
  gf_lib_path = "dist/build/rgl"
  
  -- | List files, excluding "." and ".."
  ls path = filter (`notElem` [".",".."]) `fmap` getDirectoryContents path
  