diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+0.7.4.1
+=======
+
+  * Made the test-suite less dependent on a particular system configuration
+
 0.7.4
 =====
 
diff --git a/Gemfile b/Gemfile
new file mode 100644
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,3 @@
+source "https://rubygems.org"
+
+gem "guard-haskell", "~> 2.0"
diff --git a/Guardfile b/Guardfile
new file mode 100644
--- /dev/null
+++ b/Guardfile
@@ -0,0 +1,8 @@
+repl_options = \
+  [ "--ghc-options=-ignore-dot-ghci -DTEST"
+  ]
+
+guard :haskell, all_on_start: true, repl_options: repl_options do
+  watch(%r{test/.+Spec\.l?hs$})
+  watch(%r{src/.+\.l?hs$})
+end
diff --git a/directory-layout.cabal b/directory-layout.cabal
--- a/directory-layout.cabal
+++ b/directory-layout.cabal
@@ -1,5 +1,5 @@
 name:                directory-layout
-version:             0.7.4
+version:             0.7.4.1
 synopsis:            Directory layout DSL
 description:
   Making, fitting, printing directory layouts
@@ -9,10 +9,12 @@
 maintainer:          matvey.aksenov@gmail.com
 category:            System, Testing
 build-type:          Simple
-cabal-version:       >=1.10
+cabal-version:       >= 1.10
 extra-source-files:
   README.md
   CHANGELOG.md
+  Gemfile
+  Guardfile
 
 source-repository head
   type:     git
@@ -21,7 +23,7 @@
 source-repository this
   type:     git
   location: https://github.com/supki/directory-layout
-  tag:      0.7.4
+  tag:      0.7.4.1
 
 library
   default-language:
@@ -99,5 +101,6 @@
     System.Directory.LayoutSpec
     System.Directory.Layout.InternalSpec
     System.Directory.Layout.InterpreterSpec
+    System.Directory.Layout.QQSpec
   cpp-options:
     -DTEST
diff --git a/test/System/Directory/Layout/InterpreterSpec.hs b/test/System/Directory/Layout/InterpreterSpec.hs
--- a/test/System/Directory/Layout/InterpreterSpec.hs
+++ b/test/System/Directory/Layout/InterpreterSpec.hs
@@ -7,6 +7,7 @@
 
 import           Control.Applicative
 import           Control.Lens
+import           Control.Monad
 import qualified Data.ByteString as ByteString
 import           Data.Foldable (traverse_)
 import           Data.List.NonEmpty (NonEmpty)
@@ -161,37 +162,43 @@
 
     it "tests file owner user id" $ do
       temporary $ \p -> do
-        writeFile (p </> "foo") ""
+        let u = p </> "foo"
+        writeFile u ""
+        n <- fileOwnerUID u
         r <- fit p $ do
           file "foo"
             & user ?~ uid 0
-        r `shouldBe` fromErrors [FitBadOwnerUser (p </> "foo") (uid 0) (uid 1000)]
+        r `shouldBe` fromErrors [FitBadOwnerUser u (uid 0) (uid n)]
 
     it "tests file owner user name" $ do
       temporary $ \p -> do
-        writeFile (p </> "foo") ""
-        n <- Posix.getEffectiveUserName
+        let u = p </> "foo"
+        writeFile u ""
+        n <- fileOwnerUserName u
         r <- fit p $ do
           file "foo"
             & user ?~ username "root"
-        r `shouldBe` fromErrors [FitBadOwnerUser (p </> "foo") (username "root") (username n)]
+        r `shouldBe` fromErrors [FitBadOwnerUser u (username "root") (username n)]
 
     it "tests file owner group id" $ do
       temporary $ \p -> do
-        writeFile (p </> "foo") ""
+        let u = p </> "foo"
+        writeFile u ""
+        n <- fileOwnerGID u
         r <- fit p $ do
           file "foo"
             & group ?~ gid 0
-        r `shouldBe` fromErrors [FitBadOwnerGroup (p </> "foo") (gid 0) (gid 1000)]
+        r `shouldBe` fromErrors [FitBadOwnerGroup u (gid 0) (gid n)]
 
     it "tests file owner group id" $ do
       temporary $ \p -> do
-        writeFile (p </> "foo") ""
-        n <- Posix.getEffectiveUserName
+        let u = p </> "foo"
+        writeFile u ""
+        n <- fileOwnerGroupName u
         r <- fit p $ do
           file "foo"
             & group ?~ groupname "root"
-        r `shouldBe` fromErrors [FitBadOwnerGroup (p </> "foo") (groupname "root") (groupname n)]
+        r `shouldBe` fromErrors [FitBadOwnerGroup u (groupname "root") (groupname n)]
 
     it "tests file permissions" $ do
       temporary $ \p -> do
@@ -457,3 +464,15 @@
 makefit l = temporary $ \p -> do
   make p l `shouldReturn` fromErrors []
   fit p l `shouldReturn` fromErrors []
+
+fileOwnerUID :: FilePath -> IO Posix.UserID
+fileOwnerUID = fmap Posix.fileOwner . Posix.getSymbolicLinkStatus
+
+fileOwnerUserName :: FilePath -> IO String
+fileOwnerUserName = fmap Posix.userName . Posix.getUserEntryForID <=< fileOwnerUID
+
+fileOwnerGID :: FilePath -> IO Posix.GroupID
+fileOwnerGID = fmap Posix.fileGroup . Posix.getSymbolicLinkStatus
+
+fileOwnerGroupName :: FilePath -> IO String
+fileOwnerGroupName = fmap Posix.groupName . Posix.getGroupEntryForID <=< fileOwnerGID
diff --git a/test/System/Directory/Layout/QQSpec.hs b/test/System/Directory/Layout/QQSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/System/Directory/Layout/QQSpec.hs
@@ -0,0 +1,96 @@
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE QuasiQuotes #-}
+module System.Directory.Layout.QQSpec
+  ( spec
+  ) where
+
+import Data.Text (Text)
+import Test.Hspec
+
+import System.Directory.Layout.QQ
+
+
+spec :: Spec
+spec = do
+  describe "dedent" $ do
+    it "gives reasonable result for the empty input" $
+      [dedent||] `shouldBe` ""
+
+    it "handles a single line input" $
+      [dedent|hello|] `shouldBe` "hello"
+
+    it "ignores the first line when it consists solely of spaces" $
+      [dedent|
+      hello|] `shouldBe` "hello"
+
+    it "considers the first line when it has non-space characters" $
+      [dedent|hello
+      world|] `shouldBe` "hello\n      world"
+
+    it "removes the minimum common amount of indentation" $
+      [dedent|
+      hello
+        world
+      !
+      |] `shouldBe` "hello\n  world\n!\n"
+
+    it "can be parsed into any IsString instance" $
+      [dedent|
+      hello
+        world
+      !
+      |] `shouldBe` ("hello\n  world\n!\n" :: Text)
+
+    it "ignores indentation in the last line if it's all spaces" $
+      [dedent|
+        hello
+          world
+        !
+      |] `shouldBe` "hello\n  world\n!\n"
+
+    it "saves empty lines at the beginning of the string" $
+      [dedent|
+
+
+        hello
+          world
+        !
+      |] `shouldBe` "\n\nhello\n  world\n!\n"
+
+
+    it "saves empty lines at the end of the string" $
+      [dedent|
+        hello
+          world
+        !
+
+
+      |] `shouldBe` "hello\n  world\n!\n\n\n"
+
+  describe "dedentSubst" $ do
+    it "is like dedent but also supports variable substitution" $ do
+      let hello = "bye" :: String
+      [dedentSubst|
+        #{hello}
+          world
+        !
+
+
+      |] `shouldBe` "bye\n  world\n!\n\n\n"
+
+    it "is supports escaping" $
+      [dedentSubst|
+        \#{hello}
+          world
+        !
+
+
+      |] `shouldBe` "#{hello}\n  world\n!\n\n\n"
+
+    it "can be parsed into any IsString instance" $ do
+      let hello = "bye" :: String
+      [dedentSubst|
+        #{hello}
+          world
+        !
+      |] `shouldBe` ("bye\n  world\n!\n" :: Text)
diff --git a/test/System/Directory/LayoutSpec.hs b/test/System/Directory/LayoutSpec.hs
--- a/test/System/Directory/LayoutSpec.hs
+++ b/test/System/Directory/LayoutSpec.hs
@@ -22,20 +22,24 @@
       dir "Layout" $ do
         file "Internal.hs"
         file "Interpreter.hs"
+        file "QQ.hs"
       file "Layout.hs"
   dir "test" $ do
     dirs ["System", "Directory"] $ do
       dir "Layout" $ do
         file "InternalSpec.hs"
         file "InterpreterSpec.hs"
+        file "QQSpec.hs"
       file "LayoutSpec.hs"
     file "Spec.hs"
       & contents ?~ [dedent|
         {-# OPTIONS_GHC -F -pgmF hspec-discover #-}
         |]
     file "SpecHelper.hs"
+    file "Doctest.hs"
   file "LICENSE"
   file "Guardfile"
+  file "Gemfile"
   file "Setup.hs"
   file "directory-layout.cabal"
 
