Skip to main content

decy_stdlib/
lib.rs

1//! # DECY Standard Library Support
2//!
3//! **RED PHASE**: Built-in C standard library function prototypes
4//!
5//! This crate provides ISO C99 §7 standard library function prototypes,
6//! enabling transpilation of C code that uses stdlib functions without
7//! requiring actual header files.
8//!
9//! **Pattern**: EXTREME TDD - Test-First Development
10//! **References**: See docs/specifications/header-support-spec.md
11//!
12//! ## Architecture
13//!
14//! ```text
15//! C Code → Prototype Injection → Parser → HIR → Rust
16//!   ↓
17//! #include <stdlib.h>
18//!   ↓ (commented out by preprocessor)
19//! Built-in prototypes injected
20//!   ↓
21//! malloc/free declarations available
22//!   ↓
23//! Parser succeeds!
24//! ```
25
26use std::collections::HashMap;
27
28mod prototypes;
29
30/// ISO C99 §7 Standard Library Headers + POSIX extensions
31#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
32pub enum StdHeader {
33    Assert,  // <assert.h>
34    Ctype,   // <ctype.h>
35    Errno,   // <errno.h>
36    Float,   // <float.h>
37    Limits,  // <limits.h>
38    Locale,  // <locale.h>
39    Math,    // <math.h>
40    Setjmp,  // <setjmp.h>
41    Signal,  // <signal.h>
42    Stdarg,  // <stdarg.h>
43    Stdbool, // <stdbool.h>
44    Stddef,  // <stddef.h>
45    Stdint,  // <stdint.h>
46    Stdio,   // <stdio.h>
47    Stdlib,  // <stdlib.h>
48    String,  // <string.h>
49    Time,    // <time.h>
50    // POSIX headers
51    Unistd,   // <unistd.h>
52    Fcntl,    // <fcntl.h>
53    Dirent,   // <dirent.h>
54    SysTypes, // <sys/types.h>
55    SysStat,  // <sys/stat.h>
56    SysMman,  // <sys/mman.h>
57    Wchar,    // <wchar.h>
58}
59
60impl StdHeader {
61    /// Parse header name from #include filename
62    ///
63    /// # Examples
64    /// ```
65    /// use decy_stdlib::StdHeader;
66    /// assert_eq!(StdHeader::from_filename("string.h"), Some(StdHeader::String));
67    /// assert_eq!(StdHeader::from_filename("stdio.h"), Some(StdHeader::Stdio));
68    /// assert_eq!(StdHeader::from_filename("unknown.h"), None);
69    /// ```
70    pub fn from_filename(filename: &str) -> Option<Self> {
71        match filename {
72            "assert.h" => Some(Self::Assert),
73            "ctype.h" => Some(Self::Ctype),
74            "errno.h" => Some(Self::Errno),
75            "float.h" => Some(Self::Float),
76            "limits.h" => Some(Self::Limits),
77            "locale.h" => Some(Self::Locale),
78            "math.h" => Some(Self::Math),
79            "setjmp.h" => Some(Self::Setjmp),
80            "signal.h" => Some(Self::Signal),
81            "stdarg.h" => Some(Self::Stdarg),
82            "stdbool.h" => Some(Self::Stdbool),
83            "stddef.h" => Some(Self::Stddef),
84            "stdint.h" => Some(Self::Stdint),
85            "stdio.h" => Some(Self::Stdio),
86            "stdlib.h" => Some(Self::Stdlib),
87            "string.h" => Some(Self::String),
88            "time.h" => Some(Self::Time),
89            // POSIX headers
90            "unistd.h" => Some(Self::Unistd),
91            "fcntl.h" => Some(Self::Fcntl),
92            "dirent.h" => Some(Self::Dirent),
93            "sys/types.h" => Some(Self::SysTypes),
94            "sys/stat.h" => Some(Self::SysStat),
95            "sys/mman.h" => Some(Self::SysMman),
96            "wchar.h" => Some(Self::Wchar),
97            _ => None,
98        }
99    }
100}
101
102/// Function parameter
103#[derive(Debug, Clone, PartialEq, Eq)]
104pub struct Parameter {
105    pub name: String,
106    pub type_str: String,
107}
108
109impl Parameter {
110    pub fn new(name: impl Into<String>, type_str: impl Into<String>) -> Self {
111        Self { name: name.into(), type_str: type_str.into() }
112    }
113}
114
115/// C Standard Library Function Prototype
116#[derive(Debug, Clone, PartialEq, Eq)]
117pub struct FunctionProto {
118    pub name: String,
119    pub return_type: String,
120    pub parameters: Vec<Parameter>,
121    pub is_variadic: bool,
122    pub header: StdHeader,
123    pub c99_section: String,
124}
125
126impl FunctionProto {
127    /// Convert to C function declaration
128    pub fn to_c_declaration(&self) -> String {
129        let params = if self.parameters.is_empty() {
130            "void".to_string()
131        } else {
132            let mut p = self
133                .parameters
134                .iter()
135                .map(|param| format!("{} {}", param.type_str, param.name))
136                .collect::<Vec<_>>()
137                .join(", ");
138
139            if self.is_variadic {
140                p.push_str(", ...");
141            }
142
143            p
144        };
145
146        format!("{} {}({});", self.return_type, self.name, params)
147    }
148}
149
150/// Built-in C Standard Library Prototype Database
151///
152/// Contains all 150+ functions from ISO C99 §7
153///
154/// # Examples
155///
156/// ```
157/// use decy_stdlib::StdlibPrototypes;
158/// let db = StdlibPrototypes::default();
159/// assert!(db.get_prototype("printf").is_some());
160/// ```
161pub struct StdlibPrototypes {
162    functions: HashMap<String, FunctionProto>,
163}
164
165impl StdlibPrototypes {
166    /// Create new prototype database with all C99 §7 functions.
167    ///
168    /// Initializes 150+ function prototypes across 8 standard library headers:
169    /// stdlib.h, stdio.h, string.h, ctype.h, time.h, math.h, unistd.h, dirent.h.
170    ///
171    /// # Examples
172    ///
173    /// ```
174    /// use decy_stdlib::StdlibPrototypes;
175    /// let protos = StdlibPrototypes::new();
176    /// assert!(protos.get_prototype("malloc").is_some());
177    /// assert!(protos.get_prototype("printf").is_some());
178    /// ```
179    pub fn new() -> Self {
180        Self::build_all_prototypes()
181    }
182
183    /// Build all C99 §7 prototypes (implementation detail).
184    fn build_all_prototypes() -> Self {
185        let mut functions = HashMap::new();
186        Self::init_stdlib(&mut functions);
187        Self::init_stdio(&mut functions);
188        Self::init_string(&mut functions);
189        Self::init_ctype(&mut functions);
190        Self::init_time(&mut functions);
191        Self::init_math(&mut functions);
192        Self::init_posix_unistd(&mut functions);
193        Self::init_posix_dirent(&mut functions);
194        Self { functions }
195    }
196
197    /// Get prototype for a stdlib function by name
198    pub fn get_prototype(&self, name: &str) -> Option<&FunctionProto> {
199        self.functions.get(name)
200    }
201
202    /// Inject prototypes for a specific header
203    ///
204    /// Only injects function declarations for the specified header.
205    /// This prevents parser overload from injecting all 55+ prototypes at once.
206    ///
207    /// # Examples
208    /// ```
209    /// use decy_stdlib::{StdlibPrototypes, StdHeader};
210    /// let stdlib = StdlibPrototypes::new();
211    /// let string_protos = stdlib.inject_prototypes_for_header(StdHeader::String);
212    /// assert!(string_protos.contains("strlen"));
213    /// assert!(!string_protos.contains("printf")); // stdio function, not string
214    /// ```
215    pub fn inject_prototypes_for_header(&self, header: StdHeader) -> String {
216        let mut result = String::new();
217
218        // Type definitions (always needed)
219        result.push_str(&format!("// Built-in prototypes for {:?} (ISO C99 §7)\n", header));
220        result.push_str("typedef unsigned long size_t;\n");
221        result.push_str("typedef long ssize_t;\n");
222        result.push_str("typedef long ptrdiff_t;\n");
223        // NULL macro (ISO C99 §7.17) - use simple 0 to avoid parser issues
224        result.push_str("#define NULL 0\n");
225
226        // Add header-specific type definitions
227        match header {
228            StdHeader::Stdio => {
229                result.push_str("struct _IO_FILE;\n");
230                result.push_str("typedef struct _IO_FILE FILE;\n");
231                // DECY-239: Add standard streams as extern declarations
232                result.push_str("extern FILE* stdin;\n");
233                result.push_str("extern FILE* stdout;\n");
234                result.push_str("extern FILE* stderr;\n");
235                // Common stdio macros
236                result.push_str("#define EOF (-1)\n");
237                result.push_str("#define SEEK_SET 0\n");
238                result.push_str("#define SEEK_CUR 1\n");
239                result.push_str("#define SEEK_END 2\n");
240                result.push_str("#define BUFSIZ 8192\n");
241                result.push_str("#define L_tmpnam 20\n");
242                result.push_str("#define _IONBF 2\n");
243                result.push_str("#define _IOLBF 1\n");
244                result.push_str("#define _IOFBF 0\n");
245            }
246            StdHeader::Errno => {
247                result.push_str("extern int errno;\n");
248                result.push_str("#define EACCES 13\n");
249                result.push_str("#define ENOENT 2\n");
250                result.push_str("#define EINVAL 22\n");
251                result.push_str("#define ENOMEM 12\n");
252                result.push_str("#define ERANGE 34\n");
253            }
254            StdHeader::Time => {
255                result.push_str("typedef long time_t;\n");
256                result.push_str("typedef long clock_t;\n");
257                result.push_str("struct tm;\n");
258                result.push_str("#define CLOCKS_PER_SEC 1000000\n");
259            }
260            StdHeader::Stdarg => {
261                // va_list is typically a pointer or array type
262                result.push_str("typedef void* va_list;\n");
263                result.push_str("#define va_start(ap, last) ((void)0)\n");
264                result.push_str("#define va_end(ap) ((void)0)\n");
265                result.push_str("#define va_arg(ap, type) (*(type*)0)\n");
266            }
267            StdHeader::Stdbool => {
268                result.push_str("typedef _Bool bool;\n");
269                result.push_str("#define true 1\n");
270                result.push_str("#define false 0\n");
271            }
272            StdHeader::Stdint => {
273                result.push_str("typedef signed char int8_t;\n");
274                result.push_str("typedef short int16_t;\n");
275                result.push_str("typedef int int32_t;\n");
276                result.push_str("typedef long long int64_t;\n");
277                result.push_str("typedef unsigned char uint8_t;\n");
278                result.push_str("typedef unsigned short uint16_t;\n");
279                result.push_str("typedef unsigned int uint32_t;\n");
280                result.push_str("typedef unsigned long long uint64_t;\n");
281                result.push_str("typedef long intptr_t;\n");
282                result.push_str("typedef unsigned long uintptr_t;\n");
283            }
284            StdHeader::Unistd => {
285                // POSIX types and file descriptor macros
286                result.push_str("typedef int pid_t;\n");
287                result.push_str("typedef long off_t;\n");
288                result.push_str("typedef unsigned int uid_t;\n");
289                result.push_str("typedef unsigned int gid_t;\n");
290                result.push_str("#define STDIN_FILENO 0\n");
291                result.push_str("#define STDOUT_FILENO 1\n");
292                result.push_str("#define STDERR_FILENO 2\n");
293                // Access mode flags
294                result.push_str("#define F_OK 0\n");
295                result.push_str("#define R_OK 4\n");
296                result.push_str("#define W_OK 2\n");
297                result.push_str("#define X_OK 1\n");
298                // sysconf names
299                result.push_str("#define _SC_OPEN_MAX 4\n");
300                result.push_str("#define _SC_PAGESIZE 30\n");
301            }
302            StdHeader::Fcntl => {
303                // File access mode flags
304                result.push_str("#define O_RDONLY 0\n");
305                result.push_str("#define O_WRONLY 1\n");
306                result.push_str("#define O_RDWR 2\n");
307                result.push_str("#define O_CREAT 0100\n");
308                result.push_str("#define O_TRUNC 01000\n");
309                result.push_str("#define O_APPEND 02000\n");
310                result.push_str("#define O_NONBLOCK 04000\n");
311                // File lock types (from flock)
312                result.push_str("#define LOCK_SH 1\n");
313                result.push_str("#define LOCK_EX 2\n");
314                result.push_str("#define LOCK_UN 8\n");
315            }
316            StdHeader::Dirent => {
317                result.push_str("struct dirent { char d_name[256]; };\n");
318                result.push_str("typedef struct __dirstream DIR;\n");
319            }
320            StdHeader::SysTypes => {
321                result.push_str("typedef int pid_t;\n");
322                result.push_str("typedef long off_t;\n");
323                result.push_str("typedef unsigned int mode_t;\n");
324                result.push_str("typedef long ssize_t;\n");
325            }
326            StdHeader::SysStat => {
327                result.push_str("struct stat { long st_size; int st_mode; };\n");
328                result.push_str("#define S_ISREG(m) (((m) & 0170000) == 0100000)\n");
329                result.push_str("#define S_ISDIR(m) (((m) & 0170000) == 0040000)\n");
330            }
331            StdHeader::SysMman => {
332                // Memory protection flags
333                result.push_str("#define PROT_NONE 0\n");
334                result.push_str("#define PROT_READ 1\n");
335                result.push_str("#define PROT_WRITE 2\n");
336                result.push_str("#define PROT_EXEC 4\n");
337                // Map flags
338                result.push_str("#define MAP_SHARED 1\n");
339                result.push_str("#define MAP_PRIVATE 2\n");
340                result.push_str("#define MAP_ANONYMOUS 0x20\n");
341                result.push_str("#define MAP_FAILED ((void*)-1)\n");
342            }
343            StdHeader::Wchar => {
344                result.push_str("typedef int wchar_t;\n");
345                result.push_str("typedef int wint_t;\n");
346                result.push_str("#define WEOF (-1)\n");
347            }
348            StdHeader::Signal => {
349                result.push_str("typedef void (*sighandler_t)(int);\n");
350                result.push_str("#define SIGINT 2\n");
351                result.push_str("#define SIGTERM 15\n");
352            }
353            StdHeader::Limits => {
354                result.push_str("#define CHAR_BIT 8\n");
355                result.push_str("#define CHAR_MIN (-128)\n");
356                result.push_str("#define CHAR_MAX 127\n");
357                result.push_str("#define SHRT_MIN (-32768)\n");
358                result.push_str("#define SHRT_MAX 32767\n");
359                result.push_str("#define INT_MIN (-2147483647-1)\n");
360                result.push_str("#define INT_MAX 2147483647\n");
361                result.push_str("#define UINT_MAX 4294967295U\n");
362                result.push_str("#define LONG_MIN (-9223372036854775807L-1)\n");
363                result.push_str("#define LONG_MAX 9223372036854775807L\n");
364                result.push_str("#define PATH_MAX 4096\n");
365            }
366            StdHeader::Ctype => {
367                // Character classification functions - ISO C99 §7.4
368                // All return non-zero if true, 0 if false
369            }
370            StdHeader::Math => {
371                // Math functions - ISO C99 §7.12
372                result.push_str("#define M_PI 3.14159265358979323846\n");
373                result.push_str("#define M_E 2.71828182845904523536\n");
374                result.push_str("#define INFINITY (1.0/0.0)\n");
375                result.push_str("#define NAN (0.0/0.0)\n");
376            }
377            _ => {}
378        }
379
380        result.push('\n');
381
382        // Filter functions by header and inject
383        // NOTE: Functions with function pointer parameters are currently skipped.
384        // Function pointer syntax like `int (*comp)(const void*, const void*)`
385        // needs special handling in to_c_declaration() - name goes inside (*name)
386        let mut protos: Vec<_> = self
387            .functions
388            .values()
389            .filter(|p| p.header == header)
390            .filter(|p| {
391                // Skip functions with function pointer parameters (contain "(*" in type)
392                !p.parameters.iter().any(|param| param.type_str.contains("(*"))
393            })
394            .collect();
395        protos.sort_by_key(|p| &p.name);
396
397        for proto in protos {
398            result.push_str(&proto.to_c_declaration());
399            result.push('\n');
400        }
401
402        result
403    }
404
405    /// Inject all stdlib prototypes as C declarations
406    ///
407    /// **Note**: Prefer `inject_prototypes_for_header()` to avoid parser overload.
408    /// This method injects ALL 55+ prototypes which may cause parsing issues.
409    pub fn inject_all_prototypes(&self) -> String {
410        let mut result = String::new();
411
412        // Type definitions (ISO C99 §7.17, §7.19, §7.21)
413        result.push_str("// Built-in stdlib prototypes (ISO C99 §7)\n");
414        result.push_str("typedef unsigned long size_t;\n");
415        result.push_str("typedef long ssize_t;\n");
416        result.push_str("typedef long ptrdiff_t;\n");
417        // NULL macro (ISO C99 §7.17) - use simple 0 to avoid parser issues
418        result.push_str("#define NULL 0\n");
419        result.push_str("struct _IO_FILE;\n");
420        result.push_str("typedef struct _IO_FILE FILE;\n");
421        // DECY-239: Standard streams
422        result.push_str("extern FILE* stdin;\n");
423        result.push_str("extern FILE* stdout;\n");
424        result.push_str("extern FILE* stderr;\n");
425        result.push_str("#define EOF (-1)\n");
426        result.push_str("#define SEEK_SET 0\n");
427        result.push_str("#define SEEK_CUR 1\n");
428        result.push_str("#define SEEK_END 2\n");
429        // Common POSIX types
430        result.push_str("typedef int pid_t;\n");
431        result.push_str("typedef long off_t;\n");
432        result.push_str("typedef long time_t;\n");
433        result.push_str("typedef long clock_t;\n");
434        result.push_str("typedef int wchar_t;\n");
435        result.push_str("extern int errno;\n");
436        // Common macros
437        result.push_str("#define CLOCKS_PER_SEC 1000000\n");
438        result.push_str("#define PATH_MAX 4096\n");
439        result.push('\n');
440
441        // Inject function prototypes
442        let mut protos: Vec<_> = self.functions.values().collect();
443        protos.sort_by_key(|p| &p.name);
444
445        for proto in protos {
446            result.push_str(&proto.to_c_declaration());
447            result.push('\n');
448        }
449
450        result
451    }
452
453    /// Get number of functions in database
454    pub fn len(&self) -> usize {
455        self.functions.len()
456    }
457
458    /// Check if database is empty
459    pub fn is_empty(&self) -> bool {
460        self.functions.is_empty()
461    }
462}
463
464impl Default for StdlibPrototypes {
465    fn default() -> Self {
466        Self::new()
467    }
468}
469
470#[cfg(test)]
471#[path = "inject_prototype_tests.rs"]
472mod inject_prototype_tests;
473
474#[cfg(test)]
475mod tests {
476    use super::*;
477
478    #[test]
479    fn test_function_proto_to_c_declaration() {
480        let proto = FunctionProto {
481            name: "malloc".to_string(),
482            return_type: "void*".to_string(),
483            parameters: vec![Parameter::new("size", "size_t")],
484            is_variadic: false,
485            header: StdHeader::Stdlib,
486            c99_section: "§7.22.3.4".to_string(),
487        };
488
489        assert_eq!(proto.to_c_declaration(), "void* malloc(size_t size);");
490    }
491
492    #[test]
493    fn test_variadic_function_proto() {
494        let proto = FunctionProto {
495            name: "printf".to_string(),
496            return_type: "int".to_string(),
497            parameters: vec![Parameter::new("format", "const char*")],
498            is_variadic: true,
499            header: StdHeader::Stdio,
500            c99_section: "§7.21.6.1".to_string(),
501        };
502
503        assert_eq!(proto.to_c_declaration(), "int printf(const char* format, ...);");
504    }
505
506    #[test]
507    fn test_no_param_function_proto() {
508        let proto = FunctionProto {
509            name: "rand".to_string(),
510            return_type: "int".to_string(),
511            parameters: vec![],
512            is_variadic: false,
513            header: StdHeader::Stdlib,
514            c99_section: "§7.22.2.1".to_string(),
515        };
516
517        assert_eq!(proto.to_c_declaration(), "int rand(void);");
518    }
519
520    // ========================================================================
521    // inject_prototypes_for_header: Common preamble tests
522    // ========================================================================
523
524    #[test]
525    fn test_inject_header_common_preamble_present_for_all_headers() {
526        let stdlib = StdlibPrototypes::new();
527        let headers = [
528            StdHeader::Stdio,
529            StdHeader::Errno,
530            StdHeader::Time,
531            StdHeader::Stdarg,
532            StdHeader::Stdbool,
533            StdHeader::Stdint,
534            StdHeader::Unistd,
535            StdHeader::Fcntl,
536            StdHeader::Dirent,
537            StdHeader::SysTypes,
538            StdHeader::SysStat,
539            StdHeader::SysMman,
540            StdHeader::Wchar,
541            StdHeader::Signal,
542            StdHeader::Limits,
543            StdHeader::Ctype,
544            StdHeader::Math,
545            StdHeader::Assert,
546            StdHeader::Float,
547            StdHeader::Locale,
548            StdHeader::Setjmp,
549            StdHeader::Stddef,
550            StdHeader::Stdlib,
551            StdHeader::String,
552        ];
553        for header in &headers {
554            let result = stdlib.inject_prototypes_for_header(*header);
555            assert!(
556                result.contains("typedef unsigned long size_t;"),
557                "{:?} missing size_t",
558                header
559            );
560            assert!(result.contains("typedef long ssize_t;"), "{:?} missing ssize_t", header);
561            assert!(result.contains("typedef long ptrdiff_t;"), "{:?} missing ptrdiff_t", header);
562            assert!(result.contains("#define NULL 0"), "{:?} missing NULL", header);
563            assert!(
564                result.contains("// Built-in prototypes for"),
565                "{:?} missing comment header",
566                header
567            );
568        }
569    }
570
571    // ========================================================================
572    // inject_prototypes_for_header: Stdio
573    // ========================================================================
574
575    #[test]
576    fn test_inject_header_stdio_type_definitions() {
577        let stdlib = StdlibPrototypes::new();
578        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdio);
579        assert!(result.contains("struct _IO_FILE;"));
580        assert!(result.contains("typedef struct _IO_FILE FILE;"));
581        assert!(result.contains("extern FILE* stdin;"));
582        assert!(result.contains("extern FILE* stdout;"));
583        assert!(result.contains("extern FILE* stderr;"));
584    }
585
586    #[test]
587    fn test_inject_header_stdio_macros() {
588        let stdlib = StdlibPrototypes::new();
589        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdio);
590        assert!(result.contains("#define EOF (-1)"));
591        assert!(result.contains("#define SEEK_SET 0"));
592        assert!(result.contains("#define SEEK_CUR 1"));
593        assert!(result.contains("#define SEEK_END 2"));
594        assert!(result.contains("#define BUFSIZ 8192"));
595        assert!(result.contains("#define L_tmpnam 20"));
596        assert!(result.contains("#define _IONBF 2"));
597        assert!(result.contains("#define _IOLBF 1"));
598        assert!(result.contains("#define _IOFBF 0"));
599    }
600
601    #[test]
602    fn test_inject_header_stdio_functions() {
603        let stdlib = StdlibPrototypes::new();
604        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdio);
605        // Formatted output
606        assert!(result.contains("int printf(const char* format, ...);"));
607        assert!(result.contains("int fprintf(FILE* stream, const char* format, ...);"));
608        assert!(result.contains("int sprintf(char* str, const char* format, ...);"));
609        assert!(result.contains("int snprintf(char* str, size_t size, const char* format, ...);"));
610        // Formatted input
611        assert!(result.contains("int scanf(const char* format, ...);"));
612        assert!(result.contains("int fscanf(FILE* stream, const char* format, ...);"));
613        assert!(result.contains("int sscanf(const char* str, const char* format, ...);"));
614        // File operations
615        assert!(result.contains("FILE* fopen("));
616        assert!(result.contains("int fclose(FILE* stream);"));
617        assert!(result.contains("size_t fread("));
618        assert!(result.contains("size_t fwrite("));
619        assert!(result.contains("int fseek("));
620        assert!(result.contains("long ftell(FILE* stream);"));
621        assert!(result.contains("void rewind(FILE* stream);"));
622        // Character I/O
623        assert!(result.contains("int getchar(void);"));
624        assert!(result.contains("int putchar(int c);"));
625        assert!(result.contains("int fgetc(FILE* stream);"));
626        assert!(result.contains("int fputc(int c, FILE* stream);"));
627        assert!(result.contains("char* fgets("));
628        assert!(result.contains("int fputs("));
629        assert!(result.contains("int puts(const char* s);"));
630    }
631
632    #[test]
633    fn test_inject_header_stdio_does_not_contain_stdlib_functions() {
634        let stdlib = StdlibPrototypes::new();
635        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdio);
636        // malloc is in stdlib, not stdio
637        assert!(!result.contains("void* malloc("));
638        assert!(!result.contains("void free("));
639    }
640
641    // ========================================================================
642    // inject_prototypes_for_header: Errno
643    // ========================================================================
644
645    #[test]
646    fn test_inject_header_errno_definitions() {
647        let stdlib = StdlibPrototypes::new();
648        let result = stdlib.inject_prototypes_for_header(StdHeader::Errno);
649        assert!(result.contains("extern int errno;"));
650        assert!(result.contains("#define EACCES 13"));
651        assert!(result.contains("#define ENOENT 2"));
652        assert!(result.contains("#define EINVAL 22"));
653        assert!(result.contains("#define ENOMEM 12"));
654        assert!(result.contains("#define ERANGE 34"));
655    }
656
657    #[test]
658    fn test_inject_header_errno_no_functions() {
659        let stdlib = StdlibPrototypes::new();
660        let result = stdlib.inject_prototypes_for_header(StdHeader::Errno);
661        // Errno header has no registered functions, only macros/declarations
662        assert!(!result.contains("int printf("));
663        assert!(!result.contains("void* malloc("));
664    }
665
666    // ========================================================================
667    // inject_prototypes_for_header: Time
668    // ========================================================================
669
670    #[test]
671    fn test_inject_header_time_type_definitions() {
672        let stdlib = StdlibPrototypes::new();
673        let result = stdlib.inject_prototypes_for_header(StdHeader::Time);
674        assert!(result.contains("typedef long time_t;"));
675        assert!(result.contains("typedef long clock_t;"));
676        assert!(result.contains("struct tm;"));
677        assert!(result.contains("#define CLOCKS_PER_SEC 1000000"));
678    }
679
680    #[test]
681    fn test_inject_header_time_functions() {
682        let stdlib = StdlibPrototypes::new();
683        let result = stdlib.inject_prototypes_for_header(StdHeader::Time);
684        assert!(result.contains("clock_t clock(void);"));
685        assert!(result.contains("time_t time(time_t* timer);"));
686    }
687
688    // ========================================================================
689    // inject_prototypes_for_header: Stdarg
690    // ========================================================================
691
692    #[test]
693    fn test_inject_header_stdarg_definitions() {
694        let stdlib = StdlibPrototypes::new();
695        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdarg);
696        assert!(result.contains("typedef void* va_list;"));
697        assert!(result.contains("#define va_start(ap, last) ((void)0)"));
698        assert!(result.contains("#define va_end(ap) ((void)0)"));
699        assert!(result.contains("#define va_arg(ap, type) (*(type*)0)"));
700    }
701
702    // ========================================================================
703    // inject_prototypes_for_header: Stdbool
704    // ========================================================================
705
706    #[test]
707    fn test_inject_header_stdbool_definitions() {
708        let stdlib = StdlibPrototypes::new();
709        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdbool);
710        assert!(result.contains("typedef _Bool bool;"));
711        assert!(result.contains("#define true 1"));
712        assert!(result.contains("#define false 0"));
713    }
714
715    // ========================================================================
716    // inject_prototypes_for_header: Stdint
717    // ========================================================================
718
719    #[test]
720    fn test_inject_header_stdint_type_definitions() {
721        let stdlib = StdlibPrototypes::new();
722        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdint);
723        assert!(result.contains("typedef signed char int8_t;"));
724        assert!(result.contains("typedef short int16_t;"));
725        assert!(result.contains("typedef int int32_t;"));
726        assert!(result.contains("typedef long long int64_t;"));
727        assert!(result.contains("typedef unsigned char uint8_t;"));
728        assert!(result.contains("typedef unsigned short uint16_t;"));
729        assert!(result.contains("typedef unsigned int uint32_t;"));
730        assert!(result.contains("typedef unsigned long long uint64_t;"));
731        assert!(result.contains("typedef long intptr_t;"));
732        assert!(result.contains("typedef unsigned long uintptr_t;"));
733    }
734
735    // ========================================================================
736    // inject_prototypes_for_header: Unistd
737    // ========================================================================
738
739    #[test]
740    fn test_inject_header_unistd_type_definitions() {
741        let stdlib = StdlibPrototypes::new();
742        let result = stdlib.inject_prototypes_for_header(StdHeader::Unistd);
743        assert!(result.contains("typedef int pid_t;"));
744        assert!(result.contains("typedef long off_t;"));
745        assert!(result.contains("typedef unsigned int uid_t;"));
746        assert!(result.contains("typedef unsigned int gid_t;"));
747    }
748
749    #[test]
750    fn test_inject_header_unistd_macros() {
751        let stdlib = StdlibPrototypes::new();
752        let result = stdlib.inject_prototypes_for_header(StdHeader::Unistd);
753        assert!(result.contains("#define STDIN_FILENO 0"));
754        assert!(result.contains("#define STDOUT_FILENO 1"));
755        assert!(result.contains("#define STDERR_FILENO 2"));
756        assert!(result.contains("#define F_OK 0"));
757        assert!(result.contains("#define R_OK 4"));
758        assert!(result.contains("#define W_OK 2"));
759        assert!(result.contains("#define X_OK 1"));
760        assert!(result.contains("#define _SC_OPEN_MAX 4"));
761        assert!(result.contains("#define _SC_PAGESIZE 30"));
762    }
763
764    #[test]
765    fn test_inject_header_unistd_functions() {
766        let stdlib = StdlibPrototypes::new();
767        let result = stdlib.inject_prototypes_for_header(StdHeader::Unistd);
768        assert!(result.contains("int pipe(int* pipefd);"));
769        assert!(result.contains("pid_t fork(void);"));
770        assert!(result.contains("ssize_t read(int fd, void* buf, size_t count);"));
771        assert!(result.contains("ssize_t write(int fd, const void* buf, size_t count);"));
772        assert!(result.contains("int close(int fd);"));
773        assert!(result.contains("off_t lseek(int fd, off_t offset, int whence);"));
774        assert!(result.contains("int dup(int oldfd);"));
775        assert!(result.contains("int dup2(int oldfd, int newfd);"));
776    }
777
778    // ========================================================================
779    // inject_prototypes_for_header: Fcntl
780    // ========================================================================
781
782    #[test]
783    fn test_inject_header_fcntl_macros() {
784        let stdlib = StdlibPrototypes::new();
785        let result = stdlib.inject_prototypes_for_header(StdHeader::Fcntl);
786        assert!(result.contains("#define O_RDONLY 0"));
787        assert!(result.contains("#define O_WRONLY 1"));
788        assert!(result.contains("#define O_RDWR 2"));
789        assert!(result.contains("#define O_CREAT 0100"));
790        assert!(result.contains("#define O_TRUNC 01000"));
791        assert!(result.contains("#define O_APPEND 02000"));
792        assert!(result.contains("#define O_NONBLOCK 04000"));
793        assert!(result.contains("#define LOCK_SH 1"));
794        assert!(result.contains("#define LOCK_EX 2"));
795        assert!(result.contains("#define LOCK_UN 8"));
796    }
797
798    #[test]
799    fn test_inject_header_fcntl_functions() {
800        let stdlib = StdlibPrototypes::new();
801        let result = stdlib.inject_prototypes_for_header(StdHeader::Fcntl);
802        assert!(result.contains("int open(const char* pathname, int flags, ...);"));
803    }
804
805    // ========================================================================
806    // inject_prototypes_for_header: Dirent
807    // ========================================================================
808
809    #[test]
810    fn test_inject_header_dirent_type_definitions() {
811        let stdlib = StdlibPrototypes::new();
812        let result = stdlib.inject_prototypes_for_header(StdHeader::Dirent);
813        assert!(result.contains("struct dirent { char d_name[256]; };"));
814        assert!(result.contains("typedef struct __dirstream DIR;"));
815    }
816
817    #[test]
818    fn test_inject_header_dirent_functions() {
819        let stdlib = StdlibPrototypes::new();
820        let result = stdlib.inject_prototypes_for_header(StdHeader::Dirent);
821        assert!(result.contains("DIR* opendir(const char* name);"));
822        assert!(result.contains("struct dirent* readdir(DIR* dirp);"));
823        assert!(result.contains("int closedir(DIR* dirp);"));
824    }
825
826    // ========================================================================
827    // inject_prototypes_for_header: SysTypes
828    // ========================================================================
829
830    #[test]
831    fn test_inject_header_sys_types_definitions() {
832        let stdlib = StdlibPrototypes::new();
833        let result = stdlib.inject_prototypes_for_header(StdHeader::SysTypes);
834        assert!(result.contains("typedef int pid_t;"));
835        assert!(result.contains("typedef long off_t;"));
836        assert!(result.contains("typedef unsigned int mode_t;"));
837        assert!(result.contains("typedef long ssize_t;"));
838    }
839
840    // ========================================================================
841    // inject_prototypes_for_header: SysStat
842    // ========================================================================
843
844    #[test]
845    fn test_inject_header_sys_stat_definitions() {
846        let stdlib = StdlibPrototypes::new();
847        let result = stdlib.inject_prototypes_for_header(StdHeader::SysStat);
848        assert!(result.contains("struct stat { long st_size; int st_mode; };"));
849        assert!(result.contains("#define S_ISREG(m)"));
850        assert!(result.contains("#define S_ISDIR(m)"));
851    }
852
853    // ========================================================================
854    // inject_prototypes_for_header: SysMman
855    // ========================================================================
856
857    #[test]
858    fn test_inject_header_sys_mman_macros() {
859        let stdlib = StdlibPrototypes::new();
860        let result = stdlib.inject_prototypes_for_header(StdHeader::SysMman);
861        assert!(result.contains("#define PROT_NONE 0"));
862        assert!(result.contains("#define PROT_READ 1"));
863        assert!(result.contains("#define PROT_WRITE 2"));
864        assert!(result.contains("#define PROT_EXEC 4"));
865        assert!(result.contains("#define MAP_SHARED 1"));
866        assert!(result.contains("#define MAP_PRIVATE 2"));
867        assert!(result.contains("#define MAP_ANONYMOUS 0x20"));
868        assert!(result.contains("#define MAP_FAILED ((void*)-1)"));
869    }
870
871    // ========================================================================
872    // inject_prototypes_for_header: Wchar
873    // ========================================================================
874
875    #[test]
876    fn test_inject_header_wchar_definitions() {
877        let stdlib = StdlibPrototypes::new();
878        let result = stdlib.inject_prototypes_for_header(StdHeader::Wchar);
879        assert!(result.contains("typedef int wchar_t;"));
880        assert!(result.contains("typedef int wint_t;"));
881        assert!(result.contains("#define WEOF (-1)"));
882    }
883
884    // ========================================================================
885    // inject_prototypes_for_header: Signal
886    // ========================================================================
887
888    #[test]
889    fn test_inject_header_signal_definitions() {
890        let stdlib = StdlibPrototypes::new();
891        let result = stdlib.inject_prototypes_for_header(StdHeader::Signal);
892        assert!(result.contains("typedef void (*sighandler_t)(int);"));
893        assert!(result.contains("#define SIGINT 2"));
894        assert!(result.contains("#define SIGTERM 15"));
895    }
896
897    // ========================================================================
898    // inject_prototypes_for_header: Limits
899    // ========================================================================
900
901    #[test]
902    fn test_inject_header_limits_macros() {
903        let stdlib = StdlibPrototypes::new();
904        let result = stdlib.inject_prototypes_for_header(StdHeader::Limits);
905        assert!(result.contains("#define CHAR_BIT 8"));
906        assert!(result.contains("#define CHAR_MIN (-128)"));
907        assert!(result.contains("#define CHAR_MAX 127"));
908        assert!(result.contains("#define SHRT_MIN (-32768)"));
909        assert!(result.contains("#define SHRT_MAX 32767"));
910        assert!(result.contains("#define INT_MIN (-2147483647-1)"));
911        assert!(result.contains("#define INT_MAX 2147483647"));
912        assert!(result.contains("#define UINT_MAX 4294967295U"));
913        assert!(result.contains("#define LONG_MIN (-9223372036854775807L-1)"));
914        assert!(result.contains("#define LONG_MAX 9223372036854775807L"));
915        assert!(result.contains("#define PATH_MAX 4096"));
916    }
917
918    // ========================================================================
919    // inject_prototypes_for_header: Ctype
920    // ========================================================================
921
922    #[test]
923    fn test_inject_header_ctype_functions() {
924        let stdlib = StdlibPrototypes::new();
925        let result = stdlib.inject_prototypes_for_header(StdHeader::Ctype);
926        assert!(result.contains("int isspace(int c);"));
927        assert!(result.contains("int isdigit(int c);"));
928        assert!(result.contains("int isalpha(int c);"));
929        assert!(result.contains("int isalnum(int c);"));
930        assert!(result.contains("int isupper(int c);"));
931        assert!(result.contains("int islower(int c);"));
932        assert!(result.contains("int tolower(int c);"));
933        assert!(result.contains("int toupper(int c);"));
934    }
935
936    #[test]
937    fn test_inject_header_ctype_no_extra_type_defs() {
938        let stdlib = StdlibPrototypes::new();
939        let result = stdlib.inject_prototypes_for_header(StdHeader::Ctype);
940        // Ctype has no header-specific type definitions beyond the common preamble
941        assert!(!result.contains("typedef struct _IO_FILE FILE;"));
942        assert!(!result.contains("typedef long time_t;"));
943    }
944
945    // ========================================================================
946    // inject_prototypes_for_header: Math
947    // ========================================================================
948
949    #[test]
950    fn test_inject_header_math_macros() {
951        let stdlib = StdlibPrototypes::new();
952        let result = stdlib.inject_prototypes_for_header(StdHeader::Math);
953        assert!(result.contains("#define M_PI 3.14159265358979323846"));
954        assert!(result.contains("#define M_E 2.71828182845904523536"));
955        assert!(result.contains("#define INFINITY (1.0/0.0)"));
956        assert!(result.contains("#define NAN (0.0/0.0)"));
957    }
958
959    #[test]
960    fn test_inject_header_math_trig_functions() {
961        let stdlib = StdlibPrototypes::new();
962        let result = stdlib.inject_prototypes_for_header(StdHeader::Math);
963        assert!(result.contains("double sin(double x);"));
964        assert!(result.contains("double cos(double x);"));
965        assert!(result.contains("double tan(double x);"));
966        assert!(result.contains("double asin(double x);"));
967        assert!(result.contains("double acos(double x);"));
968        assert!(result.contains("double atan(double x);"));
969        assert!(result.contains("double atan2(double y, double x);"));
970    }
971
972    #[test]
973    fn test_inject_header_math_power_and_log_functions() {
974        let stdlib = StdlibPrototypes::new();
975        let result = stdlib.inject_prototypes_for_header(StdHeader::Math);
976        assert!(result.contains("double sqrt(double x);"));
977        assert!(result.contains("double pow(double x, double y);"));
978        assert!(result.contains("double exp(double x);"));
979        assert!(result.contains("double log(double x);"));
980        assert!(result.contains("double log10(double x);"));
981    }
982
983    #[test]
984    fn test_inject_header_math_rounding_functions() {
985        let stdlib = StdlibPrototypes::new();
986        let result = stdlib.inject_prototypes_for_header(StdHeader::Math);
987        assert!(result.contains("double fabs(double x);"));
988        assert!(result.contains("double ceil(double x);"));
989        assert!(result.contains("double floor(double x);"));
990        assert!(result.contains("double round(double x);"));
991        assert!(result.contains("double trunc(double x);"));
992        assert!(result.contains("double fmod(double x, double y);"));
993    }
994
995    // ========================================================================
996    // inject_prototypes_for_header: Assert (wildcard arm)
997    // ========================================================================
998
999    #[test]
1000    fn test_inject_header_assert_has_common_preamble() {
1001        let stdlib = StdlibPrototypes::new();
1002        let result = stdlib.inject_prototypes_for_header(StdHeader::Assert);
1003        // Assert falls through to wildcard - only common preamble
1004        assert!(result.contains("// Built-in prototypes for Assert"));
1005        assert!(result.contains("typedef unsigned long size_t;"));
1006        assert!(result.contains("#define NULL 0"));
1007    }
1008
1009    #[test]
1010    fn test_inject_header_assert_no_header_specific_types() {
1011        let stdlib = StdlibPrototypes::new();
1012        let result = stdlib.inject_prototypes_for_header(StdHeader::Assert);
1013        // No functions are registered under Assert header
1014        assert!(!result.contains("typedef struct _IO_FILE FILE;"));
1015        assert!(!result.contains("typedef long time_t;"));
1016        assert!(!result.contains("extern int errno;"));
1017    }
1018
1019    // ========================================================================
1020    // inject_prototypes_for_header: Float (wildcard arm)
1021    // ========================================================================
1022
1023    #[test]
1024    fn test_inject_header_float_has_common_preamble() {
1025        let stdlib = StdlibPrototypes::new();
1026        let result = stdlib.inject_prototypes_for_header(StdHeader::Float);
1027        assert!(result.contains("// Built-in prototypes for Float"));
1028        assert!(result.contains("typedef unsigned long size_t;"));
1029        assert!(result.contains("#define NULL 0"));
1030    }
1031
1032    #[test]
1033    fn test_inject_header_float_no_functions() {
1034        let stdlib = StdlibPrototypes::new();
1035        let result = stdlib.inject_prototypes_for_header(StdHeader::Float);
1036        // No functions registered under Float header
1037        assert!(!result.contains("double sin("));
1038        assert!(!result.contains("int printf("));
1039    }
1040
1041    // ========================================================================
1042    // inject_prototypes_for_header: Locale (wildcard arm)
1043    // ========================================================================
1044
1045    #[test]
1046    fn test_inject_header_locale_has_common_preamble() {
1047        let stdlib = StdlibPrototypes::new();
1048        let result = stdlib.inject_prototypes_for_header(StdHeader::Locale);
1049        assert!(result.contains("// Built-in prototypes for Locale"));
1050        assert!(result.contains("typedef unsigned long size_t;"));
1051    }
1052
1053    // ========================================================================
1054    // inject_prototypes_for_header: Setjmp (wildcard arm)
1055    // ========================================================================
1056
1057    #[test]
1058    fn test_inject_header_setjmp_has_common_preamble() {
1059        let stdlib = StdlibPrototypes::new();
1060        let result = stdlib.inject_prototypes_for_header(StdHeader::Setjmp);
1061        assert!(result.contains("// Built-in prototypes for Setjmp"));
1062        assert!(result.contains("typedef unsigned long size_t;"));
1063    }
1064
1065    // ========================================================================
1066    // inject_prototypes_for_header: Stddef (wildcard arm)
1067    // ========================================================================
1068
1069    #[test]
1070    fn test_inject_header_stddef_has_common_preamble() {
1071        let stdlib = StdlibPrototypes::new();
1072        let result = stdlib.inject_prototypes_for_header(StdHeader::Stddef);
1073        assert!(result.contains("// Built-in prototypes for Stddef"));
1074        assert!(result.contains("typedef unsigned long size_t;"));
1075        assert!(result.contains("typedef long ptrdiff_t;"));
1076    }
1077
1078    // ========================================================================
1079    // inject_prototypes_for_header: Stdlib
1080    // ========================================================================
1081
1082    #[test]
1083    fn test_inject_header_stdlib_memory_functions() {
1084        let stdlib = StdlibPrototypes::new();
1085        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1086        assert!(result.contains("void* malloc(size_t size);"));
1087        assert!(result.contains("void* calloc(size_t nmemb, size_t size);"));
1088        assert!(result.contains("void* realloc(void* ptr, size_t size);"));
1089        assert!(result.contains("void free(void* ptr);"));
1090    }
1091
1092    #[test]
1093    fn test_inject_header_stdlib_conversion_functions() {
1094        let stdlib = StdlibPrototypes::new();
1095        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1096        assert!(result.contains("int atoi(const char* nptr);"));
1097        assert!(result.contains("long atol(const char* nptr);"));
1098        assert!(result.contains("double atof(const char* nptr);"));
1099        assert!(result.contains("long strtol(const char* nptr, char** endptr, int base);"));
1100        assert!(result.contains("double strtod(const char* nptr, char** endptr);"));
1101    }
1102
1103    #[test]
1104    fn test_inject_header_stdlib_process_functions() {
1105        let stdlib = StdlibPrototypes::new();
1106        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1107        assert!(result.contains("void exit(int status);"));
1108        assert!(result.contains("void abort(void);"));
1109        assert!(result.contains("char* getenv(const char* name);"));
1110        assert!(result.contains("int system(const char* command);"));
1111    }
1112
1113    #[test]
1114    fn test_inject_header_stdlib_random_functions() {
1115        let stdlib = StdlibPrototypes::new();
1116        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1117        assert!(result.contains("int rand(void);"));
1118        assert!(result.contains("void srand(unsigned int seed);"));
1119    }
1120
1121    #[test]
1122    fn test_inject_header_stdlib_arithmetic_functions() {
1123        let stdlib = StdlibPrototypes::new();
1124        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1125        assert!(result.contains("int abs(int j);"));
1126        assert!(result.contains("long labs(long j);"));
1127    }
1128
1129    #[test]
1130    fn test_inject_header_stdlib_skips_function_pointer_params() {
1131        let stdlib = StdlibPrototypes::new();
1132        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1133        // qsort and bsearch have function pointer parameters and should be skipped
1134        assert!(
1135            !result.contains("void qsort("),
1136            "qsort with function pointer param should be filtered out"
1137        );
1138        assert!(
1139            !result.contains("void* bsearch("),
1140            "bsearch with function pointer param should be filtered out"
1141        );
1142    }
1143
1144    #[test]
1145    fn test_inject_header_stdlib_does_not_contain_stdio_functions() {
1146        let stdlib = StdlibPrototypes::new();
1147        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1148        assert!(!result.contains("int printf("));
1149        assert!(!result.contains("FILE* fopen("));
1150    }
1151
1152    // ========================================================================
1153    // inject_prototypes_for_header: String
1154    // ========================================================================
1155
1156    #[test]
1157    fn test_inject_header_string_copy_functions() {
1158        let stdlib = StdlibPrototypes::new();
1159        let result = stdlib.inject_prototypes_for_header(StdHeader::String);
1160        assert!(result.contains("void* memcpy(void* dest, const void* src, size_t n);"));
1161        assert!(result.contains("void* memmove(void* dest, const void* src, size_t n);"));
1162        assert!(result.contains("char* strcpy(char* dest, const char* src);"));
1163        assert!(result.contains("char* strncpy(char* dest, const char* src, size_t n);"));
1164    }
1165
1166    #[test]
1167    fn test_inject_header_string_concat_functions() {
1168        let stdlib = StdlibPrototypes::new();
1169        let result = stdlib.inject_prototypes_for_header(StdHeader::String);
1170        assert!(result.contains("char* strcat(char* dest, const char* src);"));
1171        assert!(result.contains("char* strncat(char* dest, const char* src, size_t n);"));
1172    }
1173
1174    #[test]
1175    fn test_inject_header_string_comparison_functions() {
1176        let stdlib = StdlibPrototypes::new();
1177        let result = stdlib.inject_prototypes_for_header(StdHeader::String);
1178        assert!(result.contains("int memcmp(const void* s1, const void* s2, size_t n);"));
1179        assert!(result.contains("int strcmp(const char* s1, const char* s2);"));
1180        assert!(result.contains("int strncmp(const char* s1, const char* s2, size_t n);"));
1181    }
1182
1183    #[test]
1184    fn test_inject_header_string_search_functions() {
1185        let stdlib = StdlibPrototypes::new();
1186        let result = stdlib.inject_prototypes_for_header(StdHeader::String);
1187        assert!(result.contains("void* memchr(const void* s, int c, size_t n);"));
1188        assert!(result.contains("char* strchr(const char* s, int c);"));
1189        assert!(result.contains("char* strrchr(const char* s, int c);"));
1190        assert!(result.contains("char* strstr(const char* haystack, const char* needle);"));
1191        assert!(result.contains("char* strtok(char* str, const char* delim);"));
1192    }
1193
1194    #[test]
1195    fn test_inject_header_string_misc_functions() {
1196        let stdlib = StdlibPrototypes::new();
1197        let result = stdlib.inject_prototypes_for_header(StdHeader::String);
1198        assert!(result.contains("void* memset(void* s, int c, size_t n);"));
1199        assert!(result.contains("size_t strlen(const char* s);"));
1200        assert!(result.contains("char* strdup(const char* s);"));
1201    }
1202
1203    #[test]
1204    fn test_inject_header_string_does_not_contain_math() {
1205        let stdlib = StdlibPrototypes::new();
1206        let result = stdlib.inject_prototypes_for_header(StdHeader::String);
1207        assert!(!result.contains("double sin("));
1208        assert!(!result.contains("#define M_PI"));
1209    }
1210
1211    // ========================================================================
1212    // inject_prototypes_for_header: Cross-header isolation tests
1213    // ========================================================================
1214
1215    #[test]
1216    fn test_inject_header_isolation_no_cross_contamination() {
1217        let stdlib = StdlibPrototypes::new();
1218
1219        // Each header only gets its own functions
1220        let stdio_result = stdlib.inject_prototypes_for_header(StdHeader::Stdio);
1221        let string_result = stdlib.inject_prototypes_for_header(StdHeader::String);
1222        let math_result = stdlib.inject_prototypes_for_header(StdHeader::Math);
1223        let ctype_result = stdlib.inject_prototypes_for_header(StdHeader::Ctype);
1224
1225        // stdio should not have string functions
1226        assert!(!stdio_result.contains("size_t strlen("));
1227        assert!(!stdio_result.contains("void* memcpy("));
1228
1229        // string should not have stdio functions
1230        assert!(!string_result.contains("int printf("));
1231        assert!(!string_result.contains("FILE* fopen("));
1232
1233        // math should not have ctype functions
1234        assert!(!math_result.contains("int isspace("));
1235        assert!(!math_result.contains("int toupper("));
1236
1237        // ctype should not have math functions
1238        assert!(!ctype_result.contains("double sqrt("));
1239        assert!(!ctype_result.contains("#define M_PI"));
1240    }
1241
1242    #[test]
1243    fn test_inject_header_functions_are_sorted_alphabetically() {
1244        let stdlib = StdlibPrototypes::new();
1245        let result = stdlib.inject_prototypes_for_header(StdHeader::String);
1246
1247        // Functions should appear in alphabetical order
1248        let memchr_pos = result.find("void* memchr(").unwrap();
1249        let memcmp_pos = result.find("int memcmp(").unwrap();
1250        let memcpy_pos = result.find("void* memcpy(").unwrap();
1251        let strlen_pos = result.find("size_t strlen(").unwrap();
1252        let strstr_pos = result.find("char* strstr(").unwrap();
1253
1254        assert!(memchr_pos < memcmp_pos);
1255        assert!(memcmp_pos < memcpy_pos);
1256        assert!(memcpy_pos < strlen_pos);
1257        assert!(strlen_pos < strstr_pos);
1258    }
1259
1260    #[test]
1261    fn test_inject_header_comment_contains_header_name() {
1262        let stdlib = StdlibPrototypes::new();
1263
1264        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdio);
1265        assert!(result.contains("// Built-in prototypes for Stdio"));
1266
1267        let result = stdlib.inject_prototypes_for_header(StdHeader::Math);
1268        assert!(result.contains("// Built-in prototypes for Math"));
1269
1270        let result = stdlib.inject_prototypes_for_header(StdHeader::SysMman);
1271        assert!(result.contains("// Built-in prototypes for SysMman"));
1272    }
1273
1274    #[test]
1275    fn test_inject_header_result_ends_with_declarations() {
1276        let stdlib = StdlibPrototypes::new();
1277        // Verify that function declarations end with semicolons and newlines
1278        let result = stdlib.inject_prototypes_for_header(StdHeader::Stdlib);
1279        // All function lines should end with ";\n"
1280        for line in result.lines() {
1281            if line.contains('(')
1282                && line.contains(')')
1283                && !line.starts_with("//")
1284                && !line.starts_with("#")
1285                && !line.starts_with("typedef")
1286                && !line.starts_with("struct")
1287                && !line.starts_with("extern")
1288            {
1289                assert!(
1290                    line.ends_with(';'),
1291                    "Function declaration line should end with semicolon: {}",
1292                    line
1293                );
1294            }
1295        }
1296    }
1297}