package m31 import ( "testing" "time" "github.com/stretchr/testify/require" "onehouse/protocol" ) func TestTopologyKeepsIndependentAddressRanges(t *testing.T) { value, err := newTopology([]Module{ {Model: HostModel}, {Model: OutputModel, PulseWidths: map[int]time.Duration{15: 200 * time.Millisecond}}, {Model: AnalogModel}, {Model: InputModel}, {Model: MixedModel}, {Model: AnalogModel}, }) require.NoError(t, err) require.Len(t, value.inputs, 32) require.Len(t, value.outputs, 32) require.Len(t, value.analog, 16) require.Equal(t, "m4.di0", value.inputs[24].id) require.Equal(t, "m4.do0", value.outputs[24].id) require.EqualValues(t, 24, value.outputs[24].address) require.Equal(t, "m5.ao0", value.analog[8].id) require.EqualValues(t, 8, value.analog[8].address) require.EqualValues(t, 200, value.outputs[23].pulse) descriptor := value.descriptor() require.Len(t, descriptor.Capabilities, 80) for _, capability := range descriptor.Capabilities { if capability.ID == "m1.do15" { require.Equal(t, "pulse", capability.Type) require.False(t, capability.ReportsState) require.True(t, capability.AcceptsCommands) } } id, err := protocol.NewID(time.Now()) require.NoError(t, err) _, err = protocol.BuildDescriptor(id, protocol.Metadata{MessageID: id}, descriptor) require.NoError(t, err) } func TestTopologyRejectsUnsafeModulesAndPulseSettings(t *testing.T) { testCases := []struct { name string modules []Module }{ {name: "requires a host"}, {name: "limits total modules", modules: make([]Module, 17)}, {name: "rejects unknown models", modules: []Module{{Model: "unknown"}}}, {name: "rejects expansion at slot zero", modules: []Module{{Model: MixedModel}}}, {name: "rejects another host", modules: []Module{{Model: HostModel}, {Model: HostModel}}}, {name: "rejects negative pulse channel", modules: []Module{{Model: HostModel, PulseWidths: map[int]time.Duration{-1: time.Second}}}}, {name: "rejects excess pulse channel", modules: []Module{{Model: HostModel, PulseWidths: map[int]time.Duration{8: time.Second}}}}, {name: "rejects pulse on input module", modules: []Module{{Model: HostModel}, {Model: InputModel, PulseWidths: map[int]time.Duration{0: time.Second}}}}, {name: "rejects short pulse", modules: []Module{{Model: HostModel, PulseWidths: map[int]time.Duration{0: time.Millisecond}}}}, {name: "rejects long pulse", modules: []Module{{Model: HostModel, PulseWidths: map[int]time.Duration{0: 65536 * time.Millisecond}}}}, {name: "rejects fractional millisecond", modules: []Module{{Model: HostModel, PulseWidths: map[int]time.Duration{0: 50*time.Millisecond + time.Nanosecond}}}}, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { _, err := newTopology(tc.modules) require.Error(t, err) }) } }