segment_test.go (3664B)
1 package m3u8 2 3 import ( 4 "encoding/binary" 5 "os" 6 "reflect" 7 "testing" 8 "time" 9 ) 10 11 func TestMarshalSegments(t *testing.T) { 12 var cases = []struct { 13 name string 14 seg Segment 15 out string 16 }{ 17 { 18 "duration", 19 Segment{Duration: 10 * time.Second, URI: "bunny.ts"}, 20 "#EXTINF:10.000\nbunny.ts", 21 }, 22 { 23 "duration milliseconds", 24 Segment{URI: "something.ts", Duration: 9967 * time.Millisecond}, 25 "#EXTINF:9.967\nsomething.ts", 26 }, 27 { 28 "discontinuity with URI", 29 Segment{ 30 Duration: 30 * time.Second, 31 Discontinuity: true, 32 URI: "adbreak.ts", 33 }, 34 "#EXT-X-DISCONTINUITY\n#EXTINF:30.000\nadbreak.ts", 35 }, 36 { 37 "byte range", 38 Segment{ 39 Duration: 2 * time.Second, 40 URI: "vid.ts", 41 Range: ByteRange{69, 420}, 42 }, 43 "#EXT-X-BYTERANGE:69@420\n#EXTINF:2.000\nvid.ts", 44 }, 45 { 46 "title", 47 Segment{ 48 Duration: 2 * time.Second, 49 URI: "1.fmp4", 50 Title: "first", 51 }, 52 "#EXTINF:2.000,first\n1.fmp4", 53 }, 54 } 55 for _, tt := range cases { 56 t.Run(tt.name, func(t *testing.T) { 57 b, err := tt.seg.MarshalText() 58 if err != nil { 59 t.Fatal(err) 60 } 61 got := string(b) 62 if got != tt.out { 63 t.Errorf("segment text does not match expected") 64 t.Log("got:", got) 65 t.Log("want:", tt.out) 66 } 67 }) 68 } 69 } 70 71 func TestMarshalBadSegments(t *testing.T) { 72 var cases = []struct { 73 name string 74 seg Segment 75 }{ 76 {"empty", Segment{}}, 77 {"no duration", Segment{URI: "video.ts"}}, 78 {"impossible range", Segment{URI: "bbb.ts", Duration: 6 * time.Second, Range: ByteRange{999, 10}}}, 79 } 80 for _, tt := range cases { 81 t.Run(tt.name, func(t *testing.T) { 82 if _, err := tt.seg.MarshalText(); err == nil { 83 t.Fatalf("nil error encoding invalid segment") 84 } 85 }) 86 } 87 } 88 89 func TestWriteKey(t *testing.T) { 90 var iv [16]byte 91 binary.LittleEndian.PutUint64(iv[:8], 10000) 92 binary.LittleEndian.PutUint64(iv[8:], 98765432) 93 k := Key{ 94 Method: EncryptMethodAES128, 95 URI: "magic.key", 96 IV: iv, 97 Format: defaultKeyFormat, 98 FormatVersions: []uint32{1, 2, 5}, 99 } 100 want := `#EXT-X-KEY:METHOD=AES-128,URI="magic.key",IV=0x1027000000000000780ae30500000000,KEYFORMAT="identity",KEYFORMATVERSIONS="1/2/5"` 101 if k.String() != want { 102 t.Errorf("unexpected segment key text") 103 t.Log("got:", k.String()) 104 t.Log("want:", want) 105 } 106 } 107 108 func TestParseSegment(t *testing.T) { 109 f, err := os.Open("testdata/discontinuities.m3u8") 110 if err != nil { 111 t.Fatal(err) 112 } 113 defer f.Close() 114 115 plist, err := Decode(f) 116 if err != nil { 117 t.Fatalf("decode playlist: %v", err) 118 } 119 120 encrypted := Segment{ 121 Duration: 10 * time.Second, 122 Key: &Key{ 123 Method: EncryptMethodAES128, 124 URI: "key1.json?f=1041&s=0&p=1822767&m=1506045858", 125 IV: [...]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x1B, 0xD0, 0x2F}, 126 }, 127 DateTime: time.Date(2020, 12, 2, 18, 33, 3, 447e6, time.UTC), 128 URI: "1041_6_1822767.ts?m=1506045858", 129 } 130 131 if !reflect.DeepEqual(plist.Segments[0], encrypted) { 132 t.Errorf("decode encrypted segment: got %v, want %v", plist.Segments[0], encrypted) 133 } 134 } 135 136 func TestSegmentTitles(t *testing.T) { 137 f, err := os.Open("testdata/segment_titles.m3u8") 138 if err != nil { 139 t.Fatal(err) 140 } 141 defer f.Close() 142 143 plist, err := Decode(f) 144 if err != nil { 145 t.Fatalf("decode %s: %v", f.Name(), err) 146 } 147 148 want := Segment{ 149 Duration: 6 * time.Second, 150 Title: "second", 151 URI: "002.fmp4", 152 } 153 154 if want.Title != plist.Segments[1].Title { 155 t.Errorf("second segment title = %s, want %s", plist.Segments[1].Title, want.Title) 156 } 157 if plist.Segments[0].Title != "" || plist.Segments[2].Title != "" { 158 t.Errorf("unexpected non-empty titles in parsed segments") 159 } 160 }