{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} -- | -- Module : Clod.FileSystem.DetectionSpec -- Description : Tests for file type detection -- Copyright : (c) Fuzz Leonard, 2025 -- License : MIT -- Maintainer : ink@fuzz.ink -- Stability : experimental -- -- This module contains tests for file type detection functionality -- using magic-based file type detection. module Clod.FileSystem.DetectionSpec (spec) where import Test.Hspec import Control.Monad (forM_) import System.FilePath import System.IO.Temp (withSystemTempDirectory) import System.Directory (createDirectoryIfMissing) -- import qualified System.IO import qualified Data.ByteString as BS import Clod.Types (runClodM, fileReadCap, ClodConfig(..)) import Clod.FileSystem.Detection (safeIsTextFile, isTextDescription, needsTransformation) import Clod.TestHelpers (defaultTestConfig) -- | Our own FileType definition for testing purposes data FileType = TextFile | BinaryFile deriving (Show, Eq) -- | Test specification for FileSystem.Detection module spec :: Spec spec = do magicDetectionSpec mimeTypeSpec transformationSpec -- | Tests for magic-based file type detection magicDetectionSpec :: Spec magicDetectionSpec = describe "Magic-based file type detection" $ do it "correctly detects text files using magic" $ do withSystemTempDirectory "clod-test" $ \tmpDir -> do -- Create a plain text file - this will reliably be detected as text/plain let textFile = tmpDir "text.txt" writeFile textFile "This is plain text content with multiple lines.\nSecond line\nThird line" -- Create a config and capabilities let config = defaultTestConfig tmpDir readCap = fileReadCap [tmpDir] -- Test the text file result <- runClodM config $ do isText <- safeIsTextFile readCap textFile return (if isText then TextFile else BinaryFile) case result of Left err -> expectationFailure $ "Error detecting text file: " ++ show err Right fileType -> fileType `shouldBe` TextFile it "correctly identifies binary files" $ do withSystemTempDirectory "clod-test" $ \tmpDir -> do -- Create binary files with appropriate content let pngFile = tmpDir "image.png" let exeFile = tmpDir "program.exe" -- Write some binary data (PNG header and some random bytes) BS.writeFile pngFile $ BS.pack [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D] -- Write EXE header BS.writeFile exeFile $ BS.pack [0x4D, 0x5A, 0x90, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00] -- Create a config and capabilities let config = defaultTestConfig tmpDir readCap = fileReadCap [tmpDir] -- Test each file forM_ [pngFile, exeFile] $ \file -> do result <- runClodM config $ do isText <- safeIsTextFile readCap file return (if isText then TextFile else BinaryFile) case result of Left err -> expectationFailure $ "Error detecting binary file: " ++ show err Right fileType -> fileType `shouldBe` BinaryFile -- | Create a test environment for testing with embedded patterns setupTestEnvironment :: FilePath -> IO () setupTestEnvironment tmpDir = do -- Create the necessary directory structure let resourceDir = tmpDir "resources" createDirectoryIfMissing True resourceDir -- No need to create a patterns file anymore as we're using -- the embedded version directly in the code -- | Tests for text file detection through description mimeTypeSpec :: Spec mimeTypeSpec = describe "File description detection" $ do it "identifies text file descriptions correctly" $ do -- Prepare a test environment withSystemTempDirectory "clod-test" $ \tmpDir -> do -- Setup test environment setupTestEnvironment tmpDir -- Set config directory to our test directory let config = (defaultTestConfig tmpDir) { configDir = tmpDir } -- Test various text file descriptions let textDescriptions = [ "ASCII text" , "text/plain" , "UTF-8 text" , "JSON data" , "XML document" , "HTML document" , "source code" , "script file" ] -- For each description, test in our monad forM_ textDescriptions $ \desc -> do result <- runClodM config $ isTextDescription desc case result of Left err -> expectationFailure $ "Error checking description: " ++ show err Right isText -> isText `shouldBe` True it "identifies non-text file descriptions correctly" $ do -- Prepare a test environment withSystemTempDirectory "clod-test" $ \tmpDir -> do -- Setup test environment setupTestEnvironment tmpDir -- Set config directory to our test directory let config = (defaultTestConfig tmpDir) { configDir = tmpDir } -- Test various non-text file descriptions let nonTextDescriptions = [ "PNG image data" , "JPEG image data" , "ELF executable" , "Zip archive data" , "PDF document" , "MPEG audio" , "binary data" ] -- For each description, test in our monad forM_ nonTextDescriptions $ \desc -> do result <- runClodM config $ isTextDescription desc case result of Left err -> expectationFailure $ "Error checking description: " ++ show err Right isText -> isText `shouldBe` False -- | Tests for special file handling transformationSpec :: Spec transformationSpec = describe "Special file handling" $ do it "identifies files needing special transformation" $ do -- Test files that need special handling let specialFiles = [ "/path/to/.gitignore" , "/path/to/.env" , "/path/to/logo.svg" ] forM_ specialFiles $ \file -> needsTransformation file `shouldBe` True it "identifies files not needing special transformation" $ do -- Test regular files let regularFiles = [ "/path/to/file.txt" , "/path/to/image.png" , "/path/to/normal.html" ] forM_ regularFiles $ \file -> needsTransformation file `shouldBe` False