@@ -7,6 +7,7 @@ import Control.Applicative (many, optional, (<|>))
77import qualified Control.Concurrent as Concurrent
88import Control.Exception (SomeException , try )
99import Control.Monad (replicateM , void , forM_ , when )
10+ import Crypto.Hash (hash , Digest , SHA256 )
1011import Data.Serialize (Serialize (.. ))
1112import Data.Serialize (Get , getByteString ,
1213 getInt64le ,
@@ -35,6 +36,7 @@ import System.Environment (getEnv)
3536import System.FilePath ((<.>) , (</>) )
3637import qualified System.IO as IO
3738import qualified System.IO.Temp as Temp
39+ import qualified System.Posix.Files as Unix
3840import qualified System.Posix.Process as Unix
3941import qualified System.Process as P
4042import Test.Tasty as T
@@ -142,11 +144,19 @@ unit_nixStoreDirectory = filesystemNixStore "directory" (Nar sampleDirectory)
142144unit_nixStoreDirectory' :: HU. Assertion
143145unit_nixStoreDirectory' = filesystemNixStore " directory'" (Nar sampleDirectory')
144146
147+ -- | Test that the executable permissions are handled correctly in app bundles on macOS.
148+ -- In this case, access() returns false for a file under this specific path, even when the executable bit is set.
149+ -- NAR implementations should avoid this syscall on macOS.
150+ test_nixStoreMacOSAppBundle :: TestTree
151+ test_nixStoreMacOSAppBundle = packThenExtract " App.app" $ \ baseDir -> do
152+ let testDir = baseDir </> " App.app" </> " Resources" </> " en.lproj"
153+ Directory. createDirectoryIfMissing True testDir
154+ mkExecutableFile (testDir </> " test.strings" )
155+
145156test_nixStoreBigFile :: TestTree
146157test_nixStoreBigFile = packThenExtract " bigfile" $ \ baseDir -> do
147158 mkBigFile (baseDir </> " bigfile" )
148159
149-
150160test_nixStoreBigDir :: TestTree
151161test_nixStoreBigDir = packThenExtract " bigdir" $ \ baseDir -> do
152162 let testDir = baseDir </> " bigdir"
@@ -350,7 +360,16 @@ packThenExtract testName setup =
350360 IO. withFile hnixNarFile IO. WriteMode $ \ h ->
351361 buildNarIO narEffectsIO narFilePath h
352362
353- -- BSL.writeFile hnixNarFile narBS
363+ -- Compare the hash digests of the two NARs
364+ nixHash :: Digest SHA256 <- hash <$> BS. readFile nixNarFile
365+ hnixHash :: Digest SHA256 <- hash <$> BS. readFile hnixNarFile
366+ step $ unlines
367+ [ " Compare SHA256 digests between NARs:"
368+ , " nix: " <> show nixHash
369+ , " hnix: " <> show hnixHash
370+ ]
371+
372+ HU. assertEqual " Hash mismatch between NARs" nixHash hnixHash
354373
355374 step $ " Unpack NAR to " <> outputFile
356375 _narHandle <- IO. withFile nixNarFile IO. ReadMode $ \ h ->
@@ -567,6 +586,12 @@ mkBigFile path = do
567586 fsize <- getBigFileSize
568587 BSL. writeFile path (BSL. take fsize $ BSL. cycle " Lorem ipsum" )
569588
589+ mkExecutableFile :: FilePath -> IO ()
590+ mkExecutableFile path = do
591+ BSL. writeFile path " "
592+ st <- Unix. getSymbolicLinkStatus path
593+ let p = Unix. fileMode st `Unix.unionFileModes` Unix. ownerExecuteMode
594+ Unix. setFileMode path p
570595
571596-- | Construct FilePathPart from Text by checking that there
572597-- are no '/' or '\\NUL' characters
0 commit comments