Compare commits
No commits in common. "2f7a247dbd9e4c54bccd95c10bef2becbbe3f7a9" and "79aff7af3bf52e909ff8c0e99a278bc58374fcd5" have entirely different histories.
2f7a247dbd
...
79aff7af3b
2
elm.json
2
elm.json
|
@ -11,7 +11,6 @@
|
||||||
"Internal.Config.Default",
|
"Internal.Config.Default",
|
||||||
"Internal.Config.Leaks",
|
"Internal.Config.Leaks",
|
||||||
"Internal.Config.Text",
|
"Internal.Config.Text",
|
||||||
"Internal.Filter.Timeline",
|
|
||||||
"Internal.Tools.Decode",
|
"Internal.Tools.Decode",
|
||||||
"Internal.Tools.Encode",
|
"Internal.Tools.Encode",
|
||||||
"Internal.Tools.Hashdict",
|
"Internal.Tools.Hashdict",
|
||||||
|
@ -24,7 +23,6 @@
|
||||||
"Internal.Values.Event",
|
"Internal.Values.Event",
|
||||||
"Internal.Values.Settings",
|
"Internal.Values.Settings",
|
||||||
"Internal.Values.StateManager",
|
"Internal.Values.StateManager",
|
||||||
"Internal.Values.Timeline",
|
|
||||||
"Internal.Values.Vault",
|
"Internal.Values.Vault",
|
||||||
"Types"
|
"Types"
|
||||||
],
|
],
|
||||||
|
|
|
@ -4,7 +4,6 @@ module Internal.Filter.Timeline exposing
|
||||||
, match, run
|
, match, run
|
||||||
, and
|
, and
|
||||||
, subsetOf
|
, subsetOf
|
||||||
, encode, decoder
|
|
||||||
)
|
)
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
|
@ -40,16 +39,10 @@ for interacting with the Matrix API.
|
||||||
|
|
||||||
@docs subsetOf
|
@docs subsetOf
|
||||||
|
|
||||||
|
|
||||||
## JSON coders
|
|
||||||
|
|
||||||
@docs encode, decoder
|
|
||||||
|
|
||||||
-}
|
-}
|
||||||
|
|
||||||
import Json.Decode as D
|
|
||||||
import Json.Encode as E
|
|
||||||
import Set exposing (Set)
|
import Set exposing (Set)
|
||||||
|
import Task exposing (fail)
|
||||||
|
|
||||||
|
|
||||||
{-| Placeholder Event type so the real Event doesn't need to be imported.
|
{-| Placeholder Event type so the real Event doesn't need to be imported.
|
||||||
|
@ -160,45 +153,6 @@ and (Filter f1) (Filter f2) =
|
||||||
stdAnd
|
stdAnd
|
||||||
|
|
||||||
|
|
||||||
{-| Decode a Filter from a JSON value.
|
|
||||||
-}
|
|
||||||
decoder : D.Decoder Filter
|
|
||||||
decoder =
|
|
||||||
D.map4
|
|
||||||
(\s sb t tb ->
|
|
||||||
Filter
|
|
||||||
{ senders = s
|
|
||||||
, sendersAllowOthers = sb
|
|
||||||
, types = t
|
|
||||||
, typesAllowOthers = tb
|
|
||||||
}
|
|
||||||
)
|
|
||||||
(D.string
|
|
||||||
|> D.list
|
|
||||||
|> D.map Set.fromList
|
|
||||||
|> D.field "senders"
|
|
||||||
)
|
|
||||||
(D.field "sendersAllowOthers" D.bool)
|
|
||||||
(D.string
|
|
||||||
|> D.list
|
|
||||||
|> D.map Set.fromList
|
|
||||||
|> D.field "types"
|
|
||||||
)
|
|
||||||
(D.field "typesAllowOthers" D.bool)
|
|
||||||
|
|
||||||
|
|
||||||
{-| Encode a Filter into a JSON value.
|
|
||||||
-}
|
|
||||||
encode : Filter -> E.Value
|
|
||||||
encode (Filter f) =
|
|
||||||
E.object
|
|
||||||
[ ( "senders", E.set E.string f.senders )
|
|
||||||
, ( "sendersAllowOthers", E.bool f.sendersAllowOthers )
|
|
||||||
, ( "types", E.set E.string f.types )
|
|
||||||
, ( "typesAllowOthers", E.bool f.typesAllowOthers )
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
{-| Allow no events. This filter is likely quite useless in practice, but it is
|
{-| Allow no events. This filter is likely quite useless in practice, but it is
|
||||||
used in the test environment for sanity checks and comparisons.
|
used in the test environment for sanity checks and comparisons.
|
||||||
-}
|
-}
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
module Internal.Values.Timeline exposing
|
module Internal.Values.Timeline exposing
|
||||||
( Batch, Timeline
|
( Batch, fromToken, fromSlice
|
||||||
|
, Timeline
|
||||||
, empty, singleton
|
, empty, singleton
|
||||||
, mostRecentEvents
|
, mostRecentEvents
|
||||||
, addSync, insert
|
, addSync, insert
|
||||||
, encode, decoder
|
|
||||||
)
|
)
|
||||||
|
|
||||||
{-|
|
{-|
|
||||||
|
@ -19,7 +19,12 @@ and maintain this room state.
|
||||||
|
|
||||||
## Batch
|
## Batch
|
||||||
|
|
||||||
@docs Batch, Timeline
|
@docs Batch, fromToken, fromSlice
|
||||||
|
|
||||||
|
|
||||||
|
## Timeline
|
||||||
|
|
||||||
|
@docs Timeline
|
||||||
|
|
||||||
|
|
||||||
## Create
|
## Create
|
||||||
|
@ -36,19 +41,12 @@ and maintain this room state.
|
||||||
|
|
||||||
@docs addSync, insert
|
@docs addSync, insert
|
||||||
|
|
||||||
|
|
||||||
## JSON coder
|
|
||||||
|
|
||||||
@docs encode, decoder
|
|
||||||
|
|
||||||
-}
|
-}
|
||||||
|
|
||||||
import FastDict as Dict exposing (Dict)
|
import FastDict as Dict exposing (Dict)
|
||||||
import Internal.Filter.Timeline as Filter exposing (Filter)
|
import Internal.Filter.Timeline as Filter exposing (Filter)
|
||||||
import Internal.Tools.Hashdict as Hashdict exposing (Hashdict)
|
import Internal.Tools.Hashdict as Hashdict exposing (Hashdict)
|
||||||
import Internal.Tools.Iddict as Iddict exposing (Iddict)
|
import Internal.Tools.Iddict as Iddict exposing (Iddict)
|
||||||
import Json.Decode as D
|
|
||||||
import Json.Encode as E
|
|
||||||
import Set exposing (Set)
|
import Set exposing (Set)
|
||||||
|
|
||||||
|
|
||||||
|
@ -144,16 +142,8 @@ type alias TokenValue =
|
||||||
batch to the front of the Timeline.
|
batch to the front of the Timeline.
|
||||||
-}
|
-}
|
||||||
addSync : Batch -> Timeline -> Timeline
|
addSync : Batch -> Timeline -> Timeline
|
||||||
addSync batch timeline =
|
addSync _ timeline =
|
||||||
case insertBatch batch timeline of
|
timeline
|
||||||
( Timeline tl, { start, end } ) ->
|
|
||||||
let
|
|
||||||
oldSync : ITokenPTR
|
|
||||||
oldSync =
|
|
||||||
tl.mostRecentSync
|
|
||||||
in
|
|
||||||
Timeline { tl | mostRecentSync = end }
|
|
||||||
|> connectITokenToIToken oldSync start
|
|
||||||
|
|
||||||
|
|
||||||
{-| Append a token at the end of a batch.
|
{-| Append a token at the end of a batch.
|
||||||
|
@ -206,23 +196,19 @@ connectITokenToIToken : ITokenPTR -> ITokenPTR -> Timeline -> Timeline
|
||||||
connectITokenToIToken pointer1 pointer2 (Timeline tl) =
|
connectITokenToIToken pointer1 pointer2 (Timeline tl) =
|
||||||
case ( pointer1, pointer2 ) of
|
case ( pointer1, pointer2 ) of
|
||||||
( ITokenPTR early, ITokenPTR late ) ->
|
( ITokenPTR early, ITokenPTR late ) ->
|
||||||
if early == late then
|
Timeline
|
||||||
Timeline tl
|
{ tl
|
||||||
|
| tokens =
|
||||||
else
|
tl.tokens
|
||||||
Timeline
|
|> Hashdict.map early
|
||||||
{ tl
|
(\data ->
|
||||||
| tokens =
|
{ data | behind = Set.insert late data.behind }
|
||||||
tl.tokens
|
)
|
||||||
|> Hashdict.map early
|
|> Hashdict.map late
|
||||||
(\data ->
|
(\data ->
|
||||||
{ data | behind = Set.insert late data.behind }
|
{ data | inFrontOf = Set.insert early data.inFrontOf }
|
||||||
)
|
)
|
||||||
|> Hashdict.map late
|
}
|
||||||
(\data ->
|
|
||||||
{ data | inFrontOf = Set.insert early data.inFrontOf }
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
( _, _ ) ->
|
( _, _ ) ->
|
||||||
Timeline tl
|
Timeline tl
|
||||||
|
@ -241,153 +227,6 @@ empty =
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
{-| Decode a Timeline from a JSON value.
|
|
||||||
-}
|
|
||||||
decoder : D.Decoder Timeline
|
|
||||||
decoder =
|
|
||||||
D.map5
|
|
||||||
(\batches events filled sync tokens ->
|
|
||||||
Timeline
|
|
||||||
{ batches = batches
|
|
||||||
, events = events
|
|
||||||
, filledBatches = filled
|
|
||||||
, mostRecentSync = sync
|
|
||||||
, tokens = tokens
|
|
||||||
}
|
|
||||||
)
|
|
||||||
(D.field "batches" <| Iddict.decoder decoderIBatch)
|
|
||||||
(D.map2 Tuple.pair
|
|
||||||
(D.field "head" decoderIBatchPTR)
|
|
||||||
(D.field "tail" <| D.list decoderIBatchPTR)
|
|
||||||
|> D.keyValuePairs
|
|
||||||
|> D.map Dict.fromList
|
|
||||||
|> D.field "events"
|
|
||||||
)
|
|
||||||
(D.succeed 0)
|
|
||||||
(D.field "mostRecentSync" decoderITokenPTR)
|
|
||||||
(D.field "tokens" <| Hashdict.decoder .name decoderIToken)
|
|
||||||
|> D.map recountFilledBatches
|
|
||||||
|
|
||||||
|
|
||||||
decoderIBatch : D.Decoder IBatch
|
|
||||||
decoderIBatch =
|
|
||||||
D.map4 IBatch
|
|
||||||
(D.field "events" <| D.list D.string)
|
|
||||||
(D.field "filter" Filter.decoder)
|
|
||||||
(D.field "start" decoderITokenPTR)
|
|
||||||
(D.field "end" decoderITokenPTR)
|
|
||||||
|
|
||||||
|
|
||||||
decoderIBatchPTR : D.Decoder IBatchPTR
|
|
||||||
decoderIBatchPTR =
|
|
||||||
D.map IBatchPTR decoderIBatchPTRValue
|
|
||||||
|
|
||||||
|
|
||||||
decoderIBatchPTRValue : D.Decoder IBatchPTRValue
|
|
||||||
decoderIBatchPTRValue =
|
|
||||||
D.int
|
|
||||||
|
|
||||||
|
|
||||||
decoderIToken : D.Decoder IToken
|
|
||||||
decoderIToken =
|
|
||||||
D.map5 IToken
|
|
||||||
(D.field "name" decoderTokenValue)
|
|
||||||
(D.field "starts" <| D.map Set.fromList <| D.list decoderIBatchPTRValue)
|
|
||||||
(D.field "ends" <| D.map Set.fromList <| D.list decoderIBatchPTRValue)
|
|
||||||
(D.field "inFrontOf" <| D.map Set.fromList <| D.list decoderITokenPTRValue)
|
|
||||||
(D.field "behind" <| D.map Set.fromList <| D.list decoderITokenPTRValue)
|
|
||||||
|
|
||||||
|
|
||||||
decoderITokenPTR : D.Decoder ITokenPTR
|
|
||||||
decoderITokenPTR =
|
|
||||||
D.oneOf
|
|
||||||
[ D.map ITokenPTR decoderITokenPTRValue
|
|
||||||
, D.null StartOfTimeline
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
decoderITokenPTRValue : D.Decoder ITokenPTRValue
|
|
||||||
decoderITokenPTRValue =
|
|
||||||
D.string
|
|
||||||
|
|
||||||
|
|
||||||
decoderTokenValue : D.Decoder TokenValue
|
|
||||||
decoderTokenValue =
|
|
||||||
D.string
|
|
||||||
|
|
||||||
|
|
||||||
{-| Encode a Timeline to a JSON value.
|
|
||||||
-}
|
|
||||||
encode : Timeline -> E.Value
|
|
||||||
encode (Timeline tl) =
|
|
||||||
E.object
|
|
||||||
[ ( "batches", Iddict.encode encodeIBatch tl.batches )
|
|
||||||
, ( "events"
|
|
||||||
, E.dict identity
|
|
||||||
(\( head, tail ) ->
|
|
||||||
E.object
|
|
||||||
[ ( "head", encodeIBatchPTR head )
|
|
||||||
, ( "tail", E.list encodeIBatchPTR tail )
|
|
||||||
]
|
|
||||||
)
|
|
||||||
(Dict.toCoreDict tl.events)
|
|
||||||
)
|
|
||||||
, ( "mostRecentSync", encodeITokenPTR tl.mostRecentSync )
|
|
||||||
, ( "tokens", Hashdict.encode encodeIToken tl.tokens )
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
encodeIBatch : IBatch -> E.Value
|
|
||||||
encodeIBatch batch =
|
|
||||||
E.object
|
|
||||||
[ ( "events", E.list E.string batch.events )
|
|
||||||
, ( "filter", Filter.encode batch.filter )
|
|
||||||
, ( "start", encodeITokenPTR batch.start )
|
|
||||||
, ( "end", encodeITokenPTR batch.end )
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
encodeIBatchPTR : IBatchPTR -> E.Value
|
|
||||||
encodeIBatchPTR (IBatchPTR value) =
|
|
||||||
encodeIBatchPTRValue value
|
|
||||||
|
|
||||||
|
|
||||||
encodeIBatchPTRValue : IBatchPTRValue -> E.Value
|
|
||||||
encodeIBatchPTRValue =
|
|
||||||
E.int
|
|
||||||
|
|
||||||
|
|
||||||
encodeIToken : IToken -> E.Value
|
|
||||||
encodeIToken itoken =
|
|
||||||
E.object
|
|
||||||
[ ( "name", encodeTokenValue itoken.name )
|
|
||||||
, ( "starts", E.set encodeIBatchPTRValue itoken.starts )
|
|
||||||
, ( "ends", E.set encodeIBatchPTRValue itoken.ends )
|
|
||||||
, ( "inFrontOf", E.set encodeITokenPTRValue itoken.inFrontOf )
|
|
||||||
, ( "behind", E.set encodeITokenPTRValue itoken.behind )
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
encodeITokenPTR : ITokenPTR -> E.Value
|
|
||||||
encodeITokenPTR token =
|
|
||||||
case token of
|
|
||||||
ITokenPTR value ->
|
|
||||||
encodeITokenPTRValue value
|
|
||||||
|
|
||||||
StartOfTimeline ->
|
|
||||||
E.null
|
|
||||||
|
|
||||||
|
|
||||||
encodeITokenPTRValue : ITokenPTRValue -> E.Value
|
|
||||||
encodeITokenPTRValue =
|
|
||||||
E.string
|
|
||||||
|
|
||||||
|
|
||||||
encodeTokenValue : TokenValue -> E.Value
|
|
||||||
encodeTokenValue =
|
|
||||||
E.string
|
|
||||||
|
|
||||||
|
|
||||||
{-| Get an IBatch from the Timeline.
|
{-| Get an IBatch from the Timeline.
|
||||||
-}
|
-}
|
||||||
getIBatch : IBatchPTR -> Timeline -> Maybe IBatch
|
getIBatch : IBatchPTR -> Timeline -> Maybe IBatch
|
||||||
|
@ -395,8 +234,6 @@ getIBatch (IBatchPTR ptr) (Timeline { batches }) =
|
||||||
Iddict.get ptr batches
|
Iddict.get ptr batches
|
||||||
|
|
||||||
|
|
||||||
{-| Get an IToken from the Timeline.
|
|
||||||
-}
|
|
||||||
getITokenFromPTR : ITokenPTR -> Timeline -> Maybe IToken
|
getITokenFromPTR : ITokenPTR -> Timeline -> Maybe IToken
|
||||||
getITokenFromPTR pointer (Timeline { tokens }) =
|
getITokenFromPTR pointer (Timeline { tokens }) =
|
||||||
case pointer of
|
case pointer of
|
||||||
|
@ -410,15 +247,13 @@ getITokenFromPTR pointer (Timeline { tokens }) =
|
||||||
{-| Insert a batch anywhere else in the timeline.
|
{-| Insert a batch anywhere else in the timeline.
|
||||||
-}
|
-}
|
||||||
insert : Batch -> Timeline -> Timeline
|
insert : Batch -> Timeline -> Timeline
|
||||||
insert batch timeline =
|
insert batch (Timeline tl) =
|
||||||
timeline
|
Timeline tl
|
||||||
|> insertBatch batch
|
|
||||||
|> Tuple.first
|
|
||||||
|
|
||||||
|
|
||||||
{-| Insert a batch into the timeline.
|
{-| Insert a batch into the timeline.
|
||||||
-}
|
-}
|
||||||
insertBatch : Batch -> Timeline -> ( Timeline, { start : ITokenPTR, end : ITokenPTR } )
|
insertBatch : Batch -> Timeline -> Timeline
|
||||||
insertBatch batch timeline =
|
insertBatch batch timeline =
|
||||||
case batch.start of
|
case batch.start of
|
||||||
Just start ->
|
Just start ->
|
||||||
|
@ -426,30 +261,26 @@ insertBatch batch timeline =
|
||||||
|> invokeIToken start
|
|> invokeIToken start
|
||||||
|> Tuple.mapSecond (invokeIToken batch.end)
|
|> Tuple.mapSecond (invokeIToken batch.end)
|
||||||
|> (\( startPTR, ( endPTR, newTimeline ) ) ->
|
|> (\( startPTR, ( endPTR, newTimeline ) ) ->
|
||||||
( insertIBatch
|
insertIBatch
|
||||||
{ events = batch.events
|
{ events = batch.events
|
||||||
, filter = batch.filter
|
, filter = batch.filter
|
||||||
, start = startPTR
|
, start = startPTR
|
||||||
, end = endPTR
|
, end = endPTR
|
||||||
}
|
}
|
||||||
newTimeline
|
newTimeline
|
||||||
, { start = startPTR, end = endPTR }
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
Nothing ->
|
Nothing ->
|
||||||
timeline
|
timeline
|
||||||
|> invokeIToken batch.end
|
|> invokeIToken batch.end
|
||||||
|> (\( endPTR, newTimeline ) ->
|
|> (\( endPTR, newTimeline ) ->
|
||||||
( insertIBatch
|
insertIBatch
|
||||||
{ events = batch.events
|
{ events = batch.events
|
||||||
, filter = batch.filter
|
, filter = batch.filter
|
||||||
, start = StartOfTimeline
|
, start = StartOfTimeline
|
||||||
, end = endPTR
|
, end = endPTR
|
||||||
}
|
}
|
||||||
newTimeline
|
newTimeline
|
||||||
, { start = StartOfTimeline, end = endPTR }
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -459,31 +290,7 @@ insertIBatch : IBatch -> Timeline -> Timeline
|
||||||
insertIBatch ibatch (Timeline tl) =
|
insertIBatch ibatch (Timeline tl) =
|
||||||
case Iddict.insert ibatch tl.batches of
|
case Iddict.insert ibatch tl.batches of
|
||||||
( batchPTR, newBatches ) ->
|
( batchPTR, newBatches ) ->
|
||||||
{ tl
|
{ tl | batches = newBatches }
|
||||||
| batches = newBatches
|
|
||||||
, events =
|
|
||||||
List.foldl
|
|
||||||
(\event dict ->
|
|
||||||
Dict.update event
|
|
||||||
(\value ->
|
|
||||||
case value of
|
|
||||||
Nothing ->
|
|
||||||
Just ( IBatchPTR batchPTR, [] )
|
|
||||||
|
|
||||||
Just ( head, tail ) ->
|
|
||||||
Just ( IBatchPTR batchPTR, head :: tail )
|
|
||||||
)
|
|
||||||
dict
|
|
||||||
)
|
|
||||||
tl.events
|
|
||||||
ibatch.events
|
|
||||||
, filledBatches =
|
|
||||||
if List.isEmpty ibatch.events then
|
|
||||||
tl.filledBatches
|
|
||||||
|
|
||||||
else
|
|
||||||
tl.filledBatches + 1
|
|
||||||
}
|
|
||||||
|> Timeline
|
|> Timeline
|
||||||
|> connectITokenToIBatch ibatch.start (IBatchPTR batchPTR)
|
|> connectITokenToIBatch ibatch.start (IBatchPTR batchPTR)
|
||||||
|> connectIBatchToIToken (IBatchPTR batchPTR) ibatch.end
|
|> connectIBatchToIToken (IBatchPTR batchPTR) ibatch.end
|
||||||
|
|
|
@ -4,8 +4,6 @@ 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 Json.Decode as D
|
|
||||||
import Json.Encode as E
|
|
||||||
import Set
|
import Set
|
||||||
import Test exposing (..)
|
import Test exposing (..)
|
||||||
import Test.Values.Event as TestEvent
|
import Test.Values.Event as TestEvent
|
||||||
|
@ -420,15 +418,4 @@ suite =
|
||||||
()
|
()
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
, describe "JSON"
|
|
||||||
[ fuzz fuzzer
|
|
||||||
"encode -> decode is the same"
|
|
||||||
(\filter ->
|
|
||||||
filter
|
|
||||||
|> Filter.encode
|
|
||||||
|> E.encode 0
|
|
||||||
|> D.decodeString Filter.decoder
|
|
||||||
|> Expect.equal (Ok filter)
|
|
||||||
)
|
|
||||||
]
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,99 +1,303 @@
|
||||||
module Test.Values.Timeline exposing (..)
|
module Test.Values.Timeline exposing (..)
|
||||||
|
|
||||||
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.Timeline as Timeline exposing (Batch, Timeline)
|
import Internal.Values.Timeline as Timeline exposing (Batch, Timeline)
|
||||||
import Json.Decode as D
|
|
||||||
import Json.Encode as E
|
|
||||||
import Test exposing (..)
|
import Test exposing (..)
|
||||||
import Test.Filter.Timeline as TestFilter
|
import Test.Filter.Timeline as TestFilter
|
||||||
|
import Expect
|
||||||
|
|
||||||
|
|
||||||
fuzzer : Fuzzer Timeline
|
fuzzer : Fuzzer Timeline
|
||||||
fuzzer =
|
fuzzer =
|
||||||
TestFilter.fuzzer
|
Fuzz.map2
|
||||||
|> Fuzz.andThen
|
(\makers filter ->
|
||||||
(\globalFilter ->
|
case makers of
|
||||||
Fuzz.oneOf
|
[] ->
|
||||||
[ Fuzz.map2
|
Timeline.empty
|
||||||
(\start batches ->
|
|
||||||
List.foldl
|
head :: tail ->
|
||||||
(\b ( s, f ) ->
|
List.foldl
|
||||||
( b.end
|
(\maker ( prevToken, timeline ) ->
|
||||||
, f >> Timeline.addSync { b | start = Just s, filter = globalFilter }
|
case maker of
|
||||||
|
Sync start events end ->
|
||||||
|
( end
|
||||||
|
, Timeline.addSync
|
||||||
|
(Timeline.fromSlice
|
||||||
|
{ start =
|
||||||
|
start
|
||||||
|
|> Maybe.withDefault prevToken
|
||||||
|
|> Maybe.Just
|
||||||
|
, events = events
|
||||||
|
, filter = filter
|
||||||
|
, end = end
|
||||||
|
}
|
||||||
|
)
|
||||||
|
timeline
|
||||||
)
|
)
|
||||||
)
|
|
||||||
( start, identity )
|
Get start events efilter end ->
|
||||||
batches
|
( prevToken
|
||||||
|> Tuple.second
|
, Timeline.insert
|
||||||
)
|
(Timeline.fromSlice
|
||||||
Fuzz.string
|
{ start = start
|
||||||
(Fuzz.listOfLengthBetween 0 10 fuzzerBatch)
|
, events = events
|
||||||
, Fuzz.map2
|
, filter = Filter.and filter efilter
|
||||||
(\start batches ->
|
, end = end
|
||||||
List.foldl
|
}
|
||||||
(\b ( s, f ) ->
|
)
|
||||||
( b.end
|
timeline
|
||||||
, f >> Timeline.insert { b | start = Just s, filter = Filter.and globalFilter b.filter }
|
|
||||||
)
|
)
|
||||||
)
|
|
||||||
( start, identity )
|
|
||||||
batches
|
|
||||||
|> Tuple.second
|
|
||||||
)
|
)
|
||||||
Fuzz.string
|
(case head of
|
||||||
(Fuzz.listOfLengthBetween 0 4 fuzzerBatch)
|
Sync start events end ->
|
||||||
]
|
( end
|
||||||
|> Fuzz.listOfLengthBetween 0 10
|
, Timeline.addSync
|
||||||
|> Fuzz.map (List.foldl (<|) Timeline.empty)
|
(Timeline.fromSlice
|
||||||
)
|
{ start = start
|
||||||
|
, events = events
|
||||||
|
, filter = filter
|
||||||
|
, end = end
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Timeline.empty
|
||||||
|
)
|
||||||
|
|
||||||
|
Get start events efilter end ->
|
||||||
|
( end
|
||||||
|
, Timeline.addSync
|
||||||
|
(Timeline.fromSlice
|
||||||
|
{ start = start
|
||||||
|
, events = events
|
||||||
|
, filter = Filter.and filter efilter
|
||||||
|
, end = end
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Timeline.empty
|
||||||
|
)
|
||||||
|
)
|
||||||
|
tail
|
||||||
|
|> Tuple.second
|
||||||
|
)
|
||||||
|
(Fuzz.list fuzzerMaker)
|
||||||
|
TestFilter.fuzzer
|
||||||
|
|
||||||
|
|
||||||
fuzzerBatch : Fuzzer Batch
|
fuzzerBatch : Fuzzer Batch
|
||||||
fuzzerBatch =
|
fuzzerBatch =
|
||||||
Fuzz.map4 Batch
|
Fuzz.oneOf
|
||||||
|
[ Fuzz.map Timeline.fromToken Fuzz.string
|
||||||
|
, Fuzz.map4
|
||||||
|
(\start events filter end ->
|
||||||
|
Timeline.fromSlice
|
||||||
|
{ start = start
|
||||||
|
, events = events
|
||||||
|
, filter = filter
|
||||||
|
, end = end
|
||||||
|
}
|
||||||
|
)
|
||||||
|
(Fuzz.maybe Fuzz.string)
|
||||||
|
(Fuzz.list Fuzz.string)
|
||||||
|
TestFilter.fuzzer
|
||||||
|
Fuzz.string
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
type FuzzMaker
|
||||||
|
= Sync (Maybe String) (List String) String
|
||||||
|
| Get (Maybe String) (List String) Filter String
|
||||||
|
|
||||||
|
|
||||||
|
fuzzerMaker : Fuzzer FuzzMaker
|
||||||
|
fuzzerMaker =
|
||||||
|
Fuzz.frequency
|
||||||
|
[ ( 30, Fuzz.map (Sync Nothing []) Fuzz.string )
|
||||||
|
, ( 10
|
||||||
|
, Fuzz.map2 (Sync Nothing)
|
||||||
|
(Fuzz.listOfLengthBetween 1 32 Fuzz.string)
|
||||||
|
Fuzz.string
|
||||||
|
)
|
||||||
|
, ( 1
|
||||||
|
, Fuzz.map3 (\start events end -> Sync (Just start) events end)
|
||||||
|
Fuzz.string
|
||||||
|
(Fuzz.listOfLengthBetween 1 32 Fuzz.string)
|
||||||
|
Fuzz.string
|
||||||
|
)
|
||||||
|
, ( 1
|
||||||
|
, Fuzz.map4 Get
|
||||||
|
(Fuzz.maybe Fuzz.string)
|
||||||
|
(Fuzz.list Fuzz.string)
|
||||||
|
TestFilter.fuzzer
|
||||||
|
Fuzz.string
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
fuzzerForBatch : Fuzzer { start : String, events : List String, filter : Filter, end : String }
|
||||||
|
fuzzerForBatch =
|
||||||
|
Fuzz.map4
|
||||||
|
(\start events filter end ->
|
||||||
|
{ start = start, events = events, filter = filter, end = end }
|
||||||
|
)
|
||||||
|
Fuzz.string
|
||||||
(Fuzz.list Fuzz.string)
|
(Fuzz.list Fuzz.string)
|
||||||
TestFilter.fuzzer
|
TestFilter.fuzzer
|
||||||
(Fuzz.maybe Fuzz.string)
|
|
||||||
Fuzz.string
|
Fuzz.string
|
||||||
|
|
||||||
|
|
||||||
isEqual : Timeline -> Timeline -> Expect.Expectation
|
|
||||||
isEqual t1 t2 =
|
|
||||||
Expect.equal
|
|
||||||
(E.encode 0 <| Timeline.encode t1)
|
|
||||||
(E.encode 0 <| Timeline.encode t2)
|
|
||||||
|
|
||||||
|
|
||||||
suite : Test
|
suite : Test
|
||||||
suite =
|
suite =
|
||||||
describe "Timeline"
|
describe "Timeline"
|
||||||
[ describe "empty"
|
[ describe "Most recent events"
|
||||||
[ fuzz fuzzerBatch
|
[ fuzz fuzzerForBatch "Singleton is most recent"
|
||||||
"singleton = empty + sync"
|
|
||||||
(\batch ->
|
(\batch ->
|
||||||
isEqual
|
{ start = Just batch.start
|
||||||
(Timeline.singleton batch)
|
, events = batch.events
|
||||||
(Timeline.addSync batch Timeline.empty)
|
, filter = batch.filter
|
||||||
|
, end = batch.end
|
||||||
|
}
|
||||||
|
|> Timeline.fromSlice
|
||||||
|
|> Timeline.singleton
|
||||||
|
|> Timeline.mostRecentEvents batch.filter
|
||||||
|
|> Expect.equal batch.events
|
||||||
)
|
)
|
||||||
]
|
, fuzz2 fuzzerForBatch fuzzerForBatch "Double batch connects"
|
||||||
, describe "JSON"
|
(\batch1 batch2 ->
|
||||||
[ fuzz fuzzer
|
[ { start = Just batch1.start
|
||||||
"encode -> decode is same"
|
, events = batch1.events
|
||||||
(\timeline ->
|
, filter = batch1.filter
|
||||||
timeline
|
, end = batch2.start
|
||||||
|> Timeline.encode
|
}
|
||||||
|> E.encode 0
|
, { start = Just batch2.start
|
||||||
|> D.decodeString Timeline.decoder
|
, events = batch2.events
|
||||||
|> (\t ->
|
, filter = batch2.filter
|
||||||
case t of
|
, end = batch2.end
|
||||||
Ok v ->
|
}
|
||||||
isEqual v timeline
|
]
|
||||||
|
|> List.map Timeline.fromSlice
|
||||||
Err e ->
|
|> List.foldl Timeline.addSync Timeline.empty
|
||||||
Expect.fail (D.errorToString e)
|
|> Timeline.mostRecentEvents (Filter.and batch1.filter batch2.filter)
|
||||||
|
|> (\outcome ->
|
||||||
|
if batch2.start == batch2.end then
|
||||||
|
Expect.equal [] outcome
|
||||||
|
else if batch1.start == batch2.start then
|
||||||
|
Expect.equal batch2.events outcome
|
||||||
|
else
|
||||||
|
Expect.equal
|
||||||
|
(List.append batch1.events batch2.events)
|
||||||
|
outcome
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
, fuzz2 fuzzerForBatch fuzzerForBatch "Disconnected double batch does not connect"
|
||||||
|
(\batch1 batch2 ->
|
||||||
|
[ { start = Just batch1.start
|
||||||
|
, events = batch1.events
|
||||||
|
, filter = batch1.filter
|
||||||
|
, end = batch1.start
|
||||||
|
}
|
||||||
|
, { start = Just batch2.start
|
||||||
|
, events = batch2.events
|
||||||
|
, filter = batch2.filter
|
||||||
|
, end = batch2.end
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|> List.map Timeline.fromSlice
|
||||||
|
|> List.foldl Timeline.addSync Timeline.empty
|
||||||
|
|> Timeline.mostRecentEvents (Filter.and batch1.filter batch2.filter)
|
||||||
|
|> (\outcome ->
|
||||||
|
if batch2.start == batch2.end then
|
||||||
|
Expect.equal [] outcome
|
||||||
|
else if batch1.start == batch2.start then
|
||||||
|
Expect.equal batch2.events outcome
|
||||||
|
else if batch1.end == batch2.start then
|
||||||
|
Expect.equal
|
||||||
|
(List.append batch1.events batch2.events)
|
||||||
|
outcome
|
||||||
|
else
|
||||||
|
Expect.equal batch2.events outcome
|
||||||
|
)
|
||||||
|
)
|
||||||
|
, fuzz
|
||||||
|
( Fuzz.pair Fuzz.int (Fuzz.list Fuzz.string)
|
||||||
|
|> (\f -> Fuzz.triple f f f)
|
||||||
|
|> (\f -> Fuzz.triple f f f)
|
||||||
|
)
|
||||||
|
"Connect 8 batches"
|
||||||
|
(\(((i1, e1), (i2, e2), (i3, e3)), ((i4, e4), (i5, e5), (i6, e6)), ((i7, e7), (i8, e8), (_, e9))) ->
|
||||||
|
[ ( i1
|
||||||
|
, { start = Just <| String.fromInt 1
|
||||||
|
, events = e1
|
||||||
|
, filter = Filter.pass
|
||||||
|
, end = String.fromInt (1 + 1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, ( i2
|
||||||
|
, { start = Just <| String.fromInt 2
|
||||||
|
, events = e2
|
||||||
|
, filter = Filter.pass
|
||||||
|
, end = String.fromInt (2 + 1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, ( i3
|
||||||
|
, { start = Just <| String.fromInt 3
|
||||||
|
, events = e3
|
||||||
|
, filter = Filter.pass
|
||||||
|
, end = String.fromInt (3 + 1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, ( i4
|
||||||
|
, { start = Just <| String.fromInt 4
|
||||||
|
, events = e4
|
||||||
|
, filter = Filter.pass
|
||||||
|
, end = String.fromInt (4 + 1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, ( i5
|
||||||
|
, { start = Just <| String.fromInt 5
|
||||||
|
, events = e5
|
||||||
|
, filter = Filter.pass
|
||||||
|
, end = String.fromInt (5 + 1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, ( i6
|
||||||
|
, { start = Just <| String.fromInt 6
|
||||||
|
, events = e6
|
||||||
|
, filter = Filter.pass
|
||||||
|
, end = String.fromInt (6 + 1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, ( i7
|
||||||
|
, { start = Just <| String.fromInt 7
|
||||||
|
, events = e7
|
||||||
|
, filter = Filter.pass
|
||||||
|
, end = String.fromInt (7 + 1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, ( i8
|
||||||
|
, { start = Just <| String.fromInt 8
|
||||||
|
, events = e8
|
||||||
|
, filter = Filter.pass
|
||||||
|
, end = String.fromInt (8 + 1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|> List.sortBy Tuple.first
|
||||||
|
|> List.map Tuple.second
|
||||||
|
|> List.map Timeline.fromSlice
|
||||||
|
|> List.foldl
|
||||||
|
Timeline.insert
|
||||||
|
(Timeline.singleton
|
||||||
|
( Timeline.fromSlice
|
||||||
|
{ start = Just <| String.fromInt 9
|
||||||
|
, events = e9
|
||||||
|
, filter = Filter.pass
|
||||||
|
, end = String.fromInt (9 + 1)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|> Timeline.mostRecentEvents Filter.pass
|
||||||
|
|> Expect.equal
|
||||||
|
( e1 ++ e2 ++ e3 ++ e4 ++ e5 ++ e6 ++ e7 ++ e8 ++ e9 )
|
||||||
|
)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue