@@ -154,3 +154,184 @@ func TestDetectMatched(t *testing.T) {
154154 })
155155 }
156156}
157+
158+ func TestMatchIssuesEvent (t * testing.T ) {
159+ testCases := []struct {
160+ desc string
161+ payload * api.IssuePayload
162+ yamlOn string
163+ expected bool
164+ eventType string
165+ }{
166+ {
167+ desc : "Label deletion should trigger unlabeled event" ,
168+ payload : & api.IssuePayload {
169+ Action : api .HookIssueLabelUpdated ,
170+ Issue : & api.Issue {
171+ Labels : []* api.Label {},
172+ },
173+ Changes : & api.ChangesPayload {
174+ RemovedLabels : []* api.Label {
175+ {ID : 123 , Name : "deleted-label" },
176+ },
177+ },
178+ },
179+ yamlOn : "on:\n issues:\n types: [unlabeled]" ,
180+ expected : true ,
181+ eventType : "unlabeled" ,
182+ },
183+ {
184+ desc : "Label deletion with existing labels should trigger unlabeled event" ,
185+ payload : & api.IssuePayload {
186+ Action : api .HookIssueLabelUpdated ,
187+ Issue : & api.Issue {
188+ Labels : []* api.Label {
189+ {ID : 456 , Name : "existing-label" },
190+ },
191+ },
192+ Changes : & api.ChangesPayload {
193+ AddedLabels : nil ,
194+ RemovedLabels : []* api.Label {
195+ {ID : 123 , Name : "deleted-label" },
196+ },
197+ },
198+ },
199+ yamlOn : "on:\n issues:\n types: [unlabeled]" ,
200+ expected : true ,
201+ eventType : "unlabeled" ,
202+ },
203+ {
204+ desc : "Label addition should trigger labeled event" ,
205+ payload : & api.IssuePayload {
206+ Action : api .HookIssueLabelUpdated ,
207+ Issue : & api.Issue {
208+ Labels : []* api.Label {
209+ {ID : 123 , Name : "new-label" },
210+ },
211+ },
212+ Changes : & api.ChangesPayload {
213+ AddedLabels : []* api.Label {
214+ {ID : 123 , Name : "new-label" },
215+ },
216+ RemovedLabels : []* api.Label {}, // Empty array, no labels removed
217+ },
218+ },
219+ yamlOn : "on:\n issues:\n types: [labeled]" ,
220+ expected : true ,
221+ eventType : "labeled" ,
222+ },
223+ {
224+ desc : "Label clear should trigger unlabeled event" ,
225+ payload : & api.IssuePayload {
226+ Action : api .HookIssueLabelCleared ,
227+ Issue : & api.Issue {
228+ Labels : []* api.Label {},
229+ },
230+ },
231+ yamlOn : "on:\n issues:\n types: [unlabeled]" ,
232+ expected : true ,
233+ eventType : "unlabeled" ,
234+ },
235+ {
236+ desc : "Both adding and removing labels should trigger labeled event" ,
237+ payload : & api.IssuePayload {
238+ Action : api .HookIssueLabelUpdated ,
239+ Issue : & api.Issue {
240+ Labels : []* api.Label {
241+ {ID : 789 , Name : "new-label" },
242+ },
243+ },
244+ Changes : & api.ChangesPayload {
245+ AddedLabels : []* api.Label {
246+ {ID : 789 , Name : "new-label" },
247+ },
248+ RemovedLabels : []* api.Label {
249+ {ID : 123 , Name : "deleted-label" },
250+ },
251+ },
252+ },
253+ yamlOn : "on:\n issues:\n types: [labeled]" ,
254+ expected : true ,
255+ eventType : "labeled" ,
256+ },
257+ {
258+ desc : "Both adding and removing labels should trigger unlabeled event" ,
259+ payload : & api.IssuePayload {
260+ Action : api .HookIssueLabelUpdated ,
261+ Issue : & api.Issue {
262+ Labels : []* api.Label {
263+ {ID : 789 , Name : "new-label" },
264+ },
265+ },
266+ Changes : & api.ChangesPayload {
267+ AddedLabels : []* api.Label {
268+ {ID : 789 , Name : "new-label" },
269+ },
270+ RemovedLabels : []* api.Label {
271+ {ID : 123 , Name : "deleted-label" },
272+ },
273+ },
274+ },
275+ yamlOn : "on:\n issues:\n types: [unlabeled]" ,
276+ expected : true ,
277+ eventType : "unlabeled" ,
278+ },
279+ {
280+ desc : "Both adding and removing labels should trigger both events" ,
281+ payload : & api.IssuePayload {
282+ Action : api .HookIssueLabelUpdated ,
283+ Issue : & api.Issue {
284+ Labels : []* api.Label {
285+ {ID : 789 , Name : "new-label" },
286+ },
287+ },
288+ Changes : & api.ChangesPayload {
289+ AddedLabels : []* api.Label {
290+ {ID : 789 , Name : "new-label" },
291+ },
292+ RemovedLabels : []* api.Label {
293+ {ID : 123 , Name : "deleted-label" },
294+ },
295+ },
296+ },
297+ yamlOn : "on:\n issues:\n types: [labeled, unlabeled]" ,
298+ expected : true ,
299+ eventType : "multiple" ,
300+ },
301+ }
302+
303+ for _ , tc := range testCases {
304+ t .Run (tc .desc , func (t * testing.T ) {
305+ evts , err := GetEventsFromContent ([]byte (tc .yamlOn ))
306+ assert .NoError (t , err )
307+ assert .Len (t , evts , 1 )
308+
309+ // Test if the event matches as expected
310+ assert .Equal (t , tc .expected , matchIssuesEvent (tc .payload , evts [0 ]))
311+
312+ // For extra validation, check that action mapping works correctly
313+ if tc .eventType == "multiple" {
314+ // Skip direct action mapping validation for multiple events case
315+ // as one action can map to multiple event types
316+ return
317+ }
318+
319+ // Determine expected action for single event case
320+ var expectedAction string
321+ switch tc .payload .Action {
322+ case api .HookIssueLabelUpdated :
323+ if tc .eventType == "labeled" {
324+ expectedAction = "labeled"
325+ } else if tc .eventType == "unlabeled" {
326+ expectedAction = "unlabeled"
327+ }
328+ case api .HookIssueLabelCleared :
329+ expectedAction = "unlabeled"
330+ default :
331+ expectedAction = string (tc .payload .Action )
332+ }
333+
334+ assert .Equal (t , expectedAction , tc .eventType , "Event type should match expected" )
335+ })
336+ }
337+ }
0 commit comments