-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathinfo_select_test.go
More file actions
194 lines (177 loc) · 8.68 KB
/
Copy pathinfo_select_test.go
File metadata and controls
194 lines (177 loc) · 8.68 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
package waxtap
import (
"testing"
"github.com/colespringer/waxtap/v3/format"
"github.com/colespringer/waxtap/v3/internal/media"
)
// TestSelectIndexHonorsChannelPreference is the index-mismatch core of the
// info --probe fix: under MinimizeLoss with no channel preference a higher-bitrate
// surround track outranks stereo, so InfoResult must select with the same channel
// preference the CLI displays rather than LayoutAny.
func TestSelectIndexHonorsChannelPreference(t *testing.T) {
// Identical except for channels and bitrate: with no layout preference the
// 6ch/256k track wins on bitrate; with a stereo preference the 2ch track wins
// because the channel match ranks above bitrate.
formats := []Format{
{Itag: 251, Codec: "opus", Extension: "webm", MIMEType: "audio/webm", Channels: 2, AverageBitrate: 160000, IsOriginal: Yes},
{Itag: 338, Codec: "opus", Extension: "webm", MIMEType: "audio/webm", Channels: 6, AverageBitrate: 256000, IsOriginal: Yes},
}
anyIdx, err := selectIndex(BestAudio().WithChannels(LayoutAny), MinimizeLoss(), format.Target{}, formats)
if err != nil {
t.Fatalf("selectIndex any: %v", err)
}
stereoIdx, err := selectIndex(BestAudio().WithChannels(LayoutStereo), MinimizeLoss(), format.Target{}, formats)
if err != nil {
t.Fatalf("selectIndex stereo: %v", err)
}
if formats[anyIdx].Channels != 6 {
t.Errorf("LayoutAny selected %dch (itag %d), want the 6ch surround track", formats[anyIdx].Channels, formats[anyIdx].Itag)
}
if formats[stereoIdx].Channels != 2 {
t.Errorf("LayoutStereo selected %dch (itag %d), want the 2ch stereo track", formats[stereoIdx].Channels, formats[stereoIdx].Itag)
}
if anyIdx == stereoIdx {
t.Fatal("channel preference must change the selected index; otherwise the probe/display mismatch cannot occur")
}
}
// TestFacadeDefaultsToStereo pins the F5 contract by driving the real seam code, so
// dropping the default wiring from a seam fails this test rather than shipping green:
// - Download: the actual selectSourceIndex on a bare Request must pick stereo.
// - Info: newReadOptions must seed the facade default, overridable by WithChannels.
// - Resolve: the zero AudioSelector, transformed as Resolve transforms it, picks
// stereo (selector-level: Resolve needs a live extraction to run end to end).
//
// Opting into surround or any-fidelity still reaches the surround track. The
// format-package ranking is unchanged (see TestSelectIndexHonorsChannelPreference).
func TestFacadeDefaultsToStereo(t *testing.T) {
c := newOfflineClient(t)
// The 6ch/256k track outranks 2ch/160k on bitrate under LayoutAny, so a missing
// default would hand back surround.
formats := []Format{
{Itag: 251, Codec: "opus", Extension: "webm", MIMEType: "audio/webm", Channels: 2, AverageBitrate: 160000, IsOriginal: Yes},
{Itag: 338, Codec: "opus", Extension: "webm", MIMEType: "audio/webm", Channels: 6, AverageBitrate: 256000, IsOriginal: Yes},
}
// Download seam: the actual selection path a Request takes inside Download/Stream.
download := func(t *testing.T, req Request) Format {
t.Helper()
idx, err := c.selectSourceIndex(req, format.Target{}, formats, 0)
if err != nil {
t.Fatalf("selectSourceIndex: %v", err)
}
return formats[idx]
}
if f := download(t, Request{}); f.Itag != 251 || f.Channels != 2 {
t.Errorf("bare Request selected itag %d (%dch), want the stereo itag 251", f.Itag, f.Channels)
}
if f := download(t, Request{Audio: BestAudio().WithChannels(LayoutAny)}); f.Channels != 6 {
t.Errorf("Request WithChannels(LayoutAny) selected %dch, want the 6ch surround track", f.Channels)
}
if f := download(t, Request{Audio: BestAudio().WithChannels(LayoutSurround)}); f.Channels != 6 {
t.Errorf("Request WithChannels(LayoutSurround) selected %dch, want 6ch surround", f.Channels)
}
// Info seam: newReadOptions seeds the facade default, and WithChannels overrides it.
if got := newReadOptions(nil).layout; got != defaultFacadeLayout {
t.Errorf("newReadOptions default layout = %v, want the facade default %v", got, defaultFacadeLayout)
}
if got := newReadOptions([]ReadOption{WithChannels(LayoutAny)}).layout; got != LayoutAny {
t.Errorf("WithChannels(LayoutAny) read option layout = %v, want LayoutAny (override honored)", got)
}
// Cross-seam agreement: the selector Info builds from its default, and the one
// Resolve wraps a zero selector into, both land on the same stereo itag as Download.
agree := func(t *testing.T, name string, sel AudioSelector) {
t.Helper()
idx, err := selectIndex(sel, MinimizeLoss(), format.Target{}, formats)
if err != nil {
t.Fatalf("%s selectIndex: %v", name, err)
}
if formats[idx].Itag != 251 {
t.Errorf("%s selected itag %d, want the stereo itag 251", name, formats[idx].Itag)
}
}
agree(t, "info", BestAudio().WithChannels(newReadOptions(nil).layout))
agree(t, "resolve", AudioSelector{}.WithDefaultChannels(defaultFacadeLayout))
}
// TestProbeMutationShiftsSelection shows why InfoResult must return the index it
// probed: applyProbe mutates the selected row in place, and re-selecting on the
// mutated slice can land on a different near-tie row. The probed numbers live on
// the originally selected row, so a re-selection would label an unprobed row.
func TestProbeMutationShiftsSelection(t *testing.T) {
// Two near-tie stereo Opus rows differing only by manifest bitrate; itag 251
// wins before the probe.
formats := []Format{
{Itag: 251, Codec: "opus", Extension: "webm", MIMEType: "audio/webm", Channels: 2, Bitrate: 200000, IsOriginal: Yes},
{Itag: 250, Codec: "opus", Extension: "webm", MIMEType: "audio/webm", Channels: 2, Bitrate: 190000, IsOriginal: Yes},
}
sel := BestAudio().WithChannels(LayoutStereo)
idx, err := selectIndex(sel, MinimizeLoss(), format.Target{}, formats)
if err != nil {
t.Fatalf("selectIndex: %v", err)
}
// A probe of the selected row corrects its bitrate below the runner-up's.
applyProbe(&formats[idx], media.ProbeResult{
Streams: []media.ProbeStream{{CodecType: "audio", SampleRate: 48000, Channels: 2, BitRate: 180000}},
})
reIdx, err := selectIndex(sel, MinimizeLoss(), format.Target{}, formats)
if err != nil {
t.Fatalf("selectIndex after probe: %v", err)
}
if reIdx == idx {
t.Fatal("expected the probe correction to shift the near-tie selection")
}
// The probed numbers are on idx, not reIdx: re-selecting would display an
// unprobed row labeled (probed). InfoResult.BestIndex returns idx to prevent that.
if formats[idx].Bitrate != 180000 {
t.Errorf("probed row (idx %d) bitrate = %d, want 180000", idx, formats[idx].Bitrate)
}
if formats[reIdx].Bitrate == 180000 {
t.Errorf("re-selected row (idx %d) should not carry the probed bitrate", reIdx)
}
}
// WithSelector and WithChannels can both speak for the channel layout, so the
// precedence has to be pinned rather than left to whichever is applied last: a
// selector carries the whole intent (which encoding, in which layout), while
// WithChannels is a preference for one field of it.
//
// The layout is unexported, so this asserts through selection itself, which is
// what the precedence actually decides.
func TestReadOptionSelectorBeatsChannels(t *testing.T) {
// One surround row and one stereo row, otherwise identical, so the chosen
// index names the layout that won.
formats := []Format{
{Itag: 1, Codec: "opus", Channels: 6, Bitrate: 128000},
{Itag: 2, Codec: "opus", Channels: 2, Bitrate: 128000},
}
pick := func(t *testing.T, opts ...ReadOption) int {
t.Helper()
ro := newReadOptions(opts)
idx, err := ro.sel.WithDefaultChannels(ro.layout).Select(formats, ro.policy, Target{})
if err != nil {
t.Fatalf("Select: %v", err)
}
return formats[idx].Itag
}
t.Run("the selector's layout wins", func(t *testing.T) {
if got := pick(t, WithChannels(LayoutStereo), WithSelector(BestAudio().WithChannels(LayoutSurround))); got != 1 {
t.Errorf("chose itag %d, want the selector's surround row", got)
}
})
// Order must not decide it: the same pair the other way round is the same
// request.
t.Run("order does not matter", func(t *testing.T) {
if got := pick(t, WithSelector(BestAudio().WithChannels(LayoutSurround)), WithChannels(LayoutStereo)); got != 1 {
t.Errorf("chose itag %d, want the selector's surround row", got)
}
})
// A selector that expressed no layout is exactly what WithChannels is for.
t.Run("channels fill in a selector that named none", func(t *testing.T) {
if got := pick(t, WithChannels(LayoutSurround), WithSelector(BestAudio())); got != 1 {
t.Errorf("chose itag %d, want surround to fill in", got)
}
})
t.Run("source policy is carried", func(t *testing.T) {
ro := newReadOptions([]ReadOption{WithSourcePolicy(PreferCodec("opus"))})
if got := ro.policy.Preferred(); got != "opus" {
t.Errorf("preferred = %q, want opus", got)
}
})
}