Add human friendly string implementation

This commit is contained in:
Lukas Herman
2020-09-10 23:52:05 -07:00
parent 0cd870fd4b
commit 30d49e1fd3
8 changed files with 220 additions and 0 deletions
+7
View File
@@ -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
+27
View File
@@ -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)
}
+27
View File
@@ -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)
}
+22
View File
@@ -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, ","))
}
+27
View File
@@ -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)
}
+33
View File
@@ -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)
+57
View File
@@ -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},
},
})
})
}
+20
View File
@@ -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), ","))
}