sklears_core/
tutorial_system.rs

1use serde::{Deserialize, Serialize};
2use std::collections::{HashMap, HashSet};
3
4use crate::api_data_structures::{TraitInfo, TypeInfo};
5
6#[derive(Debug, Clone, Serialize, Deserialize)]
7pub struct TutorialSystem {
8    pub tutorials: Vec<Tutorial>,
9    pub learning_paths: Vec<LearningPath>,
10    pub progress_tracker: ProgressTracker,
11    pub assessment_engine: AssessmentEngine,
12    pub config: TutorialConfig,
13}
14
15#[derive(Debug, Clone, Serialize, Deserialize)]
16pub struct TutorialConfig {
17    pub difficulty_levels: Vec<DifficultyLevel>,
18    pub enable_interactive_examples: bool,
19    pub enable_progress_tracking: bool,
20    pub enable_assessments: bool,
21    pub max_tutorial_duration: u32,
22    pub code_execution_timeout: u32,
23    pub personalization_enabled: bool,
24}
25
26impl Default for TutorialConfig {
27    fn default() -> Self {
28        Self {
29            difficulty_levels: vec![
30                DifficultyLevel::Beginner,
31                DifficultyLevel::Intermediate,
32                DifficultyLevel::Advanced,
33            ],
34            enable_interactive_examples: true,
35            enable_progress_tracking: true,
36            enable_assessments: true,
37            max_tutorial_duration: 3600,
38            code_execution_timeout: 30,
39            personalization_enabled: true,
40        }
41    }
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
45pub enum DifficultyLevel {
46    Beginner,
47    Intermediate,
48    Advanced,
49    Expert,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct Tutorial {
54    pub id: String,
55    pub title: String,
56    pub description: String,
57    pub difficulty: DifficultyLevel,
58    pub duration_minutes: u32,
59    pub prerequisites: Vec<String>,
60    pub learning_objectives: Vec<String>,
61    pub sections: Vec<TutorialSection>,
62    pub assessment: Option<Assessment>,
63    pub metadata: TutorialMetadata,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct TutorialMetadata {
68    pub author: String,
69    pub created_at: chrono::DateTime<chrono::Utc>,
70    pub updated_at: chrono::DateTime<chrono::Utc>,
71    pub version: String,
72    pub tags: Vec<String>,
73    pub category: TutorialCategory,
74    pub language: String,
75    pub popularity_score: f64,
76}
77
78#[derive(Debug, Clone, Serialize, Deserialize)]
79pub enum TutorialCategory {
80    GettingStarted,
81    CoreConcepts,
82    AdvancedFeatures,
83    BestPractices,
84    RealWorldExamples,
85    Performance,
86    Testing,
87    Integration,
88}
89
90#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct TutorialSection {
92    pub id: String,
93    pub title: String,
94    pub content: SectionContent,
95    pub interactive_elements: Vec<InteractiveElement>,
96    pub estimated_duration: u32,
97    pub completion_criteria: CompletionCriteria,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub enum SectionContent {
102    Text {
103        content: String,
104        format: ContentFormat,
105    },
106    Code {
107        content: String,
108        language: String,
109        runnable: bool,
110    },
111    Exercise {
112        description: String,
113        starter_code: String,
114        solution: String,
115    },
116    Quiz {
117        questions: Vec<QuizQuestion>,
118    },
119    Video {
120        url: String,
121        duration: u32,
122        transcript: Option<String>,
123    },
124    Interactive {
125        component_type: String,
126        config: serde_json::Value,
127    },
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub enum ContentFormat {
132    Markdown,
133    Html,
134    PlainText,
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct InteractiveElement {
139    pub element_type: InteractiveElementType,
140    pub config: serde_json::Value,
141    pub validation_rules: Vec<ValidationRule>,
142}
143
144#[derive(Debug, Clone, Serialize, Deserialize)]
145pub enum InteractiveElementType {
146    CodeEditor,
147    LiveExample,
148    Quiz,
149    Diagram,
150    Simulation,
151    Playground,
152}
153
154#[derive(Debug, Clone, Serialize, Deserialize)]
155pub struct ValidationRule {
156    pub rule_type: ValidationType,
157    pub condition: String,
158    pub error_message: String,
159    pub hint: Option<String>,
160}
161
162#[derive(Debug, Clone, Serialize, Deserialize)]
163pub enum ValidationType {
164    Compilation,
165    Runtime,
166    Output,
167    Style,
168    Performance,
169}
170
171#[derive(Debug, Clone, Serialize, Deserialize)]
172pub struct CompletionCriteria {
173    pub required_interactions: Vec<String>,
174    pub minimum_score: Option<f64>,
175    pub time_spent_minimum: Option<u32>,
176    pub code_execution_required: bool,
177}
178
179#[derive(Debug, Clone, Serialize, Deserialize)]
180pub struct LearningPath {
181    pub id: String,
182    pub title: String,
183    pub description: String,
184    pub difficulty: DifficultyLevel,
185    pub estimated_hours: u32,
186    pub tutorial_sequence: Vec<String>,
187    pub completion_rewards: Vec<String>,
188    pub prerequisites: Vec<String>,
189}
190
191#[derive(Debug, Clone, Serialize, Deserialize)]
192pub struct ProgressTracker {
193    pub user_progress: HashMap<String, UserProgress>,
194    pub global_statistics: GlobalStatistics,
195}
196
197#[derive(Debug, Clone, Serialize, Deserialize)]
198pub struct UserProgress {
199    pub user_id: String,
200    pub completed_tutorials: HashSet<String>,
201    pub current_tutorial: Option<String>,
202    pub current_section: Option<String>,
203    pub completion_percentage: f64,
204    pub time_spent: u32,
205    pub assessment_scores: HashMap<String, f64>,
206    pub achievements: Vec<Achievement>,
207    pub learning_preferences: LearningPreferences,
208}
209
210#[derive(Debug, Clone, Serialize, Deserialize)]
211pub struct GlobalStatistics {
212    pub total_users: usize,
213    pub tutorial_completion_rates: HashMap<String, f64>,
214    pub average_scores: HashMap<String, f64>,
215    pub popular_tutorials: Vec<String>,
216    pub common_challenges: Vec<String>,
217}
218
219#[derive(Debug, Clone, Serialize, Deserialize)]
220pub struct Achievement {
221    pub id: String,
222    pub title: String,
223    pub description: String,
224    pub icon: String,
225    pub earned_at: chrono::DateTime<chrono::Utc>,
226    pub rarity: AchievementRarity,
227}
228
229#[derive(Debug, Clone, Serialize, Deserialize)]
230pub enum AchievementRarity {
231    Common,
232    Uncommon,
233    Rare,
234    Epic,
235    Legendary,
236}
237
238#[derive(Debug, Clone, Serialize, Deserialize)]
239pub struct LearningPreferences {
240    pub preferred_difficulty: DifficultyLevel,
241    pub learning_pace: LearningPace,
242    pub content_types: Vec<ContentType>,
243    pub reminder_frequency: ReminderFrequency,
244}
245
246#[derive(Debug, Clone, Serialize, Deserialize)]
247pub enum LearningPace {
248    Slow,
249    Normal,
250    Fast,
251    SelfPaced,
252}
253
254#[derive(Debug, Clone, Serialize, Deserialize)]
255pub enum ContentType {
256    Text,
257    Video,
258    Interactive,
259    Code,
260    Exercises,
261}
262
263#[derive(Debug, Clone, Serialize, Deserialize)]
264pub enum ReminderFrequency {
265    Never,
266    Daily,
267    Weekly,
268    Monthly,
269}
270
271#[derive(Debug, Clone, Serialize, Deserialize)]
272pub struct AssessmentEngine {
273    pub assessments: HashMap<String, Assessment>,
274    pub question_bank: Vec<QuizQuestion>,
275    pub scoring_algorithms: HashMap<String, ScoringAlgorithm>,
276}
277
278#[derive(Debug, Clone, Serialize, Deserialize)]
279pub struct Assessment {
280    pub id: String,
281    pub title: String,
282    pub description: String,
283    pub questions: Vec<String>,
284    pub time_limit: Option<u32>,
285    pub passing_score: f64,
286    pub max_attempts: Option<u32>,
287    pub feedback_mode: FeedbackMode,
288}
289
290#[derive(Debug, Clone, Serialize, Deserialize)]
291pub enum FeedbackMode {
292    Immediate,
293    EndOfAssessment,
294    Manual,
295}
296
297#[derive(Debug, Clone, Serialize, Deserialize)]
298pub struct QuizQuestion {
299    pub id: String,
300    pub question_type: QuestionType,
301    pub content: String,
302    pub options: Vec<String>,
303    pub correct_answer: String,
304    pub explanation: String,
305    pub difficulty: DifficultyLevel,
306    pub tags: Vec<String>,
307    pub points: u32,
308}
309
310#[derive(Debug, Clone, Serialize, Deserialize)]
311pub enum QuestionType {
312    MultipleChoice,
313    TrueFalse,
314    ShortAnswer,
315    CodeCompletion,
316    CodeReview,
317    Matching,
318}
319
320#[derive(Debug, Clone, Serialize, Deserialize)]
321pub struct ScoringAlgorithm {
322    pub name: String,
323    pub description: String,
324    pub formula: String,
325    pub parameters: HashMap<String, f64>,
326}
327
328pub struct TutorialBuilder {
329    tutorial: Tutorial,
330    current_section: Option<TutorialSection>,
331}
332
333impl TutorialBuilder {
334    pub fn new(id: String, title: String) -> Self {
335        Self {
336            tutorial: Tutorial {
337                id,
338                title,
339                description: String::new(),
340                difficulty: DifficultyLevel::Beginner,
341                duration_minutes: 0,
342                prerequisites: Vec::new(),
343                learning_objectives: Vec::new(),
344                sections: Vec::new(),
345                assessment: None,
346                metadata: TutorialMetadata {
347                    author: String::new(),
348                    created_at: chrono::Utc::now(),
349                    updated_at: chrono::Utc::now(),
350                    version: "1.0.0".to_string(),
351                    tags: Vec::new(),
352                    category: TutorialCategory::GettingStarted,
353                    language: "en".to_string(),
354                    popularity_score: 0.0,
355                },
356            },
357            current_section: None,
358        }
359    }
360
361    pub fn description(mut self, description: String) -> Self {
362        self.tutorial.description = description;
363        self
364    }
365
366    pub fn difficulty(mut self, difficulty: DifficultyLevel) -> Self {
367        self.tutorial.difficulty = difficulty;
368        self
369    }
370
371    pub fn duration(mut self, minutes: u32) -> Self {
372        self.tutorial.duration_minutes = minutes;
373        self
374    }
375
376    pub fn prerequisite(mut self, prerequisite: String) -> Self {
377        self.tutorial.prerequisites.push(prerequisite);
378        self
379    }
380
381    pub fn learning_objective(mut self, objective: String) -> Self {
382        self.tutorial.learning_objectives.push(objective);
383        self
384    }
385
386    pub fn author(mut self, author: String) -> Self {
387        self.tutorial.metadata.author = author;
388        self
389    }
390
391    pub fn category(mut self, category: TutorialCategory) -> Self {
392        self.tutorial.metadata.category = category;
393        self
394    }
395
396    pub fn tag(mut self, tag: String) -> Self {
397        self.tutorial.metadata.tags.push(tag);
398        self
399    }
400
401    pub fn section(mut self, id: String, title: String) -> Self {
402        if let Some(section) = self.current_section.take() {
403            self.tutorial.sections.push(section);
404        }
405
406        self.current_section = Some(TutorialSection {
407            id,
408            title,
409            content: SectionContent::Text {
410                content: String::new(),
411                format: ContentFormat::Markdown,
412            },
413            interactive_elements: Vec::new(),
414            estimated_duration: 0,
415            completion_criteria: CompletionCriteria {
416                required_interactions: Vec::new(),
417                minimum_score: None,
418                time_spent_minimum: None,
419                code_execution_required: false,
420            },
421        });
422
423        self
424    }
425
426    pub fn text_content(mut self, content: String, format: ContentFormat) -> Self {
427        if let Some(ref mut section) = self.current_section {
428            section.content = SectionContent::Text { content, format };
429        }
430        self
431    }
432
433    pub fn code_content(mut self, content: String, language: String, runnable: bool) -> Self {
434        if let Some(ref mut section) = self.current_section {
435            section.content = SectionContent::Code {
436                content,
437                language,
438                runnable,
439            };
440        }
441        self
442    }
443
444    pub fn exercise(mut self, description: String, starter_code: String, solution: String) -> Self {
445        if let Some(ref mut section) = self.current_section {
446            section.content = SectionContent::Exercise {
447                description,
448                starter_code,
449                solution,
450            };
451        }
452        self
453    }
454
455    pub fn interactive_element(
456        mut self,
457        element_type: InteractiveElementType,
458        config: serde_json::Value,
459    ) -> Self {
460        if let Some(ref mut section) = self.current_section {
461            section.interactive_elements.push(InteractiveElement {
462                element_type,
463                config,
464                validation_rules: Vec::new(),
465            });
466        }
467        self
468    }
469
470    pub fn section_duration(mut self, minutes: u32) -> Self {
471        if let Some(ref mut section) = self.current_section {
472            section.estimated_duration = minutes;
473        }
474        self
475    }
476
477    pub fn completion_criteria(mut self, criteria: CompletionCriteria) -> Self {
478        if let Some(ref mut section) = self.current_section {
479            section.completion_criteria = criteria;
480        }
481        self
482    }
483
484    pub fn assessment(mut self, assessment: Assessment) -> Self {
485        self.tutorial.assessment = Some(assessment);
486        self
487    }
488
489    pub fn build(mut self) -> Tutorial {
490        if let Some(section) = self.current_section.take() {
491            self.tutorial.sections.push(section);
492        }
493        self.tutorial.metadata.updated_at = chrono::Utc::now();
494        self.tutorial
495    }
496}
497
498impl TutorialSystem {
499    pub fn new(config: TutorialConfig) -> Self {
500        Self {
501            tutorials: Vec::new(),
502            learning_paths: Vec::new(),
503            progress_tracker: ProgressTracker {
504                user_progress: HashMap::new(),
505                global_statistics: GlobalStatistics {
506                    total_users: 0,
507                    tutorial_completion_rates: HashMap::new(),
508                    average_scores: HashMap::new(),
509                    popular_tutorials: Vec::new(),
510                    common_challenges: Vec::new(),
511                },
512            },
513            assessment_engine: AssessmentEngine {
514                assessments: HashMap::new(),
515                question_bank: Vec::new(),
516                scoring_algorithms: HashMap::new(),
517            },
518            config,
519        }
520    }
521
522    pub fn add_tutorial(&mut self, tutorial: Tutorial) {
523        self.tutorials.push(tutorial);
524    }
525
526    pub fn create_learning_path(&mut self, path: LearningPath) {
527        self.learning_paths.push(path);
528    }
529
530    pub fn generate_tutorial_from_trait(&self, trait_info: &TraitInfo) -> Tutorial {
531        TutorialBuilder::new(
532            format!("trait_{}", trait_info.name),
533            format!("Understanding the {} Trait", trait_info.name)
534        )
535        .description(format!("Learn how to use and implement the {} trait in your Rust code", trait_info.name))
536        .difficulty(DifficultyLevel::Intermediate)
537        .duration(30)
538        .learning_objective(format!("Understand the purpose and usage of {}", trait_info.name))
539        .learning_objective("Implement the trait in custom types".to_string())
540        .learning_objective("Use trait methods effectively".to_string())
541        .category(TutorialCategory::CoreConcepts)
542        .tag("traits".to_string())
543        .tag("rust".to_string())
544        .section("introduction".to_string(), "Introduction".to_string())
545        .text_content(
546            format!("The {} trait is a fundamental concept in Rust that allows you to define shared behavior across different types.\n\n{}",
547                trait_info.name, trait_info.description),
548            ContentFormat::Markdown
549        )
550        .section_duration(5)
551        .section("implementation".to_string(), "Implementation Guide".to_string())
552        .code_content(
553            self.generate_trait_implementation_example(trait_info),
554            "rust".to_string(),
555            true
556        )
557        .interactive_element(
558            InteractiveElementType::CodeEditor,
559            serde_json::json!({
560                "template": self.generate_trait_template(trait_info),
561                "validation": "compilation"
562            })
563        )
564        .section_duration(15)
565        .section("examples".to_string(), "Practical Examples".to_string())
566        .text_content(
567            "Let's explore some real-world examples of using this trait:".to_string(),
568            ContentFormat::Markdown
569        )
570        .section_duration(10)
571        .build()
572    }
573
574    fn generate_trait_implementation_example(&self, trait_info: &TraitInfo) -> String {
575        format!(
576            "// Example implementation of {}\n\
577             struct MyStruct {{\n    \
578                 // Your fields here\n\
579             }}\n\n\
580             impl {} for MyStruct {{\n    \
581                 // Implement required methods\n\
582             }}",
583            trait_info.name, trait_info.name
584        )
585    }
586
587    fn generate_trait_template(&self, trait_info: &TraitInfo) -> String {
588        format!(
589            "// TODO: Implement {} for your custom type\n\
590             struct YourType {{\n    \
591                 // Add your fields\n\
592             }}\n\n\
593             impl {} for YourType {{\n    \
594                 // Implement the required methods\n\
595             }}",
596            trait_info.name, trait_info.name
597        )
598    }
599
600    pub fn generate_tutorial_from_type(&self, type_info: &TypeInfo) -> Tutorial {
601        TutorialBuilder::new(
602            format!("type_{}", type_info.name),
603            format!("Working with {} Type", type_info.name),
604        )
605        .description(format!(
606            "Learn how to use the {} type effectively",
607            type_info.name
608        ))
609        .difficulty(DifficultyLevel::Beginner)
610        .duration(20)
611        .learning_objective(format!("Understand the {} type", type_info.name))
612        .learning_objective("Create and manipulate instances".to_string())
613        .category(TutorialCategory::CoreConcepts)
614        .tag("types".to_string())
615        .tag("rust".to_string())
616        .section("overview".to_string(), "Type Overview".to_string())
617        .text_content(
618            format!(
619                "{}\n\n**Type signature**: `{:?}`",
620                type_info.description, type_info.kind
621            ),
622            ContentFormat::Markdown,
623        )
624        .section_duration(10)
625        .section("usage".to_string(), "Usage Examples".to_string())
626        .code_content(
627            self.generate_type_usage_example(type_info),
628            "rust".to_string(),
629            true,
630        )
631        .section_duration(10)
632        .build()
633    }
634
635    fn generate_type_usage_example(&self, type_info: &TypeInfo) -> String {
636        format!(
637            "// Example usage of {}\n\
638             let instance = {}::new();\n\
639             // Use the instance...",
640            type_info.name, type_info.name
641        )
642    }
643
644    pub fn get_recommended_tutorials(&self, user_id: &str) -> Vec<&Tutorial> {
645        if let Some(progress) = self.progress_tracker.user_progress.get(user_id) {
646            self.tutorials
647                .iter()
648                .filter(|tutorial| {
649                    !progress.completed_tutorials.contains(&tutorial.id)
650                        && self.meets_prerequisites(tutorial, progress)
651                })
652                .collect()
653        } else {
654            self.tutorials
655                .iter()
656                .filter(|tutorial| tutorial.prerequisites.is_empty())
657                .collect()
658        }
659    }
660
661    fn meets_prerequisites(&self, tutorial: &Tutorial, progress: &UserProgress) -> bool {
662        tutorial
663            .prerequisites
664            .iter()
665            .all(|prereq| progress.completed_tutorials.contains(prereq))
666    }
667
668    pub fn start_tutorial(&mut self, user_id: String, tutorial_id: String) -> Result<(), String> {
669        if !self.tutorials.iter().any(|t| t.id == tutorial_id) {
670            return Err("Tutorial not found".to_string());
671        }
672
673        let user_id_clone = user_id.clone();
674        let progress = self
675            .progress_tracker
676            .user_progress
677            .entry(user_id)
678            .or_insert_with(|| UserProgress {
679                user_id: user_id_clone,
680                completed_tutorials: HashSet::new(),
681                current_tutorial: None,
682                current_section: None,
683                completion_percentage: 0.0,
684                time_spent: 0,
685                assessment_scores: HashMap::new(),
686                achievements: Vec::new(),
687                learning_preferences: LearningPreferences {
688                    preferred_difficulty: DifficultyLevel::Beginner,
689                    learning_pace: LearningPace::Normal,
690                    content_types: vec![ContentType::Text, ContentType::Code],
691                    reminder_frequency: ReminderFrequency::Weekly,
692                },
693            });
694
695        progress.current_tutorial = Some(tutorial_id);
696        progress.current_section = None;
697        progress.completion_percentage = 0.0;
698
699        Ok(())
700    }
701
702    pub fn complete_section(
703        &mut self,
704        user_id: &str,
705        tutorial_id: &str,
706        _section_id: &str,
707    ) -> Result<(), String> {
708        let progress = self
709            .progress_tracker
710            .user_progress
711            .get_mut(user_id)
712            .ok_or("User not found")?;
713
714        if progress.current_tutorial.as_ref() != Some(&tutorial_id.to_string()) {
715            return Err("Tutorial not in progress".to_string());
716        }
717
718        let tutorial_info = self
719            .tutorials
720            .iter()
721            .find(|t| t.id == tutorial_id)
722            .map(|t| (t.sections.len(), t.title.clone(), t.difficulty.clone()));
723
724        if let Some((total_sections, title, difficulty)) = tutorial_info {
725            let completed_sections = progress.completed_tutorials.len();
726            progress.completion_percentage =
727                (completed_sections as f64 / total_sections as f64) * 100.0;
728
729            if progress.completion_percentage >= 100.0 {
730                progress.completed_tutorials.insert(tutorial_id.to_string());
731                progress.current_tutorial = None;
732                progress.current_section = None;
733
734                self.award_completion_achievement_info(user_id, tutorial_id, &title, &difficulty);
735            }
736        }
737
738        Ok(())
739    }
740
741    fn award_completion_achievement_info(
742        &mut self,
743        user_id: &str,
744        tutorial_id: &str,
745        title: &str,
746        difficulty: &DifficultyLevel,
747    ) {
748        if let Some(progress) = self.progress_tracker.user_progress.get_mut(user_id) {
749            let achievement = Achievement {
750                id: format!("completed_{}", tutorial_id),
751                title: format!("Completed: {}", title),
752                description: format!("Successfully completed the {} tutorial", title),
753                icon: "🎓".to_string(),
754                earned_at: chrono::Utc::now(),
755                rarity: match difficulty {
756                    DifficultyLevel::Beginner => AchievementRarity::Common,
757                    DifficultyLevel::Intermediate => AchievementRarity::Uncommon,
758                    DifficultyLevel::Advanced => AchievementRarity::Rare,
759                    DifficultyLevel::Expert => AchievementRarity::Epic,
760                },
761            };
762            progress.achievements.push(achievement);
763        }
764    }
765
766    pub fn get_user_progress(&self, user_id: &str) -> Option<&UserProgress> {
767        self.progress_tracker.user_progress.get(user_id)
768    }
769
770    pub fn update_global_statistics(&mut self) {
771        self.progress_tracker.global_statistics.total_users =
772            self.progress_tracker.user_progress.len();
773
774        for tutorial in &self.tutorials {
775            let completion_count = self
776                .progress_tracker
777                .user_progress
778                .values()
779                .filter(|progress| progress.completed_tutorials.contains(&tutorial.id))
780                .count();
781
782            let completion_rate = if self.progress_tracker.global_statistics.total_users > 0 {
783                completion_count as f64 / self.progress_tracker.global_statistics.total_users as f64
784            } else {
785                0.0
786            };
787
788            self.progress_tracker
789                .global_statistics
790                .tutorial_completion_rates
791                .insert(tutorial.id.clone(), completion_rate);
792        }
793    }
794}
795
796#[allow(non_snake_case)]
797#[cfg(test)]
798mod tests {
799    use super::*;
800
801    #[test]
802    fn test_tutorial_builder() {
803        let tutorial = TutorialBuilder::new("test".to_string(), "Test Tutorial".to_string())
804            .description("Test description".to_string())
805            .difficulty(DifficultyLevel::Intermediate)
806            .duration(60)
807            .author("Test Author".to_string())
808            .build();
809
810        assert_eq!(tutorial.id, "test");
811        assert_eq!(tutorial.title, "Test Tutorial");
812        assert_eq!(tutorial.description, "Test description");
813        assert_eq!(tutorial.duration_minutes, 60);
814        assert!(matches!(tutorial.difficulty, DifficultyLevel::Intermediate));
815    }
816
817    #[test]
818    fn test_tutorial_system_creation() {
819        let config = TutorialConfig::default();
820        let system = TutorialSystem::new(config);
821        assert_eq!(system.tutorials.len(), 0);
822        assert_eq!(system.learning_paths.len(), 0);
823    }
824
825    #[test]
826    fn test_user_progress_tracking() {
827        let mut system = TutorialSystem::new(TutorialConfig::default());
828        let tutorial = TutorialBuilder::new("test".to_string(), "Test".to_string()).build();
829        system.add_tutorial(tutorial);
830
831        let result = system.start_tutorial("user1".to_string(), "test".to_string());
832        assert!(result.is_ok());
833
834        let progress = system.get_user_progress("user1");
835        assert!(progress.is_some());
836        assert_eq!(progress.unwrap().current_tutorial, Some("test".to_string()));
837    }
838
839    #[test]
840    fn test_section_completion() {
841        let mut system = TutorialSystem::new(TutorialConfig::default());
842        let tutorial = TutorialBuilder::new("test".to_string(), "Test".to_string())
843            .section("section1".to_string(), "Section 1".to_string())
844            .build();
845        system.add_tutorial(tutorial);
846
847        system
848            .start_tutorial("user1".to_string(), "test".to_string())
849            .unwrap();
850        let result = system.complete_section("user1", "test", "section1");
851        assert!(result.is_ok());
852    }
853
854    #[test]
855    fn test_tutorial_generation_from_trait() {
856        let system = TutorialSystem::new(TutorialConfig::default());
857        let trait_info = TraitInfo {
858            name: "Display".to_string(),
859            path: "std::fmt::Display".to_string(),
860            description: "Trait for formatting output".to_string(),
861            methods: vec![],
862            associated_types: vec![],
863            generics: vec![],
864            supertraits: vec![],
865            implementations: vec![],
866        };
867
868        let tutorial = system.generate_tutorial_from_trait(&trait_info);
869        assert_eq!(tutorial.id, "trait_Display");
870        assert!(tutorial.title.contains("Display"));
871        assert!(!tutorial.sections.is_empty());
872    }
873}