diff --git a/Gemfile.lock b/Gemfile.lock
index 019326f..fa11d6b 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -228,8 +228,7 @@ GEM
rb-fsevent (0.11.2)
rb-inotify (0.11.1)
ffi (~> 1.0)
- rexml (3.3.0)
- strscan
+ rexml (3.3.9)
rouge (3.30.0)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
@@ -243,7 +242,6 @@ GEM
addressable (>= 2.3.5)
faraday (>= 0.17.3, < 3)
simpleidn (0.2.3)
- strscan (3.1.0)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
typhoeus (1.4.1)
diff --git a/_posts/2025/05/2025-05-01-swift-type-scanner-2.md b/_posts/2025/05/2025-05-01-swift-type-scanner-2.md
new file mode 100644
index 0000000..64d2d38
--- /dev/null
+++ b/_posts/2025/05/2025-05-01-swift-type-scanner-2.md
@@ -0,0 +1,84 @@
+---
+layout: post
+title: "[Swift] Type Scanner (2) - Swift Testing을 분석하여 Test 타입 찾기"
+tags: [type scanner, swift, testing, Swift Testing]
+---
+{% include JB/setup %}
+
+[Test+Discovery.swift#L26](https://github.com/swiftlang/swift-testing/blob/e2ec0411e5f7407fc2d325c9feea8f0ac10a60e2/Sources/Testing/Test%2BDiscovery.swift#L26)를 보면, `__🟠$test_container__` 문자열이 포함된 타입 이름을 찾을려는 것을 `_testContainerTypeNameMagic` 속성 이름을 통해 알 수 있습니다.
+
+
+
+
+
+
+또한, 아래 all 속성에서 `enumerateTypes(withNamesContaining:)` 를 이용하여 `__🟠$test_container__` 문자열이 포함된 타입을 추출하여, 해당 타입이 `__TestContainer.Type` 타입인지 체크를 한 뒤, `__tests` 를 꺼내어 `Sequence`에 넣어, 테스트를 수행할려는 것을 확인할 수 있습니다.
+
+`enumerateTypes(withNamesContaining:)` 함수는 [Test+Discovery.swift#L69](https://github.com/swiftlang/swift-testing/blob/e2ec0411e5f7407fc2d325c9feea8f0ac10a60e2/Sources/Testing/Test%2BDiscovery.swift#L69)에서 찾을 수 있습니다.
+
+
+
+
+
+
+이 함수에서 실질적인 동작을 수행하는 함수인 `swt_enumerateTypes(withNamesContaining:_:_:)`를 찾아야 합니다.
+
+이 함수는 [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:_:_:))` 코드를 작성한 것을 확인할 수 있습니다.
+
+
+
+
+
+
+이제 `swt_enumerateTypesWithNamesContaining` 함수가 구현된 [Discovery.cpp](https://github.com/swiftlang/swift-testing/blob/5b4d6d6f7d4e0dbca4dd6593e0c8862022388d7c/Sources/_TestingInternals/Discovery.cpp#L509)를 확인해봅시다.
+
+```cpp
+void swt_enumerateTypesWithNamesContaining(const char *nameSubstring, void *context, SWTTypeEnumerator body) {
+ enumerateTypeMetadataSections([=] (const SWTSectionBounds& sectionBounds, bool *stop) {
+ for (const auto& record : sectionBounds) {
+ auto contextDescriptor = record.getContextDescriptor();
+ if (!contextDescriptor) {
+ // This type metadata record is invalid (or we don't understand how to
+ // get its context descriptor), so skip it.
+ continue;
+ } else if (contextDescriptor->isGeneric()) {
+ // Generic types cannot be fully instantiated without generic
+ // parameters, which is not something we can know abstractly.
+ continue;
+ }
+
+ // Check that the type's name passes. This will be more expensive than the
+ // checks above, but should be cheaper than realizing the metadata.
+ const char *typeName = contextDescriptor->getName();
+ bool nameOK = typeName && nullptr != std::strstr(typeName, nameSubstring);
+ if (!nameOK) {
+ continue;
+ }
+
+ if (void *typeMetadata = contextDescriptor->getMetadata()) {
+ body(sectionBounds.imageAddress, typeMetadata, stop, context);
+ }
+ }
+ });
+}
+```
+
+`enumerateTypeMetadataSections` 함수를 통해 현재 프로세스에 로드된 Swift 타입 메타데이터 섹션을 열거하고, 각 섹션 내의 모든 타입 메타데이터 레코드를 반복 처리합니다.
+
+메타데이터 레코드가 유효하지 않거나, 제네릭이면 건너뜁니다.
+
+`const char *typeName = contextDescriptor->getName();` 에서 타입 이름을 가져와서, 해당 이름에 `__🟠$test_container__` 문자열이 포함되어 있는지 검사하고, 일치하면 타입 메타데이터를 가져와 이미지 주소, 타입 메타데이터, 중지 플래그, 컨텍스트 정보를 전달합니다.
+
+즉, 타입 이름에 주어진 문자열이 포함되는 Swift 타입들을 찾아 넘겨주는 역할을 합니다. 이 방식은 enum, struct, class 등의 모든 타입을 찾아내기 위에 사용할 수 있습니다.
+
+이를 이용하면, 타입 메타데이터를 스캔하는 기능을 만들어낼 수 있습니다.
+
+
+
+## 참고자료
+
+* [Swift Testing](https://github.com/swiftlang/swift-testing)
+* [Displaying all SwiftUI Previews in a Storybook app](https://medium.com/eureka-engineering/displaying-all-swiftui-previews-in-a-storybook-app-1dd8e925d777)
+ * [eure/Storybook-ios](https://github.com/eure/Storybook-ios)
+* GitHub
+ * [minsone/DIContainer](https://github.com/minsOne/DIContainer/blob/d331a2c64ceefef5ea67bb0e46d0d0ae71aac750/Sources/DIContainer/Scanner/MachOLoader/MachOLoader.swift)
\ No newline at end of file
diff --git a/image/2025/05/01.png b/image/2025/05/01.png
new file mode 100644
index 0000000..4b403f6
Binary files /dev/null and b/image/2025/05/01.png differ
diff --git a/image/2025/05/02.png b/image/2025/05/02.png
new file mode 100644
index 0000000..4b83d78
Binary files /dev/null and b/image/2025/05/02.png differ
diff --git a/image/2025/05/03.png b/image/2025/05/03.png
new file mode 100644
index 0000000..e23500f
Binary files /dev/null and b/image/2025/05/03.png differ