+
+
+pickle_odds_info :: PU JFileGameOddsInfo
+pickle_odds_info =
+ xpElem "Odds_Info" $
+ xpWrap (from_tuple, to_tuple') $
+ xp19Tuple (xpElem "ListDate" (xpOption xp_date))
+ (xpElem "HomeTeamID" (xpOption xpText))
+ (xpElem "AwayTeamID" (xpOption xpText))
+ (xpElem "HomeAbbr" (xpOption xpText))
+ (xpElem "AwayAbbr" (xpOption xpText))
+ (xpElem "HomeTeamName" (xpOption xpText))
+ (xpElem "AwayTeamName" (xpOption xpText))
+ (xpElem "HStarter" (xpOption xpText))
+ (xpElem "AStarter" (xpOption xpText))
+ (xpElem "GameDate" (xpOption xp_datetime))
+ (xpElem "HGameKey" (xpOption xpInt))
+ (xpElem "AGameKey" (xpOption xpInt))
+ (xpElem "CurrentTimeStamp" (xpOption xp_time_dots))
+ (xpElem "Live" (xpOption xpPrim))
+ (xpElem "Notes1" xpText0)
+ (xpElem "Notes2" xpText0)
+ (xpElem "Notes3" xpText0)
+ (xpElem "Notes4" xpText0)
+ (xpElem "Notes5" xpText0)
+ where
+ from_tuple (x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,n1,n2,n3,n4,n5) =
+ JFileGameOddsInfo x1 x2 x3 x4 x5 x6 x7 x8 x9 x10 x11 x12 x13 x14 notes
+ where
+ notes = intercalate "\n" [n1,n2,n3,n4,n5]
+
+ to_tuple' o = (db_list_date o,
+ db_info_home_team_id o,
+ db_info_away_team_id o,
+ db_home_abbr o,
+ db_away_abbr o,
+ db_home_team_name o,
+ db_away_team_name o,
+ db_home_starter o,
+ db_away_starter o,
+ db_game_date o,
+ db_home_game_key o,
+ db_away_game_key o,
+ db_current_timestamp o,
+ db_live o,
+ n1,n2,n3,n4,n5)
+ where
+ note_lines = split "\n" (db_notes o)
+ n1 = case note_lines of
+ (notes1:_) -> notes1
+ _ -> ""
+ n2 = case note_lines of
+ (_:notes2:_) -> notes2
+ _ -> ""
+ n3 = case note_lines of
+ (_:_:notes3:_) -> notes3
+ _ -> ""
+ n4 = case note_lines of
+ (_:_:_:notes4:_) -> notes4
+ _ -> ""
+ n5 = case note_lines of
+ (_:_:_:_:notes5:_) -> notes5
+ _ -> ""
+
+-- | (Un)pickle a home team to/from the dual XML/DB representation
+-- 'Team'.
+--
+pickle_home_team :: PU HTeam
+pickle_home_team =
+ xpElem "hteam" $
+ xpWrap (from_tuple, to_tuple') $
+ xpTriple (xpAttr "teamid" xpText) -- Yeah, they're text.
+ (xpAttr "abbr" (xpOption xpText)) -- Some are blank
+ (xpOption xpText) -- Yup, some are nameless
+ where
+ from_tuple = HTeam . (uncurryN Team)
+ to_tuple' (HTeam t) = H.convert t
+
+
+-- | (Un)pickle an away team to/from the dual XML/DB representation
+-- 'Team'.
+--
+pickle_away_team :: PU VTeam
+pickle_away_team =
+ xpElem "vteam" $
+ xpWrap (from_tuple, to_tuple') $
+ xpTriple (xpAttr "teamid" xpText) -- Yeah, they're text.
+ (xpAttr "abbr" (xpOption xpText)) -- Some are blank
+ (xpOption xpText) -- Yup, some are nameless
+ where
+ from_tuple = VTeam . (uncurryN Team)
+ to_tuple' (VTeam t) = H.convert t
+
+
+pickle_status :: PU JFileGameStatus
+pickle_status =
+ xpElem "status" $
+ xpWrap (from_tuple, to_tuple') $
+ xpPair (xpAttr "numeral" xpInt)
+ (xpOption xpText)
+ where
+ from_tuple = uncurry JFileGameStatus
+
+ -- Avoid unused field warnings.
+ to_tuple' JFileGameStatus{..} = (db_status_numeral, db_status)
+
+
+--
+-- Tasty Tests
+--
+
+-- | A list of all tests for this module.
+--
+jfile_tests :: TestTree
+jfile_tests =
+ testGroup
+ "JFile tests"
+ [ test_on_delete_cascade,
+ test_pickle_of_unpickle_is_identity,
+ test_unpickle_succeeds ]
+
+
+-- | If we unpickle something and then pickle it, we should wind up
+-- with the same thing we started with. WARNING: success of this
+-- test does not mean that unpickling succeeded.
+--
+test_pickle_of_unpickle_is_identity :: TestTree
+test_pickle_of_unpickle_is_identity = testGroup "pickle-unpickle tests"
+ [ check "pickle composed with unpickle is the identity"
+ "test/xml/jfilexml.xml",
+ check "pickle composed with unpickle is the identity (missing fields)"
+ "test/xml/jfilexml-missing-fields.xml",
+
+ check "pickle composed with unpickle is the identity (TBA game time)"
+ "test/xml/jfilexml-tba-game-time.xml"]
+ where
+ check desc path = testCase desc $ do
+ (expected, actual) <- pickle_unpickle pickle_message path
+ actual @?= expected
+
+
+
+-- | Make sure we can actually unpickle these things.
+--
+test_unpickle_succeeds :: TestTree
+test_unpickle_succeeds = testGroup "unpickle tests"
+ [ check "unpickling succeeds" "test/xml/jfilexml.xml",
+
+ check "unpickling succeeds (missing fields)"
+ "test/xml/jfilexml-missing-fields.xml",
+
+ check "unpickling succeeds (TBA game time)"
+ "test/xml/jfilexml-tba-game-time.xml" ]
+ where
+ check desc path = testCase desc $ do
+ actual <- unpickleable path pickle_message
+
+ let expected = True
+ actual @?= expected
+
+
+
+-- | Make sure everything gets deleted when we delete the top-level
+-- record.
+--
+test_on_delete_cascade :: TestTree
+test_on_delete_cascade = testGroup "cascading delete tests"
+ [ check "deleting auto_racing_results deletes its children"
+ "test/xml/jfilexml.xml"
+ 20, -- teams
+
+ check "deleting auto_racing_results deletes its children (missing fields)"
+ "test/xml/jfilexml-missing-fields.xml"
+ 44,
+
+ check "deleting auto_racing_results deletes its children (TBA game time)"
+ "test/xml/jfilexml-tba-game-time.xml"
+ 8 ]
+ where
+ check desc path expected = testCase desc $ do
+ results <- unsafe_unpickle path pickle_message
+ let a = undefined :: Team
+ let b = undefined :: JFile
+ let c = undefined :: JFileGame
+
+ actual <- withSqliteConn ":memory:" $ runDbConn $ do
+ runMigrationSilent $ do
+ migrate a
+ migrate b
+ migrate c
+ _ <- dbimport results
+ deleteAll b
+ count_a <- countAll a
+ count_b <- countAll b
+ count_c <- countAll c
+ return $ sum [count_a, count_b, count_c]
+ actual @?= expected