---
generated_at: 2026-01-30 14:00:00
metrics:
  claims_total: 60
  claims_with_evidence: 58
  claims_without_evidence: 2
confidence_derived: 0.97
---

# 根拠レポート：Microsoft.Bcl.TimeProvider 単体テストケース一覧

## 本レポートについて

### 目的
本レポートは、生成された単体テストケース一覧の信頼性を検証し、人間レビュアーが効率的にレビューできるようにすることを目的としています。

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

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

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

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

---

## 1) サマリー（まず見るところ）
- 総合信頼度（derived）：**0.97**
  - 根拠あり：58 / 60、根拠なし：2
- 優先レビュー（高）
  1. **UT-BTP-058, UT-BTP-059**：内部クラス（DelayState, WaitAsyncState）のテストは#if !NETディレクティブ内にあり、.NET 8以降では存在しない
  2. **競合状態テスト（UT-BTP-060）**：実装上の競合状態処理は確認できるが、テスト実行可能性の検証が必要

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

- E-01: `/Users/tomoka.baba/Work/runtime-main/src/libraries/Microsoft.Bcl.TimeProvider/src/System/Threading/Tasks/TimeProviderTaskExtensions.cs`
- E-02: `/Users/tomoka.baba/Work/runtime-main/src/libraries/Microsoft.Bcl.TimeProvider/src/Microsoft.Bcl.TimeProvider.Forwards.cs`
- E-03: `/Users/tomoka.baba/Work/runtime-main/src/libraries/Common/src/System/TimeProvider.cs`
- E-04: `/Users/tomoka.baba/Work/runtime-main/src/libraries/Common/src/System/Threading/ITimer.cs`
- E-05: `/Users/tomoka.baba/Work/runtime-main/src/libraries/Microsoft.Bcl.TimeProvider/src/Microsoft.Bcl.TimeProvider.csproj`

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

### TimeProviderTaskExtensions.Delay メソッド

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-01 (UT-BTP-001) | TimeProvider.Systemでショートカット処理が行われる | E-01 (Line 54-57: `if (timeProvider == TimeProvider.System) return Task.Delay(delay, cancellationToken);`) | ○ |
| C-02 (UT-BTP-002) | カスタムTimeProviderでCreateTimerが呼ばれる | E-01 (Line 78: `state.Timer = timeProvider.CreateTimer(...)`) | ○ |
| C-03 (UT-BTP-003) | delay=TimeSpan.Zeroで即座に完了 | E-01 (Line 71-74: `if (delay == TimeSpan.Zero) return Task.CompletedTask;`) | ○ |
| C-04 (UT-BTP-004) | delay=InfiniteTimeSpanで無期限待機 | E-01 (Line 61: InfiniteTimeSpanは負値チェックから除外される) | ○ |
| C-05 (UT-BTP-005) | CancellationTokenでキャンセル機能 | E-01 (Line 86-100: `state.Registration = cancellationToken.Register(...)`) | ○ |
| C-06 (UT-BTP-006) | 既にキャンセル済みで即座にキャンセル | E-01 (Line 66-69: `if (cancellationToken.IsCancellationRequested) return Task.FromCanceled(cancellationToken);`) | ○ |
| C-07 (UT-BTP-007) | timeProvider=nullでArgumentNullException | E-01 (Line 59: `ArgumentNullException.ThrowIfNull(timeProvider);`) | ○ |
| C-08 (UT-BTP-008) | 負のdelayでArgumentOutOfRangeException | E-01 (Line 61-64: `if (delay != Timeout.InfiniteTimeSpan && delay < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(delay));`) | ○ |
| C-09 (UT-BTP-009) | TimeSpan.MaxValueでも動作 | E-01 (Line 78-84: CreateTimerに渡される) | ○ |

### TimeProviderTaskExtensions.WaitAsync メソッド

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-10 (UT-BTP-010) | タスク完了時に元タスクが返却 | E-01 (Line 177-187: ContinueWithでタスク完了処理) | ○ |
| C-11 (UT-BTP-011) | 完了済みタスクが即座に返却 | E-01 (Line 144-147: `if (task.IsCompleted) return task;`) | ○ |
| C-12 (UT-BTP-012) | InfiniteTimeSpanかつCancellationTokenなしで元タスク返却 | E-01 (Line 149-152: `if (timeout == Timeout.InfiniteTimeSpan && !cancellationToken.CanBeCanceled) return task;`) | ○ |
| C-13 (UT-BTP-013) | タイムアウト時にTimeoutException | E-01 (Line 170: `state.TrySetException(new TimeoutException());`) | ○ |
| C-14 (UT-BTP-014) | timeout=ZeroでTimeoutException | E-01 (Line 159-161: `if (timeout == TimeSpan.Zero) return Task.FromException(new TimeoutException());`) | ○ |
| C-15 (UT-BTP-015) | CancellationTokenでキャンセル | E-01 (Line 189-197: `state.Registration = cancellationToken.Register(...)`) | ○ |
| C-16 (UT-BTP-016) | 既にキャンセル済みで即座にキャンセル | E-01 (Line 154-157: `if (cancellationToken.IsCancellationRequested) return Task.FromCanceled(cancellationToken);`) | ○ |
| C-17 (UT-BTP-017) | Faulted状態の例外伝播 | E-01 (Line 181: `if (t.IsFaulted) state.TrySetException(t.Exception.InnerExceptions);`) | ○ |
| C-18 (UT-BTP-018) | Canceled状態の伝播 | E-01 (Line 182: `else if (t.IsCanceled) state.TrySetCanceled();`) | ○ |
| C-19 (UT-BTP-019) | task=nullでArgumentNullException | E-01 (Line 135: `ArgumentNullException.ThrowIfNull(task);`) | ○ |
| C-20 (UT-BTP-020) | timeProvider=nullでArgumentNullException | E-01 (Line 142: `ArgumentNullException.ThrowIfNull(timeProvider);`) | ○ |
| C-21 (UT-BTP-021) | 負のtimeoutでArgumentOutOfRangeException | E-01 (Line 137-140: `if (timeout != Timeout.InfiniteTimeSpan && timeout < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(timeout));`) | ○ |

### TimeProviderTaskExtensions.WaitAsync<TResult> メソッド

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-22 (UT-BTP-022) | ジェネリック版でタスク結果が返却 | E-01 (Line 224-228: `await ((Task)task).WaitAsync(...); return task.Result;`) | ○ |
| C-23 (UT-BTP-023) | ジェネリック版でタイムアウト時にTimeoutException | E-01 (Line 226: 非ジェネリック版WaitAsyncを呼び出し) | ○ |
| C-24 (UT-BTP-024) | ジェネリック版でキャンセル時にTaskCanceledException | E-01 (Line 226: 非ジェネリック版WaitAsyncを呼び出し) | ○ |

### TimeProviderTaskExtensions.CreateCancellationTokenSource メソッド

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-25 (UT-BTP-025) | TimeProvider.Systemで指定時間後にキャンセル | E-01 (Line 259-261: `if (timeProvider == TimeProvider.System) return new CancellationTokenSource(delay);`) | ○ |
| C-26 (UT-BTP-026) | カスタムTimeProviderでCreateTimer使用 | E-01 (Line 266-273: `ITimer timer = timeProvider.CreateTimer(...)`) | ○ |
| C-27 (UT-BTP-027) | InfiniteTimeSpanでキャンセルされない | E-01 (Line 254-257: InfiniteTimeSpanは負値チェックから除外) | ○ |
| C-28 (UT-BTP-028) | CTSのDisposeでタイマーもDispose | E-01 (Line 275: `cts.Token.Register(static t => ((ITimer)t!).Dispose(), timer);`) | ○ |
| C-29 (UT-BTP-029) | timeProvider=nullでArgumentNullException | E-01 (Line 252: `ArgumentNullException.ThrowIfNull(timeProvider);`) | ○ |
| C-30 (UT-BTP-030) | 負のdelayでArgumentOutOfRangeException | E-01 (Line 254-257: `if (delay != Timeout.InfiniteTimeSpan && delay < TimeSpan.Zero) throw new ArgumentOutOfRangeException(nameof(delay));`) | ○ |

### TimeProvider クラス

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-31 (UT-BTP-031) | SystemTimeProviderでDateTimeOffset.UtcNow | E-03 (Line 38: `public virtual DateTimeOffset GetUtcNow() => DateTimeOffset.UtcNow;`) | ○ |
| C-32 (UT-BTP-032) | カスタム実装で指定時刻返却 | E-03 (Line 38: virtualメソッドなのでオーバーライド可能) | ○ |
| C-33 (UT-BTP-033) | UTCオフセットが正しく適用 | E-03 (Line 47-71: GetLocalNow実装) | ○ |
| C-34 (UT-BTP-034) | オフセット0でUTC時刻がそのまま | E-03 (Line 60-63: `if (offset.Ticks is 0) return utcDateTime;`) | ○ |
| C-35 (UT-BTP-035) | MaxValueを超える場合クランプ | E-03 (Line 66-69: `if ((ulong)localTicks > (ulong)s_maxDateTicks) localTicks = ... s_maxDateTicks;`) | ○ |
| C-36 (UT-BTP-036) | MinValueを下回る場合クランプ | E-03 (Line 68: `localTicks = localTicks < s_minDateTicks ? s_minDateTicks : s_maxDateTicks;`) | ○ |
| C-37 (UT-BTP-037) | LocalTimeZone=nullでInvalidOperationException | E-03 (Line 51-58: `if (zoneInfo is null) throw new InvalidOperationException(...)`) | ○ |
| C-38 (UT-BTP-038) | SystemTimeProviderでTimeZoneInfo.Local | E-03 (Line 80: `public virtual TimeZoneInfo LocalTimeZone => TimeZoneInfo.Local;`) | ○ |
| C-39 (UT-BTP-039) | SystemTimeProviderでStopwatch.Frequency | E-03 (Line 88: `public virtual long TimestampFrequency => Stopwatch.Frequency;`) | ○ |
| C-40 (UT-BTP-040) | TimestampFrequency<=0でInvalidOperationException | E-03 (Line 108-115: `if (timestampFrequency <= 0) throw new InvalidOperationException(...)`) | ○ |
| C-41 (UT-BTP-041) | SystemTimeProviderでStopwatch.GetTimestamp() | E-03 (Line 97: `public virtual long GetTimestamp() => Stopwatch.GetTimestamp();`) | ○ |
| C-42 (UT-BTP-042) | 連続呼び出しで単調増加 | E-03 (Stopwatch.GetTimestamp()の仕様に基づく) | ○ |
| C-43 (UT-BTP-043) | 2つのタイムスタンプ間の経過時間計算 | E-03 (Line 105-118: GetElapsedTime実装) | ○ |
| C-44 (UT-BTP-044) | 同一タイムスタンプでTimeSpan.Zero | E-03 (Line 117: 計算式 `(endingTimestamp - startingTimestamp) * ...` で差分0ならZero) | ○ |
| C-45 (UT-BTP-045) | 逆順タイムスタンプで負のTimeSpan | E-03 (Line 117: 計算式から負の値が算出される) | ○ |
| C-46 (UT-BTP-046) | 単一引数GetElapsedTime | E-03 (Line 125: `public TimeSpan GetElapsedTime(long startingTimestamp) => GetElapsedTime(startingTimestamp, GetTimestamp());`) | ○ |
| C-47 (UT-BTP-047) | タイマーがdueTime後にコールバック呼び出し | E-03 (Line 160-165: CreateTimer実装) | ○ |
| C-48 (UT-BTP-048) | タイマーがperiodで繰り返し | E-03 (Line 160-165: CreateTimer実装、periodパラメータ) | ○ |
| C-49 (UT-BTP-049) | dueTime=InfiniteTimeSpanでタイマー不発火 | E-03 (Line 145-146: ドキュメントコメントに記載) | ○ |
| C-50 (UT-BTP-050) | タイマーDisposeでコールバック停止 | E-03 (Line 219: `public void Dispose() => _timer.Dispose();`) | ○ |
| C-51 (UT-BTP-051) | callback=nullでArgumentNullException | E-03 (Line 162: `ArgumentNullException.ThrowIfNull(callback);`) | ○ |

### ITimer インターフェース

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-52 (UT-BTP-052) | Changeでタイマー間隔変更 | E-03 (Line 207-217: `public bool Change(TimeSpan dueTime, TimeSpan period)`) | ○ |
| C-53 (UT-BTP-053) | Dispose後のChangeがfalse | E-03 (Line 209-216: `catch (ObjectDisposedException) return false;`) | ○ |
| C-54 (UT-BTP-054) | 同期Dispose | E-03 (Line 219: `public void Dispose() => _timer.Dispose();`) | ○ |
| C-55 (UT-BTP-055) | 非同期DisposeAsync | E-03 (Line 225-229: DisposeAsync実装) | ○ |

### TimeProvider.System プロパティ

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-56 (UT-BTP-056) | TimeProvider.SystemがSystemTimeProviderを返す | E-03 (Line 21: `public static TimeProvider System { get; } = new SystemTimeProvider();`) | ○ |
| C-57 (UT-BTP-057) | TimeProvider.Systemが同一インスタンス | E-03 (Line 21: staticプロパティとして1回だけ初期化) | ○ |

### 内部クラス

| Claim ID | 主張 | Evidence | 状態 |
|---|---|---|---|
| C-58 (UT-BTP-058) | DelayStateのコンストラクタ | E-01 (Line 16-26: #if !NET内) | △ |
| C-59 (UT-BTP-059) | WaitAsyncStateのコンストラクタ | E-01 (Line 28-39: #if !NET内) | △ |
| C-60 (UT-BTP-060) | 競合状態でリソース解放 | E-01 (Line 102-114: レースコンディション対策コメントと実装) | ○ |

## 4) 不足情報（Unknown / Missing）
- **UT-BTP-058, UT-BTP-059**：DelayStateおよびWaitAsyncStateはprivate sealed classであり、`#if !NET`ディレクティブ内に定義されている。.NET 8以降ではこれらのクラスは存在せず、代わりにフレームワーク組み込みの実装が使用される。テスト対象として含めるかはターゲットフレームワークに依存する。
  - 候補：.NET Framework / .NET Standard 2.0向けテストとして実施 / テスト対象外として除外

## 5) リスクフラグ（レビュー観点）
- **0: 低リスク** - ほとんどのテストケースはソースコードから直接導出可能
- **1: 中リスク** - 競合状態テスト（UT-BTP-060）は実行環境依存の可能性あり
- **1: 中リスク** - 内部クラステスト（UT-BTP-058, 059）は条件付きコンパイル対象

## 6) レビュアーチェックリスト（最小）
- [ ] TimeProviderTaskExtensions.Delayの全分岐パス（正常/キャンセル/タイムアウト）がカバーされているか
- [ ] WaitAsyncの非ジェネリック版とジェネリック版の両方がテストされているか
- [ ] CreateCancellationTokenSourceでTimeProvider.Systemとカスタム実装の両方がテストされているか
- [ ] TimeProviderの各virtualメソッド（GetUtcNow, LocalTimeZone, TimestampFrequency, GetTimestamp, CreateTimer）のデフォルト実装とオーバーライドがテストされているか
- [ ] ITimer.Change/Dispose/DisposeAsyncの動作がテストされているか
- [ ] 境界値（TimeSpan.Zero, Timeout.InfiniteTimeSpan, DateTime.MaxValue/MinValue）が網羅されているか
- [ ] 引数チェック（null, 負の値）が網羅されているか
- [ ] 条件付きコンパイル（#if !NET）の対象クラスをテスト対象に含めるか方針決定済みか
