• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Courseography / courseography / 91986145-cc23-45ad-b40f-6f7e0c8efd41

26 Jul 2026 10:21AM UTC coverage: 59.086% (+0.5%) from 58.617%
91986145-cc23-45ad-b40f-6f7e0c8efd41

Pull #1774

circleci

Purplegaze
initial solution, no tests yet
Pull Request #1774: Refactor hybrid text parsing to account for arbitrarily-nested ANDs and ORs

514 of 977 branches covered (52.61%)

Branch coverage included in aggregate %.

78 of 95 new or added lines in 2 files covered. (82.11%)

658 existing lines in 34 files now uncovered.

2422 of 3992 relevant lines covered (60.67%)

162.8 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.93
/app/DynamicGraphs/GraphNodeUtils.hs
1
module DynamicGraphs.GraphNodeUtils
2
    ( stringifyModAnd
3
    , formatModOr
4
    , concatModOr
5
    , maybeHead
6
    , paddingSpaces
7
    ) where
8

9
import Database.Requirement (Modifier (..), Req (..))
10

11
-- | Converts the given number of credits and list of modifiers into a string
12
-- | in readable English
13
-- | Assumes each modifier constructor appears in modifiers at most once
14
-- | The ModOr constructor may appear more than once, but each occurrence
15
-- | of ModOr contains exactly one constructor for all its elements
16
-- | and such constructor does not appear anywhere else in ModAnd
17
stringifyModAnd :: Float -> [Modifier] -> String
18
stringifyModAnd creds modifiers = let
9✔
19
    dept = maybeHead [x | Department x <- modifiers]
9✔
20
    deptFormatted = case dept of
9✔
21
        Nothing -> ""
1✔
22
        Just x -> ' ' : x
5✔
23
    depts = maybeHead [xs | ModOr xs@((Department _):_) <- modifiers]
9✔
24
    deptsFormatted = case depts of
9✔
25
        Nothing -> ""
1✔
26
        Just xs -> ' ' : concatModOr xs
3✔
27
    level = maybeHead [x | Level x <- modifiers]
9✔
28
    levelFormatted = case level of
9✔
29
        Nothing -> ""
1✔
30
        Just x -> " at the " ++ x ++ " level"
4✔
31
    levels = maybeHead [xs | ModOr xs@((Level _):_) <- modifiers]
9✔
32
    levelsFormatted = case levels of
9✔
33
        Nothing -> ""
1✔
34
        Just xs -> " at the " ++ concatModOr xs ++ " level"
4✔
35
    raw = maybeHead [x | Requirement (Raw x) <- modifiers]
9✔
36
    rawFormatted = case raw of
9✔
37
        Nothing -> ""
1✔
38
        Just x -> " from " ++ x
4✔
39
    raws = maybeHead [xs | ModOr xs@((Requirement (Raw _)):_) <- modifiers]
9✔
40
    rawsFormatted = case raws of
9✔
41
        Nothing -> ""
1✔
UNCOV
42
        Just xs -> " from " ++ concatModOr xs
×
43

44
    in show creds ++ deptFormatted ++ deptsFormatted ++ " FCEs"
9✔
45
        ++ levelFormatted ++ levelsFormatted ++ rawFormatted ++ rawsFormatted
9✔
46

47
-- | Formats a ModOr into Fces string
48
-- | Assumes all modifiers in the ModOr have the same constructor
49
formatModOr :: Float -> [Modifier] -> String
UNCOV
50
formatModOr creds mods@((Department _):_) = show creds ++ " " ++ concatModOr mods ++ " FCEs"
×
UNCOV
51
formatModOr creds mods@((Level _):_) = show creds ++ " FCEs at the " ++ concatModOr mods ++ " level"
×
UNCOV
52
formatModOr creds mods@((Requirement (Raw _)):_) = show creds ++ " FCEs from " ++ concatModOr mods
×
UNCOV
53
formatModOr _ _ = "" -- we should never get here
×
54

55
-- | Joins a list of modifiers in ModOr together with a "/" or "or"
56
-- | Assumes all modifiers in the list have the same constructor
57
concatModOr :: [Modifier] -> String
58
concatModOr [Level x] = x
5✔
59
concatModOr ((Level x):xs) = x ++ "/" ++ concatModOr xs
5✔
60
concatModOr [Department x] = x
5✔
61
concatModOr ((Department x):xs) = x ++ "/" ++ concatModOr xs
7✔
62
concatModOr [Requirement (Raw x)] = x
1✔
63
concatModOr ((Requirement (Raw x)):xs) = x ++ " or " ++ concatModOr xs
1✔
UNCOV
64
concatModOr _ = "" -- we should never get here
×
65

66
-- | Returns Just the first element of the given list, or Nothing if the list is empty
67
maybeHead :: [a] -> Maybe a
68
maybeHead [] = Nothing
2✔
69
maybeHead (x:_) = Just x
20✔
70

71
paddingSpaces :: Int -> [Char]
UNCOV
72
paddingSpaces n = Prelude.replicate n ' '
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc