#![allow(missing_docs)]
use ruchy::frontend::parser::Parser;
use ruchy::runtime::interpreter::Interpreter;
#[test]
fn test_http002d_01_html_parse_returns_html_document() {
let code = r#"
let html = Html.parse("<div>Hello</div>")
html
"#;
let mut parser = Parser::new(code);
let ast = parser.parse().expect("Parse failed");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&ast);
assert!(result.is_ok(), "Html.parse() should return HtmlDocument");
assert_eq!(
result.unwrap().type_name(),
"html_document",
"Should return html_document type"
);
}
#[test]
fn test_http002d_02_html_document_select_class_selector() {
let code = r#"
let html = Html.parse("<div class='test'>Content</div>")
let elements = html.select(".test")
elements.length()
"#;
let mut parser = Parser::new(code);
let ast = parser.parse().expect("Parse failed");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&ast);
assert!(
result.is_ok(),
"HtmlDocument.select() should work: {:?}",
result.err()
);
match result.unwrap() {
ruchy::runtime::Value::Integer(n) => assert_eq!(n, 1),
other => panic!("Expected integer length, got: {}", other.type_name()),
}
}
#[test]
fn test_http002d_03_html_document_select_tag_selector() {
let code = r#"
let html = Html.parse("<div>One</div><div>Two</div>")
let elements = html.select("div")
elements.length()
"#;
let mut parser = Parser::new(code);
let ast = parser.parse().expect("Parse failed");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&ast);
assert!(
result.is_ok(),
"Tag selector should work: {:?}",
result.err()
);
match result.unwrap() {
ruchy::runtime::Value::Integer(n) => assert_eq!(n, 2),
other => panic!("Expected integer length, got: {}", other.type_name()),
}
}
#[test]
fn test_http002d_04_html_document_select_id_selector() {
let code = r##"
let html = Html.parse("<div id='main'>Content</div>")
let elements = html.select("#main")
elements.length()
"##;
let mut parser = Parser::new(code);
let ast = parser.parse().expect("Parse failed");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&ast);
assert!(
result.is_ok(),
"ID selector should work: {:?}",
result.err()
);
match result.unwrap() {
ruchy::runtime::Value::Integer(n) => assert_eq!(n, 1),
other => panic!("Expected integer length, got: {}", other.type_name()),
}
}
#[test]
fn test_http002d_05_html_element_text_extraction() {
let code = r#"
let html = Html.parse("<div class='test'>Hello World</div>")
let elements = html.select(".test")
elements[0].text()
"#;
let mut parser = Parser::new(code);
let ast = parser.parse().expect("Parse failed");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&ast);
assert!(
result.is_ok(),
"HtmlElement.text() should work: {:?}",
result.err()
);
match result.unwrap() {
ruchy::runtime::Value::String(s) => assert_eq!(s.as_ref(), "Hello World"),
other => panic!("Expected string, got: {}", other.type_name()),
}
}
#[test]
fn test_http002d_06_html_element_text_nested_elements() {
let code = r#"
let html = Html.parse("<div><p>First</p><p>Second</p></div>")
let elements = html.select("div")
elements[0].text()
"#;
let mut parser = Parser::new(code);
let ast = parser.parse().expect("Parse failed");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&ast);
assert!(
result.is_ok(),
"Nested element text should work: {:?}",
result.err()
);
match result.unwrap() {
ruchy::runtime::Value::String(s) => {
let text = s.as_ref();
assert!(text.contains("First"), "Should contain 'First'");
assert!(text.contains("Second"), "Should contain 'Second'");
}
other => panic!("Expected string, got: {}", other.type_name()),
}
}
#[test]
fn test_http002d_07_html_document_query_selector_single_match() {
let code = r#"
let html = Html.parse("<div class='test'>First</div><div class='test'>Second</div>")
let element = html.query_selector(".test")
element.text()
"#;
let mut parser = Parser::new(code);
let ast = parser.parse().expect("Parse failed");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&ast);
assert!(
result.is_ok(),
"query_selector should work: {:?}",
result.err()
);
match result.unwrap() {
ruchy::runtime::Value::String(s) => assert_eq!(s.as_ref(), "First"),
other => panic!("Expected string, got: {}", other.type_name()),
}
}
#[test]
fn test_http002d_08_html_document_query_selector_no_match() {
let code = r#"
let html = Html.parse("<div>Content</div>")
html.query_selector(".nonexistent")
"#;
let mut parser = Parser::new(code);
let ast = parser.parse().expect("Parse failed");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&ast);
assert!(
result.is_ok(),
"query_selector should work: {:?}",
result.err()
);
assert!(result.unwrap().is_nil(), "Should return nil when no match");
}
#[test]
#[ignore = "PARSER-081: Array literals fail after multiple let statements (not HTML-specific)"]
fn test_http002d_09_html_web_scraping_workflow() {
let code = r#"
let html = Html.parse("<html><body><h1>Title</h1><p class='content'>Paragraph 1</p><p class='content'>Paragraph 2</p></body></html>")
// Extract title
let title = html.query_selector("h1").text()
// Extract all paragraphs
let paragraphs = html.select(".content")
let count = paragraphs.length()
// Return tuple with results
[title, count]
"#;
let mut parser = Parser::new(code);
let ast = parser.parse().expect("Parse failed");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&ast);
assert!(
result.is_ok(),
"Web scraping workflow should work: {:?}",
result.err()
);
match result.unwrap() {
ruchy::runtime::Value::Array(arr) => {
assert_eq!(arr.len(), 2);
if let ruchy::runtime::Value::String(s) = &arr[0] {
assert_eq!(s.as_ref(), "Title");
} else {
panic!("Expected string for title");
}
if let ruchy::runtime::Value::Integer(n) = arr[1] {
assert_eq!(n, 2);
} else {
panic!("Expected integer for count");
}
}
other => panic!("Expected array, got: {}", other.type_name()),
}
}
#[test]
fn test_http002d_10_html_error_invalid_selector() {
let code = r#"
let html = Html.parse("<div>Content</div>")
html.select("[invalid[selector")
"#;
let mut parser = Parser::new(code);
let ast = parser.parse().expect("Parse failed");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&ast);
assert!(
result.is_err(),
"Invalid selector should return error, got: {result:?}"
);
}
#[test]
#[ignore = "BUG: HTML method chaining test failing"]
fn test_http002d_11_html_method_chaining() {
let code = r#"
Html.parse("<div class='content'>Hello World</div>").select(".content")[0].text()
"#;
let mut parser = Parser::new(code);
let ast = parser.parse().expect("Parse failed");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&ast);
assert!(
result.is_ok(),
"Method chaining should work: {:?}",
result.err()
);
match result.unwrap() {
ruchy::runtime::Value::String(s) => assert_eq!(s.as_ref(), "Hello World"),
other => panic!("Expected string, got: {}", other.type_name()),
}
}
#[test]
fn test_http002d_12_html_empty_document() {
let code = r#"
let html = Html.parse("")
html.select("div").length()
"#;
let mut parser = Parser::new(code);
let ast = parser.parse().expect("Parse failed");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&ast);
assert!(
result.is_ok(),
"Empty document should work: {:?}",
result.err()
);
match result.unwrap() {
ruchy::runtime::Value::Integer(n) => assert_eq!(n, 0),
other => panic!("Expected integer, got: {}", other.type_name()),
}
}
#[test]
fn test_http002d_13_html_malformed_html() {
let code = r#"
let html = Html.parse("<div><p>Unclosed tags")
html.select("div").length()
"#;
let mut parser = Parser::new(code);
let ast = parser.parse().expect("Parse failed");
let mut interpreter = Interpreter::new();
let result = interpreter.eval_expr(&ast);
assert!(
result.is_ok(),
"Malformed HTML should be handled: {:?}",
result.err()
);
match result.unwrap() {
ruchy::runtime::Value::Integer(n) => assert!(n > 0),
other => panic!("Expected integer, got: {}", other.type_name()),
}
}