Write Grammar tests
parent
203205f53c
commit
b3e103a5d9
|
@ -1,6 +1,6 @@
|
|||
module Internal.Grammar.ServerName exposing
|
||||
( ServerName, toString, fromString
|
||||
, servernameParser
|
||||
, serverNameParser
|
||||
)
|
||||
|
||||
{-|
|
||||
|
@ -83,9 +83,11 @@ dnsNameParser =
|
|||
|> P.getChompedString
|
||||
|
||||
|
||||
{-| Convert a string to a server name.
|
||||
-}
|
||||
fromString : String -> Maybe ServerName
|
||||
fromString s =
|
||||
P.run (servernameParser |. P.end) s
|
||||
P.run (serverNameParser |. P.end) s
|
||||
|> (\out ->
|
||||
case out of
|
||||
Ok _ ->
|
||||
|
@ -212,8 +214,11 @@ portParser =
|
|||
)
|
||||
|
||||
|
||||
servernameParser : Parser ServerName
|
||||
servernameParser =
|
||||
{-| Parse a server name. Generally used by other identifiers that have a server
|
||||
name as one of its parts.
|
||||
-}
|
||||
serverNameParser : Parser ServerName
|
||||
serverNameParser =
|
||||
P.succeed ServerName
|
||||
|= hostnameParser
|
||||
|= P.oneOf
|
||||
|
@ -224,6 +229,8 @@ servernameParser =
|
|||
]
|
||||
|
||||
|
||||
{-| Convert a parsed server name back to a string.
|
||||
-}
|
||||
toString : ServerName -> String
|
||||
toString { host, port_ } =
|
||||
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 :
|
||||
|
||||
|
||||
## User ID
|
||||
|
||||
@docs UserID, toString, fromString
|
||||
|
||||
|
||||
## Extra
|
||||
|
||||
@docs userIdParser, isHistorical
|
||||
|
||||
-}
|
||||
|
||||
import Internal.Grammar.ServerName as ServerName exposing (ServerName)
|
||||
|
@ -43,13 +56,39 @@ import Internal.Tools.ParserExtra as PE
|
|||
import Parser as P exposing ((|.), (|=), Parser)
|
||||
|
||||
|
||||
{-| The User ID type defining a user.
|
||||
-}
|
||||
type alias UserID =
|
||||
{ localpart : String, domain : ServerName }
|
||||
|
||||
|
||||
{-| Convert a Matrix User ID back into its uniquely identifying string.
|
||||
-}
|
||||
fromString : String -> Maybe UserID
|
||||
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
|
||||
|
@ -60,18 +99,23 @@ localpartParser =
|
|||
|> P.map String.concat
|
||||
|
||||
|
||||
{-| Convert a parsed User ID to a string.
|
||||
-}
|
||||
toString : UserID -> String
|
||||
toString { localpart, domain } =
|
||||
String.concat [ "@", localpart, ":", ServerName.toString domain ]
|
||||
|
||||
|
||||
{-| Parse a UserID from a string.
|
||||
-}
|
||||
userIdParser : Parser UserID
|
||||
userIdParser =
|
||||
P.succeed UserID
|
||||
|. P.symbol "@"
|
||||
|= localpartParser
|
||||
|. P.symbol ":"
|
||||
|= ServerName.servernameParser
|
||||
|= ServerName.serverNameParser
|
||||
|> PE.maxLength 255
|
||||
|
||||
|
||||
validHistoricalUsernameChar : Char -> Bool
|
||||
|
|
|
@ -101,8 +101,7 @@ suite =
|
|||
(\server ->
|
||||
SN.fromString server
|
||||
|> Maybe.map SN.toString
|
||||
|> Maybe.map (String.replace "::" ":")
|
||||
|> Expect.equal (Just <| String.replace "::" ":" server)
|
||||
|> Expect.equal (Just server)
|
||||
)
|
||||
, 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