packages feed

kmonad-0.4.3: test/KMonad/ButtonDocSpec.hs

module KMonad.ButtonDocSpec (spec) where

import KMonad.Args.Parser
import KMonad.Args.Types
import KMonad.Prelude

import Data.Char (isSpace)
import Data.Data
import qualified RIO.Text as T

import Test.Hspec

spec :: Spec
spec = do
  docsExistForEveryButtons
  tutorialMentionsEveryButton

docsExistForEveryButtons :: Spec
docsExistForEveryButtons =
  (describe "button-docs" . traverse_ checkForDocsIn)
    [ quickReferencePath
    , tutorialPath
    ]
 where
  checkForDocsIn file = do
    cnt <- runIO $ readFileUtf8 file
    describe file . sequence_ $ traverse checkForDoc keywordButtons (lines cnt)
  checkForDoc btn cnt =
    it ("Doc mentions " <> unpack (fst btn)) $
      unless (buttonDocExist btn cnt) (expectationFailure "button is not mentioned in documentation")
  buttonDocExist = any . checkerFromButton . fst
  -- ignore deprecated names
  checkerFromButton "momentary-layer" = const True
  checkerFromButton "permanent-layer" = const True
  checkerFromButton btn =
    T.isPrefixOf ("- `(" <> btn <> " ") . T.dropWhile isSpace
      <||> T.isInfixOf ("`" <> btn <> "`")
      <||> T.isInfixOf ("`" <> btn <> "'")
  (<||>) = liftA2 (||)
  infixr 2 <||>

tutorialMentionsEveryButton :: Spec
tutorialMentionsEveryButton =
  describe "button-usage" $
    sequence_ . traverse checkButtonUsed buttonConstrs =<< runIO getTutorial
 where
  checkButtonUsed btn cnt =
    it ("Buttontype `" <> showConstr btn <> "` appears outside of comments")
      . unless (containsButton btn cnt)
      $ expectationFailure ("Buttontype `" <> showConstr btn <> "` is never used")
  containsButton btn = any . anyButton $ (== btn) . toConstr
  anyButton f (KDefLayer DefLayer{_layerSettings = lyrBtns}) = anyOf (each . _LButton) (anySubButton f) lyrBtns
  anyButton f (KDefAlias als) = any (anySubButton f . snd) als
  anyButton _ _ = False
  anySubButton f x = f x || anyOf plate f x
  buttonConstrs = dataTypeConstrs $ dataTypeOf (undefined :: DefButton)

getTutorial :: IO [KExpr]
getTutorial =
  either cannotParseTutorial pure . parseTokens
    =<< readFileUtf8 tutorialPath
 where
  cannotParseTutorial err =
    fail ("Could not parse `" <> tutorialPath <> "`:\n" <> show err)
      $> []

quickReferencePath :: FilePath
quickReferencePath = "doc/quick-reference.md"
tutorialPath :: FilePath
tutorialPath = "keymap/tutorial.kbd"