module System.AtomicWrite.Writer.ByteStringBuilderSpec (spec) where import Test.Hspec (it, describe, shouldBe, Spec) import System.AtomicWrite.Writer.ByteStringBuilder (atomicWriteFile, atomicWriteFileWithMode) import System.IO.Temp (withSystemTempDirectory) import System.FilePath.Posix (joinPath) import System.PosixCompat.Files (setFileMode, setFileCreationMask, getFileStatus, fileMode) import Data.ByteString.Builder (lazyByteString) import Data.ByteString.Lazy.Char8 (pack) spec :: Spec spec = do describe "atomicWriteFile" $ do it "writes contents to a file" $ withSystemTempDirectory "atomicFileTest" $ \tmpDir -> do let path = joinPath [ tmpDir, "writeTest.tmp" ] atomicWriteFile path $ lazyByteString $ pack "just testing" contents <- readFile path contents `shouldBe` "just testing" it "preserves the permissions of original file, regardless of umask" $ withSystemTempDirectory "atomicFileTest" $ \tmpDir -> do let filePath = joinPath [tmpDir, "testFile"] writeFile filePath "initial contents" setFileMode filePath 0o100644 newStat <- getFileStatus filePath fileMode newStat `shouldBe` 0o100644 -- New files are created with 100600 perms. _ <- setFileCreationMask 0o100066 -- Create a new file once different mask is set and make sure that mask -- is applied. writeFile (joinPath [tmpDir, "sanityCheck"]) "with sanity check mask" sanityCheckStat <- getFileStatus $ joinPath [tmpDir, "sanityCheck"] fileMode sanityCheckStat `shouldBe` 0o100600 -- Since we move, this makes the new file assume the filemask of 0600 atomicWriteFile filePath $ lazyByteString $ pack "new contents" resultStat <- getFileStatus filePath -- reset mask to not break subsequent specs _ <- setFileCreationMask 0o100022 -- Fails when using atomic mv command unless apply perms on initial file fileMode resultStat `shouldBe` 0o100644 it "creates a new file with permissions based on active umask" $ withSystemTempDirectory "atomicFileTest" $ \tmpDir -> do let filePath = joinPath [tmpDir, "testFile"] sampleFilePath = joinPath [tmpDir, "sampleFile"] -- Set somewhat distinctive defaults for test _ <- setFileCreationMask 0o100171 -- We don't know what the default file permissions are, so create a -- file to sample them. writeFile sampleFilePath "I'm being written to sample permissions" newStat <- getFileStatus sampleFilePath fileMode newStat `shouldBe` 0o100606 atomicWriteFile filePath $ lazyByteString $ pack "new contents" resultStat <- getFileStatus filePath -- reset mask to not break subsequent specs _ <- setFileCreationMask 0o100022 -- The default tempfile permissions are 0600, so this fails unless we -- make sure that the default umask is relied on for creation of the -- tempfile. fileMode resultStat `shouldBe` 0o100606 describe "atomicWriteFileWithMode" $ do it "writes contents to a file" $ withSystemTempDirectory "atomicFileTest" $ \tmpDir -> do let path = joinPath [ tmpDir, "writeTest.tmp" ] atomicWriteFileWithMode 0o100777 path $ lazyByteString $ pack "just testing" contents <- readFile path contents `shouldBe` "just testing" it "changes the permissions of a previously created file, regardless of umask" $ withSystemTempDirectory "atomicFileTest" $ \tmpDir -> do let filePath = joinPath [tmpDir, "testFile"] writeFile filePath "initial contents" setFileMode filePath 0o100644 newStat <- getFileStatus filePath fileMode newStat `shouldBe` 0o100644 -- New files are created with 100600 perms. _ <- setFileCreationMask 0o100066 -- Create a new file once different mask is set and make sure that mask -- is applied. writeFile (joinPath [tmpDir, "sanityCheck"]) "with sanity check mask" sanityCheckStat <- getFileStatus $ joinPath [tmpDir, "sanityCheck"] fileMode sanityCheckStat `shouldBe` 0o100600 -- Since we move, this makes the new file assume the filemask of 0600 atomicWriteFileWithMode 0o100655 filePath $ lazyByteString $ pack "new contents" resultStat <- getFileStatus filePath -- reset mask to not break subsequent specs _ <- setFileCreationMask 0o100022 -- Fails when using atomic mv command unless apply perms on initial file fileMode resultStat `shouldBe` 0o100655 it "creates a new file with specified permissions" $ withSystemTempDirectory "atomicFileTest" $ \tmpDir -> do let filePath = joinPath [tmpDir, "testFile"] atomicWriteFileWithMode 0o100606 filePath $ lazyByteString $ pack "new contents" resultStat <- getFileStatus filePath fileMode resultStat `shouldBe` 0o100606