github.com/anacrolix/torrent@v1.61.0/metainfo/metainfo_test.go (about) 1 package metainfo 2 3 import ( 4 "io" 5 "os" 6 "path" 7 "path/filepath" 8 "strings" 9 "testing" 10 11 "github.com/anacrolix/missinggo/v2" 12 "github.com/davecgh/go-spew/spew" 13 qt "github.com/go-quicktest/qt" 14 "github.com/stretchr/testify/assert" 15 "github.com/stretchr/testify/require" 16 17 "github.com/anacrolix/torrent/bencode" 18 ) 19 20 func testFile(t *testing.T, filename string) { 21 mi, err := LoadFromFile(filename) 22 require.NoError(t, err) 23 info, err := mi.UnmarshalInfo() 24 require.NoError(t, err) 25 26 if len(info.Files) == 1 { 27 t.Logf("Single file: %s (length: %d)\n", info.BestName(), info.Files[0].Length) 28 } else { 29 t.Logf("Multiple files: %s\n", info.BestName()) 30 for _, f := range info.Files { 31 t.Logf(" - %s (length: %d)\n", path.Join(f.Path...), f.Length) 32 } 33 } 34 35 for _, group := range mi.AnnounceList { 36 for _, tracker := range group { 37 t.Logf("Tracker: %s\n", tracker) 38 } 39 } 40 41 b, err := bencode.Marshal(&info) 42 require.NoError(t, err) 43 assert.EqualValues(t, string(b), string(mi.InfoBytes)) 44 } 45 46 func TestFile(t *testing.T) { 47 testFile(t, "testdata/archlinux-2011.08.19-netinstall-i686.iso.torrent") 48 testFile(t, "testdata/continuum.torrent") 49 testFile(t, "testdata/23516C72685E8DB0C8F15553382A927F185C4F01.torrent") 50 testFile(t, "testdata/trackerless.torrent") 51 _, err := LoadFromFile("testdata/minimal-trailing-newline.torrent") 52 qt.Check(t, qt.ErrorMatches(err, ".*expected EOF")) 53 } 54 55 // Ensure that the correct number of pieces are generated when hashing files. 56 func TestNumPieces(t *testing.T) { 57 for _, _case := range []struct { 58 PieceLength int64 59 Files []FileInfo 60 NumPieces int 61 }{ 62 {256 * 1024, []FileInfo{{Length: 1024*1024 + -1}}, 4}, 63 {256 * 1024, []FileInfo{{Length: 1024 * 1024}}, 4}, 64 {256 * 1024, []FileInfo{{Length: 1024*1024 + 1}}, 5}, 65 {5, []FileInfo{{Length: 1}, {Length: 12}}, 3}, 66 {5, []FileInfo{{Length: 4}, {Length: 12}}, 4}, 67 } { 68 info := Info{ 69 Files: _case.Files, 70 PieceLength: _case.PieceLength, 71 } 72 err := info.GeneratePieces(func(fi FileInfo) (io.ReadCloser, error) { 73 return io.NopCloser(missinggo.ZeroReader), nil 74 }) 75 assert.NoError(t, err) 76 assert.EqualValues(t, _case.NumPieces, info.NumPieces()) 77 } 78 } 79 80 func touchFile(path string) (err error) { 81 f, err := os.Create(path) 82 if err != nil { 83 return 84 } 85 err = f.Close() 86 return 87 } 88 89 func TestBuildFromFilePathOrder(t *testing.T) { 90 td := t.TempDir() 91 require.NoError(t, touchFile(filepath.Join(td, "b"))) 92 require.NoError(t, touchFile(filepath.Join(td, "a"))) 93 info := Info{ 94 PieceLength: 1, 95 } 96 require.NoError(t, info.BuildFromFilePath(td)) 97 assert.EqualValues(t, []FileInfo{{ 98 Path: []string{"a"}, 99 }, { 100 Path: []string{"b"}, 101 }}, info.Files) 102 } 103 104 func testUnmarshal(t *testing.T, input string, expected *MetaInfo) { 105 var actual MetaInfo 106 err := bencode.Unmarshal([]byte(input), &actual) 107 if expected == nil { 108 assert.Error(t, err) 109 return 110 } 111 assert.NoError(t, err) 112 assert.EqualValues(t, *expected, actual) 113 } 114 115 func TestUnmarshal(t *testing.T) { 116 testUnmarshal(t, `de`, &MetaInfo{}) 117 testUnmarshal(t, `d4:infoe`, nil) 118 testUnmarshal(t, `d4:infoabce`, nil) 119 testUnmarshal(t, `d4:infodee`, &MetaInfo{InfoBytes: []byte("de")}) 120 } 121 122 func TestMetainfoWithListURLList(t *testing.T) { 123 mi, err := LoadFromFile("testdata/SKODAOCTAVIA336x280_archive.torrent") 124 require.NoError(t, err) 125 assert.Len(t, mi.UrlList, 3) 126 qt.Assert(t, qt.ContentEquals(mi.Magnet(nil, nil).String(), 127 strings.Join([]string{ 128 "magnet:?xt=urn:btih:d4b197dff199aad447a9a352e31528adbbd97922", 129 "tr=http%3A%2F%2Fbt1.archive.org%3A6969%2Fannounce", 130 "tr=http%3A%2F%2Fbt2.archive.org%3A6969%2Fannounce", 131 "ws=https%3A%2F%2Farchive.org%2Fdownload%2F", 132 "ws=http%3A%2F%2Fia601600.us.archive.org%2F26%2Fitems%2F", 133 "ws=http%3A%2F%2Fia801600.us.archive.org%2F26%2Fitems%2F", 134 }, "&"))) 135 } 136 137 func TestMetainfoWithStringURLList(t *testing.T) { 138 mi, err := LoadFromFile("testdata/flat-url-list.torrent") 139 require.NoError(t, err) 140 assert.Len(t, mi.UrlList, 1) 141 qt.Assert(t, qt.ContentEquals(mi.Magnet(nil, nil).String(), 142 strings.Join([]string{ 143 "magnet:?xt=urn:btih:9da24e606e4ed9c7b91c1772fb5bf98f82bd9687", 144 "tr=http%3A%2F%2Fbt1.archive.org%3A6969%2Fannounce", 145 "tr=http%3A%2F%2Fbt2.archive.org%3A6969%2Fannounce", 146 "ws=https%3A%2F%2Farchive.org%2Fdownload%2F", 147 }, "&"))) 148 } 149 150 // https://github.com/anacrolix/torrent/issues/247 151 // 152 // The decoder buffer wasn't cleared before starting the next dict item after 153 // a syntax error on a field with the ignore_unmarshal_type_error tag. 154 func TestStringCreationDate(t *testing.T) { 155 var mi MetaInfo 156 assert.NoError(t, bencode.Unmarshal([]byte("d13:creation date23:29.03.2018 22:18:14 UTC4:infodee"), &mi)) 157 } 158 159 // See https://github.com/anacrolix/torrent/issues/843. 160 func TestUnmarshalEmptyStringNodes(t *testing.T) { 161 var mi MetaInfo 162 err := bencode.Unmarshal([]byte("d5:nodes0:e"), &mi) 163 qt.Assert(t, qt.IsNil(err)) 164 } 165 166 func TestUnmarshalV2Metainfo(t *testing.T) { 167 mi, err := LoadFromFile("../testdata/bittorrent-v2-test.torrent") 168 qt.Assert(t, qt.IsNil(err)) 169 info, err := mi.UnmarshalInfo() 170 qt.Assert(t, qt.IsNil(err)) 171 spew.Dump(info) 172 qt.Check(t, qt.Not(qt.Equals(info.NumPieces(), 0))) 173 err = ValidatePieceLayers(mi.PieceLayers, &info.FileTree, info.PieceLength) 174 qt.Check(t, qt.IsNil(err)) 175 }