package ocpp import ( "encoding/json" "testing" ) func TestDecodeCall(t *testing.T) { m, err := DecodeMessage([]byte(`[2,"abc","BootNotification",{"chargePointModel":"A5191"}]`)) if err != nil { t.Fatal(err) } if m.Type != MessageTypeCall || m.ID != "abc" || m.Action != "BootNotification" { t.Fatalf("bad decode: %+v", m) } var p struct { Model string `json:"chargePointModel"` } if err := json.Unmarshal(m.Payload, &p); err != nil || p.Model != "A5191" { t.Fatalf("payload = %s (%v)", m.Payload, err) } } func TestDecodeCallResultAndError(t *testing.T) { r, err := DecodeMessage([]byte(`[3,"abc",{"status":"Accepted"}]`)) if err != nil || r.Type != MessageTypeCallResult { t.Fatalf("callresult decode: %+v %v", r, err) } e, err := DecodeMessage([]byte(`[4,"abc","NotImplemented","nope",{}]`)) if err != nil || e.Type != MessageTypeCallError || e.ErrorCode != "NotImplemented" || e.ErrorDescription != "nope" { t.Fatalf("callerror decode: %+v %v", e, err) } } func TestEncodeRoundTrip(t *testing.T) { b, err := EncodeCall("id1", "Reset", map[string]any{"type": "Soft"}) if err != nil { t.Fatal(err) } m, err := DecodeMessage(b) if err != nil || m.Action != "Reset" { t.Fatalf("round trip: %+v %v", m, err) } } func TestEncodeEmptyPayloadIsObject(t *testing.T) { // OCPP requires the payload be a JSON object, never null. b, err := EncodeCallResult("id1", nil) if err != nil { t.Fatal(err) } if string(b) != `[3,"id1",{}]` { t.Fatalf("empty payload encoded as %s, want [3,\"id1\",{}]", b) } } func TestDecodeRejectsGarbage(t *testing.T) { if _, err := DecodeMessage([]byte(`{"not":"an array"}`)); err == nil { t.Fatal("expected error decoding non-array") } if _, err := DecodeMessage([]byte(`[2,"id"]`)); err == nil { t.Fatal("expected error decoding short CALL") } }