1use std::fs;
2use std::path::Path;
3use std::error::Error;
4
5pub mod tui;
6
7pub fn greeting() -> String {
9 String::from("Hello Warp, I am David Parker.")
10}
11
12pub fn load_content(filename: &str) -> String {
14 let path = Path::new(env!("CARGO_MANIFEST_DIR"))
15 .join("src")
16 .join("static")
17 .join("content")
18 .join(filename);
19
20 match fs::read_to_string(&path) {
21 Ok(content) => content,
22 Err(_) => format!("Error: Failed to load content from '{}'", filename),
23 }
24}
25
26pub fn about() -> String {
28 load_content("about.md")
29}
30
31pub fn skills() -> String {
33 load_content("skills.md")
34}
35
36pub fn projects() -> String {
38 load_content("projects.md")
39}
40
41
42pub fn welcome() -> String {
44 load_content("welcome.md")
45}
46
47pub fn timeline() -> String {
49 load_content("timeline.md")
50}
51
52pub fn contact() -> String {
54 load_content("contact.md")
55}
56
57pub fn load_timeline_data() -> Result<Vec<TimelineEvent>, Box<dyn Error>> {
59 let path = Path::new(env!("CARGO_MANIFEST_DIR"))
60 .join("src")
61 .join("static")
62 .join("content")
63 .join("timeline.json");
64
65 let content = fs::read_to_string(&path)?;
66 let timeline_events: Vec<TimelineEvent> = serde_json::from_str(&content)?;
67 Ok(timeline_events)
68}
69
70#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
72pub struct ProjectLink {
73 pub text: String,
74 pub url: String,
75}
76
77#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
79pub struct ProjectLinks {
80 pub links: Vec<ProjectLink>,
81}
82
83pub fn load_project_links() -> Result<ProjectLinks, Box<dyn Error>> {
85 let path = Path::new(env!("CARGO_MANIFEST_DIR"))
86 .join("src")
87 .join("static")
88 .join("content")
89 .join("projects.json");
90
91 let content = fs::read_to_string(&path)?;
92 let project_links: ProjectLinks = serde_json::from_str(&content)?;
93 Ok(project_links)
94}
95
96#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
98pub struct TimelineEvent {
99 pub year: u32,
100 pub title: String,
101 pub organization: String,
102 pub description: String,
103 pub highlights: Vec<String>,
104 pub technologies: Vec<String>,
105}
106
107#[cfg(not(test))]
109pub fn run_tui() -> Result<(), Box<dyn Error>> {
110 tui::run()?;
111 Ok(())
112}
113
114#[cfg(test)]
116pub fn run_tui() -> Result<(), Box<dyn Error>> {
117 Ok(())
118}
119
120#[cfg(test)]
121mod tests {
122 use super::*;
123
124 #[test]
125 fn test_greeting() {
126 assert_eq!(greeting(), "Hello Warp, I am David Parker.");
127 }
128
129 #[test]
130 fn test_about_content() {
131 let about_content = about();
132 assert!(about_content.contains("About David Parker"));
133 assert!(about_content.contains("Warp team"));
134 }
135
136 #[test]
137 fn test_skills_content() {
138 let skills_content = skills();
139 assert!(!skills_content.is_empty());
140 assert!(!skills_content.contains("Error: Failed to load content from 'skills.md'"));
141 }
142
143 #[test]
144 fn test_projects_content() {
145 let projects_content = projects();
146 assert!(!projects_content.is_empty());
147 assert!(!projects_content.contains("Error: Failed to load content from 'projects.md'"));
148 }
149
150
151 #[test]
152 fn test_welcome_content() {
153 let welcome_content = welcome();
154 assert!(!welcome_content.is_empty());
155 assert!(!welcome_content.contains("Error: Failed to load content from 'welcome.md'"));
156 }
157
158 #[test]
159 fn test_timeline_content() {
160 let timeline_content = timeline();
161 assert!(!timeline_content.is_empty());
162 assert!(!timeline_content.contains("Error: Failed to load content from 'timeline.md'"));
163 }
164
165 #[test]
166 fn test_contact_content() {
167 let contact_content = contact();
168 assert!(!contact_content.is_empty());
169 assert!(!contact_content.contains("Error: Failed to load content from 'contact.md'"));
170 }
171
172 #[test]
173 fn test_load_timeline_data() {
174 let result = load_timeline_data();
175 assert!(result.is_ok());
176
177 let timeline_events = result.unwrap();
178 assert!(!timeline_events.is_empty());
179
180 let first_event = &timeline_events[0];
181 assert!(first_event.year > 0);
182 assert!(!first_event.title.is_empty());
183 assert!(!first_event.organization.is_empty());
184 assert!(!first_event.description.is_empty());
185 }
186
187 #[test]
188 fn test_load_content_error_handling() {
189 let content = load_content("nonexistent_file.md");
190 assert!(content.contains("Error: Failed to load content from 'nonexistent_file.md'"));
191 }
192
193 #[test]
194 fn test_run_tui() {
195 let result = run_tui();
196 assert!(result.is_ok());
197 }
198}