@@ -21,78 +21,117 @@ the testing library are stored in dedicated platform-specific sections:
2121
2222| Platform | Binary Format | Section Name |
2323| -| :-:| -|
24- | macOS | Mach-O | ` __DATA_CONST,__swift5_tests ` |
25- | iOS | Mach-O | ` __DATA_CONST,__swift5_tests ` |
26- | watchOS | Mach-O | ` __DATA_CONST,__swift5_tests ` |
27- | tvOS | Mach-O | ` __DATA_CONST,__swift5_tests ` |
28- | visionOS | Mach-O | ` __DATA_CONST,__swift5_tests ` |
29- | Linux | ELF | ` PT_NOTE ` [ ^ 1 ] |
30- | FreeBSD | ELF | ` PT_NOTE ` [ ^ 1 ] |
31- | Android | ELF | ` PT_NOTE ` [ ^ 1 ] |
24+ | macOS, iOS, watchOS, tvOS, visionOS | Mach-O | ` __DATA_CONST,__swift5_tests ` |
25+ | Linux, FreeBSD, Android | ELF | ` PT_NOTE ` [ ^ 1 ] |
3226| WASI | Statically Linked | ` swift5_tests ` |
3327| Windows | PE/COFF | ` .sw5test ` |
3428
3529[ ^ 1 ] : On platforms that use the ELF binary format natively, test content records
3630 are stored in ELF program headers of type ` PT_NOTE ` . Take care not to
3731 remove these program headers (for example, by invoking [ ` strip(1) ` ] ( https://www.man7.org/linux/man-pages/man1/strip.1.html ) .)
3832
39- ### Determining the type of test content
40-
33+ ### Record headers
34+
4135Regardless of platform, all test content records created and discoverable by the
42- testing library start have the name ` "Swift Testing" ` stored in the implied
43- ` n_name ` field of their underlying ELF Notes. Each record's _ type_ (stored in
44- the underlying ELF Note's ` n_type ` field) determines how the record will be
45- interpreted at runtime:
36+ testing library have the following structure:
37+
38+ ``` c
39+ struct SWTTestContentHeader {
40+ int32_t n_namesz;
41+ int32_t n_descsz;
42+ int32_t n_type;
43+ char n_name[ n_namesz] ;
44+ // ...
45+ };
46+ ```
47+
48+ This structure can be represented in Swift as a heterogenous tuple:
49+
50+ ``` swift
51+ typealias SWTTestContentHeader = (
52+ n_namesz: Int32 ,
53+ n_descsz: Int32 ,
54+ n_type: Int32 ,
55+ n_name: (CChar , CChar , /* ... */ ),
56+ // ...
57+ )
58+ ```
59+
60+ The size of ` n_name ` is dynamic and cannot be statically computed. The testing
61+ library always generates the name ` "Swift Testing" ` and specifies an ` n_namesz `
62+ value of ` 20 ` (the string being null-padded to the correct length), but other
63+ content may be present in the same section whose header size differs. For more
64+ information about this structure such as its alignment requirements, see the
65+ documentation for the [ ELF format] ( https://man7.org/linux/man-pages/man5/elf.5.html ) .
66+
67+ Each record's _ kind_ (stored in the ` n_type ` field) determines how the record
68+ will be interpreted at runtime:
4669
4770| Type Value | Interpretation |
4871| -:| -|
49- | < ` 0 ` | Undefined (** do not use** ) |
50- | ` 0 ` ... ` 99 ` | Reserved |
72+ | ` < 0` | Undefined (** do not use** ) |
73+ | ` 0 ... 99 ` | Reserved |
5174| ` 100 ` | Test or suite declaration |
5275| ` 101 ` | Exit test |
5376
5477<!-- When adding cases to this enumeration, be sure to also update the
5578corresponding enumeration in Discovery.h and TestContentGeneration.swift. -->
5679
57- ### Loading test content from a record
80+ ### Record contents
5881
59- For all currently-defined record types, the header and name are followed by a
60- structure of the following form:
82+ For all currently-defined record types, the header structure is immediately
83+ followed by the actual content of the record. A test content record currently
84+ contains an ` accessor ` function to load the corresponding Swift content and a
85+ ` flags ` field whose value depends on the type of record. The overall structure
86+ of a record therefore looks like:
6187
6288``` c
6389struct SWTTestContent {
64- bool (* accessor)(void * );
65- uint64_t flags;
90+ SWTTestContentHeader header;
91+ bool (* accessor)(void * outValue);
92+ uint32_t flags;
93+ uint32_t reserved;
6694};
6795```
6896
69- #### The accessor field
70-
71- The function ` accessor ` is a C function whose signature in Swift can be restated
72- as:
97+ Or, in Swift as a tuple:
7398
7499``` swift
75- @convention (c) (_ outValue: UnsafeMutableRawPointer ) -> Bool
100+ typealias SWTTestContent = (
101+ header: SWTTestContentHeader,
102+ accessor: @convention (c) (_ outValue: UnsafeMutableRawPointer ) -> Bool ,
103+ flags: UInt32 ,
104+ reserved: UInt32
105+ )
76106```
77107
78- When called, it initializes the memory at ` outValue ` to an instance of some
79- Swift type and returns ` true ` , or returns ` false ` if it could not generate the
80- relevant content. On successful return, the caller is responsible for
81- deinitializing the memory at ` outValue ` when done with it .
108+ This structure may grow in the future as needed. Check the ` header.n_descsz `
109+ field to determine if there are additional fields present. Do not assume that
110+ the size of this structure will remain fixed over time or that all discovered
111+ test content records are the same size .
82112
83- The concrete Swift type of ` accessor ` 's result depends on the type of record:
113+ #### The accessor field
114+
115+ The function ` accessor ` is a C function. When called, it initializes the memory
116+ at its argument ` outValue ` to an instance of some Swift type and returns ` true ` ,
117+ or returns ` false ` if it could not generate the relevant content. On successful
118+ return, the caller is responsible for deinitializing the memory at ` outValue `
119+ when done with it.
120+
121+ The concrete Swift type of the value written to ` outValue ` depends on the type
122+ of record:
84123
85124| Type Value | Return Type |
86125| -:| -|
87126| < ` 0 ` | Undefined (** do not use** ) |
88- | ` 0 ` ... ` 99 ` | ` nil ` |
127+ | ` 0 ` ... ` 99 ` | Reserved ( ** do not use ** ) |
89128| ` 100 ` | ` @Sendable () async -> Test ` [ ^ 2 ] |
90- | ` 101 ` | ` ExitTest ` (owned by caller) |
129+ | ` 101 ` | ` ExitTest ` (consumed by caller) |
91130
92131[ ^ 2 ] : This signature is not the signature of ` accessor ` , but of the Swift
93- function reference it returns . This level of indirection is necessary
94- because loading a test or suite declaration is an asynchronous operation,
95- but C functions cannot be ` async ` .
132+ function reference it writes to ` outValue ` . This level of indirection is
133+ necessary because loading a test or suite declaration is an asynchronous
134+ operation, but C functions cannot be ` async ` .
96135
97136#### The flags field
98137
@@ -105,6 +144,10 @@ For test or suite declarations (type `100`), the following flags are defined:
105144
106145For exit test declarations (type ` 101 ` ), no flags are currently defined.
107146
147+ #### The reserved field
148+
149+ This field is reserved for future use. Always set it to ` 0 ` .
150+
108151## Third-party test content
109152
110153TODO: elaborate how tools can reuse the same ` n_name ` and ` n_type ` fields to
0 commit comments