kcode_k1_daemon_lib_testkit/
lib.rs1#![forbid(unsafe_code)]
2
3const REQUIRED_LINES: &[&str] = &[
4 "kcode-k1-access = \"0.6.2\"",
5 "kcode-k1-access-audio-classifier = \"0.1.0\"",
6 "kcode-k1-access-full-audio = \"0.10.0\"",
7 "kcode-k1-access-launch-nodes = \"0.2.2\"",
8 "kcode-k1-access-persons = \"0.3.0\"",
9 "kcode-k1-access-profiles = \"0.6.2\"",
10 "kcode-k1-audio-classification = \"0.6.0\"",
11 "kcode-k1-audio-classifier = \"0.1.1\"",
12 "kcode-k1-authority-filters = \"0.2.0\"",
13 "kcode-k1-chat-service = \"0.10.4\"",
14 "kcode-k1-codex-adapter = \"0.5.3\"",
15 "kcode-k1-codex-websearch = \"0.2.0\"",
16 "kcode-k1-daemon-http-boundary = \"0.1.1\"",
17 "kcode-k1-daemon-provider-config = \"0.1.6\"",
18 "kcode-k1-daemon-web-startup = \"0.1.0\"",
19 "kcode-k1-full-audio = \"0.4.0\"",
20 "kcode-k1-http-access-context = \"0.2.0\"",
21 "kcode-k1-http-access-profile-presentation = \"0.1.0\"",
22 "kcode-k1-http-audio = \"0.4.0\"",
23 "kcode-k1-http-chat = \"0.7.2\"",
24 "kcode-k1-http-kmap = \"0.1.0\"",
25 "kcode-k1-http-launch-nodes = \"0.3.0\"",
26 "kcode-k1-http-people = \"0.9.0\"",
27 "kcode-k1-http-persons = \"0.3.0\"",
28 "kcode-k1-ktool-set-launch-node = \"0.1.0\"",
29 "kcode-k1-ktool-social = \"0.1.1\"",
30 "kcode-k1-launch-nodes = \"0.4.0\"",
31 "kcode-k1-peering = \"0.3.1\"",
32 "kcode-k1-txn-ordering = \"0.5.1\"",
33 "kcode-speaker-v3-analysis = \"0.3.5\"",
34];
35
36const OBSOLETE_LINES: &[&str] = &[
37 "kcode-k1-access = \"0.6.1\"",
38 "kcode-k1-access-full-audio = \"0.9.1\"",
39 "kcode-k1-access-full-audio = \"0.9.4\"",
40 "kcode-k1-access-launch-nodes = \"0.2.0\"",
41 "kcode-k1-audio-classification = \"0.5.9\"",
42 "kcode-k1-audio-classification = \"0.5.10\"",
43 "kcode-k1-chat-service = \"0.3.0\"",
44 "kcode-k1-chat-service = \"0.6.0\"",
45 "kcode-k1-chat-service = \"0.7.0\"",
46 "kcode-k1-chat-service = \"0.8.0\"",
47 "kcode-k1-chat-service = \"0.9.0\"",
48 "kcode-k1-chat-service = \"0.10.0\"",
49 "kcode-k1-chat-service = \"0.10.1\"",
50 "kcode-k1-chat-service = \"0.10.2\"",
51 "kcode-k1-chat-service = \"0.10.3\"",
52 "kcode-k1-codex-adapter = \"0.5.0\"",
53 "kcode-k1-codex-adapter = \"0.5.1\"",
54 "kcode-k1-codex-websearch = \"0.1.0\"",
55 "kcode-k1-daemon-http-boundary = \"0.1.0\"",
56 "kcode-k1-daemon-provider-config = \"0.1.4\"",
57 "kcode-k1-daemon-provider-config = \"0.1.5\"",
58 "kcode-k1-full-audio = \"0.3.7\"",
59 "kcode-k1-http-audio = \"0.3.0\"",
60 "kcode-k1-http-audio = \"0.3.1\"",
61 "kcode-k1-http-chat = \"0.2.0\"",
62 "kcode-k1-http-chat = \"0.5.0\"",
63 "kcode-k1-http-chat = \"0.6.0\"",
64 "kcode-k1-http-chat = \"0.6.1\"",
65 "kcode-k1-http-chat = \"0.7.0\"",
66 "kcode-k1-http-chat = \"0.7.1\"",
67 "kcode-k1-http-launch-nodes = \"0.2.0\"",
68 "kcode-k1-ktool-social = \"0.1.0\"",
69 "kcode-k1-launch-nodes = \"0.3.0\"",
70 "kcode-k1-peering = \"0.3.0\"",
71 "kcode-k1-web-http = \"0.1.0\"",
72];
73
74const REQUIRED_SOURCE: &[&str] = &[
75 "AudioClassification::open(",
76 ".shutdown()",
77 "kcode_k1_http_audio::authenticated_routes",
78 "SocialKtools::new(",
79 "SetLaunchNodeKtool::new(",
80 "K1ChatService::open_with_social_and_set_launch_node(",
81];
82
83const PROHIBITED_SOURCE: &[&str] = &[
84 "audio-classification-v2",
85 "http_audio_artifacts",
86 "retry_fragment",
87 "artifact_route",
88 "let chat = K1ChatService::open(",
89 "K1ChatService::open_with_social(",
90];
91
92pub fn verify_manifest(manifest: &str) {
93 for required in REQUIRED_LINES {
94 assert!(
95 manifest.lines().any(|line| line == *required),
96 "missing required manifest line: {required}"
97 );
98 }
99 for obsolete in OBSOLETE_LINES {
100 assert!(
101 !manifest.lines().any(|line| line == *obsolete),
102 "obsolete manifest line: {obsolete}"
103 );
104 }
105 assert!(
106 !manifest.lines().any(|line| line
107 .trim_start()
108 .starts_with("kcode-k1-http-audio-artifacts")),
109 "artifact manifest selection"
110 );
111 assert!(
112 !manifest.lines().any(|line| line.contains(" = \"=")),
113 "manifest contains an exact internal pin"
114 );
115}
116
117pub fn verify_source(source: &str) {
118 for required in REQUIRED_SOURCE {
119 assert!(
120 source.contains(required),
121 "missing required source evidence: {required}"
122 );
123 }
124 for prohibited in PROHIBITED_SOURCE {
125 assert!(
126 !source.contains(prohibited),
127 "prohibited source token: {prohibited}"
128 );
129 }
130}
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 fn good_manifest() -> String {
137 REQUIRED_LINES.join("\n")
138 }
139
140 fn good_source() -> &'static str {
141 "AudioClassification::open(\nservice.shutdown()\nkcode_k1_http_audio::authenticated_routes\nSocialKtools::new(\nSetLaunchNodeKtool::new(\nK1ChatService::open_with_social_and_set_launch_node("
142 }
143
144 #[test]
145 fn accepts_current_inputs() {
146 verify_manifest(&good_manifest());
147 verify_source(good_source());
148 }
149
150 #[test]
151 fn rejects_missing_audio_requirements() {
152 for line in [
153 "kcode-k1-access-full-audio = \"0.10.0\"",
154 "kcode-k1-audio-classification = \"0.6.0\"",
155 "kcode-k1-full-audio = \"0.4.0\"",
156 "kcode-k1-http-audio = \"0.4.0\"",
157 "kcode-k1-peering = \"0.3.1\"",
158 "kcode-speaker-v3-analysis = \"0.3.5\"",
159 ] {
160 assert!(
161 std::panic::catch_unwind(|| verify_manifest(&good_manifest().replace(line, "")))
162 .is_err()
163 );
164 }
165 }
166
167 #[test]
168 fn rejects_missing_composition_manifest_requirements() {
169 for line in [
170 "kcode-k1-chat-service = \"0.10.4\"",
171 "kcode-k1-ktool-set-launch-node = \"0.1.0\"",
172 "kcode-k1-ktool-social = \"0.1.1\"",
173 ] {
174 assert!(
175 std::panic::catch_unwind(|| verify_manifest(&good_manifest().replace(line, "")))
176 .is_err()
177 );
178 }
179 }
180
181 #[test]
182 fn rejects_missing_source_evidence() {
183 for evidence in REQUIRED_SOURCE {
184 assert!(
185 std::panic::catch_unwind(|| verify_source(&good_source().replace(evidence, "")))
186 .is_err()
187 );
188 }
189 }
190
191 #[test]
192 fn rejects_prohibited_source_tokens() {
193 for token in PROHIBITED_SOURCE {
194 assert!(
195 std::panic::catch_unwind(|| verify_source(&format!("{} {token}", good_source())))
196 .is_err()
197 );
198 }
199 }
200
201 #[test]
202 fn rejects_artifact_package_selection() {
203 assert!(
204 std::panic::catch_unwind(|| verify_manifest(&format!(
205 "{}\n kcode-k1-http-audio-artifacts = \"0.4.0\"",
206 good_manifest()
207 )))
208 .is_err()
209 );
210 }
211
212 #[test]
213 fn rejects_old_audio_and_displaced_composition_lines() {
214 for line in [
215 "kcode-k1-audio-classification = \"0.5.10\"",
216 "kcode-k1-full-audio = \"0.3.7\"",
217 "kcode-k1-access-full-audio = \"0.9.4\"",
218 "kcode-k1-http-audio = \"0.3.1\"",
219 "kcode-k1-peering = \"0.3.0\"",
220 "kcode-k1-chat-service = \"0.10.3\"",
221 "kcode-k1-ktool-social = \"0.1.0\"",
222 ] {
223 assert!(
224 std::panic::catch_unwind(|| verify_manifest(&format!(
225 "{}\n{line}",
226 good_manifest()
227 )))
228 .is_err()
229 );
230 }
231 }
232
233 #[test]
234 fn current_chat_composition_does_not_match_former_name() {
235 assert!(
236 !"K1ChatService::open_with_social_and_set_launch_node("
237 .contains("K1ChatService::open_with_social(")
238 );
239 }
240
241 #[test]
242 fn rejects_exact_internal_pin() {
243 assert!(
244 std::panic::catch_unwind(|| verify_manifest(&format!(
245 "{}\nkcode-k1-peering = \"=0.3.1\"",
246 good_manifest()
247 )))
248 .is_err()
249 );
250 }
251
252 #[test]
253 fn rejects_unrelated_obsolete_line() {
254 assert!(
255 std::panic::catch_unwind(|| verify_manifest(&format!(
256 "{}\nkcode-k1-http-chat = \"0.7.1\"",
257 good_manifest()
258 )))
259 .is_err()
260 );
261 }
262}