Add subsetOf Filter function
parent
3739043f87
commit
e8ee125def
|
@ -3,6 +3,7 @@ module Internal.Filter.Timeline exposing
|
||||||
, pass, onlySenders, allSendersExcept, onlyTypes, allTypesExcept, fail
|
, pass, onlySenders, allSendersExcept, onlyTypes, allTypesExcept, fail
|
||||||
, match, run
|
, match, run
|
||||||
, and
|
, and
|
||||||
|
, subsetOf
|
||||||
)
|
)
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
|
@ -33,6 +34,11 @@ for interacting with the Matrix API.
|
||||||
|
|
||||||
@docs and
|
@docs and
|
||||||
|
|
||||||
|
|
||||||
|
## Compare
|
||||||
|
|
||||||
|
@docs subsetOf
|
||||||
|
|
||||||
-}
|
-}
|
||||||
|
|
||||||
import Set exposing (Set)
|
import Set exposing (Set)
|
||||||
|
@ -132,15 +138,15 @@ and (Filter f1) (Filter f2) =
|
||||||
|
|
||||||
( False, False ) ->
|
( False, False ) ->
|
||||||
Set.intersect f1.types f2.types
|
Set.intersect f1.types f2.types
|
||||||
, typesAllowOthers = f2.typesAllowOthers && f2.typesAllowOthers
|
, typesAllowOthers = f1.typesAllowOthers && f2.typesAllowOthers
|
||||||
}
|
}
|
||||||
in
|
in
|
||||||
case stdAnd of
|
case stdAnd of
|
||||||
Filter f ->
|
Filter f ->
|
||||||
if Set.isEmpty f.senders && (not f.sendersAllowOthers) then
|
if Set.isEmpty f.senders && not f.sendersAllowOthers then
|
||||||
fail
|
fail
|
||||||
|
|
||||||
else if Set.isEmpty f.types && (not f.typesAllowOthers) then
|
else if Set.isEmpty f.types && not f.typesAllowOthers then
|
||||||
fail
|
fail
|
||||||
|
|
||||||
else
|
else
|
||||||
|
@ -235,3 +241,36 @@ pass =
|
||||||
run : Filter -> List (Event a) -> List (Event a)
|
run : Filter -> List (Event a) -> List (Event a)
|
||||||
run f events =
|
run f events =
|
||||||
List.filter (match f) events
|
List.filter (match f) events
|
||||||
|
|
||||||
|
|
||||||
|
{-| Determine whether the second argument is a subset filter of the first
|
||||||
|
argument.
|
||||||
|
-}
|
||||||
|
subsetOf : Filter -> Filter -> Bool
|
||||||
|
subsetOf (Filter big) (Filter small) =
|
||||||
|
let
|
||||||
|
isSSof : Set String -> Set String -> Bool
|
||||||
|
isSSof b s =
|
||||||
|
Set.intersect b s == s
|
||||||
|
|
||||||
|
isSubsetFor : ( Bool, Set String ) -> ( Bool, Set String ) -> Bool
|
||||||
|
isSubsetFor ( bb, sb ) ( bs, ss ) =
|
||||||
|
case ( bb, bs ) of
|
||||||
|
( True, True ) ->
|
||||||
|
isSSof ss sb
|
||||||
|
|
||||||
|
( True, False ) ->
|
||||||
|
Set.isEmpty (Set.intersect sb ss)
|
||||||
|
|
||||||
|
( False, True ) ->
|
||||||
|
False
|
||||||
|
|
||||||
|
( False, False ) ->
|
||||||
|
isSSof sb ss
|
||||||
|
in
|
||||||
|
isSubsetFor
|
||||||
|
( big.sendersAllowOthers, big.senders )
|
||||||
|
( small.sendersAllowOthers, small.senders )
|
||||||
|
&& isSubsetFor
|
||||||
|
( big.typesAllowOthers, big.types )
|
||||||
|
( small.typesAllowOthers, small.types )
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
module Internal.Values.Event exposing
|
module Internal.Values.Event exposing
|
||||||
( Event
|
( Event
|
||||||
, UnsignedData(..), age, prevContent, redactedBecause, transactionId
|
, UnsignedData(..), age, prevContent, redactedBecause, transactionId
|
||||||
, encode, decoder, isEqual
|
, encode, decoder
|
||||||
|
, isEqual
|
||||||
)
|
)
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
|
@ -24,6 +25,7 @@ of a room.
|
||||||
|
|
||||||
@docs encode, decoder
|
@docs encode, decoder
|
||||||
|
|
||||||
|
|
||||||
## Test functions
|
## Test functions
|
||||||
|
|
||||||
@docs isEqual
|
@docs isEqual
|
||||||
|
@ -133,48 +135,58 @@ isEqual : Event -> Event -> Bool
|
||||||
isEqual e1 e2 =
|
isEqual e1 e2 =
|
||||||
if e1.eventId /= e2.eventId then
|
if e1.eventId /= e2.eventId then
|
||||||
False
|
False
|
||||||
|
|
||||||
else if e1.originServerTs /= e2.originServerTs then
|
else if e1.originServerTs /= e2.originServerTs then
|
||||||
False
|
False
|
||||||
|
|
||||||
else if e1.roomId /= e2.roomId then
|
else if e1.roomId /= e2.roomId then
|
||||||
False
|
False
|
||||||
|
|
||||||
else if e1.sender /= e2.sender then
|
else if e1.sender /= e2.sender then
|
||||||
False
|
False
|
||||||
|
|
||||||
else if e1.stateKey /= e2.stateKey then
|
else if e1.stateKey /= e2.stateKey then
|
||||||
False
|
False
|
||||||
|
|
||||||
else if e1.eventType /= e2.eventType then
|
else if e1.eventType /= e2.eventType then
|
||||||
False
|
False
|
||||||
|
|
||||||
else
|
else
|
||||||
case (e1.unsigned, e2.unsigned) of
|
case ( e1.unsigned, e2.unsigned ) of
|
||||||
( Nothing, Nothing ) ->
|
( Nothing, Nothing ) ->
|
||||||
True
|
True
|
||||||
|
|
||||||
( Just _, Nothing ) ->
|
( Just _, Nothing ) ->
|
||||||
False
|
False
|
||||||
|
|
||||||
( Nothing, Just _ ) ->
|
( Nothing, Just _ ) ->
|
||||||
False
|
False
|
||||||
|
|
||||||
( Just ( UnsignedData d1), Just ( UnsignedData d2 )) ->
|
( Just (UnsignedData d1), Just (UnsignedData d2) ) ->
|
||||||
if d1.age /= d2.age then
|
if d1.age /= d2.age then
|
||||||
False
|
False
|
||||||
|
|
||||||
else if d1.transactionId /= d2.transactionId then
|
else if d1.transactionId /= d2.transactionId then
|
||||||
False
|
False
|
||||||
|
|
||||||
else if Maybe.map (E.encode 0) d1.prevContent /= Maybe.map (E.encode 0) d2.prevContent then
|
else if Maybe.map (E.encode 0) d1.prevContent /= Maybe.map (E.encode 0) d2.prevContent then
|
||||||
False
|
False
|
||||||
|
|
||||||
else
|
else
|
||||||
case (d1.redactedBecause, d2.redactedBecause) of
|
case ( d1.redactedBecause, d2.redactedBecause ) of
|
||||||
( Nothing, Nothing) ->
|
( Nothing, Nothing ) ->
|
||||||
True
|
True
|
||||||
|
|
||||||
( Nothing, Just _ ) ->
|
( Nothing, Just _ ) ->
|
||||||
False
|
False
|
||||||
|
|
||||||
( Just _, Nothing ) ->
|
( Just _, Nothing ) ->
|
||||||
False
|
False
|
||||||
|
|
||||||
( Just se1, Just se2 ) ->
|
( Just se1, Just se2 ) ->
|
||||||
isEqual se1 se2
|
isEqual se1 se2
|
||||||
|
|
||||||
|
|
||||||
{-| Determine the previous `content` value for this event. This field is only a
|
{-| Determine the previous `content` value for this event. This field is only a
|
||||||
`Just value` if the event is a state event, and the Matrix Vault has permission
|
`Just value` if the event is a state event, and the Matrix Vault has permission
|
||||||
to see the previous content.
|
to see the previous content.
|
||||||
|
|
|
@ -4,6 +4,7 @@ import Expect
|
||||||
import Fuzz exposing (Fuzzer)
|
import Fuzz exposing (Fuzzer)
|
||||||
import Internal.Filter.Timeline as Filter exposing (Filter)
|
import Internal.Filter.Timeline as Filter exposing (Filter)
|
||||||
import Internal.Values.Event as Event
|
import Internal.Values.Event as Event
|
||||||
|
import Set
|
||||||
import Test exposing (..)
|
import Test exposing (..)
|
||||||
import Test.Values.Event as TestEvent
|
import Test.Values.Event as TestEvent
|
||||||
|
|
||||||
|
@ -138,6 +139,138 @@ suite =
|
||||||
|> Filter.and (Filter.allTypesExcept types)
|
|> Filter.and (Filter.allTypesExcept types)
|
||||||
|> Expect.equal Filter.fail
|
|> Expect.equal Filter.fail
|
||||||
)
|
)
|
||||||
|
, fuzz2 (Fuzz.list Fuzz.string)
|
||||||
|
(Fuzz.list Fuzz.string)
|
||||||
|
"Only list + all except list = common types"
|
||||||
|
(\t1 t2 ->
|
||||||
|
Expect.equal
|
||||||
|
(Filter.and
|
||||||
|
(Filter.onlyTypes t1)
|
||||||
|
(Filter.allTypesExcept t2)
|
||||||
|
)
|
||||||
|
(Set.diff (Set.fromList t1) (Set.fromList t2)
|
||||||
|
|> Set.toList
|
||||||
|
|> Filter.onlyTypes
|
||||||
|
)
|
||||||
|
)
|
||||||
|
, fuzz2 (Fuzz.list Fuzz.string)
|
||||||
|
(Fuzz.list Fuzz.string)
|
||||||
|
"Only list + all except list = common senders"
|
||||||
|
(\t1 t2 ->
|
||||||
|
Expect.equal
|
||||||
|
(Filter.and
|
||||||
|
(Filter.onlySenders t1)
|
||||||
|
(Filter.allSendersExcept t2)
|
||||||
|
)
|
||||||
|
(Set.diff (Set.fromList t1) (Set.fromList t2)
|
||||||
|
|> Set.toList
|
||||||
|
|> Filter.onlySenders
|
||||||
|
)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
, describe "Subset testing"
|
||||||
|
[ fuzz2 fuzzer
|
||||||
|
fuzzer
|
||||||
|
"Combining two filters is always a subset"
|
||||||
|
(\filter1 filter2 ->
|
||||||
|
filter1
|
||||||
|
|> Filter.and filter2
|
||||||
|
|> Expect.all
|
||||||
|
[ Filter.subsetOf filter1 >> Expect.equal True
|
||||||
|
, Filter.subsetOf filter2 >> Expect.equal True
|
||||||
|
]
|
||||||
|
)
|
||||||
|
, fuzz
|
||||||
|
(Fuzz.bool
|
||||||
|
|> Fuzz.andThen
|
||||||
|
(\same ->
|
||||||
|
if same then
|
||||||
|
Fuzz.map (\a -> ( a, a )) fuzzer
|
||||||
|
|
||||||
|
else
|
||||||
|
Fuzz.map2 Tuple.pair fuzzer fuzzer
|
||||||
|
)
|
||||||
|
)
|
||||||
|
"subset goes both way iff equal"
|
||||||
|
(\( filter1, filter2 ) ->
|
||||||
|
Expect.equal
|
||||||
|
(filter1 == filter2)
|
||||||
|
(Filter.subsetOf filter1 filter2
|
||||||
|
&& Filter.subsetOf filter2 filter1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
, fuzz2 Fuzz.string
|
||||||
|
(Fuzz.list Fuzz.string)
|
||||||
|
"One more excluded sender is a subset"
|
||||||
|
(\head tail ->
|
||||||
|
Filter.allSendersExcept (head :: tail)
|
||||||
|
|> Filter.subsetOf (Filter.allSendersExcept tail)
|
||||||
|
|> Expect.equal True
|
||||||
|
)
|
||||||
|
, fuzz2 Fuzz.string
|
||||||
|
(Fuzz.list Fuzz.string)
|
||||||
|
"One more excluded type is a subset"
|
||||||
|
(\head tail ->
|
||||||
|
Filter.allTypesExcept (head :: tail)
|
||||||
|
|> Filter.subsetOf (Filter.allTypesExcept tail)
|
||||||
|
|> Expect.equal True
|
||||||
|
)
|
||||||
|
, fuzz2 Fuzz.string
|
||||||
|
(Fuzz.list Fuzz.string)
|
||||||
|
"One less included sender is a subset"
|
||||||
|
(\head tail ->
|
||||||
|
Filter.onlySenders tail
|
||||||
|
|> Filter.subsetOf (Filter.onlySenders (head :: tail))
|
||||||
|
|> Expect.equal True
|
||||||
|
)
|
||||||
|
, fuzz2 Fuzz.string
|
||||||
|
(Fuzz.list Fuzz.string)
|
||||||
|
"One less included type is a subset"
|
||||||
|
(\head tail ->
|
||||||
|
Filter.onlyTypes tail
|
||||||
|
|> Filter.subsetOf (Filter.onlyTypes (head :: tail))
|
||||||
|
|> Expect.equal True
|
||||||
|
)
|
||||||
|
, fuzz3 Fuzz.string
|
||||||
|
(Fuzz.list Fuzz.string)
|
||||||
|
fuzzer
|
||||||
|
"One more excluded sender is a subset - even when combined with another fuzzer"
|
||||||
|
(\head tail filter ->
|
||||||
|
Filter.allSendersExcept (head :: tail)
|
||||||
|
|> Filter.and filter
|
||||||
|
|> Filter.subsetOf (Filter.and filter <| Filter.allSendersExcept tail)
|
||||||
|
|> Expect.equal True
|
||||||
|
)
|
||||||
|
, fuzz3 Fuzz.string
|
||||||
|
(Fuzz.list Fuzz.string)
|
||||||
|
fuzzer
|
||||||
|
"One more excluded type is a subset - even when combined with another fuzzer"
|
||||||
|
(\head tail filter ->
|
||||||
|
Filter.allTypesExcept (head :: tail)
|
||||||
|
|> Filter.and filter
|
||||||
|
|> Filter.subsetOf (Filter.and filter <| Filter.allTypesExcept tail)
|
||||||
|
|> Expect.equal True
|
||||||
|
)
|
||||||
|
, fuzz3 Fuzz.string
|
||||||
|
(Fuzz.list Fuzz.string)
|
||||||
|
fuzzer
|
||||||
|
"One less included sender is a subset - even when combined with another fuzzer"
|
||||||
|
(\head tail filter ->
|
||||||
|
Filter.onlySenders tail
|
||||||
|
|> Filter.and filter
|
||||||
|
|> Filter.subsetOf (Filter.and filter <| Filter.onlySenders (head :: tail))
|
||||||
|
|> Expect.equal True
|
||||||
|
)
|
||||||
|
, fuzz3 Fuzz.string
|
||||||
|
(Fuzz.list Fuzz.string)
|
||||||
|
fuzzer
|
||||||
|
"One less included type is a subset - even when combined with another fuzzer"
|
||||||
|
(\head tail filter ->
|
||||||
|
Filter.onlyTypes tail
|
||||||
|
|> Filter.and filter
|
||||||
|
|> Filter.subsetOf (Filter.and filter <| Filter.onlyTypes (head :: tail))
|
||||||
|
|> Expect.equal True
|
||||||
|
)
|
||||||
]
|
]
|
||||||
, describe "Use case testing"
|
, describe "Use case testing"
|
||||||
[ fuzz3 (Fuzz.list TestEvent.fuzzer)
|
[ fuzz3 (Fuzz.list TestEvent.fuzzer)
|
||||||
|
@ -150,30 +283,29 @@ suite =
|
||||||
l1 =
|
l1 =
|
||||||
events
|
events
|
||||||
|> Filter.run
|
|> Filter.run
|
||||||
( Filter.and
|
(Filter.and
|
||||||
( Filter.onlySenders senders )
|
(Filter.onlySenders senders)
|
||||||
( Filter.onlyTypes types )
|
(Filter.onlyTypes types)
|
||||||
)
|
)
|
||||||
|
|
||||||
l2 : List Event.Event
|
l2 : List Event.Event
|
||||||
l2 =
|
l2 =
|
||||||
( List.filter
|
List.filter
|
||||||
(\e ->
|
(\e ->
|
||||||
(List.member e.sender senders) &&
|
List.member e.sender senders
|
||||||
(List.member e.eventType types)
|
&& List.member e.eventType types
|
||||||
)
|
)
|
||||||
events
|
events
|
||||||
)
|
|
||||||
in
|
in
|
||||||
Expect.all
|
Expect.all
|
||||||
[ Expect.equal (List.length l1) (List.length l2)
|
[ Expect.equal (List.length l1) (List.length l2)
|
||||||
|> always
|
|> always
|
||||||
, List.map2 Event.isEqual l1 l2
|
, List.map2 Event.isEqual l1 l2
|
||||||
|> List.all identity
|
|> List.all identity
|
||||||
|> Expect.equal True
|
|> Expect.equal True
|
||||||
|> always
|
|> always
|
||||||
]
|
]
|
||||||
()
|
()
|
||||||
)
|
)
|
||||||
, fuzz3 (Fuzz.list TestEvent.fuzzer)
|
, fuzz3 (Fuzz.list TestEvent.fuzzer)
|
||||||
(Fuzz.list Fuzz.string)
|
(Fuzz.list Fuzz.string)
|
||||||
|
@ -185,30 +317,29 @@ suite =
|
||||||
l1 =
|
l1 =
|
||||||
events
|
events
|
||||||
|> Filter.run
|
|> Filter.run
|
||||||
( Filter.and
|
(Filter.and
|
||||||
( Filter.onlySenders senders )
|
(Filter.onlySenders senders)
|
||||||
( Filter.allTypesExcept types )
|
(Filter.allTypesExcept types)
|
||||||
)
|
)
|
||||||
|
|
||||||
l2 : List Event.Event
|
l2 : List Event.Event
|
||||||
l2 =
|
l2 =
|
||||||
( List.filter
|
List.filter
|
||||||
(\e ->
|
(\e ->
|
||||||
(List.member e.sender senders) &&
|
List.member e.sender senders
|
||||||
(not <| List.member e.eventType types)
|
&& (not <| List.member e.eventType types)
|
||||||
)
|
)
|
||||||
events
|
events
|
||||||
)
|
|
||||||
in
|
in
|
||||||
Expect.all
|
Expect.all
|
||||||
[ Expect.equal (List.length l1) (List.length l2)
|
[ Expect.equal (List.length l1) (List.length l2)
|
||||||
|> always
|
|> always
|
||||||
, List.map2 Event.isEqual l1 l2
|
, List.map2 Event.isEqual l1 l2
|
||||||
|> List.all identity
|
|> List.all identity
|
||||||
|> Expect.equal True
|
|> Expect.equal True
|
||||||
|> always
|
|> always
|
||||||
]
|
]
|
||||||
()
|
()
|
||||||
)
|
)
|
||||||
, fuzz3 (Fuzz.list TestEvent.fuzzer)
|
, fuzz3 (Fuzz.list TestEvent.fuzzer)
|
||||||
(Fuzz.list Fuzz.string)
|
(Fuzz.list Fuzz.string)
|
||||||
|
@ -220,30 +351,29 @@ suite =
|
||||||
l1 =
|
l1 =
|
||||||
events
|
events
|
||||||
|> Filter.run
|
|> Filter.run
|
||||||
( Filter.and
|
(Filter.and
|
||||||
( Filter.allSendersExcept senders )
|
(Filter.allSendersExcept senders)
|
||||||
( Filter.onlyTypes types )
|
(Filter.onlyTypes types)
|
||||||
)
|
)
|
||||||
|
|
||||||
l2 : List Event.Event
|
l2 : List Event.Event
|
||||||
l2 =
|
l2 =
|
||||||
( List.filter
|
List.filter
|
||||||
(\e ->
|
(\e ->
|
||||||
(not <| List.member e.sender senders) &&
|
(not <| List.member e.sender senders)
|
||||||
(List.member e.eventType types)
|
&& List.member e.eventType types
|
||||||
)
|
)
|
||||||
events
|
events
|
||||||
)
|
|
||||||
in
|
in
|
||||||
Expect.all
|
Expect.all
|
||||||
[ Expect.equal (List.length l1) (List.length l2)
|
[ Expect.equal (List.length l1) (List.length l2)
|
||||||
|> always
|
|> always
|
||||||
, List.map2 Event.isEqual l1 l2
|
, List.map2 Event.isEqual l1 l2
|
||||||
|> List.all identity
|
|> List.all identity
|
||||||
|> Expect.equal True
|
|> Expect.equal True
|
||||||
|> always
|
|> always
|
||||||
]
|
]
|
||||||
()
|
()
|
||||||
)
|
)
|
||||||
, fuzz3 (Fuzz.list TestEvent.fuzzer)
|
, fuzz3 (Fuzz.list TestEvent.fuzzer)
|
||||||
(Fuzz.list Fuzz.string)
|
(Fuzz.list Fuzz.string)
|
||||||
|
@ -255,30 +385,29 @@ suite =
|
||||||
l1 =
|
l1 =
|
||||||
events
|
events
|
||||||
|> Filter.run
|
|> Filter.run
|
||||||
( Filter.and
|
(Filter.and
|
||||||
( Filter.allSendersExcept senders )
|
(Filter.allSendersExcept senders)
|
||||||
( Filter.allTypesExcept types )
|
(Filter.allTypesExcept types)
|
||||||
)
|
)
|
||||||
|
|
||||||
l2 : List Event.Event
|
l2 : List Event.Event
|
||||||
l2 =
|
l2 =
|
||||||
( List.filter
|
List.filter
|
||||||
(\e ->
|
(\e ->
|
||||||
(not <| List.member e.sender senders) &&
|
(not <| List.member e.sender senders)
|
||||||
(not <| List.member e.eventType types)
|
&& (not <| List.member e.eventType types)
|
||||||
)
|
)
|
||||||
events
|
events
|
||||||
)
|
|
||||||
in
|
in
|
||||||
Expect.all
|
Expect.all
|
||||||
[ Expect.equal (List.length l1) (List.length l2)
|
[ Expect.equal (List.length l1) (List.length l2)
|
||||||
|> always
|
|> always
|
||||||
, List.map2 Event.isEqual l1 l2
|
, List.map2 Event.isEqual l1 l2
|
||||||
|> List.all identity
|
|> List.all identity
|
||||||
|> Expect.equal True
|
|> Expect.equal True
|
||||||
|> always
|
|> always
|
||||||
]
|
]
|
||||||
()
|
()
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
module Test.Values.Event exposing (..)
|
module Test.Values.Event exposing (..)
|
||||||
|
|
||||||
|
import Expect
|
||||||
import Fuzz exposing (Fuzzer)
|
import Fuzz exposing (Fuzzer)
|
||||||
import Internal.Values.Event as Event exposing (Event)
|
import Internal.Values.Event as Event exposing (Event)
|
||||||
import Json.Encode as E
|
import Json.Encode as E
|
||||||
import Test exposing (..)
|
import Test exposing (..)
|
||||||
import Test.Tools.Timestamp as TestTimestamp
|
import Test.Tools.Timestamp as TestTimestamp
|
||||||
import Expect
|
|
||||||
|
|
||||||
|
|
||||||
fuzzer : Fuzzer Event
|
fuzzer : Fuzzer Event
|
||||||
|
@ -67,10 +67,12 @@ valueFuzzer =
|
||||||
, Fuzz.map Event.encode (Fuzz.lazy (\_ -> fuzzer))
|
, Fuzz.map Event.encode (Fuzz.lazy (\_ -> fuzzer))
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
suite : Test
|
suite : Test
|
||||||
suite =
|
suite =
|
||||||
describe "Sanity check"
|
describe "Sanity check"
|
||||||
[ fuzz fuzzer "event = event"
|
[ fuzz fuzzer
|
||||||
|
"event = event"
|
||||||
(\event ->
|
(\event ->
|
||||||
Event.isEqual event event
|
Event.isEqual event event
|
||||||
|> Expect.equal True
|
|> Expect.equal True
|
||||||
|
|
Loading…
Reference in New Issue