From f7a2e1a287db1475a1dfc087a76d29d1878da70d Mon Sep 17 00:00:00 2001 From: Joshua Clayton Date: Sun, 8 May 2016 06:29:55 -0400 Subject: [PATCH] Add Hspec and tests around parsing --- src/Unused/Parser.hs | 18 +------ src/Unused/Types.hs | 21 +++++++- test/Spec.hs | 3 +- test/Unused/ParserSpec.hs | 36 ++++++++++++++ test/Unused/ResponseFilterSpec.hs | 79 +++++++++++++++++++++++++++++++ test/Unused/TypesSpec.hs | 18 +++++++ unused.cabal | 5 ++ 7 files changed, 159 insertions(+), 21 deletions(-) create mode 100644 test/Unused/ParserSpec.hs create mode 100644 test/Unused/ResponseFilterSpec.hs create mode 100644 test/Unused/TypesSpec.hs diff --git a/src/Unused/Parser.hs b/src/Unused/Parser.hs index bccd723..3d93c17 100644 --- a/src/Unused/Parser.hs +++ b/src/Unused/Parser.hs @@ -18,23 +18,7 @@ parseLines = responseFromParse :: Either ParseError [TermMatch] -> ParseResponse responseFromParse = - fmap $ Map.fromList . map (second resultsFromMatches) . groupBy tmTerm - -resultsFromMatches :: [TermMatch] -> TermResults -resultsFromMatches m = - calculateLikelihood TermResults - { trTerm = resultTerm terms - , trMatches = m - , trTotalFiles = totalFiles - , trTotalOccurrences = totalOccurrences - , trRemovalLikelihood = High - } - where - totalFiles = length m - totalOccurrences = sum $ fmap tmOccurrences m - terms = map tmTerm m - resultTerm (x:_) = x - resultTerm _ = "" + fmap $ Map.fromList . map (second $ calculateLikelihood . resultsFromMatches) . groupBy tmTerm parseTermMatches :: Parser [TermMatch] parseTermMatches = do diff --git a/src/Unused/Types.hs b/src/Unused/Types.hs index f0f78a7..8900c7a 100644 --- a/src/Unused/Types.hs +++ b/src/Unused/Types.hs @@ -4,6 +4,7 @@ module Unused.Types , TermMatchSet , ParseResponse , RemovalLikelihood(..) + , resultsFromMatches ) where import Text.Parsec (ParseError) @@ -13,7 +14,7 @@ data TermMatch = TermMatch { tmTerm :: String , tmPath :: String , tmOccurrences :: Int - } deriving Show + } deriving (Eq, Show) data TermResults = TermResults { trTerm :: String @@ -21,10 +22,26 @@ data TermResults = TermResults , trTotalFiles :: Int , trTotalOccurrences :: Int , trRemovalLikelihood :: RemovalLikelihood - } deriving Show + } deriving (Eq, Show) data RemovalLikelihood = High | Medium | Low | Unknown deriving (Eq, Show) type TermMatchSet = Map.Map String TermResults type ParseResponse = Either ParseError TermMatchSet + +resultsFromMatches :: [TermMatch] -> TermResults +resultsFromMatches m = + TermResults + { trTerm = resultTerm terms + , trMatches = m + , trTotalFiles = totalFiles + , trTotalOccurrences = totalOccurrences + , trRemovalLikelihood = Unknown + } + where + totalFiles = length m + totalOccurrences = sum $ fmap tmOccurrences m + terms = map tmTerm m + resultTerm (x:_) = x + resultTerm _ = "" diff --git a/test/Spec.hs b/test/Spec.hs index cd4753f..a824f8c 100644 --- a/test/Spec.hs +++ b/test/Spec.hs @@ -1,2 +1 @@ -main :: IO () -main = putStrLn "Test suite not yet implemented" +{-# OPTIONS_GHC -F -pgmF hspec-discover #-} diff --git a/test/Unused/ParserSpec.hs b/test/Unused/ParserSpec.hs new file mode 100644 index 0000000..b60c512 --- /dev/null +++ b/test/Unused/ParserSpec.hs @@ -0,0 +1,36 @@ +module Unused.ParserSpec where + +import Test.Hspec +import Unused.Types (TermResults(..), TermMatch(..), RemovalLikelihood(..)) +import Unused.Parser +import qualified Data.Map.Strict as Map + +main :: IO () +main = hspec spec + +spec :: Spec +spec = parallel $ + describe "parseLines" $ do + it "parses from the correct format" $ do + let input = "method_name:app/path/foo.rb:1\n\ + \other:app/path/other.rb:1\n\ + \method_name:app/path/other.rb:5\n\ + \method_name:spec/path/foo_spec.rb:10\n" + + let r1Matches = [ TermMatch "method_name" "app/path/foo.rb" 1 + , TermMatch "method_name" "app/path/other.rb" 5 + , TermMatch "method_name" "spec/path/foo_spec.rb" 10 + ] + let r1Results = TermResults "method_name" r1Matches 3 16 Low + + let r2Matches = [ TermMatch "other" "app/path/other.rb" 1 ] + let r2Results = TermResults "other" r2Matches 1 1 High + + let (Right result) = parseLines input + + result `shouldBe` + Map.fromList [ ("method_name", r1Results), ("other", r2Results) ] + + it "handles empty input" $ do + let (Left result) = parseLines "" + show result `shouldContain` "unexpected end of input" diff --git a/test/Unused/ResponseFilterSpec.hs b/test/Unused/ResponseFilterSpec.hs new file mode 100644 index 0000000..92b7731 --- /dev/null +++ b/test/Unused/ResponseFilterSpec.hs @@ -0,0 +1,79 @@ +module Unused.ResponseFilterSpec where + +import Test.Hspec +import Unused.Types (TermMatch(..), resultsFromMatches) +import Unused.ResponseFilter + +main :: IO () +main = hspec spec + +spec :: Spec +spec = parallel $ do + describe "railsSingleOkay" $ do + it "allows controllers" $ do + let match = TermMatch "ApplicationController" "app/controllers/application_controller.rb" 1 + let result = resultsFromMatches [match] + + railsSingleOkay result `shouldBe` True + + it "allows helpers" $ do + let match = TermMatch "ApplicationHelper" "app/helpers/application_helper.rb" 1 + let result = resultsFromMatches [match] + + railsSingleOkay result `shouldBe` True + + it "allows migrations" $ do + let match = TermMatch "CreateUsers" "db/migrate/20160101120000_create_users.rb" 1 + let result = resultsFromMatches [match] + + railsSingleOkay result `shouldBe` True + + it "disallows service objects" $ do + let match = TermMatch "CreatePostWithNotifications" "app/services/create_post_with_notifications.rb" 1 + let result = resultsFromMatches [match] + + railsSingleOkay result `shouldBe` False + + it "disallows methods" $ do + let match = TermMatch "my_method" "app/services/create_post_with_notifications.rb" 1 + let result = resultsFromMatches [match] + + railsSingleOkay result `shouldBe` False + + describe "elixirSingleOkay" $ do + it "disallows controllers" $ do + let match = TermMatch "PageController" "web/controllers/page_controller.rb" 1 + let result = resultsFromMatches [match] + + elixirSingleOkay result `shouldBe` False + + it "allows views" $ do + let match = TermMatch "PageView" "web/views/page_view.rb" 1 + let result = resultsFromMatches [match] + + elixirSingleOkay result `shouldBe` True + + it "allows migrations" $ do + let match = TermMatch "CreateUsers" "priv/repo/migrations/20160101120000_create_users.exs" 1 + let result = resultsFromMatches [match] + + elixirSingleOkay result `shouldBe` True + + it "allows tests" $ do + let match = TermMatch "UserTest" "test/models/user_test.exs" 1 + let result = resultsFromMatches [match] + + elixirSingleOkay result `shouldBe` True + + + it "disallows service modules" $ do + let match = TermMatch "CreatePostWithNotifications" "web/services/create_post_with_notifications.ex" 1 + let result = resultsFromMatches [match] + + elixirSingleOkay result `shouldBe` False + + it "disallows functions" $ do + let match = TermMatch "my_function" "web/services/create_post_with_notifications.ex" 1 + let result = resultsFromMatches [match] + + elixirSingleOkay result `shouldBe` False diff --git a/test/Unused/TypesSpec.hs b/test/Unused/TypesSpec.hs new file mode 100644 index 0000000..71153f3 --- /dev/null +++ b/test/Unused/TypesSpec.hs @@ -0,0 +1,18 @@ +module Unused.TypesSpec where + +import Test.Hspec +import Unused.Types + +main :: IO () +main = hspec spec + +spec :: Spec +spec = parallel $ + describe "resultsFromMatches" $ + it "batches files together to calculate information" $ do + let matches = [ TermMatch "ApplicationController" "app/controllers/application_controller.rb" 1 + , TermMatch "ApplicationController" "spec/controllers/application_controller_spec.rb" 10 + ] + + resultsFromMatches matches `shouldBe` + TermResults "ApplicationController" matches 2 11 Unknown diff --git a/unused.cabal b/unused.cabal index 6e41a0d..68231a7 100644 --- a/unused.cabal +++ b/unused.cabal @@ -57,6 +57,11 @@ test-suite unused-test main-is: Spec.hs build-depends: base , unused + , hspec + , containers + other-modules: Unused.ParserSpec + , Unused.ResponseFilterSpec + , Unused.TypesSpec ghc-options: -threaded -rtsopts -with-rtsopts=-N -Wall -Werror default-language: Haskell2010