# 帳票設計書 8-Test Report (JUnit/Markdown)

## 概要

本ドキュメントは、LLVMプロジェクトのテスト結果レポート機能の設計仕様を記載する。JUnit XMLファイルを解析しMarkdown形式のテスト結果レポートを生成する。

### 本帳票の処理概要

Test Reportは、CI/CDパイプラインで生成されたJUnit XML形式のテスト結果とninjaビルドログを解析し、人間が読みやすいMarkdown形式のレポートを生成するPythonライブラリである。

**業務上の目的・背景**：LLVMプロジェクトのCI/CDパイプラインでは、多数のテストが実行され、その結果を開発者に分かりやすく伝える必要がある。本機能は、JUnit XMLとninjaログからテスト結果を抽出し、GitHubのPull Requestコメントやアノテーションとして表示可能なMarkdown形式に変換する。失敗したテストの詳細情報を折りたたみ形式で提供し、既知の失敗（Likely Already Failing）を識別する機能も備える。

**帳票の利用シーン**：GitHub Pull Requestへのテスト結果投稿、CIパイプラインのアノテーション生成、ビルド失敗時の詳細レポート、Pre-mergeテスト結果の通知時に利用される。

**主要な出力内容**：
1. テスト結果サマリー（成功/スキップ/失敗件数）
2. 失敗テスト一覧（テストスイート別）
3. ビルド失敗情報（ninjaログから抽出）
4. 折りたたみ可能な失敗詳細
5. 既知の失敗の識別と説明

**帳票の出力タイミング**：CI/CDパイプラインのテスト完了後、generate_report()関数呼び出し時に生成される。

**帳票の利用者**：ソフトウェア開発者、CI/CDシステム、コードレビュアー、リリースマネージャー

## 帳票種別

Markdown形式テスト結果レポート

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| - | GitHub PR | Pull Request Comments | 自動投稿 |
| - | CI Annotation | GitHub Actions Annotation | 自動表示 |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | Markdown |
| 用紙サイズ | - |
| 向き | - |
| ファイル名 | (文字列として返却) |
| 出力方法 | 文字列返却 |
| 文字コード | UTF-8 |

### サイズ制限

| 項目 | 内容 |
|-----|------|
| デフォルト制限 | 1MB (1024 * 1024 bytes) |
| 超過時動作 | list_failures=False で再生成 |

## 帳票レイアウト

### レイアウト概要

Markdown形式で以下の構造を持つ。

```markdown
# {title}

* {tests_passed} tests passed
* {tests_skipped} tests skipped
* {tests_failed} tests failed

## Failed Tests
(click on a test name to see its output)

### {testsuite_name}

<details>
<summary>{test_name}</summary>

```
{failure_message}
```

</details>

{UNRELATED_FAILURES_STR}
```

### ヘッダー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | title | レポートタイトル | 引数 | `# {title}` |

### サマリー部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | tests_passed | 成功テスト数 | tests_run - tests_skipped - tests_failed | `* N tests passed` |
| 2 | tests_skipped | スキップテスト数 | testsuite.skipped | `* N tests skipped` |
| 3 | tests_failed | 失敗テスト数 | testsuite.failures | `* N tests failed` |

### 失敗テスト部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | testsuite_name | テストスイート名 | testsuite.name | `### {name}` |
| 2 | test_name | テスト名 | test.classname + test.name | `<details><summary>` |
| 3 | failure_message | 失敗メッセージ | test.result[0].text | コードブロック |
| 4 | explanation | 既知失敗の説明 | failure_explanations | テキスト |

### ビルド失敗部

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | failed_action | 失敗アクション名 | ninja_log | `<summary>` |
| 2 | failure_message | 失敗詳細 | ninja_log | コードブロック |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| junit_objects | JUnitXmlオブジェクト配列 | Yes |
| return_code | ビルドリターンコード | Yes |
| ninja_logs | ninjaログ（行の配列の配列） | No |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | テストスイート名 | 辞書順 |

## データベース参照仕様

### 参照データソース一覧

| データソース | 用途 | 取得方法 |
|-------------|------|---------|
| *.xml (JUnit) | テスト結果 | JUnitXml.fromfile() |
| *.log (ninja) | ビルドログ | ファイル読込 |

### JUnit XML構造

| 要素 | 属性 | 説明 |
|------|------|------|
| testsuite | name, tests, skipped, failures | テストスイート |
| testcase | classname, name | テストケース |
| failure | - | 失敗情報（text属性） |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| tests_passed | tests_run - tests_skipped - tests_failed | - | 整数 |
| result | crash_count + bug_counter.total | - | 整数 |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[generate_report呼出] --> B[get_failures]
    B --> C[テスト統計計算]
    C --> D{tests_run == 0?}
    D -->|Yes| E{return_code == 0?}
    E -->|Yes| F[成功メッセージ]
    E -->|No| G[find_failure_in_ninja_logs]
    G --> H[ビルド失敗レポート]
    D -->|No| I[サマリー生成]
    I --> J{failures存在?}
    J -->|Yes| K[失敗テストレポート]
    J -->|No| L{return_code != 0?}
    L -->|Yes| G
    L -->|No| M[成功メッセージ]
    K --> N[サイズチェック]
    H --> N
    F --> O[終了]
    M --> O
    N --> P{size > limit?}
    P -->|Yes| Q[list_failures=Falseで再生成]
    P -->|No| O
    Q --> O
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| サイズ超過 | レポート > size_limit | (縮小版生成) | list_failures=False |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数千テスト |
| 目標出力時間 | 数秒 |
| 同時出力数上限 | 1 |

## セキュリティ考慮事項

- テスト名・失敗メッセージがレポートに含まれる
- 機密情報がテスト出力に含まれる可能性

## 備考

- UNRELATED_FAILURES_STRで無関係な失敗についての案内を表示
- failure_explanationsで既知の失敗を識別し「Likely Already Failing」としてマーク
- NINJA_LOG_SIZE_THRESHOLD（500行）でninjaログの最大サイズを制限

---

## コードリーディングガイド

本帳票を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | generate_test_report_lib.py | `.ci/generate_test_report_lib.py` | FailureExplanation TypedDict（行14-17）を理解 |

**読解のコツ**: FailureExplanationはname, explained, reasonの3フィールドを持つ辞書型で、既知の失敗を識別するために使用される。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | generate_test_report_lib.py | 同上 | generate_report()関数（行176-329） |

**主要処理フロー**:
- **行185**: get_failures()でJUnitから失敗情報抽出
- **行186-206**: テスト統計計算
- **行208-251**: テスト未実行時の処理
- **行253-317**: テスト実行時の結果処理
- **行319-328**: サイズ制限チェックと再帰呼出

#### Step 3: ninjaログ解析を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | generate_test_report_lib.py | 同上 | _parse_ninja_log()（行31-84）とfind_failure_in_ninja_logs()（行87-106） |

**主要処理フロー**:
- **行36-47**: "FAILED:"行を探索
- **行61-83**: 失敗情報の抽出（アクション名、失敗メッセージ）

#### Step 4: フォーマット処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | generate_test_report_lib.py | 同上 | _format_failures()（行109-138） |

**主要処理フロー**:
- **行119-136**: `<details>/<summary>`タグでの折りたたみ生成

### プログラム呼び出し階層図

```
generate_report()
    │
    ├─ get_failures()
    │      └─ JUnit XML解析
    │
    ├─ are_all_failures_explained()
    │
    ├─ find_failure_in_ninja_logs()
    │      └─ _parse_ninja_log()
    │
    ├─ _format_failures()
    │
    └─ [サイズ超過時]
           └─ generate_report(list_failures=False) [再帰]
```

### データフロー図

```
[入力]                      [処理]                           [出力]

*.xml (JUnit) ──────▶ JUnitXml.fromfile()
                            │
                            ▼
                      get_failures()
                            │
*.log (ninja) ──────▶ find_failure_in_ninja_logs()
                            │
                            ▼
                    ┌───────┴───────┐
                    │               │
                    ▼               ▼
              failures[]      ninja_failures[]
                    │               │
                    └───────┬───────┘
                            │
failure_explanations ──────▶ _format_failures()
                            │
                            ▼
                    generate_report()
                            │
                            ▼
                    [Markdown文字列]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| generate_test_report_lib.py | `.ci/generate_test_report_lib.py` | ソース | レポート生成ライブラリ |
| generate_test_report.py | `.ci/generate_test_report.py` | ソース | コマンドラインエントリーポイント（推定） |
| junitparser | (外部ライブラリ) | 依存 | JUnit XML解析 |
