Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a test, that fails on Windows #10

Merged
merged 8 commits into from Jun 23, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .ghci
@@ -0,0 +1 @@
:set -isrc -itest -idist/build/autogen -DUNIX
6 changes: 6 additions & 0 deletions .travis.yml
@@ -0,0 +1,6 @@
language: haskell

install:
- cabal update
- cabal install hspec-shouldbe
- cabal install
87 changes: 80 additions & 7 deletions silently.cabal
@@ -1,6 +1,6 @@
name: silently name: silently
version: 1.1.5 version: 1.1.5
cabal-version: >= 1.2 cabal-version: >= 1.8
build-type: Simple build-type: Simple
license: BSD3 license: BSD3
license-file: LICENSE license-file: LICENSE
Expand All @@ -20,17 +20,90 @@ extra-source-files:
src/unix/System/IO/Silently.hs src/unix/System/IO/Silently.hs
src/other/System/IO/Silently.hs src/other/System/IO/Silently.hs


source-repository head
type: git
location: https://github.com/trystan/silently

Library Library
build-depends: base >=4 && <=5, directory -any build-depends:
base >=4 && <=5
, directory
, deepseq
exposed-modules: System.IO.Silently exposed-modules: System.IO.Silently
exposed: True exposed: True
buildable: True buildable: True


hs-source-dirs:
src

if os(windows)
cpp-options: -DWINDOWS
if os(linux) || os(osx) || os(freebsd) || os(openbsd) || os(netbsd)
cpp-options: -DUNIX

test-suite spec-windows
main-is:
Spec.hs
type:
exitcode-stdio-1.0
ghc-options:
-Wall -threaded
-- FIXME: use -Werror
-- -Wall -Werror -threaded
hs-source-dirs:
src
, test

if os(windows) if os(windows)
hs-source-dirs: src/windows cpp-options: -DWINDOWS
else else
if os(linux) || os(osx) || os(freebsd) || os(openbsd) || os(netbsd) buildable: False
hs-source-dirs: src/unix
else build-depends:
hs-source-dirs: src/other base
, hspec-shouldbe
, directory
, deepseq

test-suite spec-unix
main-is:
Spec.hs
type:
exitcode-stdio-1.0
ghc-options:
-Wall -threaded
-- FIXME: use -Werror
-- -Wall -Werror -threaded
hs-source-dirs:
src
, test

if os(linux) || os(osx) || os(freebsd) || os(openbsd) || os(netbsd)
cpp-options: -DUNIX
else
buildable: False

build-depends:
base
, hspec-shouldbe
, directory
, deepseq

test-suite spec-generic
main-is:
Spec.hs
type:
exitcode-stdio-1.0
ghc-options:
-Wall -threaded
-- FIXME: use -Werror
-- -Wall -Werror -threaded
hs-source-dirs:
src
, test


build-depends:
base
, hspec-shouldbe
, directory
, deepseq
45 changes: 32 additions & 13 deletions src/windows/System/IO/Silently.hs → src/System/IO/Silently.hs
@@ -1,4 +1,4 @@

{-# LANGUAGE CPP #-}
-- | Need to prevent output to the terminal, a file, or stderr? Need to capture it and use it for -- | Need to prevent output to the terminal, a file, or stderr? Need to capture it and use it for
-- your own means? Now you can, with 'silence' and 'capture'. -- your own means? Now you can, with 'silence' and 'capture'.


Expand All @@ -8,28 +8,50 @@ module System.IO.Silently (
) where ) where


import GHC.IO.Handle (hDuplicate, hDuplicateTo) import GHC.IO.Handle (hDuplicate, hDuplicateTo)
import System.IO (Handle, stdout, hClose, openTempFile, openFile, IOMode(..)) import System.IO
import System.IO.Error
import Control.Exception (bracket) import Control.Exception (bracket)
import Control.DeepSeq
import System.Directory (removeFile,getTemporaryDirectory) import System.Directory (removeFile,getTemporaryDirectory)


mNullDevice :: Maybe FilePath
#ifdef WINDOWS
mNullDevice = Just "NUL"
#elif UNIX
mNullDevice = Just "/dev/null"
#else
mNullDevice = Nothing
#endif

-- | Run an IO action while preventing all output to stdout. -- | Run an IO action while preventing all output to stdout.
silence :: IO a -> IO a silence :: IO a -> IO a
silence = hSilence [stdout] silence = hSilence [stdout]


-- | Run an IO action while preventing all output to the given handles. -- | Run an IO action while preventing all output to the given handles.
hSilence :: [Handle] -> IO a -> IO a hSilence :: [Handle] -> IO a -> IO a
hSilence handles action = bracket (openFile "NUL" AppendMode) hSilence handles action = case mNullDevice of
Just nullDevice -> bracket (openFile nullDevice AppendMode)
hClose hClose
prepareAndRun prepareAndRun

Nothing -> do
tmpDir <- getTempOrCurrentDirectory
bracket (openTempFile tmpDir "silence")
cleanup
(prepareAndRun . snd)

where where
cleanup (tmpFile,tmpHandle) = do
hClose tmpHandle
removeFile tmpFile
prepareAndRun tmpHandle = go handles prepareAndRun tmpHandle = go handles
where where
go [] = action go [] = action
go hs = goBracket go tmpHandle hs go hs = goBracket go tmpHandle hs




getTempOrCurrentDirectory :: IO String getTempOrCurrentDirectory :: IO String
getTempOrCurrentDirectory = getTemporaryDirectory `Prelude.catch` (\ex -> return ".") getTempOrCurrentDirectory = getTemporaryDirectory `catchIOError` (\_ -> return ".")


-- | Run an IO action while preventing and capturing all output to stdout. -- | Run an IO action while preventing and capturing all output to stdout.
-- This will, as a side effect, create and delete a temp file in the temp directory or current directory if there is no temp directory. -- This will, as a side effect, create and delete a temp file in the temp directory or current directory if there is no temp directory.
Expand All @@ -43,24 +65,21 @@ hCapture handles action = do
tmpDir <- getTempOrCurrentDirectory tmpDir <- getTempOrCurrentDirectory
bracket (openTempFile tmpDir "capture") bracket (openTempFile tmpDir "capture")
cleanup cleanup
prepareAndRun (prepareAndRun . snd)
where where
cleanup (tmpFile,tmpHandle) = do cleanup (tmpFile,tmpHandle) = do
hClose tmpHandle hClose tmpHandle
removeFile tmpFile removeFile tmpFile
prepareAndRun (tmpFile,tmpHandle) = go handles prepareAndRun tmpHandle = go handles
where where
go [] = do go [] = do
a <- action a <- action
hClose tmpHandle mapM_ hFlush handles
str <- readFile tmpFile hSeek tmpHandle AbsoluteSeek 0
forceList str str <- hGetContents tmpHandle
return (str,a) str `deepseq` return (str,a)
go hs = goBracket go tmpHandle hs go hs = goBracket go tmpHandle hs


forceList [] = return ()
forceList (x:xs) = forceList xs

goBracket :: ([Handle] -> IO a) -> Handle -> [Handle] -> IO a goBracket :: ([Handle] -> IO a) -> Handle -> [Handle] -> IO a
goBracket go tmpHandle (h:hs) = bracket (do old <- hDuplicate h goBracket go tmpHandle (h:hs) = bracket (do old <- hDuplicate h
hDuplicateTo tmpHandle h hDuplicateTo tmpHandle h
Expand Down
76 changes: 0 additions & 76 deletions src/other/System/IO/Silently.hs

This file was deleted.

65 changes: 0 additions & 65 deletions src/unix/System/IO/Silently.hs

This file was deleted.

29 changes: 29 additions & 0 deletions test/Spec.hs
@@ -0,0 +1,29 @@
module Main (main) where

import Test.Hspec.ShouldBe

import System.IO
import System.IO.Silently
import System.Directory

import Control.Exception

main :: IO ()
main = hspec spec

spec :: Spec
spec = do

describe "hSilence" $ do
it "prevents output to a given handle" $ let file = "test/foo.txt" in do
h <- openFile file ReadWriteMode
hSilence [h] $ do
hPutStrLn h "foo bar baz"
hFlush h
hSeek h AbsoluteSeek 0
hGetContents h `shouldReturn` ""
`finally` removeFile file

describe "capture" $ do
it "captures stdout" $ do
capture (putStr "foo" >> return 23) `shouldReturn` ("foo", 23 :: Int)