/ internal / daemon / types_test.go
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  }