use crate::pagination::{ListOptions, QueryEncode};
use crate::{Deserialize, Serialize};
#[derive(Debug, Clone, Default)]
pub struct ListLabelsOptions {
pub list_options: ListOptions,
}
impl QueryEncode for ListLabelsOptions {
fn query_encode(&self) -> String {
self.list_options.query_encode()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CreateLabelOption {
pub name: String,
pub color: String,
pub description: String,
pub exclusive: bool,
#[serde(rename = "is_archived")]
pub is_archived: bool,
}
impl CreateLabelOption {
pub fn validate(&self) -> crate::Result<()> {
let color = self.color.trim_start_matches('#');
if color.len() != 6 || !color.chars().all(|c| c.is_ascii_hexdigit()) {
return Err(crate::Error::Validation("invalid color format".to_string()));
}
if self.name.trim().is_empty() {
return Err(crate::Error::Validation(
"empty name not allowed".to_string(),
));
}
Ok(())
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EditLabelOption {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub color: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub description: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub exclusive: Option<bool>,
#[serde(
rename = "is_archived",
default,
skip_serializing_if = "Option::is_none"
)]
pub is_archived: Option<bool>,
}
impl EditLabelOption {
pub fn validate(&self) -> crate::Result<()> {
if let Some(ref color) = self.color {
let color = color.trim_start_matches('#');
if color.len() != 6 || !color.chars().all(|c| c.is_ascii_hexdigit()) {
return Err(crate::Error::Validation("invalid color format".to_string()));
}
}
if let Some(ref name) = self.name
&& name.trim().is_empty()
{
return Err(crate::Error::Validation(
"empty name not allowed".to_string(),
));
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_label_option_validate_success() {
let opt = CreateLabelOption {
name: "bug".to_string(),
color: "ff0000".to_string(),
description: String::new(),
exclusive: false,
is_archived: false,
};
assert!(opt.validate().is_ok());
}
#[test]
fn test_create_label_option_validate_invalid_color() {
let opt = CreateLabelOption {
name: "bug".to_string(),
color: "red".to_string(),
description: String::new(),
exclusive: false,
is_archived: false,
};
assert!(opt.validate().is_err());
}
#[test]
fn test_create_label_option_validate_empty_name() {
let opt = CreateLabelOption {
name: String::new(),
color: "ff0000".to_string(),
description: String::new(),
exclusive: false,
is_archived: false,
};
assert!(opt.validate().is_err());
}
#[test]
fn test_create_label_option_validate_color_with_hash() {
let opt = CreateLabelOption {
name: "bug".to_string(),
color: "#00ff00".to_string(),
description: String::new(),
exclusive: false,
is_archived: false,
};
assert!(opt.validate().is_ok());
}
#[test]
fn test_edit_label_option_validate_success() {
let opt = EditLabelOption {
name: Some("new-name".to_string()),
color: Some("abcdef".to_string()),
description: None,
exclusive: None,
is_archived: None,
};
assert!(opt.validate().is_ok());
}
#[test]
fn test_edit_label_option_validate_invalid_color() {
let opt = EditLabelOption {
name: None,
color: Some("zzz".to_string()),
description: None,
exclusive: None,
is_archived: None,
};
assert!(opt.validate().is_err());
}
#[test]
fn test_edit_label_option_validate_empty_name() {
let opt = EditLabelOption {
name: Some(" ".to_string()),
color: None,
description: None,
exclusive: None,
is_archived: None,
};
assert!(opt.validate().is_err());
}
}