github.com/jshiv/can-go@v0.2.1-0.20210224011015-069e90e90bdf/internal/generate/example_test.go (about) 1 package generate 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "reflect" 8 "testing" 9 "time" 10 11 "go.einride.tech/can" 12 "go.einride.tech/can/pkg/generated" 13 "go.einride.tech/can/pkg/socketcan" 14 examplecan "go.einride.tech/can/testdata/gen/go/example" 15 "golang.org/x/sync/errgroup" 16 "gotest.tools/v3/assert" 17 ) 18 19 func TestExampleDatabase_MarshalUnmarshal(t *testing.T) { 20 for _, tt := range []struct { 21 name string 22 m can.Message 23 f can.Frame 24 }{ 25 { 26 name: "IODebug", 27 m: examplecan.NewIODebug(). 28 SetTestUnsigned(5). 29 SetTestEnum(examplecan.IODebug_TestEnum_Two). 30 SetTestSigned(-42). 31 SetTestFloat(61.5). 32 SetTestBoolEnum(examplecan.IODebug_TestBoolEnum_One). 33 SetRawTestScaledEnum(examplecan.IODebug_TestScaledEnum_Four), 34 f: can.Frame{ 35 ID: 500, 36 Length: 6, 37 Data: can.Data{5, 2, 214, 123, 1, 2}, 38 }, 39 }, 40 41 { 42 name: "MotorStatus1", 43 m: examplecan.NewMotorStatus(). 44 SetSpeedKph(0.423). 45 SetWheelError(true), 46 f: can.Frame{ 47 ID: 400, 48 Length: 3, 49 Data: can.Data{0x1, 0xa7, 0x1}, 50 }, 51 }, 52 53 { 54 name: "MotorStatus2", 55 m: examplecan.NewMotorStatus(). 56 SetSpeedKph(12), 57 f: can.Frame{ 58 ID: 400, 59 Length: 3, 60 Data: can.Data{0x00, 0xe0, 0x2e}, 61 }, 62 }, 63 } { 64 tt := tt 65 t.Run(tt.name, func(t *testing.T) { 66 f, err := tt.m.MarshalFrame() 67 assert.NilError(t, err) 68 assert.Equal(t, tt.f, f) 69 // allocate new message of same type as tt.m 70 msg := reflect.New(reflect.ValueOf(tt.m).Elem().Type()).Interface().(generated.Message) 71 assert.NilError(t, msg.UnmarshalFrame(f)) 72 assert.Assert(t, reflect.DeepEqual(tt.m, msg)) 73 }) 74 } 75 } 76 77 func TestExampleDatabase_UnmarshalFrame_Error(t *testing.T) { 78 for _, tt := range []struct { 79 name string 80 f can.Frame 81 m generated.Message 82 err string 83 }{ 84 { 85 name: "wrong ID", 86 f: can.Frame{ID: 11, Length: 8}, 87 m: examplecan.NewSensorSonars(), 88 err: "unmarshal SensorSonars: expects ID 200 (got 00B#0000000000000000 with ID 11)", 89 }, 90 { 91 name: "wrong length", 92 f: can.Frame{ID: 200, Length: 4}, 93 m: examplecan.NewSensorSonars(), 94 err: "unmarshal SensorSonars: expects length 8 (got 0C8#00000000 with length 4)", 95 }, 96 { 97 name: "remote frame", 98 f: can.Frame{ID: 200, Length: 8, IsRemote: true}, 99 m: examplecan.NewSensorSonars(), 100 err: "unmarshal SensorSonars: expects non-remote frame (got remote frame 0C8#R8)", 101 }, 102 { 103 name: "extended ID", 104 f: can.Frame{ID: 200, Length: 8, IsExtended: true}, 105 m: examplecan.NewSensorSonars(), 106 err: "unmarshal SensorSonars: expects standard ID (got 000000C8#0000000000000000 with extended ID)", 107 }, 108 } { 109 tt := tt 110 t.Run(tt.name, func(t *testing.T) { 111 assert.Equal(t, tt.err, tt.m.UnmarshalFrame(tt.f).Error()) 112 }) 113 } 114 } 115 116 func TestExampleDatabase_TestEnum_String(t *testing.T) { 117 assert.Equal(t, "One", examplecan.IODebug_TestEnum_One.String()) 118 assert.Equal(t, "Two", examplecan.IODebug_TestEnum_Two.String()) 119 assert.Equal(t, "IODebug_TestEnum(3)", examplecan.IODebug_TestEnum(3).String()) 120 } 121 122 func TestExampleDatabase_Message_String(t *testing.T) { 123 const expected = "{WheelError: true, SpeedKph: 42km/h}" 124 msg := examplecan.NewMotorStatus(). 125 SetSpeedKph(42). 126 SetWheelError(true) 127 assert.Equal(t, expected, msg.String()) 128 assert.Equal(t, expected, fmt.Sprintf("%v", msg)) 129 } 130 131 func TestExampleDatabase_OutOfBoundsValue(t *testing.T) { 132 const expected = examplecan.IODebug_TestEnum(63) 133 actual := examplecan.NewIODebug().SetTestEnum(255).TestEnum() 134 assert.Equal(t, expected, actual) 135 } 136 137 func TestExampleDatabase_MultiplexedSignals(t *testing.T) { 138 // Given a message with multiplexed signals 139 msg := examplecan.NewSensorSonars(). 140 SetErrCount(1). 141 SetMux(1). 142 SetLeft(20). 143 SetMiddle(30). 144 SetRight(40). 145 SetRear(50). 146 SetNoFiltLeft(60). 147 SetNoFiltMiddle(70). 148 SetNoFiltRight(80). 149 SetNoFiltRear(90) 150 for _, tt := range []struct { 151 expectedMux uint8 152 expectedErrCount uint16 153 expectedLeft float64 154 expectedMiddle float64 155 expectedRight float64 156 expectedRear float64 157 expectedNoFiltLeft float64 158 expectedNoFiltMiddle float64 159 expectedNoFiltRight float64 160 expectedNoFiltRear float64 161 }{ 162 { 163 expectedMux: 0, 164 expectedErrCount: 1, 165 expectedLeft: 20, 166 expectedMiddle: 30, 167 expectedRight: 40, 168 expectedRear: 50, 169 expectedNoFiltLeft: 0, 170 expectedNoFiltMiddle: 0, 171 expectedNoFiltRight: 0, 172 expectedNoFiltRear: 0, 173 }, 174 { 175 expectedMux: 1, 176 expectedErrCount: 1, 177 expectedLeft: 0, 178 expectedMiddle: 0, 179 expectedRight: 0, 180 expectedRear: 0, 181 expectedNoFiltLeft: 60, 182 expectedNoFiltMiddle: 70, 183 expectedNoFiltRight: 80, 184 expectedNoFiltRear: 90, 185 }, 186 } { 187 tt := tt 188 t.Run(fmt.Sprintf("mux=%v", tt.expectedMux), func(t *testing.T) { 189 unmarshal1 := examplecan.NewSensorSonars() 190 // When the multiplexer signal is 0 and we marshal the message 191 // to a CAN frame 192 msg.SetMux(tt.expectedMux) 193 f1, err := msg.MarshalFrame() 194 assert.NilError(t, err) 195 // When we unmarshal the CAN frame back to a message 196 assert.NilError(t, unmarshal1.UnmarshalFrame(f1)) 197 // Then only the multiplexed signals with multiplexer value 0 198 // should be unmarshaled 199 assert.Equal(t, tt.expectedMux, unmarshal1.Mux(), "Mux") 200 assert.Equal(t, tt.expectedErrCount, unmarshal1.ErrCount(), "ErrCount") 201 assert.Equal(t, tt.expectedLeft, unmarshal1.Left(), "Left") 202 assert.Equal(t, tt.expectedMiddle, unmarshal1.Middle(), "Middle") 203 assert.Equal(t, tt.expectedRight, unmarshal1.Right(), "Right") 204 assert.Equal(t, tt.expectedRear, unmarshal1.Rear(), "Rear") 205 assert.Equal(t, tt.expectedNoFiltLeft, unmarshal1.NoFiltLeft(), "NoFiltLeft") 206 assert.Equal(t, tt.expectedNoFiltMiddle, unmarshal1.NoFiltMiddle(), "NoFiltMiddle") 207 assert.Equal(t, tt.expectedNoFiltRight, unmarshal1.NoFiltRight(), "NoFiltRight") 208 assert.Equal(t, tt.expectedNoFiltRear, unmarshal1.NoFiltRear(), "NoFiltRear") 209 }) 210 } 211 } 212 213 func TestExampleDatabase_CopyFrom(t *testing.T) { 214 // Given: an original message 215 from := examplecan.NewIODebug(). 216 SetRawTestScaledEnum(examplecan.IODebug_TestScaledEnum_Four). 217 SetTestBoolEnum(true). 218 SetTestFloat(0.1). 219 SetTestSigned(-10). 220 SetTestUnsigned(10) 221 // When: another message copies from the original message 222 to := examplecan.NewIODebug().CopyFrom(from) 223 // Then: 224 // all fields should be equal... 225 assert.Equal(t, from.String(), to.String()) 226 assert.Equal(t, from.TestScaledEnum(), to.TestScaledEnum()) 227 assert.Equal(t, from.TestBoolEnum(), to.TestBoolEnum()) 228 assert.Equal(t, from.TestFloat(), to.TestFloat()) 229 assert.Equal(t, from.TestSigned(), to.TestSigned()) 230 assert.Equal(t, from.TestUnsigned(), to.TestUnsigned()) 231 // ...and changes to the original should not affect the new message 232 from.SetTestUnsigned(100) 233 assert.Equal(t, uint8(10), to.TestUnsigned()) 234 } 235 236 func TestExample_Nodes(t *testing.T) { 237 const testTimeout = 2 * time.Second 238 requireVCAN0(t) 239 // given a DRIVER node and a MOTOR node 240 motor := examplecan.NewMOTOR("can", "vcan0") 241 driver := examplecan.NewDRIVER("can", "vcan0") 242 // when starting them 243 ctx, cancel := context.WithTimeout(context.Background(), testTimeout) 244 g, ctx := errgroup.WithContext(ctx) 245 g.Go(func() error { 246 return motor.Run(ctx) 247 }) 248 g.Go(func() error { 249 return driver.Run(ctx) 250 }) 251 // and the MOTOR node is configured to send a speed report 252 const expectedSpeedKph = 42 253 motor.Lock() 254 motor.Tx().MotorStatus().SetSpeedKph(expectedSpeedKph) 255 motor.Tx().MotorStatus().SetCyclicTransmissionEnabled(true) 256 motor.Unlock() 257 // and the DRIVER node is configured to send a steering command 258 const expectedSteer = -4 259 driver.Lock() 260 driver.Tx().MotorCommand().SetSteer(expectedSteer) 261 driver.Tx().MotorCommand().SetCyclicTransmissionEnabled(true) 262 driver.Unlock() 263 // and the MOTOR node is listening for the steering command 264 expectedSteerReceivedChan := make(chan struct{}) 265 motor.Lock() 266 motor.Rx().MotorCommand().SetAfterReceiveHook(func(context.Context) error { 267 motor.Lock() 268 if motor.Rx().MotorCommand().Steer() == expectedSteer { 269 close(expectedSteerReceivedChan) 270 motor.Rx().MotorCommand().SetAfterReceiveHook(func(context.Context) error { return nil }) 271 } 272 motor.Unlock() 273 return nil 274 }) 275 motor.Unlock() 276 // and the DRIVER node is listening for the speed report 277 expectedSpeedReceivedChan := make(chan struct{}) 278 driver.Lock() 279 driver.Rx().MotorStatus().SetAfterReceiveHook(func(context.Context) error { 280 driver.Lock() 281 if driver.Rx().MotorStatus().SpeedKph() == expectedSpeedKph { 282 close(expectedSpeedReceivedChan) 283 driver.Rx().MotorStatus().SetAfterReceiveHook(func(context.Context) error { return nil }) 284 } 285 driver.Unlock() 286 return nil 287 }) 288 driver.Unlock() 289 // then the steer command transmitted by DRIVER should be received by MOTOR 290 select { 291 case <-expectedSteerReceivedChan: 292 case <-ctx.Done(): 293 t.Fatalf("expected steer not received: %v", expectedSteer) 294 } 295 // and the speed report transmitted by MOTOR should be received by DRIVER 296 select { 297 case <-expectedSpeedReceivedChan: 298 case <-ctx.Done(): 299 t.Fatalf("expected speed not received: %v", expectedSpeedKph) 300 } 301 cancel() 302 assert.NilError(t, g.Wait()) 303 } 304 305 func TestExample_Node_NoEmptyMessages(t *testing.T) { 306 const testTimeout = 2 * time.Second 307 requireVCAN0(t) 308 // given a DRIVER node and a MOTOR node 309 motor := examplecan.NewMOTOR("can", "vcan0") 310 // when starting them 311 ctx, cancel := context.WithTimeout(context.Background(), testTimeout) 312 handler := func(ctx context.Context) error { 313 motor.Lock() 314 motor.Tx().MotorStatus().SetSpeedKph(100).SetWheelError(true) 315 motor.Unlock() 316 return nil 317 } 318 motor.Tx().MotorStatus().SetBeforeTransmitHook(handler) 319 motor.Tx().MotorStatus().SetCyclicTransmissionEnabled(true) 320 c, err := socketcan.Dial("can", "vcan0") 321 r := socketcan.NewReceiver(c) 322 assert.NilError(t, err) 323 g := errgroup.Group{} 324 g.Go(func() error { 325 return motor.Run(ctx) 326 }) 327 assert.Assert(t, r.Receive()) 328 assert.Equal(t, examplecan.NewMotorStatus().SetSpeedKph(100).SetWheelError(true).Frame(), r.Frame()) 329 cancel() 330 assert.NilError(t, g.Wait()) 331 } 332 333 func requireVCAN0(t *testing.T) { 334 t.Helper() 335 if _, err := net.InterfaceByName("vcan0"); err != nil { 336 t.Skip("interface vcan0 does not exist") 337 } 338 }