module Test.Stan.Analysis.AntiPattern ( analysisAntiPatternSpec ) where import Test.Hspec (Spec, describe, it, xit) import Stan.Analysis (Analysis) import Test.Stan.Analysis.Common (noObservationAssert, observationAssert, observationAssertMulti) import qualified Stan.Inspection.AntiPattern as AntiPattern analysisAntiPatternSpec :: Analysis -> Spec analysisAntiPatternSpec analysis = describe "Anti-patterns" $ do let checkObservation = observationAssert ["AntiPattern"] analysis let noObservation = noObservationAssert ["AntiPattern"] analysis it "STAN-0201: finds usage of '[0 .. length xs]'" $ checkObservation AntiPattern.stan0201 16 19 35 it "STAN-0201: doesn't trigger on '[0 .. length xs - 1]'" $ noObservation AntiPattern.stan0201 19 it "STAN-0202: finds usage of 'foldl'" $ checkObservation AntiPattern.stan0202 22 13 18 it "STAN-0203: finds usage of 'Data.ByteString.Char8.pack'" $ checkObservation AntiPattern.stan0203 25 13 21 it "STAN-0204: finds usage of 'Data.HashMap.size'" $ checkObservation AntiPattern.stan0204 28 19 26 it "STAN-0204: finds usage of 'length' for 'HashMap'" $ checkObservation AntiPattern.stan0204 31 21 27 it "STAN-0205: finds usage of 'Data.HashSet.size'" $ checkObservation AntiPattern.stan0205 34 19 26 it "STAN-0205: finds usage of 'length' for 'HashSet'" $ checkObservation AntiPattern.stan0205 37 21 27 strictFieldsSpec analysis it "STAN-0207: 'length' for (,)" $ checkObservation AntiPattern.stan0207 40 19 25 it "STAN-0207: 'null' for Maybe" $ checkObservation AntiPattern.stan0207 43 17 21 it "STAN-0207: 'foldr' for Either" $ checkObservation AntiPattern.stan0207 46 19 24 it "STAN-0208: finds usage of 'length' for 'Text'" $ checkObservation AntiPattern.stan0208 49 18 29 it "STAN-0209: finds usage of 'nub' for lists" $ checkObservation AntiPattern.stan0209 52 11 19 it "STAN-0210: finds usage of 'for_' for ranges" $ checkObservation AntiPattern.stan0210 55 12 35 it "STAN-0210: finds usage of 'forM_' for ranges" $ checkObservation AntiPattern.stan0210 58 15 29 it "STAN-0211: finds usage of 'http://' ''" $ checkObservation AntiPattern.stan0211 61 12 41 it "STAN-0211: finds usage of 'fooUrl' ''" $ checkObservation AntiPattern.stan0211 64 12 28 it "STAN-0211: finds usage of '' 'fooUrl'" $ checkObservation AntiPattern.stan0211 70 12 28 it "STAN-0211: doesn't trigger on 'fooUral' ''" $ noObservation AntiPattern.stan0211 76 unsafeFunctionsSpec analysis patternMatchSpec analysis compareSpec analysis it "STAN-0215: finds usage of '/' in '' path left" $ checkObservation AntiPattern.stan0215 82 19 38 it "STAN-0215: finds usage of '/' in '' path right" $ checkObservation AntiPattern.stan0215 88 20 39 it "STAN-0215: finds usage of '\\' in '' path left" $ checkObservation AntiPattern.stan0215 85 22 42 it "STAN-0215: finds usage of '\\' in '' path right" $ checkObservation AntiPattern.stan0215 91 23 43 it "STAN-0215: don't triggered when no slashes" $ noObservation AntiPattern.stan0215 94 strictFieldsSpec :: Analysis -> Spec strictFieldsSpec analysis = describe "STAN-0206: Strict data type fields" $ do describe "Without extensions" $ do let checkObservation = observationAssert ["AntiPattern", "Stan0206"] analysis let noObservation = noObservationAssert ["AntiPattern", "Stan0206"] analysis it "Doesn't trigger on strict field" $ noObservation AntiPattern.stan0206 7 it "Finds simple lazy field" $ checkObservation AntiPattern.stan0206 8 7 25 it "Finds polymorphic lazy field" $ checkObservation AntiPattern.stan0206 9 7 23 it "Doesn't trigger on plain newtype" $ noObservation AntiPattern.stan0206 12 it "Doesn't trigger on a record newtype" $ noObservation AntiPattern.stan0206 14 it "Doesn't trigger on strict sum type field among many fields" $ noObservation AntiPattern.stan0206 19 it "Finds lazy field in a sum type constructor with multiple fields" $ checkObservation AntiPattern.stan0206 20 9 12 it "Doesn't trigger on a single strict sum type field" $ noObservation AntiPattern.stan0206 21 it "Finds single lazy field in a sum type with multiple constructors" $ checkObservation AntiPattern.stan0206 22 11 15 describe "With the 'StrictData' extension" $ do let noObservation = noObservationAssert ["AntiPattern", "Stan0206Extensions"] analysis it "Doesn't trigger on a simple record field" $ noObservation AntiPattern.stan0206 9 it "Doesn't trigger on explicitly lazy field" $ noObservation AntiPattern.stan0206 10 it "Doesn't trigger on plain data type" $ noObservation AntiPattern.stan0206 13 unsafeFunctionsSpec :: Analysis -> Spec unsafeFunctionsSpec analysis = describe "STAN-0212: Unsafe functions" $ do let checkObservation = observationAssert ["AntiPattern", "Stan0212"] analysis it "Find: undefined" $ checkObservation AntiPattern.stan0212 10 17 26 it "Find: unsafeCoerce" $ checkObservation AntiPattern.stan0212 13 20 32 it "Find: unsafePerformIO" $ checkObservation AntiPattern.stan0212 16 23 38 it "Find: unsafeInterleaveIO" $ checkObservation AntiPattern.stan0212 19 26 44 it "Find: unsafeDupablePerformIO" $ checkObservation AntiPattern.stan0212 22 30 52 it "Find: unsafeFixIO" $ checkObservation AntiPattern.stan0212 25 19 30 patternMatchSpec :: Analysis -> Spec patternMatchSpec analysis = describe "STAN-0212: Pattern Matching on _" $ do let checkObservation = observationAssert ["AntiPattern", "Stan0213"] analysis let noObservation = noObservationAssert ["AntiPattern", "Stan0213"] analysis it "for lambda case" $ checkObservation AntiPattern.stan0213 12 5 17 it "not triggered for lambda case on integers" $ noObservation AntiPattern.stan0213 17 it "for case" $ checkObservation AntiPattern.stan0213 23 5 18 it "not triggered for case on strings" $ noObservation AntiPattern.stan0213 29 it "not triggered for case on all constructors" $ do noObservation AntiPattern.stan0213 33 noObservation AntiPattern.stan0213 34 noObservation AntiPattern.stan0213 35 it "not triggered for lambda case on all constructors" $ do noObservation AntiPattern.stan0213 39 noObservation AntiPattern.stan0213 40 noObservation AntiPattern.stan0213 41 it "for case on maybe" $ checkObservation AntiPattern.stan0213 46 5 20 it "for lambda case on maybe" $ checkObservation AntiPattern.stan0213 51 5 20 it "not triggered for lambda case on maybe with full pm" $ noObservation AntiPattern.stan0213 56 it "not triggered for lambda case on one branch _" $ noObservation AntiPattern.stan0213 60 it "not triggered for lambda case on Chars" $ noObservation AntiPattern.stan0213 65 compareSpec :: Analysis -> Spec compareSpec analysis = describe "STAN-0214: Replace multiple comparison operators" $ do let checkObservation = observationAssertMulti ["AntiPattern", "Stan0214"] analysis AntiPattern.stan0214 let noObservation = noObservationAssert ["AntiPattern", "Stan0214"] analysis AntiPattern.stan0214 it "Finds: < and >" $ checkObservation 7 1 10 23 it "Finds: == and <" $ checkObservation 13 1 16 23 it "No warning on: == on different expressions" $ do noObservation 19 noObservation 20 noObservation 21 noObservation 22 it "No warning on: Single >=" $ do noObservation 25 noObservation 26 noObservation 27 it "No warning on: >= with different constants" $ do noObservation 30 noObservation 31 noObservation 32 noObservation 33 noObservation 34 noObservation 35 xit "Handles functions with pattern-matching" $ checkObservation 41 1 44 20