Skip to main content

kcode_k1_daemon_lib_testkit/
lib.rs

1#![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.1\"",
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-launch-nodes = \"0.4.0\"",
29    "kcode-k1-peering = \"0.3.1\"",
30    "kcode-k1-txn-ordering = \"0.5.1\"",
31    "kcode-speaker-v3-analysis = \"0.3.5\"",
32];
33
34const OBSOLETE_LINES: &[&str] = &[
35    "kcode-k1-access = \"0.6.1\"",
36    "kcode-k1-access-full-audio = \"0.9.1\"",
37    "kcode-k1-access-full-audio = \"0.9.4\"",
38    "kcode-k1-access-launch-nodes = \"0.2.0\"",
39    "kcode-k1-audio-classification = \"0.5.9\"",
40    "kcode-k1-audio-classification = \"0.5.10\"",
41    "kcode-k1-chat-service = \"0.3.0\"",
42    "kcode-k1-chat-service = \"0.6.0\"",
43    "kcode-k1-chat-service = \"0.7.0\"",
44    "kcode-k1-chat-service = \"0.8.0\"",
45    "kcode-k1-chat-service = \"0.9.0\"",
46    "kcode-k1-chat-service = \"0.10.0\"",
47    "kcode-k1-codex-adapter = \"0.5.0\"",
48    "kcode-k1-codex-adapter = \"0.5.1\"",
49    "kcode-k1-codex-websearch = \"0.1.0\"",
50    "kcode-k1-daemon-http-boundary = \"0.1.0\"",
51    "kcode-k1-daemon-provider-config = \"0.1.4\"",
52    "kcode-k1-daemon-provider-config = \"0.1.5\"",
53    "kcode-k1-full-audio = \"0.3.7\"",
54    "kcode-k1-http-audio = \"0.3.0\"",
55    "kcode-k1-http-audio = \"0.3.1\"",
56    "kcode-k1-http-chat = \"0.2.0\"",
57    "kcode-k1-http-chat = \"0.5.0\"",
58    "kcode-k1-http-chat = \"0.6.0\"",
59    "kcode-k1-http-chat = \"0.6.1\"",
60    "kcode-k1-http-chat = \"0.7.0\"",
61    "kcode-k1-http-chat = \"0.7.1\"",
62    "kcode-k1-http-launch-nodes = \"0.2.0\"",
63    "kcode-k1-launch-nodes = \"0.3.0\"",
64    "kcode-k1-peering = \"0.3.0\"",
65    "kcode-k1-web-http = \"0.1.0\"",
66];
67
68const REQUIRED_SOURCE: &[&str] = &[
69    "AudioClassification::open(",
70    ".shutdown()",
71    "kcode_k1_http_audio::authenticated_routes",
72];
73
74const PROHIBITED_SOURCE: &[&str] = &[
75    "audio-classification-v2",
76    "http_audio_artifacts",
77    "retry_fragment",
78    "artifact_route",
79];
80
81pub fn verify_manifest(manifest: &str) {
82    for required in REQUIRED_LINES {
83        assert!(
84            manifest.lines().any(|line| line == *required),
85            "missing required manifest line: {required}"
86        );
87    }
88    for obsolete in OBSOLETE_LINES {
89        assert!(
90            !manifest.lines().any(|line| line == *obsolete),
91            "obsolete manifest line: {obsolete}"
92        );
93    }
94    assert!(
95        !manifest.lines().any(|line| line
96            .trim_start()
97            .starts_with("kcode-k1-http-audio-artifacts")),
98        "artifact manifest selection"
99    );
100    assert!(
101        !manifest.lines().any(|line| line.contains(" = \"=")),
102        "manifest contains an exact internal pin"
103    );
104}
105
106pub fn verify_source(source: &str) {
107    for required in REQUIRED_SOURCE {
108        assert!(
109            source.contains(required),
110            "missing required source evidence: {required}"
111        );
112    }
113    for prohibited in PROHIBITED_SOURCE {
114        assert!(
115            !source.contains(prohibited),
116            "prohibited source token: {prohibited}"
117        );
118    }
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124
125    fn good_manifest() -> String {
126        REQUIRED_LINES.join("\n")
127    }
128
129    fn good_source() -> &'static str {
130        "AudioClassification::open(\nservice.shutdown()\nkcode_k1_http_audio::authenticated_routes"
131    }
132
133    #[test]
134    fn accepts_current_inputs() {
135        verify_manifest(&good_manifest());
136        verify_source(good_source());
137    }
138
139    #[test]
140    fn rejects_missing_audio_requirements() {
141        for line in [
142            "kcode-k1-access-full-audio = \"0.10.0\"",
143            "kcode-k1-audio-classification = \"0.6.0\"",
144            "kcode-k1-full-audio = \"0.4.0\"",
145            "kcode-k1-http-audio = \"0.4.0\"",
146            "kcode-k1-peering = \"0.3.1\"",
147            "kcode-speaker-v3-analysis = \"0.3.5\"",
148        ] {
149            assert!(
150                std::panic::catch_unwind(|| verify_manifest(&good_manifest().replace(line, "")))
151                    .is_err()
152            );
153        }
154    }
155
156    #[test]
157    fn rejects_missing_source_evidence() {
158        for evidence in REQUIRED_SOURCE {
159            assert!(
160                std::panic::catch_unwind(|| verify_source(&good_source().replace(evidence, "")))
161                    .is_err()
162            );
163        }
164    }
165
166    #[test]
167    fn rejects_prohibited_source_tokens() {
168        for token in PROHIBITED_SOURCE {
169            assert!(
170                std::panic::catch_unwind(|| verify_source(&format!("{} {token}", good_source())))
171                    .is_err()
172            );
173        }
174    }
175
176    #[test]
177    fn rejects_artifact_package_selection() {
178        assert!(
179            std::panic::catch_unwind(|| verify_manifest(&format!(
180                "{}\n kcode-k1-http-audio-artifacts = \"0.4.0\"",
181                good_manifest()
182            )))
183            .is_err()
184        );
185    }
186
187    #[test]
188    fn rejects_old_audio_lines() {
189        for line in [
190            "kcode-k1-audio-classification = \"0.5.10\"",
191            "kcode-k1-full-audio = \"0.3.7\"",
192            "kcode-k1-access-full-audio = \"0.9.4\"",
193            "kcode-k1-http-audio = \"0.3.1\"",
194            "kcode-k1-peering = \"0.3.0\"",
195        ] {
196            assert!(
197                std::panic::catch_unwind(|| verify_manifest(&format!(
198                    "{}\n{line}",
199                    good_manifest()
200                )))
201                .is_err()
202            );
203        }
204    }
205
206    #[test]
207    fn rejects_exact_internal_pin() {
208        assert!(
209            std::panic::catch_unwind(|| verify_manifest(&format!(
210                "{}\nkcode-k1-peering = \"=0.3.1\"",
211                good_manifest()
212            )))
213            .is_err()
214        );
215    }
216
217    #[test]
218    fn rejects_unrelated_obsolete_line() {
219        assert!(
220            std::panic::catch_unwind(|| verify_manifest(&format!(
221                "{}\nkcode-k1-http-chat = \"0.7.1\"",
222                good_manifest()
223            )))
224            .is_err()
225        );
226    }
227}