libcnb_data/buildpack/
api.rs1use serde::Deserialize;
2use std::fmt;
3use std::fmt::{Display, Formatter};
4
5#[derive(Deserialize, Debug, Eq, PartialEq)]
9#[serde(try_from = "String")]
10pub struct BuildpackApi {
11 pub major: u64,
12 pub minor: u64,
13}
14
15impl TryFrom<String> for BuildpackApi {
16 type Error = BuildpackApiError;
17
18 fn try_from(value: String) -> Result<Self, Self::Error> {
19 let (major, minor) = &value.split_once('.').unwrap_or((&value, "0"));
22
23 Ok(Self {
24 major: major
25 .parse()
26 .map_err(|_| Self::Error::InvalidBuildpackApi(value.clone()))?,
27 minor: minor
28 .parse()
29 .map_err(|_| Self::Error::InvalidBuildpackApi(value.clone()))?,
30 })
31 }
32}
33
34impl Display for BuildpackApi {
35 fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
36 formatter.write_str(&format!("{}.{}", self.major, self.minor))
37 }
38}
39
40#[derive(thiserror::Error, Debug)]
41pub enum BuildpackApiError {
42 #[error("Invalid Buildpack API version: `{0}`")]
43 InvalidBuildpackApi(String),
44}
45
46#[cfg(test)]
47mod tests {
48 use serde_test::{Token, assert_de_tokens, assert_de_tokens_error};
49
50 use super::*;
51
52 #[test]
53 fn deserialize_valid_api_versions() {
54 assert_de_tokens(
55 &BuildpackApi { major: 1, minor: 3 },
56 &[Token::BorrowedStr("1.3")],
57 );
58 assert_de_tokens(
59 &BuildpackApi { major: 0, minor: 0 },
60 &[Token::BorrowedStr("0.0")],
61 );
62 assert_de_tokens(
63 &BuildpackApi {
64 major: 2020,
65 minor: 10,
66 },
67 &[Token::BorrowedStr("2020.10")],
68 );
69 assert_de_tokens(
70 &BuildpackApi { major: 2, minor: 0 },
71 &[Token::BorrowedStr("2")],
72 );
73 }
74
75 #[test]
76 fn reject_invalid_api_versions() {
77 assert_de_tokens_error::<BuildpackApi>(
78 &[Token::BorrowedStr("1.2.3")],
79 "Invalid Buildpack API version: `1.2.3`",
80 );
81 assert_de_tokens_error::<BuildpackApi>(
82 &[Token::BorrowedStr("1.2-dev")],
83 "Invalid Buildpack API version: `1.2-dev`",
84 );
85 assert_de_tokens_error::<BuildpackApi>(
86 &[Token::BorrowedStr("-1")],
87 "Invalid Buildpack API version: `-1`",
88 );
89 assert_de_tokens_error::<BuildpackApi>(
90 &[Token::BorrowedStr(".1")],
91 "Invalid Buildpack API version: `.1`",
92 );
93 assert_de_tokens_error::<BuildpackApi>(
94 &[Token::BorrowedStr("1.")],
95 "Invalid Buildpack API version: `1.`",
96 );
97 assert_de_tokens_error::<BuildpackApi>(
98 &[Token::BorrowedStr("1..2")],
99 "Invalid Buildpack API version: `1..2`",
100 );
101 assert_de_tokens_error::<BuildpackApi>(
102 &[Token::BorrowedStr("")],
103 "Invalid Buildpack API version: ``",
104 );
105 }
106
107 #[test]
108 fn buildpack_api_display() {
109 assert_eq!(BuildpackApi { major: 1, minor: 0 }.to_string(), "1.0");
110 assert_eq!(BuildpackApi { major: 1, minor: 2 }.to_string(), "1.2");
111 assert_eq!(
112 BuildpackApi {
113 major: 0,
114 minor: 10
115 }
116 .to_string(),
117 "0.10"
118 );
119 }
120}