cutesetup-0.1.0.0: test/Spec.hs
module Main (main) where
import Test.QuickCheck
import System.Exit (exitFailure, exitSuccess)
import Control.Monad (unless)
import Data.List (isInfixOf, isPrefixOf)
import qualified Data.Map.Strict as Map
import Languages
import NixGen
import NixSearch (Channel(..))
-- Generate arbitrary Language
instance Arbitrary Language where
arbitrary = arbitraryBoundedEnum
-- Generate arbitrary Channel
instance Arbitrary Channel where
arbitrary = arbitraryBoundedEnum
-- Generate arbitrary LangPackage
instance Arbitrary LangPackage where
arbitrary = do
name <- listOf1 (elements ['a'..'z'])
label <- listOf1 (elements ['a'..'z'])
desc <- listOf (elements (['a'..'z'] ++ [' ']))
def <- arbitrary
return (LangPackage name label desc def)
-- Generate arbitrary GenerateConfig
instance Arbitrary GenerateConfig where
arbitrary = do
lang <- arbitrary
pkgs <- listOf arbitrary
extraAttrs <- listOf $ do
attr <- listOf1 (elements ['a'..'z'])
chan <- arbitrary
return (attr, chan)
targetDir <- listOf (elements (['a'..'z'] ++ ['/']))
systemArch <- elements ["x86_64-linux", "aarch64-linux"]
pythonVenv <- arbitrary
nixpkgsStable <- elements ["nixos-25.11", "nixos-24.11"]
return $ GenerateConfig
{ gcLang = lang
, gcPackages = pkgs
, gcExtraAttrs = extraAttrs
, gcTargetDir = targetDir
, gcSystemArch = systemArch
, gcPythonVenv = pythonVenv
, gcNixpkgsStable = nixpkgsStable
}
-- Property: Generated flake always starts with a valid Nix brace layout
prop_validFlakeBraceLayout :: GenerateConfig -> Bool
prop_validFlakeBraceLayout cfg =
let flake = generateFlake cfg
in "{" `isPrefixOf` flake && "}" `isInfixOf` flake
-- Property: Package inclusion in flake nativeBuildInputs
prop_allPackagesIncluded :: GenerateConfig -> Bool
prop_allPackagesIncluded cfg =
let flake = generateFlake cfg
-- All unstable packages in gcPackages should be in nativeBuildInputs as pkgs.<name>
unstablePkgs = [pkgName p | p <- gcPackages cfg] ++ [attr | (attr, Unstable) <- gcExtraAttrs cfg]
-- All stable packages in gcExtraAttrs should be as pkgs-stable.<name>
stablePkgs = [attr | (attr, Stable) <- gcExtraAttrs cfg]
checkUnstable = all (\p -> ("pkgs." ++ p) `isInfixOf` flake) unstablePkgs
checkStable = all (\p -> ("pkgs-stable." ++ p) `isInfixOf` flake) stablePkgs
in checkUnstable && checkStable
-- Property: Python virtual environment shellHook logic
prop_pythonVenvHook :: GenerateConfig -> Bool
prop_pythonVenvHook cfg =
let flake = generateFlake cfg
hasVenv = gcPythonVenv cfg
in if hasVenv
then "python3 -m venv .venv" `isInfixOf` flake && "source .venv/bin/activate" `isInfixOf` flake
else not ("source .venv/bin/activate" `isInfixOf` flake)
-- Property: Correct language description in the header/description field
prop_correctDescription :: GenerateConfig -> Bool
prop_correctDescription cfg =
let flake = generateFlake cfg
expectedDesc = show (gcLang cfg) ++ " development environment"
in expectedDesc `isInfixOf` flake
-- Property: .envrc is always correctly generated
prop_validEnvrc :: GenerateConfig -> Bool
prop_validEnvrc cfg =
let envrc = generateEnvrc cfg
in "use flake" `isInfixOf` envrc && "# Generated by cutesetup" `isInfixOf` envrc
runProperty :: Testable prop => String -> prop -> IO Bool
runProperty name prop = do
putStrLn $ "Running property: " ++ name
res <- quickCheckResult prop
case res of
Success {} -> return True
_ -> return False
main :: IO ()
main = do
putStrLn "=== Running Cutesetup Property Tests ==="
r1 <- runProperty "valid flake brace layout" prop_validFlakeBraceLayout
r2 <- runProperty "all packages included in inputs" prop_allPackagesIncluded
r3 <- runProperty "python venv shellHook activation" prop_pythonVenvHook
r4 <- runProperty "correct description field" prop_correctDescription
r5 <- runProperty "valid envrc structure" prop_validEnvrc
let success = r1 && r2 && r3 && r4 && r5
if success
then do
putStrLn "All property tests passed!"
exitSuccess
else do
putStrLn "Some tests failed."
exitFailure