diff --git a/Data/String/Conv.hs b/Data/String/Conv.hs
deleted file mode 100644
--- a/Data/String/Conv.hs
+++ /dev/null
@@ -1,118 +0,0 @@
-{-# LANGUAGE FlexibleInstances     #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-
-module Data.String.Conv
-  ( StringConv (..)
-  , toS
-  , toSL
-  , convS
-  , convSL
-  , Leniency (..)
-  ) where
-
-------------------------------------------------------------------------------
-import           Data.ByteString.Char8      as B
-import           Data.ByteString.Lazy.Char8 as LB
-import           Data.Text                  as T
-import           Data.Text.Encoding         as T
-import           Data.Text.Encoding.Error   as T
-import           Data.Text.Lazy             as LT
-import           Data.Text.Lazy.Encoding    as LT
-------------------------------------------------------------------------------
-
-
-------------------------------------------------------------------------------
--- | Data type representing the two leniency modes defining how decoding
--- failure is handled.
-data Leniency = Lenient | Strict
-  deriving (Eq,Show,Read,Ord,Enum,Bounded)
-
-
-------------------------------------------------------------------------------
--- | A type class to standardize string conversions.  With this type class you
--- only need to remember one function for converting between any two string
--- variants.  This package includes support for String, ByteString, and Text
--- as well as the Lazy and Strict variants where necessary.
---
--- This type class lets you control how conversion should behave when failure
--- is possible.  Strict mode will cause an exception to be thrown when
--- decoding fails.  Lenient mode will attempt to recover, inserting a
--- replacement character for invalid bytes.
---
--- StringConv's `toS` function is most useful when you have a fully defined
--- string conversion with a fixed (non-polymorphic) input and output type.  Of
--- course you can still use it when you don't have a fixed type.  In that case
--- you might need to specify a type class constraint such as @StringConv
--- s String@.
-class StringConv a b where
-    strConv :: Leniency -> a -> b
-
-
-------------------------------------------------------------------------------
--- | Universal string conversion function for strict decoding.
-toS :: StringConv a b => a -> b
-toS = strConv Strict
-
-
-------------------------------------------------------------------------------
--- | Universal string conversion function for lenient decoding.
-toSL :: StringConv a b => a -> b
-toSL = strConv Lenient
-
-
-instance StringConv String String where strConv _ = id
-instance StringConv String B.ByteString where strConv l = T.encodeUtf8 . strConv l
-instance StringConv String LB.ByteString where strConv l = LT.encodeUtf8 . strConv l
-instance StringConv String T.Text where strConv _ = T.pack
-instance StringConv String LT.Text where strConv _ = LT.pack
-
-instance StringConv B.ByteString String where strConv l = T.unpack . strConv l
-instance StringConv B.ByteString B.ByteString where strConv _ = id
-instance StringConv B.ByteString LB.ByteString where strConv _ = LB.fromChunks . return
-instance StringConv B.ByteString T.Text where strConv = decodeUtf8T
-instance StringConv B.ByteString LT.Text where strConv l = strConv l . LB.fromChunks . return
-
-instance StringConv LB.ByteString String where strConv l = LT.unpack . strConv l
-instance StringConv LB.ByteString B.ByteString where strConv _ = B.concat . LB.toChunks
-instance StringConv LB.ByteString LB.ByteString where strConv _ = id
-instance StringConv LB.ByteString T.Text where strConv l = decodeUtf8T l . strConv l
-instance StringConv LB.ByteString LT.Text where strConv = decodeUtf8LT
-
-instance StringConv T.Text String where strConv _ = T.unpack
-instance StringConv T.Text B.ByteString where strConv _ = T.encodeUtf8
-instance StringConv T.Text LB.ByteString where strConv l = strConv l . T.encodeUtf8
-instance StringConv T.Text LT.Text where strConv _ = LT.fromStrict
-instance StringConv T.Text T.Text where strConv _ = id
-
-instance StringConv LT.Text String where strConv _ = LT.unpack
-instance StringConv LT.Text T.Text where strConv _ = LT.toStrict
-instance StringConv LT.Text LT.Text where strConv _ = id
-instance StringConv LT.Text LB.ByteString where strConv _ = LT.encodeUtf8
-instance StringConv LT.Text B.ByteString where strConv l = strConv l . LT.encodeUtf8
-
-
-------------------------------------------------------------------------------
--- | Convenience helper for dispatching based on leniency.
-decodeUtf8T :: Leniency -> B.ByteString -> T.Text
-decodeUtf8T Lenient = T.decodeUtf8With T.lenientDecode
-decodeUtf8T Strict = T.decodeUtf8With T.strictDecode
-
-
-------------------------------------------------------------------------------
--- | Convenience helper for dispatching based on leniency.
-decodeUtf8LT :: Leniency -> LB.ByteString -> LT.Text
-decodeUtf8LT Lenient = LT.decodeUtf8With T.lenientDecode
-decodeUtf8LT Strict = LT.decodeUtf8With T.strictDecode
-
-
-------------------------------------------------------------------------------
--- | A lens for 'toS' to make it slightly more convenient in some scenarios.
-convS :: (StringConv a b, StringConv b a, Functor f) => (b -> f b) -> a -> f a
-convS f a = fmap toS (f (toS a))
-
-
-------------------------------------------------------------------------------
--- | A lens for 'toSL' to make it slightly more convenient in some scenarios.
-convSL :: (StringConv a b, StringConv b a, Functor f) => (b -> f b) -> a -> f a
-convSL f a = fmap toSL (f (toSL a))
-
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,2 +1,3 @@
 import Distribution.Simple
+
 main = defaultMain
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,6 +1,8 @@
-0.1.2
+0.2.0
 =====
-* Fixed bug where String <-> ByteString conversion would trim characters to 8 bits. Now it goes through conversion to Text first.
+* Don't set optimization flag for library
+* Add property tests and fix to make String <-> ByteString conversion safer [PR 6](https://github.com/Soostone/string-conv/pull/6).
+* Add lib-Werror flag for development
 
 0.1.1
 =====
diff --git a/src/Data/String/Conv.hs b/src/Data/String/Conv.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/String/Conv.hs
@@ -0,0 +1,138 @@
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE MultiParamTypeClasses #-}
+
+module Data.String.Conv
+  ( StringConv (..),
+    toS,
+    toSL,
+    convS,
+    convSL,
+    Leniency (..),
+  )
+where
+
+------------------------------------------------------------------------------
+import Data.ByteString as B
+import Data.ByteString.Lazy as LB
+import Data.Text as T
+import Data.Text.Encoding as T
+import Data.Text.Encoding.Error as T
+import Data.Text.Lazy as LT
+import Data.Text.Lazy.Encoding as LT
+
+------------------------------------------------------------------------------
+
+------------------------------------------------------------------------------
+
+-- | Data type representing the two leniency modes defining how decoding
+-- failure is handled.
+data Leniency = Lenient | Strict
+  deriving (Eq, Show, Read, Ord, Enum, Bounded)
+
+------------------------------------------------------------------------------
+
+-- | A type class to standardize string conversions.  With this type class you
+-- only need to remember one function for converting between any two string
+-- variants.  This package includes support for String, ByteString, and Text
+-- as well as the Lazy and Strict variants where necessary.
+--
+-- This type class lets you control how conversion should behave when failure
+-- is possible.  Strict mode will cause an exception to be thrown when
+-- decoding fails.  Lenient mode will attempt to recover, inserting a
+-- replacement character for invalid bytes.
+--
+-- StringConv's `toS` function is most useful when you have a fully defined
+-- string conversion with a fixed (non-polymorphic) input and output type.  Of
+-- course you can still use it when you don't have a fixed type.  In that case
+-- you might need to specify a type class constraint such as @StringConv
+-- s String@.
+class StringConv a b where
+  strConv :: Leniency -> a -> b
+
+------------------------------------------------------------------------------
+
+-- | Universal string conversion function for strict decoding.
+toS :: StringConv a b => a -> b
+toS = strConv Strict
+
+------------------------------------------------------------------------------
+
+-- | Universal string conversion function for lenient decoding.
+toSL :: StringConv a b => a -> b
+toSL = strConv Lenient
+
+instance StringConv String String where strConv _ = id
+
+instance StringConv String B.ByteString where strConv _ = T.encodeUtf8 . T.pack
+
+instance StringConv String LB.ByteString where strConv _ = LT.encodeUtf8 . LT.pack
+
+instance StringConv String T.Text where strConv _ = T.pack
+
+instance StringConv String LT.Text where strConv _ = LT.pack
+
+instance StringConv B.ByteString String where strConv l = T.unpack . decodeUtf8T l
+
+instance StringConv B.ByteString B.ByteString where strConv _ = id
+
+instance StringConv B.ByteString LB.ByteString where strConv _ = LB.fromChunks . return
+
+instance StringConv B.ByteString T.Text where strConv = decodeUtf8T
+
+instance StringConv B.ByteString LT.Text where strConv l = strConv l . LB.fromChunks . return
+
+instance StringConv LB.ByteString String where strConv l = LT.unpack . decodeUtf8LT l
+
+instance StringConv LB.ByteString B.ByteString where strConv _ = B.concat . LB.toChunks
+
+instance StringConv LB.ByteString LB.ByteString where strConv _ = id
+
+instance StringConv LB.ByteString T.Text where strConv l = decodeUtf8T l . strConv l
+
+instance StringConv LB.ByteString LT.Text where strConv = decodeUtf8LT
+
+instance StringConv T.Text String where strConv _ = T.unpack
+
+instance StringConv T.Text B.ByteString where strConv _ = T.encodeUtf8
+
+instance StringConv T.Text LB.ByteString where strConv l = strConv l . T.encodeUtf8
+
+instance StringConv T.Text LT.Text where strConv _ = LT.fromStrict
+
+instance StringConv T.Text T.Text where strConv _ = id
+
+instance StringConv LT.Text String where strConv _ = LT.unpack
+
+instance StringConv LT.Text T.Text where strConv _ = LT.toStrict
+
+instance StringConv LT.Text LT.Text where strConv _ = id
+
+instance StringConv LT.Text LB.ByteString where strConv _ = LT.encodeUtf8
+
+instance StringConv LT.Text B.ByteString where strConv l = strConv l . LT.encodeUtf8
+
+------------------------------------------------------------------------------
+
+-- | Convenience helper for dispatching based on leniency.
+decodeUtf8T :: Leniency -> B.ByteString -> T.Text
+decodeUtf8T Lenient = T.decodeUtf8With T.lenientDecode
+decodeUtf8T Strict = T.decodeUtf8With T.strictDecode
+
+------------------------------------------------------------------------------
+
+-- | Convenience helper for dispatching based on leniency.
+decodeUtf8LT :: Leniency -> LB.ByteString -> LT.Text
+decodeUtf8LT Lenient = LT.decodeUtf8With T.lenientDecode
+decodeUtf8LT Strict = LT.decodeUtf8With T.strictDecode
+
+------------------------------------------------------------------------------
+
+-- | A lens for 'toS' to make it slightly more convenient in some scenarios.
+convS :: (StringConv a b, StringConv b a, Functor f) => (b -> f b) -> a -> f a
+convS f a = fmap toS (f (toS a))
+
+------------------------------------------------------------------------------
+
+-- | A lens for 'toSL' to make it slightly more convenient in some scenarios.
+convSL :: (StringConv a b, StringConv b a, Functor f) => (b -> f b) -> a -> f a
+convSL f a = fmap toSL (f (toSL a))
diff --git a/string-conv.cabal b/string-conv.cabal
--- a/string-conv.cabal
+++ b/string-conv.cabal
@@ -1,35 +1,71 @@
-name:                string-conv
-version:             0.1.2
-synopsis:            Standardized conversion between string types
-description:         Avoids the need to remember many different functions
-                     for converting string types.  Just use one universal
-                     function toS for all monomorphic string conversions.
-license:             BSD3
-license-file:        LICENSE
-author:              Ozgun Ataman
-maintainer:          ozgun.ataman@soostone.com
-copyright:           Soostone Inc, 2012-2015
-category:            Data, String, Text
-homepage:            https://github.com/Soostone/string-conv
-bug-reports:         https://github.com/Soostone/string-conv/issues
-build-type:          Simple
-cabal-version:       >=1.8
+cabal-version: 1.12
+
+-- This file has been generated from package.yaml by hpack version 0.34.6.
+--
+-- see: https://github.com/sol/hpack
+
+name:           string-conv
+version:        0.2.0
+synopsis:       Standardized conversion between string types
+description:    Avoids the need to remember many different functions for converting string types. Just use one universal function toS for all monomorphic string conversions.
+category:       Data, String, Text
+homepage:       https://github.com/Soostone/string-conv
+bug-reports:    https://github.com/Soostone/string-conv/issues
+author:         Ozgun Ataman
+maintainer:     ozgun.ataman@soostone.com
+copyright:      Soostone Inc, 2012-2015
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
 extra-source-files:
-  README.md
-  changelog.md
+    README.md
+    changelog.md
 
+source-repository head
+  type: git
+  location: https://github.com/Soostone/string-conv
+
 flag lib-Werror
-  default: False
-  manual: True
+  description: Turn on -Wall and -Werror. Should always be enabled in development.
 
-source-repository head
-  type:     git
-  location: https://github.com/Soostone/string-conv.git
+  manual: True
+  default: False
 
 library
-  exposed-modules:     Data.String.Conv
-  build-depends:       base >= 4.4 && < 5, bytestring, text
+  exposed-modules:
+      Data.String.Conv
+  other-modules:
+      Paths_string_conv
+  hs-source-dirs:
+      src
+  build-depends:
+      base >=4.4 && <5
+    , bytestring
+    , text
   if flag(lib-Werror)
-    ghc-options: -Werror
+    ghc-options: -Wall -Werror -fwarn-redundant-constraints -Wincomplete-record-updates -Wincomplete-uni-patterns -Widentities
+  else
+    ghc-options: -Wall -fwarn-redundant-constraints -Wincomplete-record-updates -Widentities
+  default-language: Haskell2010
 
-  ghc-options: -Wall
+test-suite tests
+  type: exitcode-stdio-1.0
+  main-is: Main.hs
+  other-modules:
+      Paths_string_conv
+  hs-source-dirs:
+      test
+  ghc-options: -threaded -rtsopts -with-rtsopts=-N
+  build-depends:
+      base >=4.4 && <5
+    , bytestring
+    , quickcheck-instances >=0.3.17
+    , string-conv
+    , tasty
+    , tasty-quickcheck
+    , text
+  if flag(lib-Werror)
+    ghc-options: -Wall -Werror -fwarn-redundant-constraints -Wincomplete-record-updates -Wincomplete-uni-patterns -Widentities
+  else
+    ghc-options: -Wall -fwarn-redundant-constraints -Wincomplete-record-updates -Widentities
+  default-language: Haskell2010
diff --git a/test/Main.hs b/test/Main.hs
new file mode 100644
--- /dev/null
+++ b/test/Main.hs
@@ -0,0 +1,92 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+import Data.ByteString as B
+import Data.ByteString.Lazy as LB
+import Data.String.Conv
+import Data.Text as T
+import Data.Text.Lazy as LT
+import Test.QuickCheck.Instances.ByteString ()
+import Test.QuickCheck.Instances.Text ()
+import Test.Tasty
+import Test.Tasty.QuickCheck
+
+main :: IO ()
+main =
+  defaultMain $
+    testGroup
+      " tests"
+      [ strictDecoding,
+        lenientDecoding
+      ]
+
+strictDecoding :: TestTree
+strictDecoding =
+  testGroup
+    "strict decoding (toS method)"
+    [ testProperty "converting String to String" $ do
+        \s -> s == (toS (toS (s :: String) :: String)),
+      testProperty "converting String to strict ByteString" $ do
+        \s -> s == (toS (toS (s :: String) :: B.ByteString)),
+      testProperty "converting String to lazy ByteString" $ do
+        \s -> s == (toS (toS (s :: String) :: LB.ByteString)),
+      testProperty "converting String to strict Text" $ do
+        \s -> s == (toS (toS (s :: String) :: T.Text)),
+      testProperty "converting String to lazy Text" $ do
+        \s -> s == (toS (toS (s :: String) :: LT.Text)),
+      testProperty "converting strict ByteString to strict ByteString" $ do
+        \s -> s == (toS (toS (s :: B.ByteString) :: B.ByteString)),
+      testProperty "converting strict ByteString to lazy ByteString" $ do
+        \s -> s == (toS (toS (s :: B.ByteString) :: LB.ByteString)),
+      testProperty "converting lazy ByteString to lazy ByteString" $ do
+        \s -> s == (toS (toS (s :: LB.ByteString) :: LB.ByteString)),
+      testProperty "converting strict Text to lazy ByteString" $ do
+        \s -> s == (toS (toS (s :: T.Text) :: LB.ByteString)),
+      testProperty "converting strict Text to strict ByteString" $ do
+        \s -> s == (toS (toS (s :: LB.ByteString) :: B.ByteString)),
+      testProperty "converting strict Text to strict Text" $ do
+        \s -> s == (toS (toS (s :: T.Text) :: T.Text)),
+      testProperty "converting strict Text to lazy Text" $ do
+        \s -> s == (toS (toS (s :: T.Text) :: LT.Text)),
+      testProperty "converting lazy Text to strict ByteString" $ do
+        \s -> s == (toS (toS (s :: LT.Text) :: B.ByteString)),
+      testProperty "converting lazy Text to lazy ByteString" $ do
+        \s -> s == (toS (toS (s :: LT.Text) :: LB.ByteString)),
+      testProperty "converting lazy Text to lazy Text" $ do
+        \s -> s == (toS (toS (s :: LT.Text) :: LT.Text))
+    ]
+
+lenientDecoding :: TestTree
+lenientDecoding =
+  testGroup
+    "lenient decoding (toSL method)"
+    [ testProperty "converting String to String" $ do
+        \s -> s == (toSL (toSL (s :: String) :: String)),
+      testProperty "converting String to strict ByteString" $ do
+        \s -> s == (toSL (toSL (s :: String) :: B.ByteString)),
+      testProperty "converting String to lazy ByteString" $ do
+        \s -> s == (toSL (toSL (s :: String) :: LB.ByteString)),
+      testProperty "converting String to strict Text" $ do
+        \s -> s == (toSL (toSL (s :: String) :: T.Text)),
+      testProperty "converting String to lazy Text" $ do
+        \s -> s == (toSL (toSL (s :: String) :: LT.Text)),
+      testProperty "converting strict ByteString to strict ByteString" $ do
+        \s -> s == (toSL (toSL (s :: B.ByteString) :: B.ByteString)),
+      testProperty "converting strict ByteString to lazy ByteString" $ do
+        \s -> s == (toSL (toSL (s :: B.ByteString) :: LB.ByteString)),
+      testProperty "converting lazy ByteString to lazy ByteString" $ do
+        \s -> s == (toSL (toSL (s :: LB.ByteString) :: LB.ByteString)),
+      testProperty "converting strict Text to lazy ByteString" $ do
+        \s -> s == (toSL (toSL (s :: T.Text) :: LB.ByteString)),
+      testProperty "converting strict Text to strict ByteString" $ do
+        \s -> s == (toSL (toSL (s :: LB.ByteString) :: B.ByteString)),
+      testProperty "converting strict Text to strict Text" $ do
+        \s -> s == (toSL (toSL (s :: T.Text) :: T.Text)),
+      testProperty "converting strict Text to lazy Text" $ do
+        \s -> s == (toSL (toSL (s :: T.Text) :: LT.Text)),
+      testProperty "converting lazy Text to strict ByteString" $ do
+        \s -> s == (toSL (toSL (s :: LT.Text) :: B.ByteString)),
+      testProperty "converting lazy Text to lazy ByteString" $ do
+        \s -> s == (toSL (toSL (s :: LT.Text) :: LB.ByteString)),
+      testProperty "converting lazy Text to lazy Text" $ do
+        \s -> s == (toSL (toSL (s :: LT.Text) :: LT.Text))
+    ]
