module SessionUIUnitTests (macroTests) where import Prelude () import Game.LambdaHack.Core.Prelude import qualified Data.Map.Strict as M import Test.Tasty import Test.Tasty.HUnit import Test.Tasty.QuickCheck import qualified Game.LambdaHack.Client.UI.Content.Input as IC import qualified Game.LambdaHack.Client.UI.HumanCmd as HumanCmd import qualified Game.LambdaHack.Client.UI.Key as K import Game.LambdaHack.Client.UI.SessionUI import qualified Client.UI.Content.Input as Content.Input import SessionUIMock -- Run @test -p "In-game" --quickcheck-verbose@ to verify that quickcheck -- properties are not too often satisfied voidly. macroTests :: TestTree macroTests = testGroup "macroTests" $ let coinput = IC.makeData Nothing Content.Input.standardKeysAndMouse stringToKeyMacro = KeyMacro . map (K.mkKM . (: [])) listToKeyMacro = KeyMacro . map K.mkKM bindInput l input = let ltriple = M.fromList $ map (\(k, ks) -> (K.mkKM k, ([], "", HumanCmd.Macro $ map (: []) ks))) l in input {IC.bcmdMap = M.union ltriple $ IC.bcmdMap input} in [ testCase "Macro 1 from PR#192 description" $ fst <$> unwindMacros coinput (stringToKeyMacro "'j''j'") @?= [ [ (Right "", "'j''j'", "") ] , [ (Left "", "j''j'", "") ] , [ (Left "j", "''j'", "j") ] , [ (Right "j", "'j'", "j") ] , [ (Left "", "j'", "j") ] , [ (Left "j", "'", "j") ] , [ (Right "j", "", "j") ] ] , testCase "Macro 1 from Issue#189 description" $ snd (last (unwindMacros (bindInput [ ("a", "'bc'V") , ("c", "'aaa'V") ] coinput) (stringToKeyMacro "a"))) @?= "Macro looped" , testCase "Macro 2 from Issue#189 description" $ snd (last (unwindMacros (bindInput [("a", "'x'")] coinput) (stringToKeyMacro "'a'"))) @?= "x" , testCase "Macro 3 from Issue#189 description" $ snd (last (unwindMacros coinput (stringToKeyMacro "'x''x'"))) @?= "xx" , testCase "Macro 4 from Issue#189 description" $ snd (last (unwindMacros coinput (stringToKeyMacro "'x''x'V"))) @?= "xxx" , testCase "Macro 5 from Issue#189 description" $ snd (last (unwindMacros coinput (stringToKeyMacro "x'x'V"))) @?= "xxx" , testCase "Macro test 10" $ snd (last (unwindMacros coinput (stringToKeyMacro "x'y'V"))) @?= "xyy" , testCase "Macro test 11" $ snd (last (unwindMacros coinput (stringToKeyMacro "'x''y'V"))) @?= "xyy" , testCase "Macro test 12" $ snd (last (unwindMacros coinput (listToKeyMacro ["x", "C-V"]))) @?= "x" , testCase "Macro test 13" $ snd (last (unwindMacros coinput (listToKeyMacro ["'", "x", "'", "C-V"]))) @?= "xxxxxxxxxxxxxxxxxxxxxxxxxx" , testCase "Macro test 14" $ snd (last (unwindMacros coinput (listToKeyMacro ["'", "x", "'", "y", "C-V"]))) @?= "xyxxxxxxxxxxxxxxxxxxxxxxxxx" , testCase "Macro test 15" $ snd (last (unwindMacros (bindInput [("a", "x")] coinput) (stringToKeyMacro "'a'V"))) @?= "xx" , testCase "Macro test 16" $ snd (last (unwindMacros (bindInput [("a", "'x'")] coinput) (stringToKeyMacro "'a'V"))) @?= "xx" , testCase "Macro test 17" $ snd (last (unwindMacros (bindInput [("a", "'x'V")] coinput) (stringToKeyMacro "a"))) @?= "xx" , testCase "Macro test 18" $ snd (last (unwindMacros (bindInput [("a", "'x'V")] coinput) (stringToKeyMacro "'a'"))) @?= "xx" , testCase "Macro test 19" $ snd (last (unwindMacros (bindInput [("a", "'x'V")] coinput) (stringToKeyMacro "'a'V"))) @?= "xxxx" , testCase "Macro test 20" $ snd (last (unwindMacros (bindInput [ ("a", "'bz'V") , ("c", "'aaa'V") ] coinput) (stringToKeyMacro "c"))) @?= "bzbzbzbzbzbzbzbzbzbzbzbz" , testCase "RepeatLast test 10" $ snd (last (unwindMacros coinput (stringToKeyMacro "x'y'v"))) @?= "xyy" , testCase "RepeatLast test 11" $ snd (last (unwindMacros coinput (stringToKeyMacro "'x'yv"))) @?= "xyy" , testCase "RepeatLast test 12" $ snd (last (unwindMacros coinput (listToKeyMacro ["v", "C-v"]))) @?= "" , testCase "RepeatLast test 13" $ snd (last (unwindMacros coinput (listToKeyMacro ["'", "x", "'", "C-v"]))) @?= "xxxxxxxxxxxxxxxxxxxxxxxxxx" , testCase "RepeatLast test 14" $ snd (last (unwindMacros coinput (listToKeyMacro ["'", "x", "'", "V", "C-v"]))) @?= "xxxxxxxxxxxxxxxxxxxxxxxxxxx" , testCase "RepeatLast test 15" $ snd (last (unwindMacros (bindInput [("a", "x")] coinput) (stringToKeyMacro "av"))) @?= "xx" , testCase "RepeatLast test 16" $ snd (last (unwindMacros (bindInput [("a", "'x'")] coinput) (stringToKeyMacro "'a'v"))) @?= "xx" , testCase "RepeatLast test 17" $ snd (last (unwindMacros (bindInput [("a", "'x'v")] coinput) (stringToKeyMacro "a"))) @?= "xx" , testCase "RepeatLast test 18" $ snd (last (unwindMacros (bindInput [("a", "'x'v")] coinput) (stringToKeyMacro "'a'"))) @?= "xx" , testCase "RepeatLast test 19" $ snd (last (unwindMacros (bindInput [("a", "'x'v")] coinput) (stringToKeyMacro "'a'v"))) @?= "xxxx" , testCase "RepeatLast test 20" $ snd (last (unwindMacros (bindInput [ ("a", "'bz'v") , ("c", "'aaa'v") ] coinput) (stringToKeyMacro "c"))) @?= "bzzbzzbzzbzz" , testCase "RepeatLast test 21" $ snd (last (unwindMacros (bindInput [("a", "'x'V")] coinput) (stringToKeyMacro "'a'v"))) @?= "xxxx" , testCase "RepeatLast test 22" $ snd (last (unwindMacros (bindInput [("a", "'xy'V")] coinput) (stringToKeyMacro "'aa'v"))) @?= "xyxyxyxyxyxy" , testCase "RepeatLast test 23" $ snd (last (unwindMacros (bindInput [("a", "'xy'v")] coinput) (stringToKeyMacro "'aa'V"))) @?= "xyyxyyxyyxyy" , testCase "RepeatLast test 24" $ snd (last (unwindMacros (bindInput [("a", "'xy'vv")] coinput) (stringToKeyMacro "'aa'vv"))) @?= "xyyyxyyyxyyyxyyy" , testCase "RepeatLast test 25" $ snd (last (unwindMacros (bindInput [("a", "'xyv'v")] coinput) (stringToKeyMacro "'a'a'vv'"))) @?= "xyyyxyyyxyyyxyyy" , testCase "RepeatLast test 26" $ snd (last (unwindMacros (bindInput [ ("a", "'xy'v") , ("b", "'za'v") , ("c", "'ab'v") ] coinput) (stringToKeyMacro "'c'v"))) @?= "xyyzxyyxyyzxyyxyyxyyzxyyxyyzxyyxyy" , testCase "RepeatLast test 27" $ snd (last (unwindMacros (bindInput [ ("a", "'xy'V") , ("b", "'za'v") , ("c", "'ab'v") ] coinput) (stringToKeyMacro "'c'v"))) @?= "xyxyzxyxyxyxyzxyxyxyxyxyxyzxyxyxyxyzxyxyxyxy" , testCase "RepeatLast test 28" $ snd (last (unwindMacros (bindInput [ ("a", "'xy'v") , ("b", "'za'V") , ("c", "'ab'v") ] coinput) (stringToKeyMacro "'c'v"))) @?= "xyyzxyyzxyyzxyyzxyyxyyzxyyzxyyzxyyzxyy" , testCase "RepeatLast test 29" $ snd (last (unwindMacros (bindInput [ ("a", "'xy'v") , ("b", "'za'V") , ("c", "'ab'V") ] coinput) (stringToKeyMacro "'c'v"))) @?= "xyyzxyyzxyyxyyzxyyzxyyxyyzxyyzxyyxyyzxyyzxyy" , testCase "RepeatLast test 30" $ snd (last (unwindMacros (bindInput [ ("a", "'xy'v") , ("b", "'za'V") , ("c", "'ab'V") ] coinput) (stringToKeyMacro "'c'V"))) @?= "xyyzxyyzxyyxyyzxyyzxyyxyyzxyyzxyyxyyzxyyzxyy" , testCase "RepeatLast test 31" $ snd (last (unwindMacros (bindInput [ ("a", "'xy'v") , ("b", "'za'v") , ("c", "'ab'V") ] coinput) (stringToKeyMacro "'c'V"))) @?= "xyyzxyyxyyxyyzxyyxyyxyyzxyyxyyxyyzxyyxyy" , testCase "RepeatLast test 32" $ snd (last (unwindMacros (bindInput [ ("a", "'xy'v") , ("b", "'za'v") ] coinput) (stringToKeyMacro "'ab'vv"))) @?= "xyyzxyyxyyzxyyxyyzxyyxyy" , testCase "RepeatLast test 33" $ snd (last (unwindMacros (bindInput [ ("a", "'xy'V") ] coinput) (stringToKeyMacro "a'za'vvv"))) @?= "xyxyzxyxyxyxyxyxyxyxy" , testCase "RepeatLast test 34" $ snd (last (unwindMacros (bindInput [ ("a", "'xy'v") , ("c", "a'za'Vv") ] coinput) (stringToKeyMacro "'c'v"))) @?= "xyyzxyyzxyyzxyyxyyzxyyzxyyzxyy" , testCase "RepeatLast test 35" $ snd (last (unwindMacros (bindInput [ ("a", "'xy'v") , ("b", "'za'V") ] coinput) (stringToKeyMacro "'ab'Vv"))) @?= "xyyzxyyzxyyxyyzxyyzxyyxyyzxyyzxyy" , testCase "RepeatLast test 36" $ snd (last (unwindMacros (bindInput [ ("a", "'xy'v") , ("b", "za'za'") ] coinput) (stringToKeyMacro "'ab'V'ab'V"))) @?= "xyyzxyyzxyyxyyzxyyzxyyxyyzxyyzxyyxyyzxyyzxyy" , testCase "RepeatLast test 37" $ snd (last (unwindMacros (bindInput [ ("b", "z'xy'vv") , ("c", "'xyvb'V") ] coinput) (stringToKeyMacro "'c'V"))) @?= "xyyzxyyyxyyzxyyyxyyzxyyyxyyzxyyy" , testCase "RepeatLast test 38" $ snd (last (unwindMacros coinput (stringToKeyMacro "'xv'V"))) @?= "xxxx" , testCase "RepeatLast test 39" $ fst <$> unwindMacros coinput (stringToKeyMacro "'xv'V") @?= [[(Right "", "'xv'V", "")], [(Left "", "xv'V", "")], [(Left "x", "v'V", "x")], [(Left "x", "x'V", "x")], [(Left "xx", "'V", "x")], [(Right "xx", "V", "x")], [(Right "", "xx", ""), (Right "xx", "", "V")], [(Right "", "x", "x"), (Right "xx", "", "V")], [(Right "xx", "", "V")]] , testCase "RepeatLast test 40" $ snd (last (unwindMacros coinput (stringToKeyMacro "'xy'Vv"))) @?= "xyxyxy" , testCase "RepeatLast test 41; named macros not referentially transparent" $ snd (last (unwindMacros (bindInput [("a", "'xy'V")] coinput) (stringToKeyMacro "av"))) @?= "xyxyxyxy" -- because @a@ repeated; good! , testCase "RepeatLast test 42" $ snd (last (unwindMacros (bindInput [("a", "xy")] coinput) (stringToKeyMacro "'a'Vv"))) @?= "xyxyxy" -- because @V@ repeated; good! , testCase "RepeatLast test 43" $ snd (last (unwindMacros coinput (stringToKeyMacro "'xyV'V"))) @?= "xyxy" , testCase "RepeatLast test 44" $ snd (last (unwindMacros coinput (stringToKeyMacro "'xyV'v"))) @?= "xyxy" , testCase "RepeatLast test 45" $ snd (last (unwindMacros (bindInput [("a", "xyV")] coinput) (stringToKeyMacro "'a'V"))) @?= "xyxy" , testCase "RepeatLast test 46" $ snd (last (unwindMacros (bindInput [("a", "xyV")] coinput) (stringToKeyMacro "'a'v"))) @?= "xyxy" , testProperty "In-game macro and equivalent predefined macro agree" $ forAll (listOf (elements "`ABvV")) $ \macro -> let bindings = bindInput [("a", macro)] coinput inGameResult = snd (last (unwindMacros coinput (stringToKeyMacro macro))) in inGameResult === snd (last (unwindMacros bindings (stringToKeyMacro "a"))) .&&. inGameResult =/= "Macro looped" -- may not loop , testProperty "In-game and predefined with limited minimal bindings" $ forAll (listOf (elements "````''''ABCABCABCABCvVvVvVa")) $ -- may loop \macro -> let bindings = bindInput [("a", macro)] coinput in snd (last (unwindMacros bindings (stringToKeyMacro macro))) === snd (last (unwindMacros bindings (stringToKeyMacro "a"))) , testProperty "In-game and predefined with limited multiple bindings" $ forAll (listOf (elements "```ABCDvVabccc")) $ \macro -> -- The macros may still loop due to mutual recursion, -- even though direct recursion is ruled out by filtering. let macroA = filter (/= 'a') macro macroB = filter (/= 'b') $ take 5 $ reverse macro bindings = bindInput [ ("a", macroA) , ("b", macroB) , ("c", "A'B''CD'") ] coinput in snd (last (unwindMacros bindings (stringToKeyMacro macroA))) === snd (last (unwindMacros bindings (stringToKeyMacro "a"))) ]