crates_readme_table/
lib.rs1mod api;
4mod readme;
5mod table;
6
7pub use api::{CRATES_IO_USER_AGENT, Crate, CratesResponse, Meta, get_all_crates, get_crates};
8pub use readme::update_readme_with_table;
9pub use table::build_crates_table;
10
11#[cfg(test)]
12mod tests {
13 use super::*;
14 use crate::api::Crate;
15 use crate::readme::{SECTION_END, SECTION_START, update_readme_with_table_internal};
16 use crate::table::base_url;
17 use std::fs;
18 use std::io::Write;
19 use tempfile::NamedTempFile;
20
21 #[tokio::test]
22 async fn test_get_crates() {
23 let client = reqwest::Client::builder()
24 .user_agent(CRATES_IO_USER_AGENT)
25 .build()
26 .unwrap();
27 let crates = get_crates(&client, 1, 10, "alpha", 335369).await.unwrap();
28 println!("{:?}", crates);
29 }
30
31 #[tokio::test]
32 async fn test_get_all_crates() {
33 let client = reqwest::Client::builder()
34 .user_agent(CRATES_IO_USER_AGENT)
35 .build()
36 .unwrap();
37 let crates = get_all_crates(&client, 335369).await.unwrap();
38 assert!(!crates.is_empty());
39 }
40
41 #[test]
42 fn test_base_url_prefers_homepage_then_repository_then_crates_io() {
43 let c_with_homepage = Crate {
44 id: "id1".into(),
45 name: "crate1".into(),
46 description: None,
47 homepage: Some("https://example.com/home".into()),
48 repository: Some("https://github.com/owner/repo.git".into()),
49 links: None,
50 };
51 assert_eq!(
52 base_url(&c_with_homepage),
53 "https://example.com/home".to_string()
54 );
55
56 let c_with_repo_only = Crate {
57 id: "id1".into(),
58 name: "crate1".into(),
59 description: None,
60 homepage: None,
61 repository: Some("https://github.com/owner/repo.git".into()),
62 links: None,
63 };
64 assert_eq!(
65 base_url(&c_with_repo_only),
66 "https://github.com/owner/repo".to_string()
67 );
68
69 let c_fallback = Crate {
70 id: "id1".into(),
71 name: "crate1".into(),
72 description: None,
73 homepage: None,
74 repository: None,
75 links: None,
76 };
77 assert_eq!(
78 base_url(&c_fallback),
79 "https://crates.io/crates/crate1".to_string()
80 );
81 }
82
83 #[test]
84 fn test_build_crates_table_produces_expected_markdown() {
85 let c = Crate {
86 id: "id1".into(),
87 name: "crate1".into(),
88 description: Some("Line1\nLine2".into()),
89 homepage: Some("https://github.com/owner/repo".into()),
90 repository: None,
91 links: None,
92 };
93 let table = build_crates_table(&[c]);
94 assert!(table.contains("|package|introduction|total downloads|"));
95 assert!(table.contains("@crate1"));
96 assert!(table.contains("Line1 Line2"));
97 assert!(table.contains("https://img.shields.io/crates/d/crate1"));
98 }
99
100 #[test]
101 fn test_update_readme_with_table_replaces_existing_section() {
102 let mut tmp = NamedTempFile::new().unwrap();
103 writeln!(
104 tmp,
105 "Header\n{}\n\nold table\n\n{}",
106 SECTION_START, SECTION_END
107 )
108 .unwrap();
109
110 let path = tmp.path().to_path_buf();
111 let table = "|header|";
112 update_readme_with_table_internal(&path, table).unwrap();
113
114 let contents = fs::read_to_string(&path).unwrap();
115 assert!(contents.contains(table));
116 assert!(contents.contains(SECTION_START));
117 assert!(contents.contains(SECTION_END));
118 assert!(!contents.contains("old table"));
119 }
120
121 #[test]
122 fn test_update_readme_with_table_appends_section_when_missing() {
123 let mut tmp = NamedTempFile::new().unwrap();
124 writeln!(tmp, "Some content").unwrap();
125
126 let path = tmp.path().to_path_buf();
127 let table = "|header|";
128 update_readme_with_table_internal(&path, table).unwrap();
129
130 let contents = fs::read_to_string(&path).unwrap();
131 assert!(contents.contains("Some content"));
132 assert!(contents.contains(SECTION_START));
133 assert!(contents.contains(SECTION_END));
134 assert!(contents.contains(table));
135 }
136}