1use super::types::{
6 AddrRange, AllocConfig, AllocStats, AtomicVersion, Budget, BuildInfo, BumpAlloc, ByteOrder,
7 CapabilitySet, CfgSnapshot, CodeSection, CompatLayer, CompatMatrix, CompatibilityReport,
8 CompileFlags, ConditionalInit, CounterCell, CrossPlatformTimer, ErrorCode, FeatureFlags,
9 InstructionBuffer, LibraryManifest, LinearScanAllocator, MemoryLayout, ObjectFile, OsResource,
10 PageMap, PlatformCaps, PlatformInfo, RelocEntry, RuntimeVersion, ScratchBuffer, ShimRegistry,
11 SpinFlag, StackGuard, StaticStr, StdCompat, SymbolTable, VersionConstraint, WasmFeatureSet,
12 WasmMemRegion, WasmMemTable,
13};
14
15#[macro_export]
20macro_rules! cfg_if_std {
21 (if_std { $($std_item:item)* } else { $($no_std_item:item)* }) => {
22 $($std_item)*
23 };
24}
25#[cfg(test)]
26mod tests {
27 use super::*;
28 #[test]
29 fn test_std_compat_alloc_types() {
30 let types = StdCompat::required_alloc_types();
31 assert!(types.contains(&"Vec"));
32 assert!(types.contains(&"HashMap"));
33 assert!(types.contains(&"Box"));
34 assert!(types.contains(&"String"));
35 }
36 #[test]
37 fn test_std_compat_required_features() {
38 let features = StdCompat::required_features();
39 assert!(features.contains(&"alloc"));
40 assert!(features.contains(&"core"));
41 }
42 #[test]
43 fn test_std_compat_wasm_limitations() {
44 let limitations = StdCompat::wasm_limitations();
45 assert!(limitations.contains(&"No file I/O"));
46 assert!(limitations.contains(&"No threads"));
47 assert!(limitations.contains(&"No env vars"));
48 }
49 #[test]
50 fn test_alloc_config_default() {
51 let cfg = AllocConfig::default();
52 assert!(cfg.use_global_allocator);
53 assert!(cfg.max_heap_bytes.is_none());
54 }
55 #[test]
56 fn test_alloc_config_for_wasm() {
57 let cfg = AllocConfig::for_wasm();
58 assert!(cfg.use_global_allocator);
59 assert_eq!(cfg.max_heap_bytes, Some(256 * 1024 * 1024));
60 let desc = cfg.describe();
61 assert!(desc.contains("256"));
62 }
63 #[test]
64 fn test_platform_info() {
65 assert!(!PlatformInfo::is_no_std());
66 let ps = PlatformInfo::pointer_size();
67 assert!(ps == 4 || ps == 8);
68 assert!(!PlatformInfo::platform_name().is_empty());
69 }
70 #[test]
71 fn test_wasm_feature_set() {
72 let mut set = WasmFeatureSet::new();
73 assert!(!set.has("bulk-memory"));
74 set.require("bulk-memory");
75 assert!(set.has("bulk-memory"));
76 set.require("bulk-memory");
77 assert_eq!(set.features.len(), 1);
78 let standard = WasmFeatureSet::standard_wasm_features();
79 assert!(standard.has("mutable-globals"));
80 assert!(standard.has("bulk-memory"));
81 assert!(standard.has("reference-types"));
82 }
83 #[test]
84 fn test_compatibility_report() {
85 let report = CompatibilityReport::generate();
86 assert!(!report.platform.is_empty());
87 assert!(report.std_available);
88 assert!(report.alloc_available);
89 if !PlatformInfo::is_wasm() {
90 assert!(report.is_compatible());
91 }
92 let summary = report.report_string();
93 assert!(summary.contains("Platform:"));
94 assert!(summary.contains("std available:"));
95 }
96}
97#[cfg(test)]
98mod tests_compat_ext {
99 use super::*;
100 #[test]
101 fn test_feature_flags() {
102 let _ = FeatureFlags::parallel_enabled();
103 let _ = FeatureFlags::serde_enabled();
104 let feats = FeatureFlags::known_features();
105 assert!(!feats.is_empty());
106 }
107 #[test]
108 fn test_conditional_init() {
109 let mut slot: ConditionalInit<u32> = ConditionalInit::uninit();
110 assert!(!slot.is_init());
111 slot.init(42);
112 assert!(slot.is_init());
113 assert_eq!(*slot.get(), 42);
114 }
115 #[test]
116 #[should_panic]
117 fn test_conditional_init_double_init() {
118 let mut slot: ConditionalInit<u32> = ConditionalInit::uninit();
119 slot.init(1);
120 slot.init(2);
121 }
122 #[test]
123 fn test_platform_caps() {
124 let caps = PlatformCaps::detect();
125 assert!(caps.heap);
126 }
127 #[test]
128 fn test_byte_order_round_trip() {
129 let val = 0xDEAD_BEEF_CAFE_BABEu64;
130 let le_bytes = ByteOrder::LittleEndian.u64_to_bytes(val);
131 let back = ByteOrder::LittleEndian.u64_from_bytes(le_bytes);
132 assert_eq!(back, val);
133 let be_bytes = ByteOrder::BigEndian.u64_to_bytes(val);
134 let back_be = ByteOrder::BigEndian.u64_from_bytes(be_bytes);
135 assert_eq!(back_be, val);
136 }
137 #[test]
138 fn test_static_str() {
139 let s = StaticStr::from_static("hello");
140 assert_eq!(s.as_str(), "hello");
141 assert!(!s.is_empty());
142 assert_eq!(s.len(), 5);
143 let owned = StaticStr::from_owned("world".to_string());
144 assert_eq!(owned.as_str(), "world");
145 assert_eq!(format!("{owned}"), "world");
146 }
147 #[test]
148 fn test_alloc_stats() {
149 let mut stats = AllocStats::new();
150 stats.record_alloc(100);
151 stats.record_alloc(200);
152 assert_eq!(stats.alloc_count, 2);
153 assert_eq!(stats.current_bytes, 300);
154 assert_eq!(stats.peak_bytes, 300);
155 stats.record_dealloc(100);
156 assert_eq!(stats.live_allocs(), 1);
157 assert_eq!(stats.current_bytes, 200);
158 }
159 #[test]
160 fn test_scratch_buffer() {
161 let mut buf = ScratchBuffer::with_capacity(64);
162 assert!(buf.capacity() >= 64);
163 {
164 let v = buf.fresh();
165 v.push(1);
166 v.push(2);
167 }
168 assert_eq!(buf.len(), 2);
169 buf.fresh();
170 assert_eq!(buf.len(), 0);
171 }
172 #[test]
173 fn test_spin_flag() {
174 let flag = SpinFlag::new(false);
175 assert!(!flag.get());
176 flag.set();
177 assert!(flag.get());
178 let old = flag.test_and_set();
179 assert!(old);
180 flag.clear();
181 assert!(!flag.get());
182 }
183 #[test]
184 fn test_counter_cell() {
185 let c = CounterCell::zero();
186 assert_eq!(c.get(), 0);
187 c.inc();
188 c.inc();
189 assert_eq!(c.get(), 2);
190 c.add(10);
191 assert_eq!(c.get(), 12);
192 c.reset();
193 assert_eq!(c.get(), 0);
194 }
195 #[test]
196 fn test_os_resource() {
197 let r = OsResource::FileDescriptor(3);
198 assert!(r.is_available());
199 assert_eq!(r.fd(), Some(3));
200 let u = OsResource::Unavailable;
201 assert!(!u.is_available());
202 assert_eq!(u.fd(), None);
203 }
204 #[test]
205 fn test_runtime_version() {
206 let v = RuntimeVersion::CURRENT;
207 let s = v.as_str();
208 assert!(s.starts_with('0'));
209 let other = RuntimeVersion {
210 major: 0,
211 minor: 99,
212 patch: 0,
213 pre: None,
214 };
215 assert!(v.is_compatible_with(&other));
216 let incompat = RuntimeVersion {
217 major: 1,
218 minor: 0,
219 patch: 0,
220 pre: None,
221 };
222 assert!(!v.is_compatible_with(&incompat));
223 }
224 #[test]
225 fn test_build_info() {
226 assert!(!BuildInfo::version().is_empty());
227 assert!(!BuildInfo::package_name().is_empty());
228 assert!(!BuildInfo::summary().is_empty());
229 }
230 #[test]
231 fn test_memory_layout() {
232 let _align = MemoryLayout::simd_alignment();
233 let _cl = MemoryLayout::cache_line_size();
234 let ncpus = MemoryLayout::num_cpus();
235 assert!(ncpus >= 1);
236 }
237 #[test]
238 fn test_compat_layer() {
239 let diag = CompatLayer::diagnostics();
240 assert!(!diag.is_empty());
241 }
242}
243#[allow(dead_code)]
245pub type PlatformResult<T> = Result<T, ErrorCode>;
246#[allow(dead_code)]
248pub fn bool_to_platform_result(ok: bool) -> PlatformResult<()> {
249 if ok {
250 Ok(())
251 } else {
252 Err(ErrorCode::Fail)
253 }
254}
255#[allow(dead_code)]
260pub fn str_to_os_bytes(s: &str) -> Vec<u8> {
261 s.as_bytes().to_vec()
262}
263#[allow(dead_code)]
265pub fn os_bytes_to_string(b: &[u8]) -> String {
266 String::from_utf8_lossy(b).into_owned()
267}
268#[cfg(test)]
269mod tests_compat_ext2 {
270 use super::*;
271 #[test]
272 fn test_error_code() {
273 assert!(ErrorCode::Ok.is_ok());
274 assert!(!ErrorCode::Fail.is_ok());
275 assert!(!ErrorCode::Oom.description().is_empty());
276 assert_eq!(ErrorCode::Ok.as_i32(), 0);
277 }
278 #[test]
279 fn test_bool_to_platform_result() {
280 assert!(bool_to_platform_result(true).is_ok());
281 assert!(bool_to_platform_result(false).is_err());
282 }
283 #[test]
284 fn test_stack_guard() {
285 let mut depth = 0usize;
286 {
287 let g = StackGuard::new(&mut depth, 10);
288 assert_eq!(g.current_depth(), 1);
289 }
290 assert_eq!(depth, 0);
291 }
292 #[test]
293 fn test_budget() {
294 let mut b = Budget::new(10);
295 assert!(b.consume(5).is_ok());
296 assert_eq!(b.remaining(), 5);
297 assert!(b.consume(6).is_err());
298 b.refuel(20);
299 assert!(b.has_remaining());
300 }
301 #[test]
302 fn test_compat_matrix() {
303 let mut m = CompatMatrix::new();
304 let a = m.add_component("alpha");
305 let b = m.add_component("beta");
306 assert!(m.is_compatible(a, a));
307 assert!(!m.is_compatible(a, b));
308 m.mark_compatible(a, b);
309 assert!(m.is_compatible(a, b));
310 assert!(m.is_compatible(b, a));
311 }
312 #[test]
313 fn test_version_constraint() {
314 let c = VersionConstraint::major_minor(0, 1);
315 let v_ok = RuntimeVersion {
316 major: 0,
317 minor: 1,
318 patch: 0,
319 pre: None,
320 };
321 let v_bad = RuntimeVersion {
322 major: 1,
323 minor: 0,
324 patch: 0,
325 pre: None,
326 };
327 assert!(c.satisfied_by(&v_ok));
328 assert!(!c.satisfied_by(&v_bad));
329 }
330 #[test]
331 fn test_atomic_version() {
332 let av = AtomicVersion::new();
333 assert_eq!(av.current(), 0);
334 assert_eq!(av.bump(), 1);
335 assert_eq!(av.bump(), 2);
336 }
337 #[test]
338 fn test_capability_set() {
339 let mut caps = CapabilitySet::empty();
340 caps.add(CapabilitySet::THREADS);
341 assert!(caps.has(CapabilitySet::THREADS));
342 assert!(!caps.has(CapabilitySet::NETWORK));
343 caps.remove(CapabilitySet::THREADS);
344 assert!(!caps.has(CapabilitySet::THREADS));
345 }
346 #[test]
347 fn test_shim_registry() {
348 let mut reg = ShimRegistry::new();
349 let i0 = reg.register("file_shim", true);
350 let i1 = reg.register("net_shim", false);
351 assert!(reg.is_enabled(i0));
352 assert!(!reg.is_enabled(i1));
353 assert_eq!(reg.name(i0), Some("file_shim"));
354 assert_eq!(reg.count(), 2);
355 assert_eq!(reg.enabled_count(), 1);
356 }
357 #[test]
358 fn test_compile_flags() {
359 let s = CompileFlags::summary();
360 assert!(s.contains("debug="));
361 assert!(s.contains("edition=2021"));
362 }
363 #[test]
364 fn test_library_manifest() {
365 let lib = LibraryManifest::required("core", "1.0.0");
366 assert!(!lib.optional);
367 let desc = lib.describe();
368 assert!(desc.contains("core"));
369 let opt = LibraryManifest::optional("tracing", "0.1.0");
370 assert!(opt.optional);
371 }
372 #[test]
373 fn test_cfg_snapshot() {
374 let snap = CfgSnapshot::capture();
375 assert!(!snap.arch.is_empty());
376 assert!(!snap.os.is_empty());
377 let s = snap.to_string();
378 assert!(s.contains("arch="));
379 }
380 #[test]
381 fn test_cross_platform_timer() {
382 let timer = CrossPlatformTimer::start();
383 let micros = timer.elapsed_micros();
384 assert!(micros < 10_000_000);
385 }
386 #[test]
387 fn test_os_bytes_round_trip() {
388 let s = "hello/world";
389 let b = str_to_os_bytes(s);
390 let s2 = os_bytes_to_string(&b);
391 assert_eq!(s, s2);
392 }
393}
394#[cfg(test)]
395mod tests_compat_ext3 {
396 use super::*;
397 #[test]
398 fn test_wasm_mem_region() {
399 let r = WasmMemRegion::new(0, 1024, 4096, "heap");
400 assert_eq!(r.end(), 5120);
401 assert!(r.contains(1024));
402 assert!(r.contains(5119));
403 assert!(!r.contains(5120));
404 }
405 #[test]
406 fn test_wasm_mem_table() {
407 let mut tbl = WasmMemTable::new();
408 tbl.add(WasmMemRegion::new(0, 0, 1024, "stack"));
409 tbl.add(WasmMemRegion::new(1, 1024, 4096, "heap"));
410 assert_eq!(tbl.len(), 2);
411 let found = tbl.find(2000);
412 assert!(found.is_some());
413 assert_eq!(found.expect("found should be valid").label, "heap");
414 assert!(tbl.find(5200).is_none());
415 }
416 #[test]
417 fn test_bump_alloc() {
418 let mut alloc = BumpAlloc::new(0, 1024);
419 let a = alloc.alloc(64, 8).expect("a should be present");
420 assert_eq!(a, 0);
421 let b = alloc.alloc(64, 8).expect("b should be present");
422 assert_eq!(b, 64);
423 assert_eq!(alloc.used(), 128);
424 alloc.reset();
425 assert_eq!(alloc.used(), 0);
426 assert_eq!(alloc.remaining(), 1024);
427 }
428 #[test]
429 fn test_bump_alloc_oom() {
430 let mut alloc = BumpAlloc::new(0, 16);
431 assert!(alloc.alloc(17, 1).is_none());
432 }
433 #[test]
434 fn test_addr_range() {
435 let r = AddrRange::new(100, 200);
436 assert_eq!(r.size(), 100);
437 assert!(r.contains(100));
438 assert!(r.contains(199));
439 assert!(!r.contains(200));
440 let r2 = AddrRange::new(150, 250);
441 assert!(r.overlaps(&r2));
442 let r3 = AddrRange::new(200, 300);
443 assert!(!r.overlaps(&r3));
444 }
445}
446#[cfg(test)]
447mod tests_compat_final {
448 use super::*;
449 #[test]
450 fn test_page_map() {
451 let mut pm = PageMap::new(4096);
452 pm.map_page(0, "null_page");
453 pm.map_page(4096, "code");
454 pm.map_page(8192, "data");
455 assert_eq!(pm.page_count(), 3);
456 assert_eq!(pm.label_for(0), Some("null_page"));
457 assert_eq!(pm.label_for(4096), Some("code"));
458 assert_eq!(pm.label_for(100), Some("null_page"));
459 assert_eq!(pm.label_for(99999), None);
460 }
461 #[test]
462 fn test_linear_scan_allocator() {
463 let mut alloc = LinearScanAllocator::new(3);
464 alloc.add_interval(0, 5);
465 alloc.add_interval(2, 8);
466 alloc.add_interval(6, 10);
467 alloc.allocate();
468 assert_eq!(alloc.allocated_count(), 3);
469 }
470 #[test]
471 fn test_instruction_buffer() {
472 let mut buf = InstructionBuffer::new();
473 assert!(buf.is_empty());
474 buf.emit(0xDEAD_BEEF);
475 buf.emit(0x1234_5678);
476 assert_eq!(buf.len(), 2);
477 assert_eq!(buf.get(0), Some(0xDEAD_BEEF));
478 buf.patch(0, 0x0000_0001);
479 assert_eq!(buf.get(0), Some(0x0000_0001));
480 let s = buf.as_slice();
481 assert_eq!(s.len(), 2);
482 }
483}
484#[allow(dead_code)]
486pub const STANDARD_SECTIONS: &[CodeSection] = &[
487 CodeSection::new(".text", 0x0001_0000, 0x0010_0000, true, false),
488 CodeSection::new(".rodata", 0x0011_0000, 0x0004_0000, false, false),
489 CodeSection::new(".data", 0x0015_0000, 0x0002_0000, false, true),
490 CodeSection::new(".bss", 0x0017_0000, 0x0001_0000, false, true),
491];
492#[cfg(test)]
493mod tests_compat_final2 {
494 use super::*;
495 #[test]
496 fn test_code_section() {
497 let sec = CodeSection::new(".text", 0x1000, 0x2000, true, false);
498 assert_eq!(sec.vend(), 0x3000);
499 assert!(sec.contains(0x1000));
500 assert!(sec.contains(0x2FFF));
501 assert!(!sec.contains(0x3000));
502 }
503 #[test]
504 fn test_standard_sections() {
505 assert!(!STANDARD_SECTIONS.is_empty());
506 let text = STANDARD_SECTIONS.iter().find(|s| s.name == ".text");
507 assert!(text.is_some());
508 assert!(text.expect("text should be valid").executable);
509 }
510 #[test]
511 fn test_symbol_table() {
512 let mut tbl = SymbolTable::new();
513 tbl.add("main", 0x1000);
514 tbl.add("start", 0x0FFF);
515 assert_eq!(tbl.lookup("main"), Some(0x1000));
516 assert_eq!(tbl.lookup("missing"), None);
517 assert_eq!(tbl.nearest(0x1004), Some("main"));
518 assert_eq!(tbl.len(), 2);
519 }
520 #[test]
521 fn test_reloc_entry() {
522 let r = RelocEntry::new(0x10, "foo", 8);
523 let patched = r.apply(0x2000);
524 assert_eq!(patched, 0x2008);
525 }
526 #[test]
527 fn test_object_file() {
528 let mut obj = ObjectFile::new();
529 obj.add_section(".text", vec![0x90u8; 16]);
530 obj.add_symbol("foo", 0x0);
531 obj.add_reloc(RelocEntry::new(4, "bar", 0));
532 assert_eq!(obj.num_sections(), 1);
533 assert_eq!(obj.num_relocs(), 1);
534 assert_eq!(obj.section_size(".text"), Some(16));
535 assert_eq!(obj.section_size(".data"), None);
536 }
537}