From 3d131e0e70c8feab94301b969874239b8e60b747 Mon Sep 17 00:00:00 2001
From: Ramakrishnan Muthukrishnan <ram@rkrishnan.org>
Date: Sun, 17 Jul 2016 13:20:43 +0530
Subject: [PATCH] multi-file torrent metainfo tests

---
 src/FuncTorrent/Bencode.hs  |  1 +
 src/FuncTorrent/Metainfo.hs | 24 +++++++++++++++---------
 test/MetainfoSpec.hs        | 22 ++++++++++++++++++----
 3 files changed, 34 insertions(+), 13 deletions(-)

diff --git a/src/FuncTorrent/Bencode.hs b/src/FuncTorrent/Bencode.hs
index 294ad89..4703084 100644
--- a/src/FuncTorrent/Bencode.hs
+++ b/src/FuncTorrent/Bencode.hs
@@ -95,3 +95,4 @@ encode (Bdict d) = concat ["d", concat kvlist, "e"]
       kvlist :: [ByteString]
       kvlist = [encPair kv | kv <- toList d]
       encPair (k, v) = concat [encode . Bstr . pack $ k, encode v]
+
diff --git a/src/FuncTorrent/Metainfo.hs b/src/FuncTorrent/Metainfo.hs
index 596ad68..ec65294 100644
--- a/src/FuncTorrent/Metainfo.hs
+++ b/src/FuncTorrent/Metainfo.hs
@@ -23,12 +23,14 @@ module FuncTorrent.Metainfo
     (Info(..)
     , Metainfo(..)
     , DynamicInfo(..)
+    , FileInfo(..)
     , torrentToMetainfo
     ) where
 
 import Prelude hiding (lookup)
 import Data.ByteString.Char8 (ByteString, unpack)
 import Data.Map as M ((!), lookup)
+import Data.List (intercalate)
 import Crypto.Hash.SHA1 (hash)
 import Data.Maybe (maybeToList)
 
@@ -41,10 +43,7 @@ data Info = Info { pieceLength :: !Integer
                  , dyninfo :: !DynamicInfo
                  } deriving (Eq, Show)
 
-data DynamicInfo = SingleFileInfo { name :: String
-                                  , lengthInBytes :: Integer
-                                  , md5sum :: Maybe String
-                                  }
+data DynamicInfo = SingleFileInfo { file :: FileInfo }
                  | MultiFileInfo { dname :: String
                                  , files :: [FileInfo]
                                  }
@@ -64,6 +63,9 @@ data Metainfo = Metainfo { info :: !Info
                          , infoHash :: !ByteString
                          } deriving (Eq, Show)
 
+mkPath :: [BVal] -> String
+mkPath xs = intercalate "/" $ map (\b -> let (Just s) = bstrToString b in s) xs
+
 mkInfo :: BVal -> Maybe Info
 mkInfo (Bdict m) = let (Bint pieceLength') = m ! "piece length"
                        (Bstr pieces') = m ! "pieces"
@@ -82,11 +84,12 @@ mkInfo (Bdict m) = let (Bint pieceLength') = m ! "piece length"
                                                   files =
                                                       map (\(Bdict f) ->
                                                             let (Just len') = bValToInteger (f ! "length")
-                                                                (Bstr s') = f ! "path"
+                                                                (Blist ds) = f ! "path"
+                                                                path' = mkPath ds
                                                             in
                                                               FileInfo { lengthInBytes = len',
                                                                          md5sum = Nothing,
-                                                                         path = unpack s'
+                                                                         path = path'
                                                                      })
                                                       files' }
                                               }
@@ -98,9 +101,12 @@ mkInfo (Bdict m) = let (Bint pieceLength') = m ! "piece length"
                                               , pieces = pieces'
                                               , private = private'
                                               , dyninfo = SingleFileInfo {
-                                                  name = unpack name',
-                                                  lengthInBytes = length',
-                                                  md5sum = md5sum'}
+                                                  file = FileInfo {
+                                                      path = unpack name',
+                                                      lengthInBytes = length',
+                                                      md5sum = md5sum'
+                                                      }
+                                                  }
                                               }
 
 mkInfo _ = Nothing
diff --git a/test/MetainfoSpec.hs b/test/MetainfoSpec.hs
index 93bf9ab..060bf9f 100644
--- a/test/MetainfoSpec.hs
+++ b/test/MetainfoSpec.hs
@@ -23,7 +23,7 @@ module MetainfoSpec where
 
 import Test.Hspec
 
-import FuncTorrent.Metainfo (Info(..), Metainfo(..), DynamicInfo(..), torrentToMetainfo)
+import FuncTorrent.Metainfo (Info(..), Metainfo(..), DynamicInfo(..), FileInfo(..), torrentToMetainfo)
 import qualified Data.ByteString.Lazy.Char8 as BC (readFile, toStrict)
 import qualified Data.ByteString as B
 
@@ -36,11 +36,25 @@ spec =
       length (announceList m) `shouldBe` 1
       pieceLength (info m) `shouldBe` 524288
       pieces (info m) `shouldSatisfy` (\p -> B.length p `mod` 20 == 0)
-      let (SingleFileInfo name' _ _) = dyninfo $ info m
+      let (SingleFileInfo file') = dyninfo $ info m
+          (FileInfo _ _ name') = file'
+      name' `shouldNotBe` ""
+    it "torrent-file-2" $ do
+      c <- BC.readFile "data/test2.torrent"
+      let (Right m) = torrentToMetainfo (BC.toStrict c)
+          (SingleFileInfo file') = dyninfo $ info m
+          (FileInfo _ _ name') = file'
+      name' `shouldNotBe` ""
+    it "torrent-file-3" $ do
+      c <- BC.readFile "data/test3.torrent"
+      let (Right m) = torrentToMetainfo (BC.toStrict c)
+          (SingleFileInfo file') = dyninfo $ info m
+          (FileInfo _ _ name') = file'
       name' `shouldNotBe` ""
     it "torrent-file-4" $ do
       c <- BC.readFile "data/test4.torrent"
       let (Right m) = torrentToMetainfo (BC.toStrict c)
       length (announceList m) `shouldBe` 3
-      let (MultiFileInfo _ files') = dyninfo $ info m
-      length files' `shouldNotBe` 1
+      let (MultiFileInfo dname' files') = dyninfo $ info m
+      length files' `shouldBe` 9 -- 9 files in the torrent
+      dname' `shouldBe` "NASA_NTRS_Archive_19740027163"
-- 
2.45.2