Skip to main content

asupersync_conformance/
lib.rs

1//! Asupersync Conformance Test Suite
2//!
3// Allow type complexity for trait method return types - these are intentionally
4// verbose to be explicit about the async behavior and lifetimes
5#![allow(clippy::type_complexity)]
6//!
7//! This crate provides a conformance test suite for async runtime implementations.
8//! Tests are designed to verify that runtimes correctly implement the expected
9//! semantics for spawning, channels, I/O, synchronization, and cancellation.
10//!
11//! # Architecture
12//!
13//! The test suite is runtime-agnostic. Each runtime must implement the
14//! `RuntimeInterface` trait to provide the necessary primitives. Tests are
15//! written against this interface, allowing the same tests to validate
16//! different runtime implementations.
17//!
18//! # Test Categories
19//!
20//! - `Spawn`: Task spawning and join handles
21//! - `Channels`: MPSC, oneshot, broadcast, and watch channels
22//! - `IO`: File operations, TCP, and UDP networking
23//! - `Sync`: Mutex, RwLock, Semaphore, Barrier, OnceCell
24//! - `Time`: Sleep, timeout, interval
25//! - `Cancel`: Cancellation token and cooperative cancellation
26
27#![forbid(unsafe_code)]
28
29use serde::{Deserialize, Serialize};
30use std::fmt;
31use std::future::Future;
32use std::io::{self, SeekFrom};
33use std::net::SocketAddr;
34use std::path::Path;
35use std::pin::Pin;
36use std::time::Duration;
37
38pub mod atp_security;
39pub mod bench;
40pub mod h1_expect_continue_conformance;
41pub mod h1_request_building_conformance;
42pub mod h1_response_building_conformance;
43pub mod h2_connect_method_conformance;
44pub mod h2_continuation_conformance;
45pub mod h2_data_end_stream_conformance;
46pub mod h2_enable_push_conformance;
47pub mod h2_goaway_conformance;
48pub mod h2_ping_conformance;
49pub mod h2_priority_conformance;
50pub mod h2_settings_conformance;
51pub mod hpack_conformance;
52pub mod hpack_encoder_conformance;
53pub mod kafka_record_batch_v2;
54pub mod lean_coverage_matrix;
55pub mod lean_frontier;
56pub mod logging;
57pub mod mysql_conformance;
58pub mod otlp_wire_format;
59pub mod raptorq_rfc6330;
60#[path = "../raptorq_rfc6330/reporting/src/mod.rs"]
61pub mod raptorq_rfc6330_reporting;
62pub mod reference_registry;
63pub mod report;
64pub mod rfc6330_fixtures;
65pub mod rfc6330_tests;
66pub mod runner;
67pub mod tests;
68pub mod traceability;
69
70pub use atp_security::{
71    AtpSecurityContract, atp_security_conformance_tests, atp_security_coverage_matrix,
72};
73pub use bench::{
74    BenchAllocSnapshot, BenchAllocStats, BenchCategory, BenchComparisonResult,
75    BenchComparisonSummary, BenchConfig, BenchOutput, BenchRunResult, BenchRunSummary, BenchRunner,
76    BenchThresholds, Benchmark, Comparison, ComparisonConfidence, RegressionCheck,
77    RegressionConfig, RegressionMetric, Stats, StatsError, default_benchmarks,
78    run_benchmark_comparison,
79};
80pub use h1_expect_continue_conformance::{
81    ExpectContinueComplianceReport, ExpectContinueComplianceSummary, ExpectContinueConformanceCase,
82    ExpectContinueConformanceTester, ExpectContinueTestResult, ExpectContinueTestVerdict,
83};
84pub use h1_request_building_conformance::{
85    RequestBuilderOp, RequestBuildingComplianceReport, RequestBuildingComplianceSummary,
86    RequestBuildingConformanceCase, RequestBuildingConformanceTester, RequestBuildingTestResult,
87    RequestBuildingTestVerdict,
88};
89pub use h1_response_building_conformance::{
90    ResponseBuilderOp, ResponseBuildingComplianceReport, ResponseBuildingComplianceSummary,
91    ResponseBuildingConformanceCase, ResponseBuildingConformanceTester, ResponseBuildingTestResult,
92    ResponseBuildingTestVerdict,
93};
94pub use h2_connect_method_conformance::{
95    ConnectMethodComplianceReport, ConnectMethodComplianceSummary, ConnectMethodConformanceCase,
96    ConnectMethodConformanceTester, ConnectMethodTestResult, ConnectMethodTestVerdict,
97    ConnectRequest,
98};
99pub use h2_continuation_conformance::{
100    ContinuationComplianceReport, ContinuationComplianceSummary, ContinuationConformanceCase,
101    ContinuationConformanceTester, ContinuationTestResult, ContinuationTestVerdict,
102    ExpectedOutcome as ContinuationExpectedOutcome, FrameSequence,
103    RequirementLevel as ContinuationRequirementLevel, TestFrame, TestFrameResult,
104};
105pub use h2_data_end_stream_conformance::{
106    DataEndStreamComplianceReport, DataEndStreamComplianceSummary, DataEndStreamConformanceCase,
107    DataEndStreamConformanceResult, DataEndStreamConformanceTester, DataEndStreamConnectionState,
108    DataEndStreamTestVerdict, RequirementLevel as DataEndStreamRequirementLevel,
109    SerializableDataFrame, StreamEndStreamState,
110};
111pub use h2_enable_push_conformance::{
112    EnablePushComplianceReport, EnablePushComplianceSummary, EnablePushConformanceCase,
113    EnablePushConformanceTester, EnablePushTestResult, EnablePushTestVerdict, TestRequest,
114};
115pub use h2_goaway_conformance::{
116    GoAwayComplianceReport, GoAwayComplianceSummary, GoAwayConformanceCase,
117    GoAwayConformanceResult, GoAwayConformanceTester, GoAwayConnectionState, GoAwayTestVerdict,
118    RequirementLevel as GoAwayRequirementLevel, SerializableGoAwayFrame,
119};
120pub use h2_ping_conformance::{
121    PingComplianceReport, PingComplianceSummary, PingConformanceCase, PingConformanceResult,
122    PingConformanceTester, PingConnectionState, PingTestVerdict, PingTiming,
123    RequirementLevel as PingRequirementLevel, SerializablePingFrame,
124};
125pub use h2_priority_conformance::{
126    PriorityComplianceReport, PriorityComplianceSummary, PriorityConformanceCase,
127    PriorityConformanceResult, PriorityConformanceTester, PriorityTestVerdict,
128    RequirementLevel as PriorityRequirementLevel, StreamPriorityState,
129};
130pub use h2_settings_conformance::{
131    ComplianceReport as SettingsComplianceReport, ComplianceSummary as SettingsComplianceSummary,
132    ConformanceResult as SettingsConformanceResult, ExpectedOutcome, Setting,
133    SettingsConformanceCase, SettingsConformanceTester, SettingsFrame, SettingsSnapshot,
134    TestVerdict as SettingsTestVerdict,
135};
136pub use hpack_conformance::{
137    ComplianceReport as HpackComplianceReport, ComplianceSummary as HpackComplianceSummary,
138    ConformanceResult as HpackConformanceResult, ExpectedOutcome as HpackExpectedOutcome,
139    HpackConformanceCase, HpackConformanceTester, RequirementLevel as HpackRequirementLevel,
140    TestVerdict as HpackTestVerdict,
141};
142pub use hpack_encoder_conformance::{
143    EncoderTestVerdict, HpackEncoderComplianceReport, HpackEncoderComplianceSummary,
144    HpackEncoderConformanceCase, HpackEncoderConformanceTester, HpackEncoderTestResult,
145};
146pub use kafka_record_batch_v2::{
147    ConformanceTestResult, Header, KafkaConformanceHarness, RecordAttribute, RecordBatchV2,
148    RecordV2, TimestampType,
149};
150pub use lean_coverage_matrix::{
151    BlockerCode, CoverageBlocker, CoverageEvidence, CoverageRow, CoverageRowType, CoverageStatus,
152    LEAN_COVERAGE_SCHEMA_VERSION, LeanCoverageMatrix,
153};
154pub use lean_frontier::{
155    LEAN_FRONTIER_SCHEMA_VERSION, LeanDiagnosticSeverity, LeanFrontierBucket,
156    LeanFrontierDiagnostic, LeanFrontierReport, extract_frontier_report,
157};
158pub use logging::{
159    ConformanceTestLogger, LogCollector, LogConfig, LogEntry, LogLevel, TestEvent, TestEventKind,
160};
161pub use reference_registry::{
162    ReferenceRegistryError, ReferenceRegistryGuardFailure, ReferenceRegistryGuardReport,
163    ReferenceSurfaceRegistry, ReferenceSurfaceRow, ReferenceVerdictAdmission,
164    RuntimeConformanceVerdict, SOURCE_CONFORMANCE_REGISTRY_CONTRACT,
165};
166pub use report::{render_console_summary, write_json_report};
167pub use runner::{
168    ComparisonResult, ComparisonStatus, ComparisonSummary, RunConfig, RunSummary, SingleRunResult,
169    SuiteResult, SuiteTestResult, TestRunner, compare_results, run_comparison,
170    run_conformance_suite,
171};
172pub use traceability::{
173    CiReport, CoverageStats, ScanWarning, SpecRequirement, TraceabilityEntry, TraceabilityMatrix,
174    TraceabilityMatrixBuilder, TraceabilityScan, TraceabilityScanError, requirements_from_entries,
175    scan_conformance_attributes,
176};
177
178// ============================================================================
179// Requirement Levels
180// ============================================================================
181
182/// RFC 2119 requirement levels for conformance testing.
183#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
184pub enum RequirementLevel {
185    /// MUST requirements - mandatory for conformance.
186    Must,
187    /// SHOULD requirements - recommended but not mandatory.
188    Should,
189    /// MAY requirements - optional features.
190    May,
191}
192
193impl fmt::Display for RequirementLevel {
194    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195        match self {
196            RequirementLevel::Must => write!(f, "MUST"),
197            RequirementLevel::Should => write!(f, "SHOULD"),
198            RequirementLevel::May => write!(f, "MAY"),
199        }
200    }
201}
202
203// ============================================================================
204// Test Result Types
205// ============================================================================
206
207/// Result of a conformance test execution.
208#[derive(Debug, Clone, Serialize, Deserialize)]
209pub struct TestResult {
210    /// Whether the test passed.
211    pub passed: bool,
212    /// Optional failure message.
213    pub message: Option<String>,
214    /// Checkpoints recorded during test execution.
215    pub checkpoints: Vec<Checkpoint>,
216    /// Duration of test execution.
217    pub duration_ms: Option<u64>,
218}
219
220impl TestResult {
221    /// Create a passing test result.
222    pub fn passed() -> Self {
223        Self {
224            passed: true,
225            message: None,
226            checkpoints: Vec::new(),
227            duration_ms: None,
228        }
229    }
230
231    /// Create a failing test result with a message.
232    pub fn failed(message: impl Into<String>) -> Self {
233        Self {
234            passed: false,
235            message: Some(message.into()),
236            checkpoints: Vec::new(),
237            duration_ms: None,
238        }
239    }
240
241    /// Add a checkpoint to the result.
242    pub fn with_checkpoint(mut self, checkpoint: Checkpoint) -> Self {
243        self.checkpoints.push(checkpoint);
244        self
245    }
246
247    /// Set the duration.
248    pub fn with_duration(mut self, duration_ms: u64) -> Self {
249        self.duration_ms = Some(duration_ms);
250        self
251    }
252}
253
254/// A checkpoint recorded during test execution.
255#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
256pub struct Checkpoint {
257    /// Name of the checkpoint.
258    pub name: String,
259    /// Data associated with the checkpoint.
260    pub data: serde_json::Value,
261}
262
263impl Checkpoint {
264    /// Create a new checkpoint.
265    pub fn new(name: impl Into<String>, data: serde_json::Value) -> Self {
266        Self {
267            name: name.into(),
268            data,
269        }
270    }
271}
272
273/// Helper function to record a checkpoint.
274pub fn checkpoint(name: &str, data: serde_json::Value) {
275    let _ = Checkpoint::new(name, data.clone());
276    crate::logging::record_checkpoint(name, data);
277}
278
279// ============================================================================
280// Test Categories
281// ============================================================================
282
283/// Categories of conformance tests.
284#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
285pub enum TestCategory {
286    /// Task spawning and join handles.
287    Spawn,
288    /// Channel primitives (MPSC, oneshot, broadcast, watch).
289    Channels,
290    /// I/O operations (file, TCP, UDP).
291    IO,
292    /// Synchronization primitives (Mutex, RwLock, etc.).
293    Sync,
294    /// Time-related operations (sleep, timeout).
295    Time,
296    /// Cancellation mechanisms.
297    Cancel,
298    /// Security and capability enforcement.
299    Security,
300}
301
302impl fmt::Display for TestCategory {
303    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
304        match self {
305            TestCategory::Spawn => write!(f, "spawn"),
306            TestCategory::Channels => write!(f, "channels"),
307            TestCategory::IO => write!(f, "io"),
308            TestCategory::Sync => write!(f, "sync"),
309            TestCategory::Time => write!(f, "time"),
310            TestCategory::Cancel => write!(f, "cancel"),
311            TestCategory::Security => write!(f, "security"),
312        }
313    }
314}
315
316// ============================================================================
317// Test Metadata
318// ============================================================================
319
320/// Metadata for a conformance test.
321#[derive(Debug, Clone, Serialize, Deserialize)]
322pub struct TestMeta {
323    /// Unique identifier for the test.
324    pub id: String,
325    /// Human-readable name.
326    pub name: String,
327    /// Description of what the test validates.
328    pub description: String,
329    /// Category of the test.
330    pub category: TestCategory,
331    /// Tags for filtering.
332    pub tags: Vec<String>,
333    /// Expected behavior description.
334    pub expected: String,
335}
336
337// ============================================================================
338// Runtime Interface
339// ============================================================================
340
341/// Trait that async runtimes must implement to run conformance tests.
342///
343/// This trait provides the common primitives that tests require. Each method
344/// returns a concrete type that the runtime provides.
345pub trait RuntimeInterface: Sized {
346    // ---- Core Types ----
347    /// Join handle for spawned tasks.
348    type JoinHandle<T: Send + 'static>: Future<Output = T> + Send + 'static;
349
350    /// MPSC sender.
351    type MpscSender<T: Send + 'static>: MpscSender<T> + 'static;
352
353    /// MPSC receiver.
354    type MpscReceiver<T: Send + 'static>: MpscReceiver<T> + 'static;
355
356    /// Oneshot sender.
357    type OneshotSender<T: Send + 'static>: OneshotSender<T> + 'static;
358
359    /// Oneshot receiver.
360    type OneshotReceiver<T: Send + 'static>: Future<Output = Result<T, OneshotRecvError>>
361        + Send
362        + 'static;
363
364    /// Broadcast sender.
365    type BroadcastSender<T: Send + Clone + 'static>: BroadcastSender<T> + 'static;
366
367    /// Broadcast receiver.
368    type BroadcastReceiver<T: Send + Clone + 'static>: BroadcastReceiver<T> + 'static;
369
370    /// Watch sender.
371    type WatchSender<T: Send + Sync + 'static>: WatchSender<T> + 'static;
372
373    /// Watch receiver.
374    type WatchReceiver<T: Send + Sync + Clone + 'static>: WatchReceiver<T> + 'static;
375
376    /// Async file handle.
377    type File: AsyncFile + 'static;
378
379    /// TCP listener.
380    type TcpListener: TcpListener<Stream = Self::TcpStream> + 'static;
381
382    /// TCP stream.
383    type TcpStream: TcpStream + 'static;
384
385    /// UDP socket.
386    type UdpSocket: UdpSocket + 'static;
387
388    // ---- Spawn ----
389    /// Spawn an async task.
390    fn spawn<F>(&self, future: F) -> Self::JoinHandle<F::Output>
391    where
392        F: Future + Send + 'static,
393        F::Output: Send + 'static;
394
395    // ---- Block On ----
396    /// Block on a future until it completes.
397    fn block_on<F: Future>(&self, future: F) -> F::Output;
398
399    /// Snapshot allocation counters for benchmarking (if supported).
400    fn bench_alloc_snapshot(&self) -> Option<crate::bench::runner::BenchAllocSnapshot> {
401        None
402    }
403
404    // ---- Time ----
405    /// Sleep for a duration.
406    fn sleep(&self, duration: Duration) -> Pin<Box<dyn Future<Output = ()> + Send + '_>>;
407
408    /// Run a future with a timeout.
409    fn timeout<'a, F: Future + Send + 'a>(
410        &'a self,
411        duration: Duration,
412        future: F,
413    ) -> Pin<Box<dyn Future<Output = Result<F::Output, TimeoutError>> + Send + 'a>>
414    where
415        F::Output: Send;
416
417    // ---- Channels ----
418    /// Create an MPSC channel with the given capacity.
419    fn mpsc_channel<T: Send + 'static>(
420        &self,
421        capacity: usize,
422    ) -> (Self::MpscSender<T>, Self::MpscReceiver<T>);
423
424    /// Create a oneshot channel.
425    fn oneshot_channel<T: Send + 'static>(
426        &self,
427    ) -> (Self::OneshotSender<T>, Self::OneshotReceiver<T>);
428
429    /// Create a broadcast channel.
430    fn broadcast_channel<T: Send + Clone + 'static>(
431        &self,
432        capacity: usize,
433    ) -> (Self::BroadcastSender<T>, Self::BroadcastReceiver<T>);
434
435    /// Create a watch channel.
436    fn watch_channel<T: Send + Sync + Clone + 'static>(
437        &self,
438        initial: T,
439    ) -> (Self::WatchSender<T>, Self::WatchReceiver<T>);
440
441    // ---- File I/O ----
442    /// Create a file for writing.
443    fn file_create<'a>(
444        &'a self,
445        path: &'a Path,
446    ) -> Pin<Box<dyn Future<Output = io::Result<Self::File>> + Send + 'a>>;
447
448    /// Open a file for reading.
449    fn file_open<'a>(
450        &'a self,
451        path: &'a Path,
452    ) -> Pin<Box<dyn Future<Output = io::Result<Self::File>> + Send + 'a>>;
453
454    // ---- Network ----
455    /// Bind a TCP listener to an address.
456    fn tcp_listen<'a>(
457        &'a self,
458        addr: &'a str,
459    ) -> Pin<Box<dyn Future<Output = io::Result<Self::TcpListener>> + Send + 'a>>;
460
461    /// Connect to a TCP address.
462    fn tcp_connect<'a>(
463        &'a self,
464        addr: SocketAddr,
465    ) -> Pin<Box<dyn Future<Output = io::Result<Self::TcpStream>> + Send + 'a>>;
466
467    /// Bind a UDP socket to an address.
468    fn udp_bind<'a>(
469        &'a self,
470        addr: &'a str,
471    ) -> Pin<Box<dyn Future<Output = io::Result<Self::UdpSocket>> + Send + 'a>>;
472}
473
474// ============================================================================
475// Channel Traits
476// ============================================================================
477
478/// Error when receiving from a closed oneshot channel.
479#[derive(Debug, Clone, Copy, PartialEq, Eq)]
480pub struct OneshotRecvError;
481
482impl fmt::Display for OneshotRecvError {
483    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
484        write!(f, "oneshot channel sender dropped")
485    }
486}
487
488impl std::error::Error for OneshotRecvError {}
489
490/// MPSC sender trait.
491pub trait MpscSender<T: Send>: Clone + Send + Sync {
492    /// Send a value, waiting if the channel is full.
493    fn send(&self, value: T) -> Pin<Box<dyn Future<Output = Result<(), T>> + Send + '_>>;
494}
495
496/// MPSC receiver trait.
497pub trait MpscReceiver<T: Send>: Send {
498    /// Receive a value, returning None if the channel is closed.
499    fn recv(&mut self) -> Pin<Box<dyn Future<Output = Option<T>> + Send + '_>>;
500}
501
502/// Oneshot sender trait.
503pub trait OneshotSender<T: Send>: Send {
504    /// Send a value. Can only be called once.
505    fn send(self, value: T) -> Result<(), T>;
506}
507
508/// Error when receiving from a closed broadcast channel.
509#[derive(Debug, Clone, Copy, PartialEq, Eq)]
510pub enum BroadcastRecvError {
511    /// The receiver lagged too far behind.
512    Lagged(u64),
513    /// The sender was dropped.
514    Closed,
515}
516
517impl fmt::Display for BroadcastRecvError {
518    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
519        match self {
520            Self::Lagged(n) => write!(f, "receiver lagged by {n} messages"),
521            Self::Closed => write!(f, "broadcast channel closed"),
522        }
523    }
524}
525
526impl std::error::Error for BroadcastRecvError {}
527
528/// Broadcast sender trait.
529pub trait BroadcastSender<T: Send + Clone>: Clone + Send + Sync {
530    /// Send a value to all receivers.
531    fn send(&self, value: T) -> Result<usize, T>;
532
533    /// Create a new receiver.
534    fn subscribe(&self) -> Box<dyn BroadcastReceiver<T>>;
535}
536
537/// Broadcast receiver trait.
538pub trait BroadcastReceiver<T: Send + Clone>: Send {
539    /// Receive a value.
540    fn recv(&mut self) -> Pin<Box<dyn Future<Output = Result<T, BroadcastRecvError>> + Send + '_>>;
541}
542
543/// Error when receiving from a closed watch channel.
544#[derive(Debug, Clone, Copy, PartialEq, Eq)]
545pub struct WatchRecvError;
546
547impl fmt::Display for WatchRecvError {
548    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
549        write!(f, "watch channel closed")
550    }
551}
552
553impl std::error::Error for WatchRecvError {}
554
555/// Watch sender trait.
556pub trait WatchSender<T: Send + Sync>: Send + Sync {
557    /// Send a new value.
558    fn send(&self, value: T) -> Result<(), T>;
559}
560
561/// Watch receiver trait.
562pub trait WatchReceiver<T: Send + Sync>: Clone + Send + Sync {
563    /// Wait for a change.
564    fn changed(&mut self) -> Pin<Box<dyn Future<Output = Result<(), WatchRecvError>> + Send + '_>>;
565
566    /// Get the current value.
567    fn borrow_and_clone(&self) -> T;
568}
569
570// ============================================================================
571// File I/O Traits
572// ============================================================================
573
574/// Async file trait.
575pub trait AsyncFile: Send {
576    /// Write all bytes to the file.
577    fn write_all<'a>(
578        &'a mut self,
579        buf: &'a [u8],
580    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send + 'a>>;
581
582    /// Read to fill the buffer exactly.
583    fn read_exact<'a>(
584        &'a mut self,
585        buf: &'a mut [u8],
586    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send + 'a>>;
587
588    /// Read all bytes into a vector.
589    fn read_to_end<'a>(
590        &'a mut self,
591        buf: &'a mut Vec<u8>,
592    ) -> Pin<Box<dyn Future<Output = io::Result<usize>> + Send + 'a>>;
593
594    /// Seek to a position.
595    fn seek<'a>(
596        &'a mut self,
597        pos: SeekFrom,
598    ) -> Pin<Box<dyn Future<Output = io::Result<u64>> + Send + 'a>>;
599
600    /// Sync all data to disk.
601    fn sync_all(&self) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send + '_>>;
602
603    /// Shutdown the file (for sockets).
604    fn shutdown(&mut self) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send + '_>>;
605}
606
607// ============================================================================
608// Network Traits
609// ============================================================================
610
611/// Timeout error.
612#[derive(Debug, Clone, Copy, PartialEq, Eq)]
613pub struct TimeoutError;
614
615impl fmt::Display for TimeoutError {
616    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
617        write!(f, "operation timed out")
618    }
619}
620
621impl std::error::Error for TimeoutError {}
622
623/// TCP listener trait.
624pub trait TcpListener: Send {
625    /// The stream type returned by accept.
626    type Stream: TcpStream;
627
628    /// Get the local address.
629    fn local_addr(&self) -> io::Result<SocketAddr>;
630
631    /// Accept a connection.
632    fn accept(
633        &mut self,
634    ) -> Pin<Box<dyn Future<Output = io::Result<(Self::Stream, SocketAddr)>> + Send + '_>>;
635}
636
637/// TCP stream trait.
638pub trait TcpStream: Send {
639    /// Read into a buffer.
640    fn read<'a>(
641        &'a mut self,
642        buf: &'a mut [u8],
643    ) -> Pin<Box<dyn Future<Output = io::Result<usize>> + Send + 'a>>;
644
645    /// Read to fill the buffer exactly.
646    fn read_exact<'a>(
647        &'a mut self,
648        buf: &'a mut [u8],
649    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send + 'a>>;
650
651    /// Write all bytes.
652    fn write_all<'a>(
653        &'a mut self,
654        buf: &'a [u8],
655    ) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send + 'a>>;
656
657    /// Shutdown the stream.
658    fn shutdown(&mut self) -> Pin<Box<dyn Future<Output = io::Result<()>> + Send + '_>>;
659}
660
661/// UDP socket trait.
662pub trait UdpSocket: Send {
663    /// Get the local address.
664    fn local_addr(&self) -> io::Result<SocketAddr>;
665
666    /// Send to an address.
667    fn send_to<'a>(
668        &'a self,
669        buf: &'a [u8],
670        addr: SocketAddr,
671    ) -> Pin<Box<dyn Future<Output = io::Result<usize>> + Send + 'a>>;
672
673    /// Receive from any address.
674    fn recv_from<'a>(
675        &'a self,
676        buf: &'a mut [u8],
677    ) -> Pin<Box<dyn Future<Output = io::Result<(usize, SocketAddr)>> + Send + 'a>>;
678}
679
680// ============================================================================
681// Test Registration
682// ============================================================================
683
684/// A registered conformance test.
685pub struct ConformanceTest<RT: RuntimeInterface> {
686    /// Test metadata.
687    pub meta: TestMeta,
688    /// The test function.
689    pub test_fn: fn(&RT) -> TestResult,
690}
691
692impl<RT: RuntimeInterface> ConformanceTest<RT> {
693    /// Create a new conformance test.
694    pub const fn new(meta: TestMeta, test_fn: fn(&RT) -> TestResult) -> Self {
695        Self { meta, test_fn }
696    }
697
698    /// Run the test.
699    pub fn run(&self, runtime: &RT) -> TestResult {
700        (self.test_fn)(runtime)
701    }
702}
703
704/// Macro for defining conformance tests.
705///
706/// # Example
707///
708/// ```ignore
709/// conformance_test! {
710///     id: "io-001",
711///     name: "File write and read",
712///     description: "Write data to file, read it back",
713///     category: TestCategory::IO,
714///     tags: ["file", "basic"],
715///     expected: "Read data matches written data",
716///     test: |rt| {
717///         rt.block_on(async {
718///             // test implementation
719///             TestResult::passed()
720///         })
721///     }
722/// }
723/// ```
724#[macro_export]
725macro_rules! conformance_test {
726    (
727        id: $id:literal,
728        name: $name:literal,
729        description: $desc:literal,
730        category: $cat:expr,
731        tags: [$($tag:literal),* $(,)?],
732        expected: $expected:literal,
733        test: |$rt:ident| $body:expr
734    ) => {
735        {
736            fn test_fn<RT: $crate::RuntimeInterface>($rt: &RT) -> $crate::TestResult {
737                $body
738            }
739
740            $crate::ConformanceTest::new(
741                $crate::TestMeta {
742                    id: $id.to_string(),
743                    name: $name.to_string(),
744                    description: $desc.to_string(),
745                    category: $cat,
746                    tags: vec![$($tag.to_string()),*],
747                    expected: $expected.to_string(),
748                },
749                test_fn,
750            )
751        }
752    };
753}