use astrogram::astro::{
create_payload, edit_payload, extract_aaf, offset_to_szon, parse_listing, parse_nhor_from_url,
};
use astrogram::chart::{
Chart, CoordinateSystem, EventType, HouseSystem, Latitude, Longitude, Zodiac,
};
fn make_chart(name: &str) -> Chart {
Chart {
name: name.to_string(),
secondary_name: None,
city: Some("Diseworth".to_string()),
region: Some("GB".to_string()),
longitude: Longitude::new(-1.0 - 11.0 / 60.0).unwrap(),
latitude: Latitude::new(52.0 + 47.0 / 60.0).unwrap(),
year: 1602,
month: 5,
day: 11,
hour: 2,
minute: 0,
second: 0,
tz_offset_hours: -(4.0 / 60.0 + 44.0 / 3600.0),
tz_abbreviation: None,
is_lmt: true,
event_type: EventType::Male,
source_rating: None,
house_system: HouseSystem::Placidus,
zodiac: Zodiac::Tropical,
coordinate_system: CoordinateSystem::Geocentric,
sub_charts: vec![],
notes: None,
}
}
const LISTING_HTML: &str = r#"
<html><body>
<table>
<tr><td><a href="/cgi/ade.cgi?&nhor=1&ract=xx" class="txt6p" title="edit birth data for Lilly, William">Edit</a></td></tr>
<tr><td><a href="/cgi/ade.cgi?&nhor=3&ract=xx" class="txt6p" title="edit birth data for Valens">Edit</a></td></tr>
<tr><td><a href="/cgi/ade.cgi?&nhor=6&ract=xx" class="txt6p" title="edit birth data for Freud, Anna">Edit</a></td></tr>
</table>
</body></html>
"#;
#[test]
fn listing_extracts_nhor_ids_and_names() {
let charts = parse_listing(LISTING_HTML);
assert_eq!(charts.len(), 3);
assert_eq!(charts[0].nhor_id, 1);
assert_eq!(charts[1].nhor_id, 3);
assert_eq!(charts[2].nhor_id, 6);
}
#[test]
fn listing_name_from_title_attribute() {
let charts = parse_listing(LISTING_HTML);
assert_eq!(charts[0].name, "Lilly, William");
}
#[test]
fn listing_plain_name_unchanged() {
let charts = parse_listing(LISTING_HTML);
assert_eq!(charts[1].name, "Valens");
}
#[test]
fn listing_empty_html_returns_empty() {
let charts = parse_listing("<html><body></body></html>");
assert!(charts.is_empty());
}
const AAF_HTML: &str = r"
<html><body>
<h2>AAF Export</h2>
<pre>
#: Astrolog 7.80
#A93:*,Lilly,William,11.05.1602,02:00,Diseworth,GB
#B93:2306308.587,52N47,1W11,*,L
</pre>
</body></html>
";
#[test]
fn aaf_extracted_from_pre_block() {
let text = extract_aaf(AAF_HTML).unwrap();
assert!(text.contains("#A93:"));
assert!(text.contains("#B93:"));
}
#[test]
fn html_entities_decoded_in_pre() {
let html = "<html><body><pre>#: test & data\n#A93:*,A,B,01.01.2000,12:00,C,D\n#B93:0.0,0N0,0E0,0,0\n</pre></body></html>";
let text = extract_aaf(html).unwrap();
assert!(text.contains("test & data"));
}
#[test]
fn no_pre_block_returns_none() {
let text = extract_aaf("<html><body>no pre here</body></html>");
assert!(text.is_none());
}
#[test]
fn nhor_from_semicolon_query() {
let url = "https://www.astro.com/cgi/awd.cgi?;nhor=5";
assert_eq!(parse_nhor_from_url(url), Some(5));
}
#[test]
fn nhor_from_amp_query() {
let url = "https://www.astro.com/cgi/awd.cgi?lang=e&nhor=12";
assert_eq!(parse_nhor_from_url(url), Some(12));
}
#[test]
fn nhor_missing_returns_none() {
let url = "https://www.astro.com/cgi/awd.cgi?lang=e";
assert_eq!(parse_nhor_from_url(url), None);
}
#[test]
fn negative_offset_is_west() {
assert_eq!(offset_to_szon(-8.0, false), "h8w00");
}
#[test]
fn positive_offset_is_east() {
assert_eq!(offset_to_szon(1.0, false), "h1e00");
}
#[test]
fn zero_offset_is_east() {
assert_eq!(offset_to_szon(0.0, false), "h0e00");
}
#[test]
fn fractional_offset_encodes_minutes() {
assert_eq!(offset_to_szon(5.5, false), "h5e30");
}
#[test]
fn lmt_returns_lmt_string() {
assert_eq!(offset_to_szon(-8.0, true), "lmt");
}
fn find_field<'a>(payload: &'a [(String, String)], key: &str) -> Option<&'a str> {
payload
.iter()
.find(|(k, _)| k == key)
.map(|(_, v)| v.as_str())
}
#[test]
fn create_payload_has_subcon_continue() {
let p = create_payload(&make_chart("Lilly, William"), "test_cid", "tok");
assert_eq!(find_field(&p, "subcon"), Some("continue"));
}
#[test]
fn create_payload_has_btyp() {
let p = create_payload(&make_chart("X"), "c", "tok");
assert_eq!(find_field(&p, "btyp"), Some("w2at"));
}
#[test]
fn create_payload_name_with_comma_splits() {
let p = create_payload(&make_chart("Lilly, William"), "c", "tok");
assert_eq!(find_field(&p, "snam"), Some("Lilly"));
assert_eq!(find_field(&p, "sfnm"), Some("William"));
}
#[test]
fn create_payload_name_without_comma_goes_to_sfnm() {
let p = create_payload(&make_chart("Madonna"), "c", "tok");
assert_eq!(find_field(&p, "sfnm"), Some("Madonna"));
assert_eq!(find_field(&p, "snam"), Some(""));
}
#[test]
fn create_payload_tz_lmt() {
let p = create_payload(&make_chart("X"), "c", "tok");
assert_eq!(find_field(&p, "szon"), Some("lmt"));
}
#[test]
fn create_payload_male_sex() {
let p = create_payload(&make_chart("X"), "c", "tok");
assert_eq!(find_field(&p, "ssx"), Some("m"));
}
#[test]
fn create_payload_date_fields() {
let p = create_payload(&make_chart("X"), "c", "tok");
assert_eq!(find_field(&p, "sday"), Some("11"));
assert_eq!(find_field(&p, "imon"), Some("5"));
assert_eq!(find_field(&p, "syar"), Some("1602"));
}
#[test]
fn create_payload_includes_cid() {
let p = create_payload(&make_chart("X"), "my_session_abc", "tok");
assert_eq!(find_field(&p, "cid"), Some("my_session_abc"));
}
#[test]
fn edit_payload_includes_nhor() {
let p = edit_payload(&make_chart("X"), 42, "c");
assert_eq!(find_field(&p, "nhor"), Some("42"));
}
#[test]
fn edit_payload_has_subcon_continue() {
let p = edit_payload(&make_chart("X"), 1, "c");
assert_eq!(find_field(&p, "subcon"), Some("continue"));
}