//! Tests for ParseError variants and ErrorContext.

use sipha_core::{span::Span, traits::TokenKind};
use sipha_error::{
    error::{ErrorContext, ParseError},
    expected::Expected,
};

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
enum TestToken {
    Ident,
    Plus,
    Number,
}

impl TokenKind for TestToken {
    fn is_trivia(&self) -> bool {
        false
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
enum TestRule {
    Expr,
}

#[test]
fn test_unexpected_token_error() {
    let error = ParseError::UnexpectedToken {
        kind: TestToken::Plus,
        span: Span::new(5, 6),
        rule_context: Some(TestRule::Expr),
        context_stack: vec![],
    };
    match error {
        ParseError::UnexpectedToken { kind, span, .. } => {
            assert_eq!(kind, TestToken::Plus);
            assert_eq!(span, Span::new(5, 6));
        }
        _ => panic!("Expected UnexpectedToken variant"),
    }
}

#[test]
fn test_expected_error() {
    let error: ParseError<TestToken, TestRule> = ParseError::Expected {
        expected: Expected::Single(TestToken::Ident),
        found: Some(TestToken::Number),
        span: Span::new(10, 15),
        rule_context: None,
        context_stack: vec![],
    };
    match error {
        ParseError::Expected {
            expected, found, ..
        } => {
            match expected {
                Expected::Single(token) => assert_eq!(token, TestToken::Ident),
                _ => panic!("Expected Single variant"),
            }
            assert_eq!(found, Some(TestToken::Number));
        }
        _ => panic!("Expected Expected variant"),
    }
}

#[test]
fn test_unexpected_eof_error() {
    let error: ParseError<TestToken, TestRule> = ParseError::UnexpectedEof {
        span: Span::new(20, 20),
        rule_context: Some(TestRule::Expr),
        context_stack: vec![],
    };
    match error {
        ParseError::UnexpectedEof { span, .. } => {
            assert_eq!(span, Span::new(20, 20));
        }
        _ => panic!("Expected UnexpectedEof variant"),
    }
}

#[test]
fn test_error_context() {
    let ctx = ErrorContext {
        rule_id: TestRule::Expr,
        span: Span::new(0, 10),
        message: "While parsing expression".to_string(),
    };
    assert_eq!(ctx.rule_id, TestRule::Expr);
    assert_eq!(ctx.span, Span::new(0, 10));
    assert_eq!(ctx.message, "While parsing expression");
}
