---
generated_at: 2026-03-01 20:45:00
metrics:
  claims_total: 102
  claims_with_evidence: 102
  claims_without_evidence: 0
confidence_derived: 1.00
---

# 根拠レポート：storage-r2 単体テストケース一覧

## 本レポートについて

### 目的
本レポートは、生成された設計書・ドキュメントの信頼性を検証し、人間レビュアーが効率的にレビューできるようにすることを目的としています。

### チェック方法
以下の観点でドキュメントの内容（Claim：主張）を検証しています：

1. **根拠の有無確認**：各主張に対して、ソースコード・既存設計書・要件定義書などの根拠（Evidence）が存在するか
2. **根拠との整合性**：主張の内容が根拠と矛盾していないか
3. **網羅性**：参照すべき情報源を適切にカバーしているか

### 信頼度スコアの算出
- **confidence_derived** = 根拠あり件数 / 総主張件数
- 状態「○」：根拠あり、「△」：根拠不足または要確認

### 本レポートの使い方
1. まず「サマリー」で全体の信頼度と優先レビュー項目を確認
2. 「Claims と根拠の対応」で △ の項目を重点的にレビュー
3. 「不足情報」で補完が必要な情報源を確認

---

## 1) サマリー（まず見るところ）
- 総合信頼度（derived）：**1.00**
  - 根拠あり：102 / 102、根拠なし：0
- 優先レビュー（高）
  1. **なし**：全てのテストケースに根拠あり

## 2) 参照した情報（Evidence一覧）
> ここに「実在するもの」だけ列挙。抽出フェーズで付けたIDをそのまま出す。

- E-01: `packages/storage-r2/src/index.ts` - R2ストレージプラグインのメインエントリポイント、r2Storage関数、r2StorageInternal関数
- E-02: `packages/storage-r2/src/types.ts` - R2Bucket、R2Object、R2MultipartUpload等のTypeScript型定義
- E-03: `packages/storage-r2/src/handleUpload.ts` - getHandleUpload関数によるファイルアップロード処理
- E-04: `packages/storage-r2/src/handleDelete.ts` - getHandleDelete関数によるファイル削除処理
- E-05: `packages/storage-r2/src/staticHandler.ts` - getHandler関数によるファイル取得・静的ファイルハンドラ
- E-06: `packages/storage-r2/src/handleMultiPartUpload.ts` - getHandleMultiPartUpload関数によるマルチパートアップロード処理
- E-07: `packages/storage-r2/src/client/R2ClientUploadHandler.ts` - R2ClientUploadHandlerクライアントサイドアップロード処理
- E-08: `packages/storage-r2/src/exports/client.ts` - クライアントエクスポート

## 3) Claims と根拠の対応（レビューの主戦場）

### index.ts（r2Storage、r2StorageInternal）
| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-01 | プラグインが正しく設定を返す | E-01: L46-116 r2Storage関数全体 | ○ |
| C-02 | enabled=trueでプラグインが有効化される | E-01: L51, L112-115 enabled判定とcloudStoragePlugin呼び出し | ○ |
| C-03 | enabled=falseでプラグインが無効化される | E-01: L76-78 isPluginDisabled判定で早期リターン | ○ |
| C-04 | コレクションにdisableLocalStorage: trueが設定される | E-01: L95-110 コレクション設定のmap処理 | ○ |
| C-05 | clientUploadsが有効な場合initClientUploadsが呼ばれる | E-01: L53-74 initClientUploads呼び出し | ○ |
| C-06 | clientUploads.accessが設定されている場合に渡される | E-01: L66-69 access取得ロジック | ○ |
| C-07 | コレクションオプションがtrueの場合空オブジェクトとして処理される | E-01: L87 `collOptions === true ? {} : collOptions` | ○ |
| C-08 | コレクションオプションがオブジェクトの場合マージされる | E-01: L84-91 collectionsWithAdapter生成ロジック | ○ |
| C-09 | alwaysInsertFieldsがcloudStoragePluginに渡される | E-01: L113 alwaysInsertFields渡し | ○ |
| C-10 | collectionsが空オブジェクトの場合 | E-01: L81-92 Object.entriesで空でも動作 | ○ |
| C-11 | 指定されていないコレクションは変更されない | E-01: L98-100 collectionsWithAdapterに存在しない場合早期リターン | ○ |
| C-12 | extraClientHandlerPropsでprefixが設定される | E-01: L61-64 extraClientHandlerProps関数 | ○ |
| C-13 | serverHandlerPathが正しく設定される | E-01: L73 serverHandlerPath設定 | ○ |
| C-14 | GeneratedAdapterが正しく生成される | E-01: L118-131 r2StorageInternal関数 | ○ |
| C-15 | handleDeleteが設定される | E-01: L123 getHandleDelete呼び出し | ○ |
| C-16 | handleUploadが設定される | E-01: L124-128 getHandleUpload呼び出し | ○ |
| C-17 | staticHandlerが設定される | E-01: L129 getHandler呼び出し | ○ |

### handleUpload.ts（getHandleUpload）
| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-18 | ファイルがR2バケットにアップロードされる | E-03: L18-20 bucket.put呼び出し | ○ |
| C-19 | prefixが正しくパスに結合される | E-03: L18 path.posix.join(data.prefix \|\| prefix, file.filename) | ○ |
| C-20 | data.prefixがprefixより優先される | E-03: L18 `data.prefix \|\| prefix` の順序 | ○ |
| C-21 | contentTypeがhttpMetadataに設定される | E-03: L19 httpMetadata: { contentType: file.mimeType } | ○ |
| C-22 | 開発環境でBlobに変換される | E-03: L17 NODE_ENV === 'development'条件分岐 | ○ |
| C-23 | 本番環境でBufferがそのまま使用される | E-03: L17 条件分岐のelse側でfile.buffer | ○ |
| C-24 | prefixが空文字の場合 | E-03: L14 prefix = ''のデフォルト値 | ○ |
| C-25 | filenameに特殊文字が含まれる場合 | E-03: L18 path.posix.joinで処理 | ○ |
| C-26 | bucket.putがエラーをスローした場合 | E-03: L18 awaitによる非同期処理、例外伝播 | ○ |

### handleDelete.ts（getHandleDelete）
| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-27 | ファイルがR2バケットから削除される | E-04: L13 bucket.delete呼び出し | ○ |
| C-28 | prefixが正しくパスに結合される | E-04: L13 path.posix.join(prefix, filename) | ○ |
| C-29 | prefixがundefinedの場合デフォルト値が使用される | E-04: L12 `prefix = ''`のデフォルト値 | ○ |
| C-30 | bucket.deleteが失敗した場合例外がスローされる | E-04: L13 awaitによる非同期処理 | ○ |

### staticHandler.ts（getHandler）
| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-31 | ファイルが正常に取得される | E-05: L116-118 Response(obj.body)返却 | ○ |
| C-32 | ファイルが存在しない場合404が返却される | E-05: L24-25 headObj nullチェック | ○ |
| C-33 | bucket.getがnullを返す場合404が返却される | E-05: L59-61 obj nullチェック | ○ |
| C-34 | obj.bodyがundefinedの場合404が返却される | E-05: L59 obj.body == undefined判定 | ○ |
| C-35 | Rangeリクエストが正しく処理される | E-05: L36-57 getRangeRequestInfo処理 | ○ |
| C-36 | 不正なRangeヘッダーの場合416が返却される | E-05: L39-44 rangeResult.type === 'invalid' | ○ |
| C-37 | 50MB超のファイルでclientUploadContextがある場合200空レスポンス | E-05: L31-33 fileSize > 50 * 1024 * 1024条件 | ○ |
| C-38 | 50MB以下のファイルでclientUploadContextがある場合通常処理 | E-05: L31-33 条件を満たさない場合継続 | ○ |
| C-39 | SVGファイルにContent-Security-Policyが設定される | E-05: L94-97 image/svg+xml判定 | ○ |
| C-40 | 非SVGファイルにはCSPヘッダーが設定されない | E-05: L95 contentType === 'image/svg+xml'条件 | ○ |
| C-41 | ETagマッチで304が返却される | E-05: L109-114 etag比較ロジック | ○ |
| C-42 | etagヘッダーでも304が返却される | E-05: L99 req.headers.get('etag')取得 | ○ |
| C-43 | ETagが一致しない場合ファイルが返却される | E-05: L116-118 条件不成立時のResponse返却 | ○ |
| C-44 | modifyResponseHeadersが呼び出される | E-05: L101-107 modifyResponseHeaders呼び出し | ○ |
| C-45 | modifyResponseHeadersがnullを返す場合元のヘッダーが使用される | E-05: L106 `\|\| headers`のフォールバック | ○ |
| C-46 | Miniflare環境でhttpMetadataが手動設定される | E-05: L71-88 isMiniflare条件分岐 | ○ |
| C-47 | Miniflare環境でcacheControlが設定される | E-05: L74-76 cacheControl設定 | ○ |
| C-48 | Miniflare環境でcontentDispositionが設定される | E-05: L77-79 contentDisposition設定 | ○ |
| C-49 | Miniflare環境でcontentEncodingが設定される | E-05: L80-82 contentEncoding設定 | ○ |
| C-50 | Miniflare環境でcontentLanguageが設定される | E-05: L83-85 contentLanguage設定 | ○ |
| C-51 | 本番環境でwriteHttpMetadataが呼び出される | E-05: L90 obj.writeHttpMetadata(headers) | ○ |
| C-52 | Rangeがpartialの場合bucket.getにrangeオプションが渡される | E-05: L50-56 range: { offset, length }設定 | ○ |
| C-53 | Miniflare環境ではRangeオプションなしでgetが呼ばれる | E-05: L50 `&& !isMiniflare`条件 | ○ |
| C-54 | 例外発生時500が返却される | E-05: L120-121 catch句 | ○ |
| C-55 | prefixがパスに正しく適用される | E-05: L20 path.posix.join(prefix, filename) | ○ |

### handleMultiPartUpload.ts（getHandleMultiPartUpload）
| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-56 | マルチパートアップロードが初期化される | E-06: L79-89 createMultipartUpload呼び出し | ○ |
| C-57 | パートがアップロードされる | E-06: L70-76 uploadPart呼び出し | ○ |
| C-58 | マルチパートアップロードが完了する | E-06: L67-69 complete呼び出し | ○ |
| C-59 | 存在しないコレクションでAPIErrorがスローされる | E-06: L26-28 collectionConfig nullチェック | ○ |
| C-60 | カスタムaccessがfalseを返す場合Forbiddenがスローされる | E-06: L31-34 access関数呼び出し | ○ |
| C-61 | コレクションのcreateAccessがfalseを返す場合Forbiddenがスローされる | E-06: L42-47 createAccess呼び出し | ○ |
| C-62 | アクセス制御なしでユーザーがいない場合Forbiddenがスローされる | E-06: L48-51 !req.user判定 | ○ |
| C-63 | アクセス制御なしでユーザーがいる場合許可される | E-06: L48 else if条件不成立で継続 | ○ |
| C-64 | ファイル名がサニタイズされる | E-06: L55 sanitizeFilename呼び出し | ○ |
| C-65 | prefixがfileKeyに適用される | E-06: L54-56 path.posix.join(prefix, sanitizedFilename) | ○ |
| C-66 | collectionConfigがtrueの場合prefixが空になる | E-06: L54 typeof collectionConfig === 'object'条件 | ○ |
| C-67 | contentTypeがマルチパートアップロードに設定される | E-06: L80-83 contentType設定 | ○ |
| C-68 | multipartNumberがNaNの場合完了処理が実行される | E-06: L66 isNaN(multipartNumber)判定 | ○ |
| C-69 | req.payload.collectionsにコレクションがない場合APIErrorがスローされる | E-06: L38-40 collection nullチェック | ○ |
| C-70 | カスタムaccessがtrueを返す場合処理が続行される | E-06: L32 await access成功で継続 | ○ |

### R2ClientUploadHandler.ts
| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-71 | マルチパートアップロードが正常に完了する | E-07: L14-81 handler関数全体 | ○ |
| C-72 | チャンクサイズに基づいてパートが分割される | E-07: L47-55 forループ分割ロジック | ○ |
| C-73 | 最後のパートで完了リクエストが送信される | E-07: L67-78 part === partTotal条件 | ○ |
| C-74 | 初期化fetchが失敗した場合エラーがスローされる | E-07: L37-39 !multipart.ok判定 | ○ |
| C-75 | パートアップロードが失敗した場合エラーがスローされる | E-07: L61-63 !uploaded.ok判定 | ○ |
| C-76 | 完了リクエストが失敗した場合エラーがスローされる | E-07: L73-75 !complete.ok判定 | ○ |
| C-77 | prefixがエンドポイントURLに含まれる | E-07: L18 extra: { prefix = '' } | ○ |
| C-78 | デフォルトチャンクサイズが5MBである | E-07: L18 chunkSize = 5 * 1024 * 1024 | ○ |
| C-79 | カスタムチャンクサイズが適用される | E-07: L18 extra: { chunkSize }の分割代入 | ○ |
| C-80 | 正しいContent-Typeヘッダーが設定される | E-07: L58 'Content-Type': 'application/octet-stream' | ○ |
| C-81 | Content-Lengthヘッダーが設定される | E-07: L57 'Content-Length': String(body.size) | ○ |
| C-82 | 完了時にmultipartNumberパラメータが削除される | E-07: L68 delete params.multipartNumber | ○ |
| C-83 | 完了リクエストのContent-Typeがapplication/jsonである | E-07: L71 'Content-Type': 'application/json' | ○ |
| C-84 | ファイルサイズがチャンクサイズより小さい場合1パートでアップロードされる | E-07: L47 Math.ceil計算で1になる | ○ |
| C-85 | ファイルサイズがチャンクサイズの倍数の場合正しくパート分割される | E-07: L47 Math.ceil計算 | ○ |
| C-86 | formatAdminURLで正しいエンドポイントが生成される | E-07: L28-32 formatAdminURL呼び出し | ○ |
| C-87 | file.sliceで正しいバイト範囲が取得される | E-07: L50-51, L55 bytesStart/bytesEnd計算 | ○ |
| C-88 | 最後のパートのバイト範囲がファイル末尾までである | E-07: L50 Math.min(part * chunkSize, file.size) | ○ |

### types.ts（型定義）
| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-89 | R2Bucket.createMultipartUpload | E-02: L17 インターフェース定義 | ○ |
| C-90 | R2Bucket.delete単一キー | E-02: L18 インターフェース定義 | ○ |
| C-91 | R2Bucket.delete複数キー | E-02: L18 keys: string \| string[] | ○ |
| C-92 | R2Bucket.get | E-02: L19 インターフェース定義 | ○ |
| C-93 | R2Bucket.get rangeオプション | E-02: L10-14 R2GetOptionsにrange定義 | ○ |
| C-94 | R2Bucket.head | E-02: L20 インターフェース定義 | ○ |
| C-95 | R2Bucket.put | E-02: L22-26 インターフェース定義 | ○ |
| C-96 | R2Bucket.put様々な値タイプ | E-02: L24 ArrayBuffer \| Blob \| ReadableStream等 | ○ |
| C-97 | R2Bucket.resumeMultipartUpload | E-02: L27 インターフェース定義 | ○ |
| C-98 | R2MultipartUpload.abort | E-02: L52 インターフェース定義 | ○ |
| C-99 | R2MultipartUpload.complete | E-02: L53 インターフェース定義 | ○ |
| C-100 | R2MultipartUpload.uploadPart | E-02: L56-60 インターフェース定義 | ○ |
| C-101 | R2Object.writeHttpMetadata | E-02: L44 インターフェース定義 | ○ |

### exports/client.ts
| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-102 | R2ClientUploadHandlerがエクスポートされる | E-08: L1 re-export文 | ○ |

## 4) 不足情報（Unknown / Missing）
- **該当なし**：全てのテストケースに対して、ソースコードから直接根拠を確認できました。

## 5) リスクフラグ（レビュー観点）
- **0: 低リスク** - 全てのテストケースがソースコードの実装に基づいており、根拠が明確です。

以下の点は実装確認が推奨されます：
1. **環境依存の動作**: NODE_ENV='development'時のMiniflare対応処理（E-03: L17, E-05: L15, L50, L71-88）
2. **セキュリティ関連**: SVGファイルのCSPヘッダー設定（E-05: L94-97）、ファイル名サニタイズ（E-06: L55）
3. **アクセス制御**: マルチパートアップロードの認証・認可ロジック（E-06: L31-51）
4. **大容量ファイル処理**: 50MB超ファイルのメモリ保護（E-05: L31-33）

## 6) レビュアーチェックリスト（最小）
- [ ] 正常系テストケース（UT-R2S-001〜017）がプラグイン初期化とアダプタ生成をカバーしているか確認
- [ ] アップロード系テストケース（UT-R2S-018〜026、056〜070）がファイルアップロード処理を網羅しているか確認
- [ ] 削除系テストケース（UT-R2S-027〜030）がファイル削除処理を検証しているか確認
- [ ] 静的ファイルハンドラテストケース（UT-R2S-031〜055）がRange処理、キャッシュ、エラーハンドリングを網羅しているか確認
- [ ] クライアントアップロードテストケース（UT-R2S-071〜088）がマルチパートアップロードのフローを検証しているか確認
- [ ] セキュリティ関連テストケース（UT-R2S-039、060〜064）が認証・認可・CSP設定を検証しているか確認
- [ ] 境界値テストケース（UT-R2S-024、029、068、084〜085）が適切な境界条件をテストしているか確認
- [ ] 型定義テストケース（UT-R2S-089〜102）がR2 APIインターフェースの契約を検証するものとして適切か確認
