use derive_builder::Builder;
use crate::api::common::NameOrId;
use crate::api::endpoint_prelude::*;
use crate::api::projects::labels::{LabelColor, LabelPriority};
#[derive(Debug, Builder, Clone)]
#[builder(setter(strip_option), build_fn(validate = "Self::validate"))]
pub struct EditLabel<'a> {
#[builder(setter(into))]
project: NameOrId<'a>,
#[builder(setter(into))]
label: NameOrId<'a>,
#[builder(setter(into), default)]
new_name: Option<Cow<'a, str>>,
#[builder(setter(into), default)]
color: Option<LabelColor>,
#[builder(setter(into), default)]
description: Option<Cow<'a, str>>,
#[builder(setter(into), default)]
priority: Option<LabelPriority>,
}
impl<'a> EditLabel<'a> {
pub fn builder() -> EditLabelBuilder<'a> {
EditLabelBuilder::default()
}
}
static NEED_COLOR_OR_NEW_NAME: &str = "at least one of `new_name` and `color` is required";
#[non_exhaustive]
enum EditLabelBuilderValidationError {
NeedColorOrNewName,
}
impl From<EditLabelBuilderValidationError> for EditLabelBuilderError {
fn from(validation_error: EditLabelBuilderValidationError) -> Self {
match validation_error {
EditLabelBuilderValidationError::NeedColorOrNewName => {
EditLabelBuilderError::ValidationError(NEED_COLOR_OR_NEW_NAME.into())
},
}
}
}
impl EditLabelBuilder<'_> {
fn validate(&self) -> Result<(), EditLabelBuilderValidationError> {
if self.new_name.is_none() && self.color.is_none() {
return Err(EditLabelBuilderValidationError::NeedColorOrNewName);
}
Ok(())
}
}
impl Endpoint for EditLabel<'_> {
fn method(&self) -> Method {
Method::PUT
}
fn endpoint(&self) -> Cow<'static, str> {
format!("projects/{}/labels/{}", self.project, self.label).into()
}
fn body(&self) -> Result<Option<(&'static str, Vec<u8>)>, BodyError> {
let mut params = FormParams::default();
params
.push_opt("new_name", self.new_name.as_ref())
.push_opt("color", self.color.as_ref())
.push_opt("description", self.description.as_ref())
.push_opt("priority", self.priority);
params.into_body()
}
}
#[cfg(test)]
mod tests {
use crate::api::projects::labels::{
EditLabel, EditLabelBuilderError, GitlabDefaultColor, LabelPriority,
};
use crate::api::{self, Query};
use crate::test::client::{ExpectedUrl, SingleTestClient};
use http::Method;
use super::NEED_COLOR_OR_NEW_NAME;
#[test]
fn project_is_necessary() {
let err = EditLabel::builder()
.label(1)
.new_name("label")
.build()
.unwrap_err();
crate::test::assert_missing_field!(err, EditLabelBuilderError, "project");
}
#[test]
fn label_is_necessary() {
let err = EditLabel::builder()
.project(1)
.new_name("label")
.build()
.unwrap_err();
crate::test::assert_missing_field!(err, EditLabelBuilderError, "label");
}
#[test]
fn new_name_or_color_is_necessary() {
let err = EditLabel::builder()
.project(1)
.label("label")
.build()
.unwrap_err();
assert_eq!(err.to_string(), NEED_COLOR_OR_NEW_NAME);
}
#[test]
fn project_label_and_new_name_are_sufficient() {
EditLabel::builder()
.project(1)
.label("label")
.new_name("label_new")
.build()
.unwrap();
}
#[test]
fn project_label_and_color_are_sufficient() {
EditLabel::builder()
.project(1)
.label("label")
.color((0xf1, 0x00, 0xfe))
.build()
.unwrap();
}
#[test]
fn endpoint() {
let endpoint = ExpectedUrl::builder()
.method(Method::PUT)
.endpoint("projects/simple%2Fproject/labels/label%25with%25percent")
.content_type("application/x-www-form-urlencoded")
.body_str(concat!("new_name=label", "&color=%23ffffff"))
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = EditLabel::builder()
.project("simple/project")
.label("label%with%percent")
.new_name("label")
.color((0xff, 0xff, 0xff))
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_new_name() {
let endpoint = ExpectedUrl::builder()
.method(Method::PUT)
.endpoint("projects/simple%2Fproject/labels/label")
.content_type("application/x-www-form-urlencoded")
.body_str("new_name=label")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = EditLabel::builder()
.project("simple/project")
.label("label")
.new_name("label")
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_color() {
let endpoint = ExpectedUrl::builder()
.method(Method::PUT)
.endpoint("projects/simple%2Fproject/labels/label")
.content_type("application/x-www-form-urlencoded")
.body_str("color=%23ffffff")
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = EditLabel::builder()
.project("simple/project")
.label("label")
.color((0xff, 0xff, 0xff))
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_description() {
let endpoint = ExpectedUrl::builder()
.method(Method::PUT)
.endpoint("projects/simple%2Fproject/labels/label")
.content_type("application/x-www-form-urlencoded")
.body_str(concat!("new_name=new_label", "&description=description"))
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = EditLabel::builder()
.project("simple/project")
.label("label")
.new_name("new_label")
.description("description")
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_priority() {
let endpoint = ExpectedUrl::builder()
.method(Method::PUT)
.endpoint("projects/simple%2Fproject/labels/label")
.content_type("application/x-www-form-urlencoded")
.body_str(concat!("new_name=new_label", "&priority=1"))
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = EditLabel::builder()
.project("simple/project")
.label("label")
.new_name("new_label")
.priority(1)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
#[test]
fn endpoint_priority_null() {
let endpoint = ExpectedUrl::builder()
.method(Method::PUT)
.endpoint("projects/simple%2Fproject/labels/label")
.content_type("application/x-www-form-urlencoded")
.body_str(concat!("color=%23808080", "&priority=null"))
.build()
.unwrap();
let client = SingleTestClient::new_raw(endpoint, "");
let endpoint = EditLabel::builder()
.project("simple/project")
.label("label")
.color(GitlabDefaultColor::Gray)
.priority(LabelPriority::Null)
.build()
.unwrap();
api::ignore(endpoint).query(&client).unwrap();
}
}