feat(submissions): optionally disable consideration for deficit
This commit is contained in:
parent
8c4228dcba
commit
c6a6ec721c
@ -61,6 +61,8 @@ SheetSubmissionModeNoneWithoutNotGraded: Es wurde "Keine Abgabe" eingestellt, je
|
||||
SheetWarnNoActiveTo: "Aktiv bis/Ende Abgabezeitraum" sollte stets angegeben werden
|
||||
CountTutProp: Tutorien zählen gegen Proportion
|
||||
CountTutPropTip: Wenn Abgaben nach Tutorium zugeteilt werden, zählen diese Zuteilungen in Bezug auf den jeweiligen Anteil?
|
||||
ConsiderDeficits: Defizite ausgleichen
|
||||
ConsiderDeficitsTip: Wenn einem Korrektor/einer Korrektorin (nach aktuellem Datenstand) über alle Blätter des Kurses hinweg weniger Korrekturen zugeteilt wurden als nach den Anteilen vorgesehen, soll versucht werden diese Defizite mit diesem Übungsblatt auszugleichen?
|
||||
SheetCorrector: Korrektor
|
||||
CorrectorExists: Nutzer:in ist bereits als Korrektor:in eingetragen
|
||||
SheetCorrectorState: Status
|
||||
|
||||
@ -61,6 +61,8 @@ SheetSubmissionModeNoneWithoutNotGraded: The sheet was configured to be "No subm
|
||||
SheetWarnNoActiveTo: “Active to/Submission period end” should always be specified
|
||||
CountTutProp: Tutorials count against proportion
|
||||
CountTutPropTip: If submissions are assigned by tutorial, do those assignments count with regard to the set proportion?
|
||||
ConsiderDeficits: Compensate deficits
|
||||
ConsiderDeficitsTip: When a corrector (as per the current state) was assigned fewer or more corrections than would be expected according to their proportions, this is considered a deficit. Should Uni2work try to compensate for these deficits when assigning corrections for this sheet?
|
||||
SheetCorrector: Corrector
|
||||
CorrectorExists: User already is a corrector
|
||||
SheetCorrectorState: State
|
||||
|
||||
@ -1,13 +0,0 @@
|
||||
ChangelogItemFeature: Feature
|
||||
ChangelogItemBugfix: Bugfix
|
||||
SexNotKnown: Unbekannt
|
||||
SexMale: Männlich
|
||||
SexFemale: Weiblich
|
||||
SexNotApplicable: Keine Angabe
|
||||
NoSubmissions: Keine Abgabe
|
||||
CorrectorSubmissions: Abgabe extern mit Pseudonym
|
||||
UserSubmissions: Direkte Abgabe in Uni2work
|
||||
SystemExamOffice: Prüfungsverwaltung
|
||||
SystemFaculty: Fakultätsmitglied
|
||||
SystemStudent: Student:in
|
||||
BothSubmissions: Abgabe direkt in Uni2work & extern mit Pseudonym
|
||||
13
messages/uniworx/categories/model_types/de-de-formal.msg
Normal file
13
messages/uniworx/categories/model_types/de-de-formal.msg
Normal file
@ -0,0 +1,13 @@
|
||||
ChangelogItemFeature: Feature
|
||||
ChangelogItemBugfix: Bugfix
|
||||
SexNotKnown: Unknown
|
||||
SexMale: Male
|
||||
SexFemale: Female
|
||||
SexNotApplicable: Not applicable
|
||||
NoSubmissions: No submission
|
||||
CorrectorSubmissions: External submission via pseudonym
|
||||
UserSubmissions: Direct submission in Uni2work
|
||||
SystemExamOffice: Exam office
|
||||
SystemFaculty: Faculty member
|
||||
SystemStudent: Student
|
||||
BothSubmissions: Submission either directly in Uni2work or externally via pseudonym
|
||||
@ -128,7 +128,7 @@ MenuGlobalWorkflowInstanceList: Systemweite Workflows
|
||||
MenuTopWorkflowInstanceList: Workflows
|
||||
MenuTopWorkflowWorkflowList: Laufende Workflows
|
||||
MenuTopWorkflowWorkflowListHeader: Workflows
|
||||
MenuGlossary:
|
||||
MenuGlossary: Begriffsverzeichnis
|
||||
MenuVersion: Versionsgeschichte
|
||||
MenuCourseNewsNew: Neue Kursnachricht
|
||||
MenuCourseNewsEdit: Kursnachricht bearbeiten
|
||||
|
||||
@ -21,6 +21,7 @@ function translations() {
|
||||
msgFile=$1
|
||||
|
||||
sed -r 's/^([^ :]+).*$/\1/' ${msgFile} \
|
||||
| sed -r '/^\s*#/d' \
|
||||
| sort
|
||||
}
|
||||
|
||||
|
||||
@ -166,8 +166,7 @@ correctorForm loads' = wFormToAForm $ do
|
||||
loads :: Map (Either UserEmail UserId) (CorrectorState, Load)
|
||||
loads = loads' <&> \(InvDBDataSheetCorrector load cState, InvTokenDataSheetCorrector) -> (cState, load)
|
||||
|
||||
countTutRes <- wpopt checkBoxField (fslI MsgCountTutProp & setTooltip MsgCountTutPropTip) . Just . any (\(_, Load{..}) -> Just True == byTutorial) $ Map.elems loads
|
||||
|
||||
countTutRes <- wpopt checkBoxField (fslI MsgCountTutProp & setTooltip MsgCountTutPropTip) . Just . any (\(_, Load{..}) -> fromMaybe False byTutorial) $ Map.elems loads
|
||||
|
||||
let
|
||||
previousCorrectors :: E.SqlQuery (E.SqlExpr (Entity User))
|
||||
@ -203,13 +202,15 @@ correctorForm loads' = wFormToAForm $ do
|
||||
miCell _ userIdent initRes nudge csrf = do
|
||||
(stateRes, stateView) <- mreq (selectField optionsFinite) (fslI MsgSheetCorrectorState & addName (nudge "state")) $ (fst <$> initRes) <|> Just CorrectorNormal
|
||||
(byTutRes, byTutView) <- mreq checkBoxField ("" & addName (nudge "bytut")) $ (isJust . byTutorial . snd <$> initRes) <|> Just False
|
||||
(deficitRes, deficitView) <- mreq checkBoxField ("" & addName (nudge "deficit")) $ ((/= 0) . byDeficit . snd <$> initRes) <|> Just True
|
||||
(propRes, propView) <- mreq (checkBool (>= 0) MsgProportionNegative rationalField) (fslI MsgSheetCorrectorProportion & addName (nudge "prop")) $ (byProportion . snd <$> initRes) <|> Just 0
|
||||
let
|
||||
res :: FormResult (CorrectorState, Load)
|
||||
res = (,) <$> stateRes <*> (Load <$> tutRes' <*> propRes)
|
||||
res = (,) <$> stateRes <*> (Load <$> tutRes' <*> propRes <*> deficitRes')
|
||||
tutRes'
|
||||
| FormSuccess True <- byTutRes = Just <$> countTutRes
|
||||
| otherwise = Nothing <$ byTutRes
|
||||
deficitRes' = bool 0 1 <$> deficitRes
|
||||
identWidget <- case userIdent of
|
||||
Left email -> return . toWidget $ mailtoHtml email
|
||||
Right uid -> do
|
||||
|
||||
@ -186,8 +186,10 @@ planSubmissions sid restriction = do
|
||||
|
||||
-- | How many additional submission should the given corrector be assigned, if possible?
|
||||
calculateDeficit :: UserId -> Map SubmissionId (Maybe UserId, Map UserId _, SheetId) -> Rational
|
||||
calculateDeficit corrector submissionState = getSum $ foldMap Sum deficitBySheet
|
||||
calculateDeficit corrector submissionState = (* byDeficit corrLoad) . getSum $ foldMap Sum deficitBySheet
|
||||
where
|
||||
corrLoad = Map.findWithDefault mempty corrector sheetCorrectors
|
||||
|
||||
sheetSizes :: Map SheetId Integer
|
||||
-- ^ Number of assigned submissions (to anyone) per sheet
|
||||
sheetSizes = Map.map getSum . Map.fromListWith mappend $ do
|
||||
|
||||
@ -320,26 +320,40 @@ classifySubmissionMode (SubmissionMode True (Just _)) = SubmissionModeBoth
|
||||
|
||||
-- | Specify a corrector's workload
|
||||
data Load -- = ByTutorial { countsToLoad :: Bool } | ByProportion { load :: Rational }
|
||||
= Load { byTutorial :: Maybe Bool -- ^ @Just@ all from Tutorial, @True@ if counting towards overall workload
|
||||
= Load { byTutorial :: Maybe Bool -- ^ @Just@ all from Tutorial, @True@ if counting towards overall workload
|
||||
, byProportion :: Rational -- ^ workload proportion of all submission not assigned to tutorial leaders
|
||||
, byDeficit :: Rational -- ^ multiply accumulated deficit by this before considering for distribution
|
||||
}
|
||||
deriving (Show, Read, Eq, Ord, Generic)
|
||||
deriving anyclass (Hashable, NFData)
|
||||
|
||||
deriveJSON defaultOptions ''Load
|
||||
instance ToJSON Load where
|
||||
toJSON Load{..} = Aeson.object $ catMaybes
|
||||
[ ("byTutorial" Aeson..=) . Just <$> byTutorial
|
||||
, ("byProportion" Aeson..=) <$> assertM' (/= 0) byProportion
|
||||
, ("byDeficit" Aeson..=) <$> assertM' (/= 1) byDeficit
|
||||
]
|
||||
instance FromJSON Load where
|
||||
parseJSON = Aeson.withObject "Load" $ \o -> do
|
||||
byTutorial <- o Aeson..:? "byTutorial"
|
||||
byProportion <- o Aeson..:? "byProportion" Aeson..!= 0
|
||||
byDeficit <- o Aeson..:? "byDeficit" Aeson..!= 1
|
||||
return Load{..}
|
||||
|
||||
derivePersistFieldJSON ''Load
|
||||
|
||||
instance Semigroup Load where
|
||||
(Load byTut prop) <> (Load byTut' prop') = Load byTut'' (prop + prop')
|
||||
(Load byTut prop byDeficit) <> (Load byTut' prop' byDeficit') = Load byTut'' (prop + prop') byDeficit''
|
||||
where
|
||||
byTut''
|
||||
| Nothing <- byTut = byTut'
|
||||
| Nothing <- byTut' = byTut
|
||||
| Just a <- byTut
|
||||
, Just b <- byTut' = Just $ a || b
|
||||
byDeficit'' = byDeficit * byDeficit'
|
||||
|
||||
instance Monoid Load where
|
||||
mempty = Load Nothing 0
|
||||
mempty = Load Nothing 0 1
|
||||
mappend = (<>)
|
||||
|
||||
{- Use (is _ByTutorial) instead of this unneeded definition:
|
||||
@ -363,8 +377,15 @@ derivePersistField "CorrectorState"
|
||||
showCompactCorrectorLoad :: Load -> CorrectorState -> Text
|
||||
showCompactCorrectorLoad load CorrectorMissing = "[" <> showCompactCorrectorLoad load CorrectorNormal <> "]"
|
||||
showCompactCorrectorLoad load CorrectorExcused = "{" <> showCompactCorrectorLoad load CorrectorNormal <> "}"
|
||||
showCompactCorrectorLoad Load{..} CorrectorNormal | byProportion == 0 = fromMaybe mempty tutorialText
|
||||
| otherwise = maybe id (\tt pt -> pt <> " + " <> tt) tutorialText proportionText
|
||||
showCompactCorrectorLoad Load{..} CorrectorNormal
|
||||
| byProportion == 0
|
||||
, Just tutorialText' <- tutorialText
|
||||
, Just deficitText' <- deficitText
|
||||
= tutorialText' <> " " <> deficitText' <> " D"
|
||||
| byProportion == 0
|
||||
= fromMaybe mempty $ tutorialText <|> fmap (<> "D") deficitText
|
||||
| otherwise
|
||||
= maybe id (\dt acc -> acc <> " " <> dt <> " D") deficitText $ maybe id (\tt acc -> acc <> " + " <> tt) tutorialText proportionText
|
||||
where
|
||||
proportionText = let propDbl :: Double
|
||||
propDbl = fromRational byProportion
|
||||
@ -372,6 +393,9 @@ showCompactCorrectorLoad Load{..} CorrectorNormal | byProportion == 0 = fromMay
|
||||
tutorialText = byTutorial <&> \case
|
||||
True -> "(T)"
|
||||
False -> "T"
|
||||
deficitText | byDeficit == 1 = Nothing
|
||||
| byDeficit > 1 = Just "+"
|
||||
| otherwise = Just "-"
|
||||
|
||||
instance Csv.ToField (SheetType epid, Maybe Points) where
|
||||
toField (_, Nothing) = mempty
|
||||
|
||||
@ -0,0 +1,2 @@
|
||||
$newline never
|
||||
Das Ausgleichen von Defiziten beim Verteilen von Korrekturen kann nun deaktiviert werden
|
||||
@ -0,0 +1,2 @@
|
||||
$newline never
|
||||
Consideration of corrector deficits when assigning corrections can now be disabled
|
||||
@ -1,5 +1,5 @@
|
||||
$newline never
|
||||
<td colspan=5>
|
||||
<td colspan=6>
|
||||
#{csrf}
|
||||
^{fvWidget addView}
|
||||
<td>
|
||||
|
||||
@ -11,6 +11,8 @@ $case userIdent
|
||||
<td>
|
||||
#{csrf}
|
||||
^{fvWidget stateView}
|
||||
<td>
|
||||
^{fvWidget deficitView}
|
||||
<td>
|
||||
^{fvWidget byTutView}
|
||||
<td>
|
||||
|
||||
@ -4,6 +4,9 @@ $newline never
|
||||
<tr .table__row .table__row--head>
|
||||
<th .table__th colspan="2">_{MsgTableCorrector}
|
||||
<th .table__th>_{MsgTableCorState}
|
||||
<th .table__th>
|
||||
_{MsgConsiderDeficits}
|
||||
^{messageTooltip =<< messageI Info MsgConsiderDeficitsTip}
|
||||
<th .table__th>_{MsgCorByTut}
|
||||
<th .table__th>_{MsgTableCorProportion}
|
||||
<td>
|
||||
|
||||
@ -918,9 +918,9 @@ fillDb = do
|
||||
forM_ [fhamann, maxMuster, tinaTester] $ \uid -> do
|
||||
p <- liftIO getRandom
|
||||
void . insert $ SheetPseudonym shId p uid
|
||||
void . insert $ SheetCorrector jost shId (Load (Just True) 0) CorrectorNormal
|
||||
void . insert $ SheetCorrector gkleen shId (Load (Just True) 1) CorrectorNormal
|
||||
void . insert $ SheetCorrector svaupel shId (Load (Just True) 1) CorrectorNormal
|
||||
void . insert $ SheetCorrector jost shId (Load (Just True) 0 1) CorrectorNormal
|
||||
void . insert $ SheetCorrector gkleen shId (Load (Just True) 1 1) CorrectorNormal
|
||||
void . insert $ SheetCorrector svaupel shId (Load (Just True) 1 1) CorrectorNormal
|
||||
void $ insertFile (SheetFileResidual shId SheetHint) "H10-2.hs"
|
||||
void $ insertFile (SheetFileResidual shId SheetSolution) "H10-3.hs"
|
||||
void $ insertFile (SheetFileResidual shId SheetExercise) "ProMo_Uebung10.pdf"
|
||||
|
||||
@ -26,7 +26,13 @@ import Database.Persist.Sql (fromSqlKey)
|
||||
|
||||
import qualified Database.Esqueleto as E
|
||||
|
||||
-- import Data.Maybe (fromJust)
|
||||
import Data.Monoid (First(..))
|
||||
|
||||
import Utils (guardOn)
|
||||
|
||||
import Control.Lens.Extras (is)
|
||||
|
||||
import Data.Maybe (fromJust)
|
||||
|
||||
|
||||
userNumber :: TVar Natural
|
||||
@ -46,8 +52,8 @@ makeUsers (fromIntegral -> n) = do
|
||||
return $ zipWith Entity uids users
|
||||
|
||||
distributionExample :: SqlPersistM [(Natural, [Maybe Load])] -- ^ Number of submissions and corrector specification
|
||||
-> ([Entity Submission] -> [Entity SheetCorrector] -> SqlPersistM ()) -- ^ Setup hook
|
||||
-> (Map (Maybe SheetCorrector) (Set SubmissionId) -> Expectation)
|
||||
-> (Natural -> [Entity Submission] -> [Entity SheetCorrector] -> SqlPersistM ()) -- ^ Setup hook
|
||||
-> (Map (Maybe SheetCorrector) (Set (SubmissionId, Maybe Natural)) -> Expectation)
|
||||
-> YesodExample UniWorX ()
|
||||
distributionExample mkParameters setupHook cont = do
|
||||
situations <- runDB $ do
|
||||
@ -88,11 +94,18 @@ distributionExample mkParameters setupHook cont = do
|
||||
|
||||
return (sid, (submissions, sheetCorrectors'))
|
||||
|
||||
mapM_ (uncurry setupHook) $ map snd situations
|
||||
mapM_ (\(n, (subs, corrs)) -> setupHook n subs corrs) . zip [1..] $ map snd situations
|
||||
|
||||
return situations
|
||||
situations' <- forM situations $ \(sid, (submissions, sheetCorrectors)) -> (sid, ) <$> do
|
||||
submissions' <- mapM (fmap fromJust . getEntity . entityKey) submissions
|
||||
sheetCorrectors' <- mapM (fmap fromJust . getEntity . entityKey) sheetCorrectors
|
||||
return (submissions', sheetCorrectors')
|
||||
|
||||
let subIds = concatMap (\(_, (subs, _)) -> map entityKey subs) situations
|
||||
return situations'
|
||||
|
||||
let
|
||||
subIds :: [SubmissionId]
|
||||
subIds = concatMap (\(_, (subs, _)) -> mapMaybe (\(Entity subId Submission{..}) -> guardOn (is _Nothing submissionRatingBy) subId) subs) situations
|
||||
|
||||
results <- runHandler . Yesod.runDB . mapM (\sid -> assignSubmissions sid Nothing) $ map fst situations
|
||||
|
||||
@ -104,15 +117,16 @@ distributionExample mkParameters setupHook cont = do
|
||||
cont . Map.fromListWith mappend $ do
|
||||
Entity subId Submission{..} <- submissions
|
||||
let key = listToMaybe . filter (\(Entity _ (SheetCorrector uid _ _ _)) -> Just uid == submissionRatingBy) $ concatMap (\(_, (_, corrs)) -> corrs) situations
|
||||
return (entityVal <$> key, Set.singleton subId)
|
||||
sheet = getFirst . foldMap (\(n, (sid, _)) -> First $ guardOn (sid == submissionSheet) n) $ zip [1..] situations
|
||||
return (entityVal <$> key, Set.singleton (subId, sheet))
|
||||
|
||||
|
||||
spec :: Spec
|
||||
spec = withApp . describe "Submission distribution" $ do
|
||||
it "is fair" $
|
||||
distributionExample
|
||||
(return [(500, replicate 10 (Just $ Load Nothing 1))])
|
||||
(\_ _ -> return ())
|
||||
(return [(500, replicate 10 (Just $ Load Nothing 1 1))])
|
||||
(\_ _ _ -> return ())
|
||||
(\result -> do
|
||||
let countResult = Map.map Set.size result
|
||||
countResult `shouldNotSatisfy` Map.member Nothing
|
||||
@ -120,20 +134,20 @@ spec = withApp . describe "Submission distribution" $ do
|
||||
)
|
||||
it "follows distribution" $
|
||||
distributionExample
|
||||
(return [(500, replicate 6 (Just $ Load Nothing 1) ++ replicate 2 (Just $ Load Nothing 2))])
|
||||
(\_ _ -> return ())
|
||||
(return [(500, replicate 6 (Just $ Load Nothing 1 1) ++ replicate 2 (Just $ Load Nothing 2 1))])
|
||||
(\_ _ _ -> return ())
|
||||
(\result -> do
|
||||
let countResult = Map.map Set.size result
|
||||
countResult `shouldNotSatisfy` Map.member Nothing
|
||||
countResult `shouldSatisfy` all (\(Just (SheetCorrector _ _ (Load _ prop) _), subsSet) -> (== 50 * prop) $ fromIntegral subsSet) . Map.toList
|
||||
countResult `shouldSatisfy` all (\(Just (SheetCorrector _ _ (Load _ prop _) _), subsSet) -> (== 50 * prop) $ fromIntegral subsSet) . Map.toList
|
||||
)
|
||||
it "follows cumulative distribution over multiple sheets" $ do
|
||||
ns <- liftIO . replicateM 5 . fmap fromInteger $ getRandomR (0, 100)
|
||||
let ns' = ns ++ [500 - sum ns]
|
||||
loads = replicate 6 (Just $ Load Nothing 1) ++ replicate 2 (Just $ Load Nothing 2)
|
||||
loads = replicate 6 (Just $ Load Nothing 1 1) ++ replicate 2 (Just $ Load Nothing 2 1)
|
||||
distributionExample
|
||||
(return [ (n, loads) | n <- ns' ])
|
||||
(\_ _ -> return ())
|
||||
(\_ _ _ -> return ())
|
||||
(\result -> do
|
||||
let countResult = Map.map Set.size result
|
||||
countResult' = Map.mapKeysWith (+) (fmap $ \SheetCorrector{..} -> (fromSqlKey sheetCorrectorUser, byProportion sheetCorrectorLoad)) countResult
|
||||
@ -144,12 +158,12 @@ spec = withApp . describe "Submission distribution" $ do
|
||||
let ns = replicate 4 100
|
||||
loads = do
|
||||
(onesBefore, onesAfter) <- zip [0,2..6] [6,4..0]
|
||||
return $ replicate onesBefore (Just $ Load Nothing 1)
|
||||
++ replicate 2 (Just $ Load Nothing 2)
|
||||
++ replicate onesAfter (Just $ Load Nothing 1)
|
||||
return $ replicate onesBefore (Just $ Load Nothing 1 1)
|
||||
++ replicate 2 (Just $ Load Nothing 2 1)
|
||||
++ replicate onesAfter (Just $ Load Nothing 1 1)
|
||||
distributionExample
|
||||
(return $ zip ns loads)
|
||||
(\_ _ -> return ())
|
||||
(\_ _ _ -> return ())
|
||||
(\result -> do
|
||||
let countResult = Map.map Set.size result
|
||||
countResult' = Map.mapKeysWith (+) (fmap $ \SheetCorrector{..} -> fromSqlKey sheetCorrectorUser) countResult
|
||||
@ -159,11 +173,11 @@ spec = withApp . describe "Submission distribution" $ do
|
||||
it "handles tutorials with proportion" $ do
|
||||
ns <- liftIO . replicateM 5 . fmap fromInteger $ getRandomR (0, 100)
|
||||
let ns' = ns ++ [500 - sum ns]
|
||||
loads = replicate 6 (Just $ Load (Just True) 1) ++ replicate 2 (Just $ Load (Just True) 2)
|
||||
loads = replicate 6 (Just $ Load (Just True) 1 1) ++ replicate 2 (Just $ Load (Just True) 2 1)
|
||||
tutSubIds <- liftIO $ newTVarIO Map.empty
|
||||
distributionExample
|
||||
(return [ (n, loads) | n <- ns' ])
|
||||
(\subs corrs -> do
|
||||
(\_ subs corrs -> do
|
||||
tutSubmissions <- liftIO $ getRandomR (5,10)
|
||||
subs' <- liftIO $ shuffleM subs
|
||||
forM_ (take tutSubmissions subs') $ \(Entity subId Submission{..}) -> do
|
||||
@ -192,3 +206,19 @@ spec = withApp . describe "Submission distribution" $ do
|
||||
-- HUnit.assertEqual ("Submission " <> show (fromSqlKey subId) <> " assigned to multiple correctors") 1 $ Set.size assignedTo
|
||||
-- HUnit.assertEqual ("Submission " <> show (fromSqlKey subId) <> " assigned to non-tutors (" <> show (Set.map fromSqlKey tutors) <> ")") Set.empty (Set.map fromSqlKey $ assignedTo `Set.difference` tutors)
|
||||
)
|
||||
it "allows disabling deficit consideration" $
|
||||
distributionExample
|
||||
(return . replicate 2 $ (500, replicate 2 (Just $ Load Nothing 1 0)))
|
||||
(\n subs corrs -> if
|
||||
| n < 2
|
||||
, Entity _ SheetCorrector{ sheetCorrectorUser = corrId } : _ <- corrs
|
||||
-> forM_ subs $ \(Entity subId _) ->
|
||||
update subId [SubmissionRatingBy =. Just corrId]
|
||||
| otherwise -> return ()
|
||||
)
|
||||
(\result -> do
|
||||
let secondResult = Map.map (Set.size . Set.filter (views _2 (== Just 1))) result
|
||||
allEqual [] = True
|
||||
allEqual ((_, c) : xs) = all (\(_, c') -> c == c') xs
|
||||
secondResult `shouldSatisfy` allEqual . Map.toList
|
||||
)
|
||||
|
||||
@ -149,6 +149,7 @@ instance Arbitrary Load where
|
||||
arbitrary = do
|
||||
byTutorial <- arbitrary
|
||||
byProportion <- getNonNegative <$> arbitrary
|
||||
byDeficit <- oneof [ pure 0, pure 1, arbitrary ]
|
||||
return Load{..}
|
||||
shrink = genericShrink
|
||||
|
||||
@ -523,16 +524,29 @@ spec = do
|
||||
toPathPiece ExamCloseSeparate `shouldBe` "separate"
|
||||
toPathPiece (ExamCloseOnFinished False) `shouldBe` "on-finished"
|
||||
toPathPiece (ExamCloseOnFinished True) `shouldBe` "on-finished-hidden"
|
||||
describe "Load" $
|
||||
it "decodes some examples from json" . example $ do
|
||||
let t str expect = Aeson.eitherDecode str `shouldBe` Right expect
|
||||
t "{}" $ Load Nothing 0 1
|
||||
t "{\"byTutorial\": true, \"byProportion\": {\"numerator\": 0, \"denominator\": 1}}" $ Load (Just True) 0 1
|
||||
describe "CompactCorrectorLoad" $ do
|
||||
it "matches expectations" . example $ do
|
||||
showCompactCorrectorLoad Load{ byTutorial = Just False, byProportion = 0 } CorrectorNormal `shouldBe` "T"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Just True, byProportion = 0 } CorrectorNormal `shouldBe` "(T)"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Nothing, byProportion = 1 } CorrectorNormal `shouldBe` "1.0"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Just False, byProportion = 1 } CorrectorNormal `shouldBe` "1.0 + T"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Just True, byProportion = 1 } CorrectorNormal `shouldBe` "1.0 + (T)"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Nothing, byProportion = 0 } CorrectorNormal `shouldBe` ""
|
||||
showCompactCorrectorLoad Load{ byTutorial = Nothing, byProportion = 1 } CorrectorMissing `shouldBe` "[1.0]"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Nothing, byProportion = 1 } CorrectorExcused `shouldBe` "{1.0}"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Just False, byProportion = 0, byDeficit = 1 } CorrectorNormal `shouldBe` "T"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Just True, byProportion = 0, byDeficit = 1 } CorrectorNormal `shouldBe` "(T)"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Nothing, byProportion = 1, byDeficit = 1 } CorrectorNormal `shouldBe` "1.0"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Just False, byProportion = 1, byDeficit = 1 } CorrectorNormal `shouldBe` "1.0 + T"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Just True, byProportion = 1, byDeficit = 1 } CorrectorNormal `shouldBe` "1.0 + (T)"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Nothing, byProportion = 0, byDeficit = 1 } CorrectorNormal `shouldBe` ""
|
||||
showCompactCorrectorLoad Load{ byTutorial = Nothing, byProportion = 1, byDeficit = 1 } CorrectorMissing `shouldBe` "[1.0]"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Nothing, byProportion = 1, byDeficit = 1 } CorrectorExcused `shouldBe` "{1.0}"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Just False, byProportion = 0, byDeficit = 0 } CorrectorNormal `shouldBe` "T - D"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Just True, byProportion = 0, byDeficit = 0 } CorrectorNormal `shouldBe` "(T) - D"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Nothing, byProportion = 1, byDeficit = 0 } CorrectorNormal `shouldBe` "1.0 - D"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Just False, byProportion = 1, byDeficit = 0 } CorrectorNormal `shouldBe` "1.0 + T - D"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Just True, byProportion = 1, byDeficit = 0 } CorrectorNormal `shouldBe` "1.0 + (T) - D"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Nothing, byProportion = 0, byDeficit = 0 } CorrectorNormal `shouldBe` "-D"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Nothing, byProportion = 1, byDeficit = 0 } CorrectorMissing `shouldBe` "[1.0 - D]"
|
||||
showCompactCorrectorLoad Load{ byTutorial = Nothing, byProportion = 1, byDeficit = 0 } CorrectorExcused `shouldBe` "{1.0 - D}"
|
||||
|
||||
termExample :: (TermIdentifier, Text) -> Expectation
|
||||
termExample (term, encoded) = example $ do
|
||||
|
||||
Loading…
Reference in New Issue
Block a user