1use thiserror::Error;
4
5#[derive(Debug, Error)]
6pub enum ProjectError {
7 #[error("manifest missing at `{path}`: expected a `prosaic.toml` at the project root")]
8 ManifestMissing { path: String },
9
10 #[error("malformed TOML in `{file}`: {cause}")]
11 TomlParse { file: String, cause: String },
12
13 #[error("malformed JSON in `{file}`: {cause}")]
14 JsonParse { file: String, cause: String },
15
16 #[error("template `{key}` validation failed: {reason}")]
17 TemplateValidation { key: String, reason: String },
18
19 #[error("partial `{name}` validation failed: {reason}")]
20 PartialValidation { name: String, reason: String },
21
22 #[error("scenario `{name}` failed: {reason}")]
23 ScenarioValidation { name: String, reason: String },
24
25 #[error("fixture `{name}` failed: {reason}")]
26 FixtureValidation { name: String, reason: String },
27
28 #[error(
29 "vocab dependency `{crate_name}` not registered: enable the `{crate_name}` feature or add it to `prosaic.toml`"
30 )]
31 UnregisteredVocab { crate_name: String },
32
33 #[error("template `{key}` references unknown partial `{partial}`")]
34 UnknownPartial { key: String, partial: String },
35
36 #[error("template `{key}` uses unknown pipe `{pipe}` (known pipes: {known})")]
37 UnknownPipe {
38 key: String,
39 pipe: String,
40 known: String,
41 },
42
43 #[error("io error reading `{path}`: {cause}")]
44 Io { path: String, cause: String },
45
46 #[error("style profile invalid: {reason}")]
47 ManifestStyle { reason: String },
48
49 #[error("engine error: {0}")]
50 Engine(#[from] prosaic_core::ProsaicError),
51}
52
53#[cfg(test)]
54mod tests {
55 use super::ProjectError;
56
57 #[test]
58 fn missing_manifest_displays_path() {
59 let e = ProjectError::ManifestMissing {
60 path: "/tmp/foo/prosaic.toml".to_string(),
61 };
62 let msg = format!("{e}");
63 assert!(msg.contains("prosaic.toml"));
64 assert!(msg.contains("/tmp/foo"));
65 }
66
67 #[test]
68 fn malformed_toml_displays_filename_and_inner() {
69 let e = ProjectError::TomlParse {
70 file: "templates/code.modified.toml".to_string(),
71 cause: "expected `=` after key".to_string(),
72 };
73 let msg = format!("{e}");
74 assert!(msg.contains("code.modified.toml"));
75 assert!(msg.contains("expected `=`"));
76 }
77
78 #[test]
79 fn template_validation_includes_key() {
80 let e = ProjectError::TemplateValidation {
81 key: "code.modified".to_string(),
82 reason: "no variants registered".to_string(),
83 };
84 let msg = format!("{e}");
85 assert!(msg.contains("code.modified"));
86 assert!(msg.contains("no variants"));
87 }
88}