types_test.go
1 package daemon 2 3 import ( 4 "encoding/json" 5 "testing" 6 ) 7 8 func TestServerMessage_UnmarshalMessage(t *testing.T) { 9 raw := `{"type":"message","message_id":"msg-001","payload":{"channel":"slack","thread_id":"t1","sender":"alice","text":"hello","timestamp":"2026-03-08T00:00:00Z"}}` 10 var sm ServerMessage 11 if err := json.Unmarshal([]byte(raw), &sm); err != nil { 12 t.Fatal(err) 13 } 14 if sm.Type != MsgTypeMessage { 15 t.Errorf("type = %q, want %q", sm.Type, MsgTypeMessage) 16 } 17 if sm.MessageID != "msg-001" { 18 t.Errorf("message_id = %q, want %q", sm.MessageID, "msg-001") 19 } 20 var payload MessagePayload 21 if err := json.Unmarshal(sm.Payload, &payload); err != nil { 22 t.Fatal(err) 23 } 24 if payload.Channel != ChannelSlack || payload.Text != "hello" { 25 t.Errorf("payload = %+v", payload) 26 } 27 } 28 29 func TestServerMessage_UnmarshalClaimAck(t *testing.T) { 30 raw := `{"type":"claim_ack","message_id":"msg-001","payload":{"granted":true}}` 31 var sm ServerMessage 32 if err := json.Unmarshal([]byte(raw), &sm); err != nil { 33 t.Fatal(err) 34 } 35 var ack ClaimAckPayload 36 if err := json.Unmarshal(sm.Payload, &ack); err != nil { 37 t.Fatal(err) 38 } 39 if !ack.Granted { 40 t.Error("expected granted=true") 41 } 42 } 43 44 func TestDaemonMessage_MarshalClaim(t *testing.T) { 45 dm := DaemonMessage{Type: MsgTypeClaim, MessageID: "msg-001"} 46 data, err := json.Marshal(dm) 47 if err != nil { 48 t.Fatal(err) 49 } 50 var decoded map[string]interface{} 51 json.Unmarshal(data, &decoded) 52 if decoded["type"] != "claim" { 53 t.Errorf("type = %v, want claim", decoded["type"]) 54 } 55 if decoded["message_id"] != "msg-001" { 56 t.Errorf("message_id = %v", decoded["message_id"]) 57 } 58 } 59 60 func TestDaemonMessage_MarshalReply(t *testing.T) { 61 payload := ReplyPayload{Channel: ChannelSlack, ThreadID: "t1", Text: "result", Format: FormatText} 62 payloadBytes, _ := json.Marshal(payload) 63 dm := DaemonMessage{Type: MsgTypeReply, MessageID: "msg-001", Payload: payloadBytes} 64 data, err := json.Marshal(dm) 65 if err != nil { 66 t.Fatal(err) 67 } 68 var decoded DaemonMessage 69 json.Unmarshal(data, &decoded) 70 if decoded.Type != MsgTypeReply { 71 t.Errorf("type = %q", decoded.Type) 72 } 73 var rp ReplyPayload 74 json.Unmarshal(decoded.Payload, &rp) 75 if rp.Text != "result" || rp.Format != FormatText { 76 t.Errorf("reply payload = %+v", rp) 77 } 78 } 79 80 func TestApprovalResolvedPayload_Serialization(t *testing.T) { 81 p := ApprovalResolvedPayload{ 82 RequestID: "apr_abc123", 83 Decision: DecisionAllow, 84 ResolvedBy: "shanclaw", 85 } 86 data, err := json.Marshal(p) 87 if err != nil { 88 t.Fatal(err) 89 } 90 var decoded ApprovalResolvedPayload 91 if err := json.Unmarshal(data, &decoded); err != nil { 92 t.Fatal(err) 93 } 94 if decoded.RequestID != "apr_abc123" { 95 t.Errorf("request_id = %q, want %q", decoded.RequestID, "apr_abc123") 96 } 97 if decoded.Decision != DecisionAllow { 98 t.Errorf("decision = %q, want %q", decoded.Decision, DecisionAllow) 99 } 100 if decoded.ResolvedBy != "shanclaw" { 101 t.Errorf("resolved_by = %q, want %q", decoded.ResolvedBy, "shanclaw") 102 } 103 } 104 105 func TestApprovalResponse_ResolvedByOmitEmpty(t *testing.T) { 106 resp := ApprovalResponse{RequestID: "apr_test", Decision: DecisionDeny} 107 data, err := json.Marshal(resp) 108 if err != nil { 109 t.Fatal(err) 110 } 111 var decoded map[string]interface{} 112 json.Unmarshal(data, &decoded) 113 if _, ok := decoded["resolved_by"]; ok { 114 t.Error("resolved_by should be omitted when empty") 115 } 116 117 resp.ResolvedBy = "slack" 118 data, _ = json.Marshal(resp) 119 json.Unmarshal(data, &decoded) 120 if decoded["resolved_by"] != "slack" { 121 t.Errorf("resolved_by = %v, want %q", decoded["resolved_by"], "slack") 122 } 123 } 124 125 func TestIsSystemChannel(t *testing.T) { 126 if !IsSystemChannel(ChannelSystem) { 127 t.Error("system channel not detected") 128 } 129 if IsSystemChannel(ChannelSlack) { 130 t.Error("slack should not be system channel") 131 } 132 }