@@ -12,6 +12,7 @@ import qualified Database.PostgreSQL.Simple.Transaction as ST
1212import Control.Applicative
1313import Control.Exception as E
1414import Control.Monad
15+import Data.Char
1516import Data.List (sort)
1617import Data.IORef
1718import Data.Typeable
@@ -20,13 +21,16 @@ import GHC.Generics (Generic)
2021import Data.Aeson
2122import Data.ByteString (ByteString)
2223import qualified Data.ByteString as B
24+import qualified Data.ByteString.Lazy.Char8 as BL
2325import Data.Map (Map)
2426import qualified Data.Map as Map
2527import Data.Text(Text)
2628import qualified Data.Text.Encoding as T
2729import qualified Data.Vector as V
30+import System.FilePath
2831
2932import Test.Tasty
33+import Test.Tasty.Golden
3034import Notify
3135import Serializable
3236import Time
@@ -47,6 +51,7 @@ tests env = testGroup "tests"
4751 , testCase "Unicode" . testUnicode
4852 , testCase "Values" . testValues
4953 , testCase "Copy" . testCopy
54+ , testCopyFailures
5055 , testCase "Double" . testDouble
5156 , testCase "1-ary generic" . testGeneric1
5257 , testCase "2-ary generic" . testGeneric2
@@ -317,6 +322,35 @@ testCopy TestEnv{..} = do
317322 CopyOutDone _ -> return rows
318323 CopyOutRow row -> loop (row:rows)
319324
325+testCopyFailures :: TestEnv -> TestTree
326+testCopyFailures env = testGroup "Copy failures"
327+ $ map ($ env)
328+ [ testCopyUniqueConstraintError ]
329+
330+goldenTest :: TestName -> IO BL.ByteString -> TestTree
331+goldenTest testName =
332+ goldenVsString testName (resultsDir </> fileName<.>"expected")
333+ where
334+ resultsDir = "test" </> "results"
335+ fileName = map normalize testName
336+ normalize c | not (isAlpha c) = '-'
337+ | otherwise = c
338+
339+-- | Test that we provide a sensible error message on failure
340+testCopyUniqueConstraintError :: TestEnv -> TestTree
341+testCopyUniqueConstraintError TestEnv{..} =
342+ goldenTest "unique constraint violation"
343+ $ handle (\(SomeException exc) -> return $ BL.pack $ show exc) $ do
344+ execute_ conn "CREATE TEMPORARY TABLE copy_unique_constraint_error_test (x int PRIMARY KEY, y text)"
345+ copy_ conn "COPY copy_unique_constraint_error_test FROM STDIN (FORMAT CSV)"
346+ mapM_ (putCopyData conn) copyRows
347+ _n <- putCopyEnd conn
348+ return BL.empty
349+ where
350+ copyRows = ["1,foo\n"
351+ ,"2,bar\n"
352+ ,"1,baz\n"]
353+
320354testDouble :: TestEnv -> Assertion
321355testDouble TestEnv{..} = do
322356 [Only (x :: Double)] <- query_ conn "SELECT 'NaN'::float8"