BREAKING CHANGES: - Relationship syntax now requires blocks for all participants - Removed self/other perspective blocks from relationships - Replaced 'guard' keyword with 'if' for behavior tree decorators Language Features: - Add tree-sitter grammar with improved if/condition disambiguation - Add comprehensive tutorial and reference documentation - Add SBIR v0.2.0 binary format specification - Add resource linking system for behaviors and schedules - Add year-long schedule patterns (day, season, recurrence) - Add behavior tree enhancements (named nodes, decorators) Documentation: - Complete tutorial series (9 chapters) with baker family examples - Complete reference documentation for all language features - SBIR v0.2.0 specification with binary format details - Added locations and institutions documentation Examples: - Convert all examples to baker family scenario - Add comprehensive working examples Tooling: - Zed extension with LSP integration - Tree-sitter grammar for syntax highlighting - Build scripts and development tools Version Updates: - Main package: 0.1.0 → 0.2.0 - Tree-sitter grammar: 0.1.0 → 0.2.0 - Zed extension: 0.1.0 → 0.2.0 - Storybook editor: 0.1.0 → 0.2.0
207 lines
5.1 KiB
Rust
207 lines
5.1 KiB
Rust
//! Tests for semantic validation integration
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use crate::lsp::document::Document;
|
|
|
|
#[test]
|
|
fn test_reserved_keyword_caught_by_parser() {
|
|
// Reserved keywords are caught by the parser, not the validator
|
|
// This test verifies that parse errors catch reserved keywords
|
|
let source = r#"
|
|
character Alice {
|
|
self: "Bad field name"
|
|
}
|
|
"#;
|
|
let doc = Document::new(source.to_string());
|
|
|
|
// Should have parse error for reserved keyword
|
|
assert!(
|
|
!doc.parse_errors.is_empty(),
|
|
"Parser should catch reserved keyword 'self' as field name"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_valid_fields_no_validation_errors() {
|
|
let source = r#"
|
|
character Alice {
|
|
age: 7
|
|
name: "Alice"
|
|
}
|
|
"#;
|
|
let doc = Document::new(source.to_string());
|
|
|
|
// Should have no validation errors
|
|
assert!(
|
|
doc.resolve_errors.is_empty(),
|
|
"Valid code should have no validation errors"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_trait_range_validation() {
|
|
let source = r#"
|
|
character Alice {
|
|
bond: 1.5
|
|
}
|
|
"#;
|
|
let doc = Document::new(source.to_string());
|
|
|
|
// Should have error for bond value out of range
|
|
assert!(
|
|
!doc.resolve_errors.is_empty(),
|
|
"Should detect bond value out of range [0.0, 1.0]"
|
|
);
|
|
|
|
let error_message = format!("{}", doc.resolve_errors[0]);
|
|
assert!(
|
|
error_message.contains("1.5") || error_message.contains("range"),
|
|
"Error should mention the value or range: {}",
|
|
error_message
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_valid_trait_ranges() {
|
|
let source = r#"
|
|
character Alice {
|
|
bond: 0.75
|
|
trust: 0.0
|
|
love: 1.0
|
|
}
|
|
"#;
|
|
let doc = Document::new(source.to_string());
|
|
|
|
// Should have no validation errors for valid trait ranges
|
|
assert!(
|
|
doc.resolve_errors.is_empty(),
|
|
"Valid trait values should produce no errors"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_life_arc_transition_validation() {
|
|
let source = r#"
|
|
life_arc Growing {
|
|
state child {
|
|
on birthday -> adult
|
|
}
|
|
}
|
|
"#;
|
|
let doc = Document::new(source.to_string());
|
|
|
|
// Should have error for transition to unknown state 'adult'
|
|
assert!(
|
|
!doc.resolve_errors.is_empty(),
|
|
"Should detect transition to undefined state"
|
|
);
|
|
|
|
let error_message = format!("{}", doc.resolve_errors[0]);
|
|
assert!(
|
|
error_message.contains("adult") || error_message.contains("unknown"),
|
|
"Error should mention unknown state"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_valid_life_arc_transitions() {
|
|
let source = r#"
|
|
life_arc Growing {
|
|
state child {
|
|
on birthday -> teen
|
|
}
|
|
state teen {
|
|
on birthday -> adult
|
|
}
|
|
state adult {}
|
|
}
|
|
"#;
|
|
let doc = Document::new(source.to_string());
|
|
|
|
// Should have no validation errors
|
|
assert!(
|
|
doc.resolve_errors.is_empty(),
|
|
"Valid life arc should produce no errors"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_schedule_overlap_validation() {
|
|
let source = r#"
|
|
schedule Daily {
|
|
08:00 -> 10:00: morning {}
|
|
09:00 -> 11:00: overlap {}
|
|
}
|
|
"#;
|
|
let doc = Document::new(source.to_string());
|
|
|
|
// Should have error for overlapping schedule blocks
|
|
assert!(
|
|
!doc.resolve_errors.is_empty(),
|
|
"Should detect overlapping schedule blocks"
|
|
);
|
|
|
|
let error_message = format!("{}", doc.resolve_errors[0]);
|
|
assert!(
|
|
error_message.contains("overlap"),
|
|
"Error should mention overlap"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_valid_schedule_no_overlaps() {
|
|
let source = r#"
|
|
schedule Daily {
|
|
08:00 -> 10:00: morning {}
|
|
10:00 -> 12:00: midday {}
|
|
12:00 -> 14:00: afternoon {}
|
|
}
|
|
"#;
|
|
let doc = Document::new(source.to_string());
|
|
|
|
// Should have no validation errors
|
|
assert!(
|
|
doc.resolve_errors.is_empty(),
|
|
"Non-overlapping schedule should produce no errors"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_multiple_validation_errors() {
|
|
// Test multiple validation errors at once
|
|
let source = r#"
|
|
character Alice {
|
|
bond: 2.0
|
|
trust: -0.5
|
|
}
|
|
"#;
|
|
let doc = Document::new(source.to_string());
|
|
|
|
// Should have multiple errors for out-of-range values
|
|
assert!(
|
|
doc.resolve_errors.len() >= 2,
|
|
"Should detect multiple range errors. Got {} errors",
|
|
doc.resolve_errors.len()
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_parse_and_validation_errors_separate() {
|
|
let source = r#"
|
|
character Alice {
|
|
character: "Reserved"
|
|
invalid syntax here
|
|
}
|
|
"#;
|
|
let doc = Document::new(source.to_string());
|
|
|
|
// Parse should fail, so we won't have validation errors
|
|
// (validation only runs on successfully parsed AST)
|
|
assert!(
|
|
!doc.parse_errors.is_empty() || !doc.resolve_errors.is_empty(),
|
|
"Should have either parse or validation errors"
|
|
);
|
|
}
|
|
}
|