@@ -21,78 +21,117 @@ the testing library are stored in dedicated platform-specific sections:
21
21
22
22
| Platform | Binary Format | Section Name |
23
23
| -| :-:| -|
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 ] |
32
26
| WASI | Statically Linked | ` swift5_tests ` |
33
27
| Windows | PE/COFF | ` .sw5test ` |
34
28
35
29
[ ^ 1 ] : On platforms that use the ELF binary format natively, test content records
36
30
are stored in ELF program headers of type ` PT_NOTE ` . Take care not to
37
31
remove these program headers (for example, by invoking [ ` strip(1) ` ] ( https://www.man7.org/linux/man-pages/man1/strip.1.html ) .)
38
32
39
- ### Determining the type of test content
40
-
33
+ ### Record headers
34
+
41
35
Regardless 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:
46
69
47
70
| Type Value | Interpretation |
48
71
| -:| -|
49
- | < ` 0 ` | Undefined (** do not use** ) |
50
- | ` 0 ` ... ` 99 ` | Reserved |
72
+ | ` < 0` | Undefined (** do not use** ) |
73
+ | ` 0 ... 99 ` | Reserved |
51
74
| ` 100 ` | Test or suite declaration |
52
75
| ` 101 ` | Exit test |
53
76
54
77
<!-- When adding cases to this enumeration, be sure to also update the
55
78
corresponding enumeration in Discovery.h and TestContentGeneration.swift. -->
56
79
57
- ### Loading test content from a record
80
+ ### Record contents
58
81
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:
61
87
62
88
``` c
63
89
struct 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;
66
94
};
67
95
```
68
96
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:
73
98
74
99
``` 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
+ )
76
106
```
77
107
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 .
82
112
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:
84
123
85
124
| Type Value | Return Type |
86
125
| -:| -|
87
126
| < ` 0 ` | Undefined (** do not use** ) |
88
- | ` 0 ` ... ` 99 ` | ` nil ` |
127
+ | ` 0 ` ... ` 99 ` | Reserved ( ** do not use ** ) |
89
128
| ` 100 ` | ` @Sendable () async -> Test ` [ ^ 2 ] |
90
- | ` 101 ` | ` ExitTest ` (owned by caller) |
129
+ | ` 101 ` | ` ExitTest ` (consumed by caller) |
91
130
92
131
[ ^ 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 ` .
96
135
97
136
#### The flags field
98
137
@@ -105,6 +144,10 @@ For test or suite declarations (type `100`), the following flags are defined:
105
144
106
145
For exit test declarations (type ` 101 ` ), no flags are currently defined.
107
146
147
+ #### The reserved field
148
+
149
+ This field is reserved for future use. Always set it to ` 0 ` .
150
+
108
151
## Third-party test content
109
152
110
153
TODO: elaborate how tools can reuse the same ` n_name ` and ` n_type ` fields to
0 commit comments