evcc-io/api/capable_test.go

89 lines
1.8 KiB
Go

package api
import (
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// mock decorated type with capability registry
type decoratedMeter struct {
Meter
caps map[reflect.Type]any
}
func (d *decoratedMeter) Capability(typ reflect.Type) (any, bool) {
c, ok := d.caps[typ]
return c, ok
}
type testMeterEnergyImpl struct{}
func (t *testMeterEnergyImpl) TotalEnergy() (float64, error) {
return 99.0, nil
}
type testMeterImpl struct{}
func (t *testMeterImpl) CurrentPower() (float64, error) {
return 100.0, nil
}
func TestCap_DirectTypeAssertion(t *testing.T) {
// concrete type that directly implements MeterEnergy
impl := &testMeterEnergyImpl{}
me, ok := Cap[MeterEnergy](impl)
require.True(t, ok)
energy, err := me.TotalEnergy()
assert.NoError(t, err)
assert.Equal(t, 99.0, energy)
}
func TestCap_CapableRegistryLookup(t *testing.T) {
base := &testMeterImpl{}
decorated := &decoratedMeter{
Meter: base,
caps: map[reflect.Type]any{
reflect.TypeFor[MeterEnergy](): &testMeterEnergyImpl{},
},
}
// should find MeterEnergy via registry
me, ok := Cap[MeterEnergy](decorated)
require.True(t, ok)
energy, err := me.TotalEnergy()
assert.NoError(t, err)
assert.Equal(t, 99.0, energy)
// should NOT find PhaseCurrents (not registered)
_, ok = Cap[PhaseCurrents](decorated)
assert.False(t, ok)
}
func TestCap_NilValue(t *testing.T) {
_, ok := Cap[MeterEnergy](nil)
assert.False(t, ok)
}
func TestCap_DirectTakesPrecedence(t *testing.T) {
// type that both directly implements AND has registry
type directAndCapable struct {
testMeterEnergyImpl
caps map[reflect.Type]any //nolint:unused
}
v := &directAndCapable{}
me, ok := Cap[MeterEnergy](v)
require.True(t, ok)
energy, err := me.TotalEnergy()
assert.NoError(t, err)
assert.Equal(t, 99.0, energy)
}