@@ -164,6 +164,87 @@ public void OnStateChanged_FiresOnStartAndNext()
164164
165165 Assert . Equal ( 3 , count ) ;
166166 }
167+
168+ [ Fact ]
169+ public void TotalChapters_ReturnsExpectedCount ( )
170+ {
171+ var svc = new TutorialService ( ) ;
172+ Assert . Equal ( TutorialContent . Chapters . Count , svc . TotalChapters ) ;
173+ }
174+
175+ [ Fact ]
176+ public void TotalSteps_ReturnsAllStepsAcrossChapters ( )
177+ {
178+ var svc = new TutorialService ( ) ;
179+ var expected = TutorialContent . Chapters . Sum ( c => c . Steps . Count ) ;
180+ Assert . Equal ( expected , svc . TotalSteps ) ;
181+ }
182+
183+ [ Fact ]
184+ public void GlobalStepIndex_TracksPositionAcrossChapters ( )
185+ {
186+ var svc = new TutorialService ( ) ;
187+ svc . StartTutorial ( ) ;
188+ Assert . Equal ( 0 , svc . GlobalStepIndex ) ;
189+
190+ // Advance through first chapter
191+ var stepsInFirst = svc . CurrentChapter ! . Steps . Count ;
192+ for ( int i = 0 ; i < stepsInFirst ; i ++ )
193+ svc . NextStep ( ) ;
194+
195+ // Should now be at the first step of the second chapter
196+ Assert . Equal ( stepsInFirst , svc . GlobalStepIndex ) ;
197+ }
198+
199+ [ Fact ]
200+ public void OverallProgressPercent_ZeroWhenNoneCompleted ( )
201+ {
202+ var svc = new TutorialService ( ) ;
203+ Assert . Equal ( 0 , svc . OverallProgressPercent ) ;
204+ }
205+
206+ [ Fact ]
207+ public void OverallProgressPercent_IncreasesOnChapterCompletion ( )
208+ {
209+ var svc = new TutorialService ( ) ;
210+ svc . StartTutorial ( ) ;
211+
212+ // Complete first chapter
213+ var stepsInFirst = svc . CurrentChapter ! . Steps . Count ;
214+ for ( int i = 0 ; i < stepsInFirst ; i ++ )
215+ svc . NextStep ( ) ;
216+
217+ Assert . True ( svc . OverallProgressPercent > 0 ) ;
218+ Assert . True ( svc . OverallProgressPercent <= 100 ) ;
219+ }
220+
221+ [ Fact ]
222+ public void OverallProgressPercent_100WhenAllCompleted ( )
223+ {
224+ var svc = new TutorialService ( ) ;
225+ svc . StartTutorial ( ) ;
226+
227+ // Complete all chapters
228+ int totalSteps = TutorialContent . Chapters . Sum ( c => c . Steps . Count ) ;
229+ for ( int i = 0 ; i < totalSteps ; i ++ )
230+ svc . NextStep ( ) ;
231+
232+ Assert . Equal ( 100 , svc . OverallProgressPercent ) ;
233+ }
234+
235+ [ Fact ]
236+ public void CompletedChapterCount_TracksCompletions ( )
237+ {
238+ var svc = new TutorialService ( ) ;
239+ Assert . Equal ( 0 , svc . CompletedChapterCount ) ;
240+
241+ svc . StartTutorial ( ) ;
242+ var stepsInFirst = svc . CurrentChapter ! . Steps . Count ;
243+ for ( int i = 0 ; i < stepsInFirst ; i ++ )
244+ svc . NextStep ( ) ;
245+
246+ Assert . Equal ( 1 , svc . CompletedChapterCount ) ;
247+ }
167248}
168249
169250public class TutorialContentTests
@@ -225,4 +306,17 @@ public void Content_HasExpectedChapterCount()
225306 {
226307 Assert . Equal ( 8 , TutorialContent . Chapters . Count ) ;
227308 }
309+
310+ [ Fact ]
311+ public void TipsAreNotEmpty_WhenPresent ( )
312+ {
313+ foreach ( var chapter in TutorialContent . Chapters )
314+ {
315+ foreach ( var step in chapter . Steps . Where ( s => s . Tip != null ) )
316+ {
317+ Assert . False ( string . IsNullOrWhiteSpace ( step . Tip ) ,
318+ $ "Step { step . Id } in { chapter . Id } has a non-null but empty Tip") ;
319+ }
320+ }
321+ }
228322}
0 commit comments