From 8091654ab2575db9815acb118cb2844ea8e60288 Mon Sep 17 00:00:00 2001 From: Dario Bertini Date: Sat, 8 Oct 2016 16:10:59 +0100 Subject: [PATCH] Add tests for ToValidFunctionName --- servant-js/servant-js.cabal | 1 + servant-js/src/Servant/JS/Internal.hs | 10 ++++------ servant-js/test/Servant/JSSpec.hs | 20 ++++++++++++++++++++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/servant-js/servant-js.cabal b/servant-js/servant-js.cabal index d29dc96c..fd94bc03 100644 --- a/servant-js/servant-js.cabal +++ b/servant-js/servant-js.cabal @@ -93,4 +93,5 @@ test-suite spec , servant , servant-js , text + , QuickCheck default-language: Haskell2010 diff --git a/servant-js/src/Servant/JS/Internal.hs b/servant-js/src/Servant/JS/Internal.hs index 54fda12a..89155a2a 100644 --- a/servant-js/src/Servant/JS/Internal.hs +++ b/servant-js/src/Servant/JS/Internal.hs @@ -1,5 +1,4 @@ {-# LANGUAGE OverloadedStrings #-} -{-# LANGUAGE ViewPatterns #-} module Servant.JS.Internal ( JavaScriptGenerator @@ -116,12 +115,11 @@ toValidFunctionName t = setFirstChar x `T.cons` T.filter remainder xs Nothing -> "_" where - setFirstChar c = if firstChar c then c else '_' - firstChar c = prefixOK c || Set.member c firstLetterOK - remainder c = prefixOK c || Set.member c remainderOK - prefixOK c = c `elem` ['$','_'] + setFirstChar c = if Set.member c firstLetterOK then c else '_' + remainder c = Set.member c remainderOK firstLetterOK = (filterBmpChars $ mconcat - [ Set.lowercaseLetter + [ Set.fromDistinctAscList "$_" + , Set.lowercaseLetter , Set.uppercaseLetter , Set.titlecaseLetter , Set.modifierLetter diff --git a/servant-js/test/Servant/JSSpec.hs b/servant-js/test/Servant/JSSpec.hs index 5a53b00a..fc4504f5 100644 --- a/servant-js/test/Servant/JSSpec.hs +++ b/servant-js/test/Servant/JSSpec.hs @@ -15,10 +15,14 @@ import Data.Monoid.Compat ((<>)) import Data.Proxy import Data.Text (Text) import qualified Data.Text as T +import Language.ECMAScript3.Lexer (identifier) import Language.ECMAScript3.Parser (program, parse) import Prelude () import Prelude.Compat import Test.Hspec hiding (shouldContain, shouldNotContain) +import Test.QuickCheck (Arbitrary (..), + choose, listOf, + property) import Servant.API.Internal.Test.ComprehensiveAPI import Servant.API.ContentTypes @@ -97,6 +101,7 @@ spec = describe "Servant.JQuery" $ do angularSpec Angular axiosSpec --angularSpec AngularCustom + internalSpec shouldContain :: Text -> Text -> Expectation a `shouldContain` b = shouldSatisfy a (T.isInfixOf b) @@ -152,6 +157,21 @@ angularSpec test = describe specLabel $ do ngOpts = NG.defAngularOptions { NG.serviceName = testName } genJS req = NG.angularService ngOpts req +instance Arbitrary T.Text where + -- Our arbitrary instance is generating only ASCII, since language-ecmascript lexer + -- is currently (October 2016) still a bit naïve + arbitrary = fmap T.pack $ listOf $ choose (minBound, '\127') + shrink xs = T.pack <$> shrink (T.unpack xs) + +internalSpec :: Spec +internalSpec = describe "Internal" $ do + it "should generate only valid javascript identifiers for any ASCII route" $ do + let parseIdentifier = fmap (T.pack . filter (< '\65536')) . parse identifier "" + property $ \x -> let valid = toValidFunctionName x in + Right valid == parseIdentifier valid + it "should generate a valid javascript identifier when supplied with hyphens, unicode whitespace, non-bmp unicode" $ do + toValidFunctionName "a_--a\66352b\6158c\65075" `shouldBe` "a_abc\65075" + generateJSSpec :: TestNames -> (AjaxReq -> Text) -> Spec generateJSSpec n gen = describe specLabel $ do let parseFromText = parse program ""