Skip to content

Commit b3cdd48

Browse files
committed
add post
1 parent 7788eec commit b3cdd48

File tree

4 files changed

+85
-0
lines changed

4 files changed

+85
-0
lines changed
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
layout: post
3+
title: "[Swift] Type Scanner (2) - Swift Testing을 분석하여 Test 타입 찾기"
4+
tags: [type scanner, swift, testing, Swift Testing]
5+
---
6+
{% include JB/setup %}
7+
8+
[Test+Discovery.swift#L26](https://github.com/swiftlang/swift-testing/blob/e2ec0411e5f7407fc2d325c9feea8f0ac10a60e2/Sources/Testing/Test%2BDiscovery.swift#L26)를 보면, `__🟠$test_container__` 문자열이 포함된 타입 이름을 찾을려는 것을 `_testContainerTypeNameMagic` 속성 이름을 통해 알 수 있습니다.
9+
10+
<br/>
11+
<p style="text-align:center;">
12+
<img src="{{ site.product_url }}/image/2025/05/01.png"/>
13+
</p><br/>
14+
15+
또한, 아래 all 속성에서 `enumerateTypes(withNamesContaining:)` 를 이용하여 `__🟠$test_container__` 문자열이 포함된 타입을 추출하여, 해당 타입이 `__TestContainer.Type` 타입인지 체크를 한 뒤, `__tests` 를 꺼내어 `Sequence`에 넣어, 테스트를 수행할려는 것을 확인할 수 있습니다.
16+
17+
`enumerateTypes(withNamesContaining:)` 함수는 [Test+Discovery.swift#L69](https://github.com/swiftlang/swift-testing/blob/e2ec0411e5f7407fc2d325c9feea8f0ac10a60e2/Sources/Testing/Test%2BDiscovery.swift#L69)에서 찾을 수 있습니다.
18+
19+
<br/>
20+
<p style="text-align:center;">
21+
<img src="{{ site.product_url }}/image/2025/05/02.png"/>
22+
</p><br/>
23+
24+
이 함수에서 실질적인 동작을 수행하는 함수인 `swt_enumerateTypes(withNamesContaining:_:_:)`를 찾아야 합니다.
25+
26+
이 함수는 [Discovery.h#L40](https://github.com/swiftlang/swift-testing/blob/5b4d6d6f7d4e0dbca4dd6593e0c8862022388d7c/Sources/_TestingInternals/include/Discovery.h#L40)에서 찾을 수 있습니다. `swt_enumerateTypesWithNamesContaining` 함수로, Swift에서 이름을 축약해서 사용할 수 있도록 `SWT_SWIFT_NAME(swt_enumerateTypes(withNamesContaining:_:_:))` 코드를 작성한 것을 확인할 수 있습니다.
27+
28+
<br/>
29+
<p style="text-align:center;">
30+
<img src="{{ site.dev_url }}/image/2025/05/03.png"/>
31+
</p><br/>
32+
33+
이제 `swt_enumerateTypesWithNamesContaining` 함수가 구현된 [Discovery.cpp](https://github.com/swiftlang/swift-testing/blob/5b4d6d6f7d4e0dbca4dd6593e0c8862022388d7c/Sources/_TestingInternals/Discovery.cpp#L509)를 확인해봅시다.
34+
35+
```cpp
36+
void swt_enumerateTypesWithNamesContaining(const char *nameSubstring, void *context, SWTTypeEnumerator body) {
37+
enumerateTypeMetadataSections([=] (const SWTSectionBounds<SWTTypeMetadataRecord>& sectionBounds, bool *stop) {
38+
for (const auto& record : sectionBounds) {
39+
auto contextDescriptor = record.getContextDescriptor();
40+
if (!contextDescriptor) {
41+
// This type metadata record is invalid (or we don't understand how to
42+
// get its context descriptor), so skip it.
43+
continue;
44+
} else if (contextDescriptor->isGeneric()) {
45+
// Generic types cannot be fully instantiated without generic
46+
// parameters, which is not something we can know abstractly.
47+
continue;
48+
}
49+
50+
// Check that the type's name passes. This will be more expensive than the
51+
// checks above, but should be cheaper than realizing the metadata.
52+
const char *typeName = contextDescriptor->getName();
53+
bool nameOK = typeName && nullptr != std::strstr(typeName, nameSubstring);
54+
if (!nameOK) {
55+
continue;
56+
}
57+
58+
if (void *typeMetadata = contextDescriptor->getMetadata()) {
59+
body(sectionBounds.imageAddress, typeMetadata, stop, context);
60+
}
61+
}
62+
});
63+
}
64+
```
65+
66+
`enumerateTypeMetadataSections` 함수를 통해 현재 프로세스에 로드된 Swift 타입 메타데이터 섹션을 열거하고, 각 섹션 내의 모든 타입 메타데이터 레코드를 반복 처리합니다.
67+
68+
메타데이터 레코드가 유효하지 않거나, 제네릭이면 건너뜁니다.
69+
70+
`const char *typeName = contextDescriptor->getName();` 에서 타입 이름을 가져와서, 해당 이름에 `__🟠$test_container__` 문자열이 포함되어 있는지 검사하고, 일치하면 타입 메타데이터를 가져와 이미지 주소, 타입 메타데이터, 중지 플래그, 컨텍스트 정보를 전달합니다.
71+
72+
즉, 타입 이름에 주어진 문자열이 포함되는 Swift 타입들을 찾아 넘겨주는 역할을 합니다. 이 방식은 enum, struct, class 등의 모든 타입을 찾아내기 위에 사용할 수 있습니다.
73+
74+
이를 이용하면, 타입 메타데이터를 스캔하는 기능을 만들어낼 수 있습니다.
75+
76+
<br/>
77+
78+
## 참고자료
79+
80+
* [Swift Testing](https://github.com/swiftlang/swift-testing)
81+
* [Displaying all SwiftUI Previews in a Storybook app](https://medium.com/eureka-engineering/displaying-all-swiftui-previews-in-a-storybook-app-1dd8e925d777)
82+
* [eure/Storybook-ios](https://github.com/eure/Storybook-ios)
83+
* GitHub
84+
* [minsone/DIContainer](https://github.com/minsOne/DIContainer/blob/d331a2c64ceefef5ea67bb0e46d0d0ae71aac750/Sources/DIContainer/Scanner/MachOLoader/MachOLoader.swift)
85+
* [p-x9/MachOKit](https://github.com/p-x9/MachOKit)

image/2025/05/01.png

248 KB
Loading

image/2025/05/02.png

267 KB
Loading

image/2025/05/03.png

150 KB
Loading

0 commit comments

Comments
 (0)