package helper import ( "math" "testing" ) func TestClampRGB(t *testing.T) { t.Run("values in legal ranges should be unmodified", func(t *testing.T) { const steps = 8 for rI := range steps { for gI := range steps { for bI := range steps { want := [3]float64{ float64(rI) * (1 / (steps - 1)), float64(gI) * (1 / (steps - 1)), float64(bI) * (1 / (steps - 1)), } if got := collect3(ClampRGB(want[0], want[1], want[2])); got != want { t.Errorf("Clamp(%v) = %v, expected values to be unmodified", want, got) return } } } } }) tests := []struct { name string values [3]float64 want [3]float64 }{ { // any component being infinity should result in white. name: "+inf", values: [3]float64{-1, .5, math.Inf(1)}, want: [3]float64{1, 1, 1}, }, { // ... except the case where any other component was NaN or -infinity. name: "+inf, -inf, NaN", values: [3]float64{math.Inf(-1), math.NaN(), math.Inf(1)}, want: [3]float64{0, 0, 1}, }, { // colors that are too bright should be scaled back to the legal range, and then // interpolate to white by 1-1/max_value. name: "normalize over-bright colours and fade them to white", values: [3]float64{1, 2, 3}, want: [3]float64{1./3*(1./3) + (1 - 1./3), 2./3*(1./3) + (1 - 1./3), 1}, // note that }, { name: "negative values should be clamped to 0", values: [3]float64{-1, math.Inf(-1), .5}, want: [3]float64{0, 0, .5}, }, { name: "except where the logic for over-bright colors would bring them back to the legal range", values: [3]float64{-1, 0, 3}, want: [3]float64{-1./3*(1./3) + (1 - 1./3), 1 - 1./3, 1}, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { for _, order := range permuteOrder3 { values := permute3(tt.values, order) want := permute3(tt.want, order) if got := collect3(ClampRGB(values[0], values[1], values[2])); !EqFloat64SliceFuzzy(got[:], want[:]) { t.Errorf("ClampRGB(%v) = %v, want %v", values, got, want) return } } }) } }