Write Grammar tests
parent
203205f53c
commit
b3e103a5d9
|
@ -1,6 +1,6 @@
|
||||||
module Internal.Grammar.ServerName exposing
|
module Internal.Grammar.ServerName exposing
|
||||||
( ServerName, toString, fromString
|
( ServerName, toString, fromString
|
||||||
, servernameParser
|
, serverNameParser
|
||||||
)
|
)
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
|
@ -83,9 +83,11 @@ dnsNameParser =
|
||||||
|> P.getChompedString
|
|> P.getChompedString
|
||||||
|
|
||||||
|
|
||||||
|
{-| Convert a string to a server name.
|
||||||
|
-}
|
||||||
fromString : String -> Maybe ServerName
|
fromString : String -> Maybe ServerName
|
||||||
fromString s =
|
fromString s =
|
||||||
P.run (servernameParser |. P.end) s
|
P.run (serverNameParser |. P.end) s
|
||||||
|> (\out ->
|
|> (\out ->
|
||||||
case out of
|
case out of
|
||||||
Ok _ ->
|
Ok _ ->
|
||||||
|
@ -212,8 +214,11 @@ portParser =
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
servernameParser : Parser ServerName
|
{-| Parse a server name. Generally used by other identifiers that have a server
|
||||||
servernameParser =
|
name as one of its parts.
|
||||||
|
-}
|
||||||
|
serverNameParser : Parser ServerName
|
||||||
|
serverNameParser =
|
||||||
P.succeed ServerName
|
P.succeed ServerName
|
||||||
|= hostnameParser
|
|= hostnameParser
|
||||||
|= P.oneOf
|
|= P.oneOf
|
||||||
|
@ -224,6 +229,8 @@ servernameParser =
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
{-| Convert a parsed server name back to a string.
|
||||||
|
-}
|
||||||
toString : ServerName -> String
|
toString : ServerName -> String
|
||||||
toString { host, port_ } =
|
toString { host, port_ } =
|
||||||
let
|
let
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
module Internal.Grammar.UserId exposing (..)
|
module Internal.Grammar.UserId exposing
|
||||||
|
( UserID, toString, fromString
|
||||||
|
, userIdParser, isHistorical
|
||||||
|
)
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
|
|
||||||
|
@ -36,6 +39,16 @@ localparts from the expanded character set:
|
||||||
|
|
||||||
extended_user_id_char = %x21-39 / %x3B-7E ; all ASCII printing chars except :
|
extended_user_id_char = %x21-39 / %x3B-7E ; all ASCII printing chars except :
|
||||||
|
|
||||||
|
|
||||||
|
## User ID
|
||||||
|
|
||||||
|
@docs UserID, toString, fromString
|
||||||
|
|
||||||
|
|
||||||
|
## Extra
|
||||||
|
|
||||||
|
@docs userIdParser, isHistorical
|
||||||
|
|
||||||
-}
|
-}
|
||||||
|
|
||||||
import Internal.Grammar.ServerName as ServerName exposing (ServerName)
|
import Internal.Grammar.ServerName as ServerName exposing (ServerName)
|
||||||
|
@ -43,13 +56,39 @@ import Internal.Tools.ParserExtra as PE
|
||||||
import Parser as P exposing ((|.), (|=), Parser)
|
import Parser as P exposing ((|.), (|=), Parser)
|
||||||
|
|
||||||
|
|
||||||
|
{-| The User ID type defining a user.
|
||||||
|
-}
|
||||||
type alias UserID =
|
type alias UserID =
|
||||||
{ localpart : String, domain : ServerName }
|
{ localpart : String, domain : ServerName }
|
||||||
|
|
||||||
|
|
||||||
|
{-| Convert a Matrix User ID back into its uniquely identifying string.
|
||||||
|
-}
|
||||||
fromString : String -> Maybe UserID
|
fromString : String -> Maybe UserID
|
||||||
fromString =
|
fromString =
|
||||||
P.run userIdParser >> Result.toMaybe
|
P.run (userIdParser |. P.end) >> Result.toMaybe
|
||||||
|
|
||||||
|
|
||||||
|
{-| Return a boolean on whether a Matrix user has a historical user ID.
|
||||||
|
Since this user ID is not SUPPOSED to be legal but clients are nevertheless
|
||||||
|
forced to support them due to backwards compatibility, clients may occasionally
|
||||||
|
attempt to break the rules in an attempt to find undefined behaviour.
|
||||||
|
|
||||||
|
As a result, an explicit method to spot historical users is added to the SDK.
|
||||||
|
|
||||||
|
-}
|
||||||
|
isHistorical : UserID -> Bool
|
||||||
|
isHistorical { localpart } =
|
||||||
|
String.any
|
||||||
|
(\c ->
|
||||||
|
let
|
||||||
|
i : Int
|
||||||
|
i =
|
||||||
|
Char.toCode c
|
||||||
|
in
|
||||||
|
not ((0x61 <= i && i <= 0x7A) || Char.isAlpha c)
|
||||||
|
)
|
||||||
|
localpart
|
||||||
|
|
||||||
|
|
||||||
localpartParser : Parser String
|
localpartParser : Parser String
|
||||||
|
@ -60,18 +99,23 @@ localpartParser =
|
||||||
|> P.map String.concat
|
|> P.map String.concat
|
||||||
|
|
||||||
|
|
||||||
|
{-| Convert a parsed User ID to a string.
|
||||||
|
-}
|
||||||
toString : UserID -> String
|
toString : UserID -> String
|
||||||
toString { localpart, domain } =
|
toString { localpart, domain } =
|
||||||
String.concat [ "@", localpart, ":", ServerName.toString domain ]
|
String.concat [ "@", localpart, ":", ServerName.toString domain ]
|
||||||
|
|
||||||
|
|
||||||
|
{-| Parse a UserID from a string.
|
||||||
|
-}
|
||||||
userIdParser : Parser UserID
|
userIdParser : Parser UserID
|
||||||
userIdParser =
|
userIdParser =
|
||||||
P.succeed UserID
|
P.succeed UserID
|
||||||
|. P.symbol "@"
|
|. P.symbol "@"
|
||||||
|= localpartParser
|
|= localpartParser
|
||||||
|. P.symbol ":"
|
|. P.symbol ":"
|
||||||
|= ServerName.servernameParser
|
|= ServerName.serverNameParser
|
||||||
|
|> PE.maxLength 255
|
||||||
|
|
||||||
|
|
||||||
validHistoricalUsernameChar : Char -> Bool
|
validHistoricalUsernameChar : Char -> Bool
|
||||||
|
|
|
@ -101,8 +101,7 @@ suite =
|
||||||
(\server ->
|
(\server ->
|
||||||
SN.fromString server
|
SN.fromString server
|
||||||
|> Maybe.map SN.toString
|
|> Maybe.map SN.toString
|
||||||
|> Maybe.map (String.replace "::" ":")
|
|> Expect.equal (Just server)
|
||||||
|> Expect.equal (Just <| String.replace "::" ":" server)
|
|
||||||
)
|
)
|
||||||
, test "Checking spec examples"
|
, test "Checking spec examples"
|
||||||
(\() ->
|
(\() ->
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
module Test.Grammar.UserId exposing (..)
|
||||||
|
|
||||||
|
import Expect
|
||||||
|
import Fuzz exposing (Fuzzer)
|
||||||
|
import Internal.Grammar.UserId as U
|
||||||
|
import Test exposing (..)
|
||||||
|
import Test.Grammar.ServerName as ServerName
|
||||||
|
|
||||||
|
|
||||||
|
modernUserCharFuzzer : Fuzzer Char
|
||||||
|
modernUserCharFuzzer =
|
||||||
|
Fuzz.oneOf
|
||||||
|
[ Fuzz.intRange 0x61 0x7A
|
||||||
|
|> Fuzz.map Char.fromCode
|
||||||
|
, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
|> String.toList
|
||||||
|
|> Fuzz.oneOfValues
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
historicalUserCharFuzzer : Fuzzer Char
|
||||||
|
historicalUserCharFuzzer =
|
||||||
|
[ ( 0x21, 0x39 ), ( 0x3B, 0x7E ) ]
|
||||||
|
|> List.map (\( low, high ) -> Fuzz.intRange low high)
|
||||||
|
|> Fuzz.oneOf
|
||||||
|
|> Fuzz.map Char.fromCode
|
||||||
|
|
||||||
|
|
||||||
|
modernUserFuzzer : Fuzzer String
|
||||||
|
modernUserFuzzer =
|
||||||
|
Fuzz.map2
|
||||||
|
(\localpart domain ->
|
||||||
|
let
|
||||||
|
maxLocalSize : Int
|
||||||
|
maxLocalSize =
|
||||||
|
255 - String.length domain - 2
|
||||||
|
in
|
||||||
|
localpart
|
||||||
|
|> List.take maxLocalSize
|
||||||
|
|> String.fromList
|
||||||
|
|> (\l -> "@" ++ l ++ ":" ++ domain)
|
||||||
|
)
|
||||||
|
(Fuzz.listOfLengthBetween 1 255 modernUserCharFuzzer)
|
||||||
|
(ServerName.serverNameFuzzer
|
||||||
|
|> Fuzz.filter
|
||||||
|
(\name ->
|
||||||
|
String.length name < 255 - 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
historicalUserFuzzer : Fuzzer String
|
||||||
|
historicalUserFuzzer =
|
||||||
|
Fuzz.map2
|
||||||
|
(\localpart domain ->
|
||||||
|
let
|
||||||
|
maxLocalSize : Int
|
||||||
|
maxLocalSize =
|
||||||
|
255 - String.length domain - 2
|
||||||
|
in
|
||||||
|
localpart
|
||||||
|
|> List.take maxLocalSize
|
||||||
|
|> String.fromList
|
||||||
|
|> (\l -> "@" ++ l ++ ":" ++ domain)
|
||||||
|
)
|
||||||
|
(Fuzz.listOfLengthBetween 1 255 historicalUserCharFuzzer)
|
||||||
|
(ServerName.serverNameFuzzer
|
||||||
|
|> Fuzz.filter
|
||||||
|
(\name ->
|
||||||
|
String.length name < 255 - 2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
userFuzzer : Fuzzer String
|
||||||
|
userFuzzer =
|
||||||
|
Fuzz.oneOf [ modernUserFuzzer, historicalUserFuzzer ]
|
||||||
|
|
||||||
|
|
||||||
|
suite : Test
|
||||||
|
suite =
|
||||||
|
describe "UserId"
|
||||||
|
[ describe "Size"
|
||||||
|
[ fuzz ServerName.serverNameFuzzer
|
||||||
|
"Username cannot be length 0"
|
||||||
|
(\domain ->
|
||||||
|
"@"
|
||||||
|
++ ":"
|
||||||
|
++ domain
|
||||||
|
|> U.fromString
|
||||||
|
|> Expect.equal Nothing
|
||||||
|
)
|
||||||
|
, fuzz2 (Fuzz.listOfLengthBetween 1 255 historicalUserCharFuzzer)
|
||||||
|
ServerName.serverNameFuzzer
|
||||||
|
"Username length cannot exceed 255"
|
||||||
|
(\localpart domain ->
|
||||||
|
let
|
||||||
|
username : String
|
||||||
|
username =
|
||||||
|
"@"
|
||||||
|
++ String.fromList localpart
|
||||||
|
++ ":"
|
||||||
|
++ domain
|
||||||
|
in
|
||||||
|
Expect.equal
|
||||||
|
(U.fromString username == Nothing)
|
||||||
|
(String.length username > 255)
|
||||||
|
)
|
||||||
|
, fuzz modernUserFuzzer
|
||||||
|
"Modern fuzzer has appropriate size"
|
||||||
|
(String.length >> Expect.lessThan 256)
|
||||||
|
, fuzz historicalUserFuzzer
|
||||||
|
"Historical fuzzer has appropriate size"
|
||||||
|
(String.length >> Expect.lessThan 256)
|
||||||
|
]
|
||||||
|
, describe "From string evaluation"
|
||||||
|
[ fuzz userFuzzer
|
||||||
|
"fromString always returns a value on fuzzer"
|
||||||
|
(U.fromString >> Expect.notEqual Nothing)
|
||||||
|
, fuzz userFuzzer
|
||||||
|
"fromString -> toString returns the same value"
|
||||||
|
(\username ->
|
||||||
|
username
|
||||||
|
|> U.fromString
|
||||||
|
|> Maybe.map U.toString
|
||||||
|
|> Expect.equal (Just username)
|
||||||
|
)
|
||||||
|
, fuzz historicalUserFuzzer
|
||||||
|
"Historical users are historical"
|
||||||
|
(\username ->
|
||||||
|
username
|
||||||
|
|> U.fromString
|
||||||
|
|> Maybe.map U.isHistorical
|
||||||
|
|> Expect.equal (Just True)
|
||||||
|
)
|
||||||
|
, fuzz modernUserFuzzer
|
||||||
|
"Modern users are not historical"
|
||||||
|
(\username ->
|
||||||
|
username
|
||||||
|
|> U.fromString
|
||||||
|
|> Maybe.map U.isHistorical
|
||||||
|
|> Expect.equal (Just False)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
]
|
Loading…
Reference in New Issue