1use std::{borrow::Cow, collections::BTreeSet, iter};
8
9use chrono::{DateTime, Utc};
10use derive_builder::Builder;
11use http::Method;
12
13use crate::api::{
14 common::{CommaSeparatedList, NameOrId, SortOrder},
15 helpers::{Labels, ReactionEmoji},
16 issues::IssueType,
17 Endpoint, Pageable, QueryParams,
18};
19
20use super::{
21 Assignee, IssueDueDateFilter, IssueEpic, IssueHealthStatus, IssueIteration, IssueMilestone,
22 IssueOrderBy, IssueScope, IssueSearchScope, IssueState, IssueWeight,
23};
24
25#[derive(Debug, Builder, Clone)]
29#[builder(setter(strip_option))]
30pub struct ProjectIssues<'a> {
31 #[builder(setter(into))]
33 project: NameOrId<'a>,
34
35 #[builder(setter(name = "_iids"), default, private)]
37 iids: BTreeSet<u64>,
38 #[builder(default)]
40 state: Option<IssueState>,
41 #[builder(setter(name = "_labels"), default, private)]
43 labels: Option<Labels<'a>>,
44 #[builder(default)]
46 with_labels_details: Option<bool>,
47 #[builder(default)]
49 iteration: Option<IssueIteration<'a>>,
50 #[builder(default)]
52 milestone_id: Option<IssueMilestone<'a>>,
53 #[builder(default)]
55 scope: Option<IssueScope>,
56 #[builder(setter(into), default)]
58 author: Option<NameOrId<'a>>,
59 #[builder(setter(name = "_assignee"), default, private)]
61 assignee: Option<Assignee<'a>>,
62 #[builder(setter(name = "_my_reaction_emoji"), default, private)]
64 my_reaction_emoji: Option<ReactionEmoji<'a>>,
65 #[builder(default)]
67 weight: Option<IssueWeight>,
68
69 #[builder(setter(into), default)]
71 search: Option<Cow<'a, str>>,
72 #[builder(setter(name = "_search_in"), default, private)]
73 search_in: Option<CommaSeparatedList<IssueSearchScope>>,
74 #[builder(default)]
76 created_after: Option<DateTime<Utc>>,
77 #[builder(default)]
79 created_before: Option<DateTime<Utc>>,
80 #[builder(default)]
82 updated_after: Option<DateTime<Utc>>,
83 #[builder(default)]
85 updated_before: Option<DateTime<Utc>>,
86 #[builder(default)]
88 confidential: Option<bool>,
89 #[builder(default)]
91 due_date: Option<IssueDueDateFilter>,
92 #[builder(setter(into), default)]
94 epic_id: Option<IssueEpic>,
95 #[builder(default)]
97 issue_type: Option<IssueType>,
98 #[builder(default)]
100 health_status: Option<IssueHealthStatus>,
101
102 #[builder(default)]
106 order_by: Option<IssueOrderBy>,
107 #[builder(default)]
109 sort: Option<SortOrder>,
110}
111
112impl<'a> ProjectIssues<'a> {
113 pub fn builder() -> ProjectIssuesBuilder<'a> {
115 ProjectIssuesBuilder::default()
116 }
117}
118
119impl<'a> ProjectIssuesBuilder<'a> {
120 pub fn iid(&mut self, iid: u64) -> &mut Self {
122 self.iids.get_or_insert_with(BTreeSet::new).insert(iid);
123 self
124 }
125
126 pub fn iids<I>(&mut self, iter: I) -> &mut Self
128 where
129 I: Iterator<Item = u64>,
130 {
131 self.iids.get_or_insert_with(BTreeSet::new).extend(iter);
132 self
133 }
134
135 pub fn unlabeled(&mut self) -> &mut Self {
137 self.labels = Some(Some(Labels::None));
138 self
139 }
140
141 pub fn with_any_label(&mut self) -> &mut Self {
143 self.labels = Some(Some(Labels::Any));
144 self
145 }
146
147 pub fn label<L>(&mut self, label: L) -> &mut Self
149 where
150 L: Into<Cow<'a, str>>,
151 {
152 let label = label.into();
153 let labels = if let Some(Some(Labels::AllOf(mut set))) = self.labels.take() {
154 set.push(label);
155 set
156 } else {
157 iter::once(label).collect()
158 };
159 self.labels = Some(Some(Labels::AllOf(labels)));
160 self
161 }
162
163 pub fn labels<I, L>(&mut self, iter: I) -> &mut Self
165 where
166 I: IntoIterator<Item = L>,
167 L: Into<Cow<'a, str>>,
168 {
169 let iter = iter.into_iter().map(Into::into);
170 let labels = if let Some(Some(Labels::AllOf(mut set))) = self.labels.take() {
171 set.extend(iter);
172 set
173 } else {
174 iter.collect()
175 };
176 self.labels = Some(Some(Labels::AllOf(labels)));
177 self
178 }
179
180 pub fn unassigned(&mut self) -> &mut Self {
182 self.assignee = Some(Some(Assignee::Unassigned));
183 self
184 }
185
186 pub fn assigned(&mut self) -> &mut Self {
188 self.assignee = Some(Some(Assignee::Assigned));
189 self
190 }
191
192 pub fn assignee_id(&mut self, assignee: u64) -> &mut Self {
194 self.assignee = Some(Some(Assignee::Id(assignee)));
195 self
196 }
197
198 pub fn assignee<A>(&mut self, assignee: A) -> &mut Self
200 where
201 A: Into<Cow<'a, str>>,
202 {
203 let assignee = assignee.into();
204 let assignees = if let Some(Some(Assignee::Usernames(mut set))) = self.assignee.take() {
205 set.insert(assignee);
206 set
207 } else {
208 let mut set = BTreeSet::new();
209 set.insert(assignee);
210 set
211 };
212 self.assignee = Some(Some(Assignee::Usernames(assignees)));
213 self
214 }
215
216 pub fn assignees<I, A>(&mut self, iter: I) -> &mut Self
218 where
219 I: IntoIterator<Item = A>,
220 A: Into<Cow<'a, str>>,
221 {
222 let iter = iter.into_iter().map(Into::into);
223 let assignees = if let Some(Some(Assignee::Usernames(mut set))) = self.assignee.take() {
224 set.extend(iter);
225 set
226 } else {
227 iter.collect()
228 };
229 self.assignee = Some(Some(Assignee::Usernames(assignees)));
230 self
231 }
232
233 pub fn no_reaction(&mut self) -> &mut Self {
235 self.my_reaction_emoji = Some(Some(ReactionEmoji::None));
236 self
237 }
238
239 pub fn any_reaction(&mut self) -> &mut Self {
241 self.my_reaction_emoji = Some(Some(ReactionEmoji::Any));
242 self
243 }
244
245 pub fn my_reaction<E>(&mut self, emoji: E) -> &mut Self
247 where
248 E: Into<Cow<'a, str>>,
249 {
250 self.my_reaction_emoji = Some(Some(ReactionEmoji::Emoji(emoji.into())));
251 self
252 }
253
254 pub fn search_in(&mut self, scope: IssueSearchScope) -> &mut Self {
256 self.search_in
257 .get_or_insert(None)
258 .get_or_insert_with(CommaSeparatedList::new)
259 .push(scope);
260 self
261 }
262}
263
264impl Endpoint for ProjectIssues<'_> {
265 fn method(&self) -> Method {
266 Method::GET
267 }
268
269 fn endpoint(&self) -> Cow<'static, str> {
270 format!("projects/{}/issues", self.project).into()
271 }
272
273 fn parameters(&self) -> QueryParams {
274 let mut params = QueryParams::default();
275
276 params
277 .extend(self.iids.iter().map(|&value| ("iids[]", value)))
278 .push_opt("state", self.state)
279 .push_opt("labels", self.labels.as_ref())
280 .push_opt("with_labels_details", self.with_labels_details)
281 .push_opt("scope", self.scope)
282 .push_opt("my_reaction_emoji", self.my_reaction_emoji.as_ref())
283 .push_opt("weight", self.weight)
284 .push_opt("search", self.search.as_ref())
285 .push_opt("in", self.search_in.as_ref())
286 .push_opt("created_after", self.created_after)
287 .push_opt("created_before", self.created_before)
288 .push_opt("updated_after", self.updated_after)
289 .push_opt("updated_before", self.updated_before)
290 .push_opt("confidential", self.confidential)
291 .push_opt("due_date", self.due_date)
292 .push_opt("epic_id", self.epic_id)
293 .push_opt("issue_type", self.issue_type)
294 .push_opt("health_status", self.health_status)
295 .push_opt("order_by", self.order_by)
296 .push_opt("sort", self.sort);
297
298 if let Some(milestone_id) = self.milestone_id.as_ref() {
299 match milestone_id {
300 IssueMilestone::Named(name) => {
301 params.push("milestone", name);
302 },
303 milestone => {
304 params.push("milestone_id", milestone);
305 },
306 }
307 }
308 if let Some(author) = self.author.as_ref() {
309 match author {
310 NameOrId::Name(name) => {
311 params.push("author_username", name);
312 },
313 NameOrId::Id(id) => {
314 params.push("author_id", *id);
315 },
316 }
317 }
318 if let Some(iteration) = self.iteration.as_ref() {
319 iteration.add_params(&mut params);
320 }
321 if let Some(assignee) = self.assignee.as_ref() {
322 assignee.add_params(&mut params);
323 }
324
325 params
326 }
327}
328
329impl Pageable for ProjectIssues<'_> {}
330
331#[cfg(test)]
332mod tests {
333 use chrono::{TimeZone, Utc};
334
335 use crate::api::common::SortOrder;
336 use crate::api::issues::{
337 projects::ProjectIssues, projects::ProjectIssuesBuilderError, IssueDueDateFilter,
338 IssueHealthStatus, IssueIteration, IssueMilestone, IssueOrderBy, IssueScope,
339 IssueSearchScope, IssueState, IssueType, IssueWeight,
340 };
341 use crate::api::{self, Query};
342 use crate::test::client::{ExpectedUrl, SingleTestClient};
343
344 #[test]
345 fn project_is_needed() {
346 let err = ProjectIssues::builder().build().unwrap_err();
347 crate::test::assert_missing_field!(err, ProjectIssuesBuilderError, "project");
348 }
349
350 #[test]
351 fn project_is_sufficient() {
352 ProjectIssues::builder().project(1).build().unwrap();
353 }
354
355 #[test]
356 fn endpoint() {
357 let endpoint = ExpectedUrl::builder()
358 .endpoint("projects/simple%2Fproject/issues")
359 .build()
360 .unwrap();
361 let client = SingleTestClient::new_raw(endpoint, "");
362
363 let endpoint = ProjectIssues::builder()
364 .project("simple/project")
365 .build()
366 .unwrap();
367 api::ignore(endpoint).query(&client).unwrap();
368 }
369
370 #[test]
371 fn endpoint_iids() {
372 let endpoint = ExpectedUrl::builder()
373 .endpoint("projects/simple%2Fproject/issues")
374 .add_query_params(&[("iids[]", "1"), ("iids[]", "2")])
375 .build()
376 .unwrap();
377 let client = SingleTestClient::new_raw(endpoint, "");
378
379 let endpoint = ProjectIssues::builder()
380 .project("simple/project")
381 .iid(1)
382 .iids([1, 2].iter().copied())
383 .build()
384 .unwrap();
385 api::ignore(endpoint).query(&client).unwrap();
386 }
387
388 #[test]
389 fn endpoint_state() {
390 let endpoint = ExpectedUrl::builder()
391 .endpoint("projects/simple%2Fproject/issues")
392 .add_query_params(&[("state", "closed")])
393 .build()
394 .unwrap();
395 let client = SingleTestClient::new_raw(endpoint, "");
396
397 let endpoint = ProjectIssues::builder()
398 .project("simple/project")
399 .state(IssueState::Closed)
400 .build()
401 .unwrap();
402 api::ignore(endpoint).query(&client).unwrap();
403 }
404
405 #[test]
406 fn endpoint_labels() {
407 let endpoint = ExpectedUrl::builder()
408 .endpoint("projects/simple%2Fproject/issues")
409 .add_query_params(&[("labels", "label,label1,label2")])
410 .build()
411 .unwrap();
412 let client = SingleTestClient::new_raw(endpoint, "");
413
414 let endpoint = ProjectIssues::builder()
415 .project("simple/project")
416 .label("label")
417 .labels(["label1", "label2"].iter().cloned())
418 .build()
419 .unwrap();
420 api::ignore(endpoint).query(&client).unwrap();
421 }
422
423 #[test]
424 fn endpoint_labels_unlabeled() {
425 let endpoint = ExpectedUrl::builder()
426 .endpoint("projects/simple%2Fproject/issues")
427 .add_query_params(&[("labels", "None")])
428 .build()
429 .unwrap();
430 let client = SingleTestClient::new_raw(endpoint, "");
431
432 let endpoint = ProjectIssues::builder()
433 .project("simple/project")
434 .unlabeled()
435 .build()
436 .unwrap();
437 api::ignore(endpoint).query(&client).unwrap();
438 }
439
440 #[test]
441 fn endpoint_labels_any() {
442 let endpoint = ExpectedUrl::builder()
443 .endpoint("projects/simple%2Fproject/issues")
444 .add_query_params(&[("labels", "Any")])
445 .build()
446 .unwrap();
447 let client = SingleTestClient::new_raw(endpoint, "");
448
449 let endpoint = ProjectIssues::builder()
450 .project("simple/project")
451 .with_any_label()
452 .build()
453 .unwrap();
454 api::ignore(endpoint).query(&client).unwrap();
455 }
456
457 #[test]
458 fn endpoint_with_labels_details() {
459 let endpoint = ExpectedUrl::builder()
460 .endpoint("projects/simple%2Fproject/issues")
461 .add_query_params(&[("with_labels_details", "true")])
462 .build()
463 .unwrap();
464 let client = SingleTestClient::new_raw(endpoint, "");
465
466 let endpoint = ProjectIssues::builder()
467 .project("simple/project")
468 .with_labels_details(true)
469 .build()
470 .unwrap();
471 api::ignore(endpoint).query(&client).unwrap();
472 }
473
474 #[test]
475 fn endpoint_iteration_none() {
476 let endpoint = ExpectedUrl::builder()
477 .endpoint("projects/simple%2Fproject/issues")
478 .add_query_params(&[("iteration_id", "None")])
479 .build()
480 .unwrap();
481 let client = SingleTestClient::new_raw(endpoint, "");
482
483 let endpoint = ProjectIssues::builder()
484 .project("simple/project")
485 .iteration(IssueIteration::None)
486 .build()
487 .unwrap();
488 api::ignore(endpoint).query(&client).unwrap();
489 }
490
491 #[test]
492 fn endpoint_iteration_any() {
493 let endpoint = ExpectedUrl::builder()
494 .endpoint("projects/simple%2Fproject/issues")
495 .add_query_params(&[("iteration_id", "Any")])
496 .build()
497 .unwrap();
498 let client = SingleTestClient::new_raw(endpoint, "");
499
500 let endpoint = ProjectIssues::builder()
501 .project("simple/project")
502 .iteration(IssueIteration::Any)
503 .build()
504 .unwrap();
505 api::ignore(endpoint).query(&client).unwrap();
506 }
507
508 #[test]
509 fn endpoint_iteration_id() {
510 let endpoint = ExpectedUrl::builder()
511 .endpoint("projects/simple%2Fproject/issues")
512 .add_query_params(&[("iteration_id", "1")])
513 .build()
514 .unwrap();
515 let client = SingleTestClient::new_raw(endpoint, "");
516
517 let endpoint = ProjectIssues::builder()
518 .project("simple/project")
519 .iteration(IssueIteration::Id(1))
520 .build()
521 .unwrap();
522 api::ignore(endpoint).query(&client).unwrap();
523 }
524
525 #[test]
526 fn endpoint_iteration_title() {
527 let endpoint = ExpectedUrl::builder()
528 .endpoint("projects/simple%2Fproject/issues")
529 .add_query_params(&[("iteration_title", "title")])
530 .build()
531 .unwrap();
532 let client = SingleTestClient::new_raw(endpoint, "");
533
534 let endpoint = ProjectIssues::builder()
535 .project("simple/project")
536 .iteration(IssueIteration::Title("title".into()))
537 .build()
538 .unwrap();
539 api::ignore(endpoint).query(&client).unwrap();
540 }
541
542 #[test]
543 fn endpoint_milestone_id() {
544 let endpoint = ExpectedUrl::builder()
545 .endpoint("projects/simple%2Fproject/issues")
546 .add_query_params(&[("milestone_id", "Upcoming")])
547 .build()
548 .unwrap();
549 let client = SingleTestClient::new_raw(endpoint, "");
550
551 let endpoint = ProjectIssues::builder()
552 .project("simple/project")
553 .milestone_id(IssueMilestone::Upcoming)
554 .build()
555 .unwrap();
556 api::ignore(endpoint).query(&client).unwrap();
557 }
558
559 #[test]
560 fn endpoint_milestone_id_named() {
561 let endpoint = ExpectedUrl::builder()
562 .endpoint("projects/simple%2Fproject/issues")
563 .add_query_params(&[("milestone", "1.0")])
564 .build()
565 .unwrap();
566 let client = SingleTestClient::new_raw(endpoint, "");
567
568 let endpoint = ProjectIssues::builder()
569 .project("simple/project")
570 .milestone_id(IssueMilestone::named("1.0"))
571 .build()
572 .unwrap();
573 api::ignore(endpoint).query(&client).unwrap();
574 }
575
576 #[test]
577 fn endpoint_scope() {
578 let endpoint = ExpectedUrl::builder()
579 .endpoint("projects/simple%2Fproject/issues")
580 .add_query_params(&[("scope", "all")])
581 .build()
582 .unwrap();
583 let client = SingleTestClient::new_raw(endpoint, "");
584
585 let endpoint = ProjectIssues::builder()
586 .project("simple/project")
587 .scope(IssueScope::All)
588 .build()
589 .unwrap();
590 api::ignore(endpoint).query(&client).unwrap();
591 }
592
593 #[test]
594 fn endpoint_author_id() {
595 let endpoint = ExpectedUrl::builder()
596 .endpoint("projects/simple%2Fproject/issues")
597 .add_query_params(&[("author_id", "1")])
598 .build()
599 .unwrap();
600 let client = SingleTestClient::new_raw(endpoint, "");
601
602 let endpoint = ProjectIssues::builder()
603 .project("simple/project")
604 .author(1)
605 .build()
606 .unwrap();
607 api::ignore(endpoint).query(&client).unwrap();
608 }
609
610 #[test]
611 fn endpoint_author_name() {
612 let endpoint = ExpectedUrl::builder()
613 .endpoint("projects/simple%2Fproject/issues")
614 .add_query_params(&[("author_username", "name")])
615 .build()
616 .unwrap();
617 let client = SingleTestClient::new_raw(endpoint, "");
618
619 let endpoint = ProjectIssues::builder()
620 .project("simple/project")
621 .author("name")
622 .build()
623 .unwrap();
624 api::ignore(endpoint).query(&client).unwrap();
625 }
626
627 #[test]
628 fn endpoint_assignee_unassigned() {
629 let endpoint = ExpectedUrl::builder()
630 .endpoint("projects/simple%2Fproject/issues")
631 .add_query_params(&[("assignee_id", "None")])
632 .build()
633 .unwrap();
634 let client = SingleTestClient::new_raw(endpoint, "");
635
636 let endpoint = ProjectIssues::builder()
637 .project("simple/project")
638 .unassigned()
639 .build()
640 .unwrap();
641 api::ignore(endpoint).query(&client).unwrap();
642 }
643
644 #[test]
645 fn endpoint_assignee_assigned() {
646 let endpoint = ExpectedUrl::builder()
647 .endpoint("projects/simple%2Fproject/issues")
648 .add_query_params(&[("assignee_id", "Any")])
649 .build()
650 .unwrap();
651 let client = SingleTestClient::new_raw(endpoint, "");
652
653 let endpoint = ProjectIssues::builder()
654 .project("simple/project")
655 .assigned()
656 .build()
657 .unwrap();
658 api::ignore(endpoint).query(&client).unwrap();
659 }
660
661 #[test]
662 fn endpoint_assignee_id() {
663 let endpoint = ExpectedUrl::builder()
664 .endpoint("projects/simple%2Fproject/issues")
665 .add_query_params(&[("assignee_id", "1")])
666 .build()
667 .unwrap();
668 let client = SingleTestClient::new_raw(endpoint, "");
669
670 let endpoint = ProjectIssues::builder()
671 .project("simple/project")
672 .assignee_id(1)
673 .build()
674 .unwrap();
675 api::ignore(endpoint).query(&client).unwrap();
676 }
677
678 #[test]
679 fn endpoint_assignee_user() {
680 let endpoint = ExpectedUrl::builder()
681 .endpoint("projects/simple%2Fproject/issues")
682 .add_query_params(&[
683 ("assignee_username[]", "name1"),
684 ("assignee_username[]", "name2"),
685 ])
686 .build()
687 .unwrap();
688 let client = SingleTestClient::new_raw(endpoint, "");
689
690 let endpoint = ProjectIssues::builder()
691 .project("simple/project")
692 .assignee("name1")
693 .assignees(["name1", "name2"].iter().copied())
694 .build()
695 .unwrap();
696 api::ignore(endpoint).query(&client).unwrap();
697 }
698
699 #[test]
700 fn endpoint_my_reaction_emoji() {
701 let endpoint = ExpectedUrl::builder()
702 .endpoint("projects/simple%2Fproject/issues")
703 .add_query_params(&[("my_reaction_emoji", "tada")])
704 .build()
705 .unwrap();
706 let client = SingleTestClient::new_raw(endpoint, "");
707
708 let endpoint = ProjectIssues::builder()
709 .project("simple/project")
710 .my_reaction("tada")
711 .build()
712 .unwrap();
713 api::ignore(endpoint).query(&client).unwrap();
714 }
715
716 #[test]
717 fn endpoint_my_reaction_emoji_no_reaction() {
718 let endpoint = ExpectedUrl::builder()
719 .endpoint("projects/simple%2Fproject/issues")
720 .add_query_params(&[("my_reaction_emoji", "None")])
721 .build()
722 .unwrap();
723 let client = SingleTestClient::new_raw(endpoint, "");
724
725 let endpoint = ProjectIssues::builder()
726 .project("simple/project")
727 .no_reaction()
728 .build()
729 .unwrap();
730 api::ignore(endpoint).query(&client).unwrap();
731 }
732
733 #[test]
734 fn endpoint_my_reaction_emoji_any_reaction() {
735 let endpoint = ExpectedUrl::builder()
736 .endpoint("projects/simple%2Fproject/issues")
737 .add_query_params(&[("my_reaction_emoji", "Any")])
738 .build()
739 .unwrap();
740 let client = SingleTestClient::new_raw(endpoint, "");
741
742 let endpoint = ProjectIssues::builder()
743 .project("simple/project")
744 .any_reaction()
745 .build()
746 .unwrap();
747 api::ignore(endpoint).query(&client).unwrap();
748 }
749
750 #[test]
751 fn endpoint_weight() {
752 let endpoint = ExpectedUrl::builder()
753 .endpoint("projects/simple%2Fproject/issues")
754 .add_query_params(&[("weight", "Any")])
755 .build()
756 .unwrap();
757 let client = SingleTestClient::new_raw(endpoint, "");
758
759 let endpoint = ProjectIssues::builder()
760 .project("simple/project")
761 .weight(IssueWeight::Any)
762 .build()
763 .unwrap();
764 api::ignore(endpoint).query(&client).unwrap();
765 }
766
767 #[test]
768 fn endpoint_search() {
769 let endpoint = ExpectedUrl::builder()
770 .endpoint("projects/simple%2Fproject/issues")
771 .add_query_params(&[("search", "query")])
772 .build()
773 .unwrap();
774 let client = SingleTestClient::new_raw(endpoint, "");
775
776 let endpoint = ProjectIssues::builder()
777 .project("simple/project")
778 .search("query")
779 .build()
780 .unwrap();
781 api::ignore(endpoint).query(&client).unwrap();
782 }
783
784 #[test]
785 fn endpoint_search_in() {
786 let endpoint = ExpectedUrl::builder()
787 .endpoint("projects/simple%2Fproject/issues")
788 .add_query_params(&[("in", "title,description")])
789 .build()
790 .unwrap();
791 let client = SingleTestClient::new_raw(endpoint, "");
792
793 let endpoint = ProjectIssues::builder()
794 .project("simple/project")
795 .search_in(IssueSearchScope::Title)
796 .search_in(IssueSearchScope::Description)
797 .build()
798 .unwrap();
799 api::ignore(endpoint).query(&client).unwrap();
800 }
801
802 #[test]
803 fn endpoint_created_after() {
804 let endpoint = ExpectedUrl::builder()
805 .endpoint("projects/simple%2Fproject/issues")
806 .add_query_params(&[("created_after", "2020-01-01T00:00:00Z")])
807 .build()
808 .unwrap();
809 let client = SingleTestClient::new_raw(endpoint, "");
810
811 let endpoint = ProjectIssues::builder()
812 .project("simple/project")
813 .created_after(Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap())
814 .build()
815 .unwrap();
816 api::ignore(endpoint).query(&client).unwrap();
817 }
818
819 #[test]
820 fn endpoint_created_before() {
821 let endpoint = ExpectedUrl::builder()
822 .endpoint("projects/simple%2Fproject/issues")
823 .add_query_params(&[("created_before", "2020-01-01T00:00:00Z")])
824 .build()
825 .unwrap();
826 let client = SingleTestClient::new_raw(endpoint, "");
827
828 let endpoint = ProjectIssues::builder()
829 .project("simple/project")
830 .created_before(Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap())
831 .build()
832 .unwrap();
833 api::ignore(endpoint).query(&client).unwrap();
834 }
835
836 #[test]
837 fn endpoint_updated_after() {
838 let endpoint = ExpectedUrl::builder()
839 .endpoint("projects/simple%2Fproject/issues")
840 .add_query_params(&[("updated_after", "2020-01-01T00:00:00Z")])
841 .build()
842 .unwrap();
843 let client = SingleTestClient::new_raw(endpoint, "");
844
845 let endpoint = ProjectIssues::builder()
846 .project("simple/project")
847 .updated_after(Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap())
848 .build()
849 .unwrap();
850 api::ignore(endpoint).query(&client).unwrap();
851 }
852
853 #[test]
854 fn endpoint_updated_before() {
855 let endpoint = ExpectedUrl::builder()
856 .endpoint("projects/simple%2Fproject/issues")
857 .add_query_params(&[("updated_before", "2020-01-01T00:00:00Z")])
858 .build()
859 .unwrap();
860 let client = SingleTestClient::new_raw(endpoint, "");
861
862 let endpoint = ProjectIssues::builder()
863 .project("simple/project")
864 .updated_before(Utc.with_ymd_and_hms(2020, 1, 1, 0, 0, 0).unwrap())
865 .build()
866 .unwrap();
867 api::ignore(endpoint).query(&client).unwrap();
868 }
869
870 #[test]
871 fn endpoint_confidential() {
872 let endpoint = ExpectedUrl::builder()
873 .endpoint("projects/simple%2Fproject/issues")
874 .add_query_params(&[("confidential", "true")])
875 .build()
876 .unwrap();
877 let client = SingleTestClient::new_raw(endpoint, "");
878
879 let endpoint = ProjectIssues::builder()
880 .project("simple/project")
881 .confidential(true)
882 .build()
883 .unwrap();
884 api::ignore(endpoint).query(&client).unwrap();
885 }
886
887 #[test]
888 fn endpoint_due_date() {
889 let endpoint = ExpectedUrl::builder()
890 .endpoint("projects/simple%2Fproject/issues")
891 .add_query_params(&[("due_date", "week")])
892 .build()
893 .unwrap();
894 let client = SingleTestClient::new_raw(endpoint, "");
895
896 let endpoint = ProjectIssues::builder()
897 .project("simple/project")
898 .due_date(IssueDueDateFilter::ThisWeek)
899 .build()
900 .unwrap();
901 api::ignore(endpoint).query(&client).unwrap();
902 }
903
904 #[test]
905 fn endpoint_epic_id() {
906 let endpoint = ExpectedUrl::builder()
907 .endpoint("projects/simple%2Fproject/issues")
908 .add_query_params(&[("epic_id", "1")])
909 .build()
910 .unwrap();
911 let client = SingleTestClient::new_raw(endpoint, "");
912
913 let endpoint = ProjectIssues::builder()
914 .project("simple/project")
915 .epic_id(1)
916 .build()
917 .unwrap();
918 api::ignore(endpoint).query(&client).unwrap();
919 }
920
921 #[test]
922 fn endpoint_issue_type() {
923 let endpoint = ExpectedUrl::builder()
924 .endpoint("projects/simple%2Fproject/issues")
925 .add_query_params(&[("issue_type", "incident")])
926 .build()
927 .unwrap();
928 let client = SingleTestClient::new_raw(endpoint, "");
929
930 let endpoint = ProjectIssues::builder()
931 .project("simple/project")
932 .issue_type(IssueType::Incident)
933 .build()
934 .unwrap();
935 api::ignore(endpoint).query(&client).unwrap();
936 }
937
938 #[test]
939 fn endpoint_health_status() {
940 let endpoint = ExpectedUrl::builder()
941 .endpoint("projects/simple%2Fproject/issues")
942 .add_query_params(&[("health_status", "at_risk")])
943 .build()
944 .unwrap();
945 let client = SingleTestClient::new_raw(endpoint, "");
946
947 let endpoint = ProjectIssues::builder()
948 .project("simple/project")
949 .health_status(IssueHealthStatus::AtRisk)
950 .build()
951 .unwrap();
952 api::ignore(endpoint).query(&client).unwrap();
953 }
954
955 #[test]
956 fn endpoint_order_by() {
957 let endpoint = ExpectedUrl::builder()
958 .endpoint("projects/simple%2Fproject/issues")
959 .add_query_params(&[("order_by", "due_date")])
960 .build()
961 .unwrap();
962 let client = SingleTestClient::new_raw(endpoint, "");
963
964 let endpoint = ProjectIssues::builder()
965 .project("simple/project")
966 .order_by(IssueOrderBy::DueDate)
967 .build()
968 .unwrap();
969 api::ignore(endpoint).query(&client).unwrap();
970 }
971
972 #[test]
973 fn endpoint_sort() {
974 let endpoint = ExpectedUrl::builder()
975 .endpoint("projects/simple%2Fproject/issues")
976 .add_query_params(&[("sort", "desc")])
977 .build()
978 .unwrap();
979 let client = SingleTestClient::new_raw(endpoint, "");
980
981 let endpoint = ProjectIssues::builder()
982 .project("simple/project")
983 .sort(SortOrder::Descending)
984 .build()
985 .unwrap();
986 api::ignore(endpoint).query(&client).unwrap();
987 }
988}