mirror of
https://github.com/pion/mediadevices.git
synced 2026-04-22 15:57:27 +08:00
Add human friendly string implementation
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package prop
|
||||
|
||||
import "fmt"
|
||||
|
||||
// BoolConstraint is an interface to represent bool value constraint.
|
||||
type BoolConstraint interface {
|
||||
Compare(bool) (float64, bool)
|
||||
@@ -20,6 +22,11 @@ func (b BoolExact) Compare(o bool) (float64, bool) {
|
||||
// Value implements BoolConstraint.
|
||||
func (b BoolExact) Value() bool { return bool(b) }
|
||||
|
||||
// String implements Stringify
|
||||
func (b BoolExact) String() string {
|
||||
return fmt.Sprintf("%t (exact)", b)
|
||||
}
|
||||
|
||||
// Bool specifies ideal bool value.
|
||||
type Bool BoolExact
|
||||
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package prop
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -23,6 +25,11 @@ func (d Duration) Compare(a time.Duration) (float64, bool) {
|
||||
// Value implements DurationConstraint.
|
||||
func (d Duration) Value() (time.Duration, bool) { return time.Duration(d), true }
|
||||
|
||||
// String implements Stringify
|
||||
func (d Duration) String() string {
|
||||
return fmt.Sprintf("%v (ideal)", time.Duration(d))
|
||||
}
|
||||
|
||||
// DurationExact specifies exact duration value.
|
||||
type DurationExact time.Duration
|
||||
|
||||
@@ -37,6 +44,11 @@ func (d DurationExact) Compare(a time.Duration) (float64, bool) {
|
||||
// Value implements DurationConstraint.
|
||||
func (d DurationExact) Value() (time.Duration, bool) { return time.Duration(d), true }
|
||||
|
||||
// String implements Stringify
|
||||
func (d DurationExact) String() string {
|
||||
return fmt.Sprintf("%v (exact)", time.Duration(d))
|
||||
}
|
||||
|
||||
// DurationOneOf specifies list of expected duration values.
|
||||
type DurationOneOf []time.Duration
|
||||
|
||||
@@ -53,6 +65,16 @@ func (d DurationOneOf) Compare(a time.Duration) (float64, bool) {
|
||||
// Value implements DurationConstraint.
|
||||
func (DurationOneOf) Value() (time.Duration, bool) { return 0, false }
|
||||
|
||||
// String implements Stringify
|
||||
func (d DurationOneOf) String() string {
|
||||
var opts []string
|
||||
for _, v := range d {
|
||||
opts = append(opts, fmt.Sprint(v))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s (one of values)", strings.Join(opts, ","))
|
||||
}
|
||||
|
||||
// DurationRanged specifies range of expected duration value.
|
||||
// If Ideal is non-zero, closest value to Ideal takes priority.
|
||||
type DurationRanged struct {
|
||||
@@ -96,3 +118,8 @@ func (d DurationRanged) Compare(a time.Duration) (float64, bool) {
|
||||
|
||||
// Value implements DurationConstraint.
|
||||
func (DurationRanged) Value() (time.Duration, bool) { return 0, false }
|
||||
|
||||
// String implements Stringify
|
||||
func (d DurationRanged) String() string {
|
||||
return fmt.Sprintf("%s - %s (range), %s (ideal)", d.Min, d.Max, d.Ideal)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package prop
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// FloatConstraint is an interface to represent float value constraint.
|
||||
@@ -22,6 +24,11 @@ func (f Float) Compare(a float32) (float64, bool) {
|
||||
// Value implements FloatConstraint.
|
||||
func (f Float) Value() (float32, bool) { return float32(f), true }
|
||||
|
||||
// String implements Stringify
|
||||
func (f Float) String() string {
|
||||
return fmt.Sprintf("%.2f (ideal)", f)
|
||||
}
|
||||
|
||||
// FloatExact specifies exact float value.
|
||||
type FloatExact float32
|
||||
|
||||
@@ -36,6 +43,11 @@ func (f FloatExact) Compare(a float32) (float64, bool) {
|
||||
// Value implements FloatConstraint.
|
||||
func (f FloatExact) Value() (float32, bool) { return float32(f), true }
|
||||
|
||||
// String implements Stringify
|
||||
func (f FloatExact) String() string {
|
||||
return fmt.Sprintf("%.2f (exact)", f)
|
||||
}
|
||||
|
||||
// FloatOneOf specifies list of expected float values.
|
||||
type FloatOneOf []float32
|
||||
|
||||
@@ -52,6 +64,16 @@ func (f FloatOneOf) Compare(a float32) (float64, bool) {
|
||||
// Value implements FloatConstraint.
|
||||
func (FloatOneOf) Value() (float32, bool) { return 0, false }
|
||||
|
||||
// String implements Stringify
|
||||
func (f FloatOneOf) String() string {
|
||||
var opts []string
|
||||
for _, v := range f {
|
||||
opts = append(opts, fmt.Sprintf("%.2f", v))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s (one of values)", strings.Join(opts, ","))
|
||||
}
|
||||
|
||||
// FloatRanged specifies range of expected float value.
|
||||
// If Ideal is non-zero, closest value to Ideal takes priority.
|
||||
type FloatRanged struct {
|
||||
@@ -95,3 +117,8 @@ func (f FloatRanged) Compare(a float32) (float64, bool) {
|
||||
|
||||
// Value implements FloatConstraint.
|
||||
func (FloatRanged) Value() (float32, bool) { return 0, false }
|
||||
|
||||
// String implements Stringify
|
||||
func (f FloatRanged) String() string {
|
||||
return fmt.Sprintf("%.2f - %.2f (range), %.2f (ideal)", f.Min, f.Max, f.Ideal)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package prop
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/pion/mediadevices/pkg/frame"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// FrameFormatConstraint is an interface to represent frame format constraint.
|
||||
@@ -25,6 +27,11 @@ func (f FrameFormat) Compare(a frame.Format) (float64, bool) {
|
||||
// Value implements FrameFormatConstraint.
|
||||
func (f FrameFormat) Value() (frame.Format, bool) { return frame.Format(f), true }
|
||||
|
||||
// String implements Stringify
|
||||
func (f FrameFormat) String() string {
|
||||
return fmt.Sprintf("%s (ideal)", frame.Format(f))
|
||||
}
|
||||
|
||||
// FrameFormatExact specifies exact frame format.
|
||||
type FrameFormatExact frame.Format
|
||||
|
||||
@@ -39,6 +46,11 @@ func (f FrameFormatExact) Compare(a frame.Format) (float64, bool) {
|
||||
// Value implements FrameFormatConstraint.
|
||||
func (f FrameFormatExact) Value() (frame.Format, bool) { return frame.Format(f), true }
|
||||
|
||||
// String implements Stringify
|
||||
func (f FrameFormatExact) String() string {
|
||||
return fmt.Sprintf("%s (exact)", frame.Format(f))
|
||||
}
|
||||
|
||||
// FrameFormatOneOf specifies list of expected frame format.
|
||||
type FrameFormatOneOf []frame.Format
|
||||
|
||||
@@ -54,3 +66,13 @@ func (f FrameFormatOneOf) Compare(a frame.Format) (float64, bool) {
|
||||
|
||||
// Value implements FrameFormatConstraint.
|
||||
func (FrameFormatOneOf) Value() (frame.Format, bool) { return "", false }
|
||||
|
||||
// String implements Stringify
|
||||
func (f FrameFormatOneOf) String() string {
|
||||
var opts []string
|
||||
for _, v := range f {
|
||||
opts = append(opts, fmt.Sprint(v))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s (one of values)", strings.Join(opts, ","))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package prop
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// IntConstraint is an interface to represent integer value constraint.
|
||||
@@ -22,6 +24,11 @@ func (i Int) Compare(a int) (float64, bool) {
|
||||
// Value implements IntConstraint.
|
||||
func (i Int) Value() (int, bool) { return int(i), true }
|
||||
|
||||
// String implements Stringify
|
||||
func (i Int) String() string {
|
||||
return fmt.Sprintf("%d (ideal)", i)
|
||||
}
|
||||
|
||||
// IntExact specifies exact int value.
|
||||
type IntExact int
|
||||
|
||||
@@ -33,6 +40,11 @@ func (i IntExact) Compare(a int) (float64, bool) {
|
||||
return 1.0, false
|
||||
}
|
||||
|
||||
// String implements Stringify
|
||||
func (i IntExact) String() string {
|
||||
return fmt.Sprintf("%d (exact)", i)
|
||||
}
|
||||
|
||||
// Value implements IntConstraint.
|
||||
func (i IntExact) Value() (int, bool) { return int(i), true }
|
||||
|
||||
@@ -52,6 +64,16 @@ func (i IntOneOf) Compare(a int) (float64, bool) {
|
||||
// Value implements IntConstraint.
|
||||
func (IntOneOf) Value() (int, bool) { return 0, false }
|
||||
|
||||
// String implements Stringify
|
||||
func (i IntOneOf) String() string {
|
||||
var opts []string
|
||||
for _, v := range i {
|
||||
opts = append(opts, fmt.Sprint(v))
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s (one of values)", strings.Join(opts, ","))
|
||||
}
|
||||
|
||||
// IntRanged specifies range of expected int value.
|
||||
// If Ideal is non-zero, closest value to Ideal takes priority.
|
||||
type IntRanged struct {
|
||||
@@ -95,3 +117,8 @@ func (i IntRanged) Compare(a int) (float64, bool) {
|
||||
|
||||
// Value implements IntConstraint.
|
||||
func (IntRanged) Value() (int, bool) { return 0, false }
|
||||
|
||||
// String implements Stringify
|
||||
func (i IntRanged) String() string {
|
||||
return fmt.Sprintf("%d - %d (range), %d (ideal)", i.Min, i.Max, i.Ideal)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package prop
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pion/mediadevices/pkg/frame"
|
||||
@@ -15,6 +17,10 @@ type MediaConstraints struct {
|
||||
AudioConstraints
|
||||
}
|
||||
|
||||
func (m *MediaConstraints) String() string {
|
||||
return prettifyStruct(m)
|
||||
}
|
||||
|
||||
// Media stores single set of media propaties.
|
||||
type Media struct {
|
||||
DeviceID string
|
||||
@@ -22,6 +28,33 @@ type Media struct {
|
||||
Audio
|
||||
}
|
||||
|
||||
func (m *Media) String() string {
|
||||
return prettifyStruct(m)
|
||||
}
|
||||
|
||||
func prettifyStruct(i interface{}) string {
|
||||
var rows []string
|
||||
var addRows func(int, reflect.Value)
|
||||
addRows = func(level int, obj reflect.Value) {
|
||||
typeOf := obj.Type()
|
||||
for i := 0; i < obj.NumField(); i++ {
|
||||
field := typeOf.Field(i)
|
||||
value := obj.Field(i)
|
||||
|
||||
padding := strings.Repeat(" ", level)
|
||||
if value.Kind() == reflect.Struct {
|
||||
rows = append(rows, fmt.Sprintf("%s%v:", padding, field.Name))
|
||||
addRows(level+1, value)
|
||||
} else {
|
||||
rows = append(rows, fmt.Sprintf("%s%v: %v", padding, field.Name, value))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addRows(0, reflect.ValueOf(i).Elem())
|
||||
return strings.Join(rows, "\n")
|
||||
}
|
||||
|
||||
// setterFn is a callback function to set value from fieldB to fieldA
|
||||
type setterFn func(fieldA, fieldB reflect.Value)
|
||||
|
||||
|
||||
@@ -309,3 +309,60 @@ func TestMergeConstraintsNested(t *testing.T) {
|
||||
t.Error("expected a.Width to be 100, but got 0")
|
||||
}
|
||||
}
|
||||
|
||||
func TestString(t *testing.T) {
|
||||
t.Run("IdealValues", func(t *testing.T) {
|
||||
t.Log("\n", &MediaConstraints{
|
||||
DeviceID: String("one"),
|
||||
VideoConstraints: VideoConstraints{
|
||||
Width: Int(1920),
|
||||
FrameRate: Float(30.0),
|
||||
FrameFormat: FrameFormat(frame.FormatI420),
|
||||
},
|
||||
AudioConstraints: AudioConstraints{
|
||||
Latency: Duration(time.Millisecond * 20),
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("ExactValues", func(t *testing.T) {
|
||||
t.Log("\n", &MediaConstraints{
|
||||
DeviceID: StringExact("one"),
|
||||
VideoConstraints: VideoConstraints{
|
||||
Width: IntExact(1920),
|
||||
FrameRate: FloatExact(30.0),
|
||||
FrameFormat: FrameFormatExact(frame.FormatI420),
|
||||
},
|
||||
AudioConstraints: AudioConstraints{
|
||||
Latency: DurationExact(time.Millisecond * 20),
|
||||
IsBigEndian: BoolExact(true),
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("OneOfValues", func(t *testing.T) {
|
||||
t.Log("\n", &MediaConstraints{
|
||||
DeviceID: StringOneOf{"one", "two"},
|
||||
VideoConstraints: VideoConstraints{
|
||||
Width: IntOneOf{1920, 1080},
|
||||
FrameRate: FloatOneOf{30.0, 60.1234},
|
||||
FrameFormat: FrameFormatOneOf{frame.FormatI420, frame.FormatI444},
|
||||
},
|
||||
AudioConstraints: AudioConstraints{
|
||||
Latency: DurationOneOf{time.Millisecond * 20, time.Millisecond * 40},
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("RangedValues", func(t *testing.T) {
|
||||
t.Log("\n", &MediaConstraints{
|
||||
VideoConstraints: VideoConstraints{
|
||||
Width: &IntRanged{Min: 1080, Max: 1920, Ideal: 1500},
|
||||
FrameRate: &FloatRanged{Min: 30.123, Max: 60.12321312, Ideal: 45.12312312},
|
||||
},
|
||||
AudioConstraints: AudioConstraints{
|
||||
Latency: &DurationRanged{Min: time.Millisecond * 20, Max: time.Millisecond * 40, Ideal: time.Millisecond * 30},
|
||||
},
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
package prop
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// StringConstraint is an interface to represent string constraint.
|
||||
type StringConstraint interface {
|
||||
Compare(string) (float64, bool)
|
||||
@@ -21,6 +26,11 @@ func (f String) Compare(a string) (float64, bool) {
|
||||
// Value implements StringConstraint.
|
||||
func (f String) Value() (string, bool) { return string(f), true }
|
||||
|
||||
// String implements Stringify
|
||||
func (f String) String() string {
|
||||
return fmt.Sprintf("%s (ideal)", string(f))
|
||||
}
|
||||
|
||||
// StringExact specifies exact string.
|
||||
type StringExact string
|
||||
|
||||
@@ -35,6 +45,11 @@ func (f StringExact) Compare(a string) (float64, bool) {
|
||||
// Value implements StringConstraint.
|
||||
func (f StringExact) Value() (string, bool) { return string(f), true }
|
||||
|
||||
// String implements Stringify
|
||||
func (f StringExact) String() string {
|
||||
return fmt.Sprintf("%s (exact)", string(f))
|
||||
}
|
||||
|
||||
// StringOneOf specifies list of expected string.
|
||||
type StringOneOf []string
|
||||
|
||||
@@ -50,3 +65,8 @@ func (f StringOneOf) Compare(a string) (float64, bool) {
|
||||
|
||||
// Value implements StringConstraint.
|
||||
func (StringOneOf) Value() (string, bool) { return "", false }
|
||||
|
||||
// String implements Stringify
|
||||
func (f StringOneOf) String() string {
|
||||
return fmt.Sprintf("%s (one of values)", strings.Join([]string(f), ","))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user