Oskar Wickström
May 2019
prop_reverse = property $ do
xs < forAll $
Gen.list
(Range.linear 0 10)
(Gen.int Range.linearBounded)
reverse (reverse xs) === xs
prop_sort = property $ do
xs < forAll $
Gen.list
(Range.linear 0 10)
(Gen.int Range.linearBounded)
mySuperSort xs === industryStandardSort xs
How many of you write sort algorithms in your day job?

hprop_flat_timeline_has_same_duration_as_hierarchical =
property $ do
t < forAll $ Gen.timeline (Range.exponential 0 20) Gen.parallelWithClips
let Just flat = Render.flattenTimeline t
durationOf AdjustedDuration t === durationOf AdjustedDuration flat
hprop_flat_timeline_has_same_clips_as_hierarchical =
property $ do
t < forAll $ Gen.timeline (Range.exponential 0 20) Gen.parallelWithClips
let Just flat = Render.flattenTimeline t
timelineVideoClips t === flatVideoClips flat
timelineAudioClips t === flatAudioClips flat
hprop_classifies_still_segments_of_min_length = property $ do
 1. Generate a minimum still segment length/duration
minStillSegmentFrames < forAll $ Gen.int (Range.linear 2 (2 * frameRate))
let minStillSegmentTime = frameCountDuration minStillSegmentFrames
 2. Generate output segments
segments < forAll $
genSegments (Range.linear 1 10)
(Range.linear 1
(minStillSegmentFrames * 2))
(Range.linear minStillSegmentFrames
(minStillSegmentFrames * 2))
resolution
...
 3. Convert test segments to actual pixel frames
let pixelFrames = testSegmentsToPixelFrames segments
 4. Run the classifier on the pixel frames
let counted = classifyMovement minStillSegmentTime (Pipes.each pixelFrames)
& Pipes.toList
& countSegments
...
...
 5. Sanity check
countTestSegmentFrames segments === totalClassifiedFrames counted
 6. Ignore last segment and verify all other segments
case initMay counted of
Just rest >
traverse_ (assertStillLengthAtLeast minStillSegmentTime) rest
Nothing > success
where
resolution = 10 :. 10
> :{
 hprop_classifies_still_segments_of_min_length
 & Hedgehog.withTests 10000
 & Hedgehog.check
 :}
✓ <interactive> passed 10000 tests.
hprop_classifies_same_scenes_as_input = property $ do
 1. Generate a minimum still still segment duration
minStillSegmentFrames < forAll $ Gen.int (Range.linear 2 (2 * frameRate))
let minStillSegmentTime = frameCountDuration minStillSegmentFrames
 2. Generate test segments
segments < forAll $
genSegments (Range.linear 1 10)
(Range.linear 1
(minStillSegmentFrames * 2))
(Range.linear minStillSegmentFrames
(minStillSegmentFrames * 2))
resolution
...
...
 3. Convert test segments to actual pixel frames
let pixelFrames = testSegmentsToPixelFrames segments
 4. Convert expected output segments to a list of expected time spans
 and the full duration
let durations = map segmentWithDuration segments
expectedSegments = movingSceneTimeSpans durations
fullDuration = foldMap unwrapSegment durations
...
...
 5. Classify movement of frames
let classifiedFrames =
Pipes.each pixelFrames
& classifyMovement minStillSegmentTime
& Pipes.toList
 6. Classify moving scene time spans
let classified =
(Pipes.each classifiedFrames
& classifyMovingScenes fullDuration)
>> Pipes.drain
& Pipes.runEffect
& runIdentity
...
...
 7. Check classified time span equivalence
expectedSegments === classified
where
resolution = 10 :. 10
classifyMovement minStillSegmentTime =
case ... of
InStillState{..} >
if someDiff > minEqualTimeForStill
then ...
else ...
InMovingState{..} >
if someOtherDiff >= minStillSegmentTime
then ...
else ...
where
minEqualTimeForStill = 0.5
hprop_undo_actions_are_undoable = property $ do
 Generate initial timeline and focus
timelineAndFocus < forAllWith showTimelineAndFocus $
Gen.timelineWithFocus (Range.linear 0 10) Gen.parallel
 Generate initial application state
initialState < forAll (initializeState timelineAndFocus)
 Generate a sequence of undoable/redoable commands
events < forAll $
Gen.list (Range.exponential 1 100) genUndoableTimelineEvent
...
...
 We begin by running 'events' on the original state
beforeUndos < runTimelineStubbedWithExit events initialState
 Then we run as many undo commands as undoable commands
afterUndos < runTimelineStubbedWithExit (undoEvent <$ events) beforeUndos
 That should result in a timeline equal to the one we at the
 beginning
timelineToTree (initialState ^. currentTimeline)
=== timelineToTree (afterUndos ^. currentTimeline)
hprop_undo_actions_are_redoable = property $ do
 Generate the initial timeline and focus
timelineAndFocus < forAllWith showTimelineAndFocus $
Gen.timelineWithFocus (Range.linear 0 10) Gen.parallel
 Generate the initial application state
initialState < forAll (initializeState timelineAndFocus)
 Generate a sequence of undoable/redoable commands
events < forAll $
Gen.list (Range.exponential 1 100) genUndoableTimelineEvent
 We begin by running 'events' on the original state
beforeUndos < runTimelineStubbedWithExit events initialState
 Then we undo and redo all of them
afterRedos <
runTimelineStubbedWithExit (undoEvent <$ events) beforeUndos
>>= runTimelineStubbedWithExit (redoEvent <$ events)
 That should result in a timeline equal to the one we had before
 starting the undos
timelineToTree (beforeUndos ^. currentTimeline)
=== timelineToTree (afterRedos ^. currentTimeline)