368 lines
9.4 KiB
Rust
368 lines
9.4 KiB
Rust
use std::io::Write;
|
|
use tempfile::NamedTempFile;
|
|
|
|
fn write_tsrc(content: &str) -> NamedTempFile {
|
|
let mut f = NamedTempFile::new().unwrap();
|
|
f.write_all(content.as_bytes()).unwrap();
|
|
f.flush().unwrap();
|
|
f
|
|
}
|
|
|
|
fn parse(content: &str) -> Result<tssr::tsrc::TsrcScript, String> {
|
|
let f = write_tsrc(content);
|
|
tssr::tsrc::parse_tsrc(f.path().to_str().unwrap())
|
|
}
|
|
|
|
#[test]
|
|
fn goal_player_not_on_team() {
|
|
let r = parse(r#"
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
goal(10, h, "Wrong Player");
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_err());
|
|
let err = r.unwrap_err();
|
|
assert!(err.contains("is not on team"), "got: {}", err);
|
|
assert!(err.contains("Wrong Player"), "got: {}", err);
|
|
}
|
|
|
|
#[test]
|
|
fn goal_duplicate_same_minute_player() {
|
|
let r = parse(r#"
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
goal(10, h, "P1");
|
|
goal(10, a, "P1");
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_err());
|
|
let err = r.unwrap_err();
|
|
assert!(err.contains("duplicate goal"), "got: {}", err);
|
|
}
|
|
|
|
#[test]
|
|
fn goal_minute_out_of_range() {
|
|
let r = parse(r#"
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
goal(95, h, "P1");
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_err());
|
|
let err = r.unwrap_err();
|
|
assert!(err.contains("between 1 and 90"), "got: {}", err);
|
|
}
|
|
|
|
#[test]
|
|
fn goal_undefined_team() {
|
|
let r = parse(r#"
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
goal(10, "Ghost Team", "P1");
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_err());
|
|
let err = r.unwrap_err();
|
|
assert!(err.contains("not a match team"), "got: {}", err);
|
|
}
|
|
|
|
#[test]
|
|
fn goal_undefined_variable() {
|
|
let r = parse(r#"
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
goal(10, ghost, "P1");
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_err());
|
|
let err = r.unwrap_err();
|
|
assert!(err.contains("undefined variable"), "got: {}", err);
|
|
assert!(err.contains("ghost"), "got: {}", err);
|
|
}
|
|
|
|
#[test]
|
|
fn script_valid_full_with_goals() {
|
|
let r = parse(r#"
|
|
string home = "GNU United";
|
|
string away = "BSD Athletic";
|
|
players["Richard Stallman"] = home;
|
|
players["Brian Fox"] = home;
|
|
players["Linus Torvalds"] = home;
|
|
players["Theo de Raadt"] = away;
|
|
players["Jordan Hubbard"] = away;
|
|
players["Ken Thompson"] = away;
|
|
goal(12, home, "Richard Stallman");
|
|
goal(34, away, "Theo de Raadt");
|
|
goal(56, home, "Brian Fox");
|
|
goal(78, "BSD Athletic", "Ken Thompson");
|
|
goal(89, home, "Linus Torvalds");
|
|
match(home, away);
|
|
"#);
|
|
assert!(r.is_ok(), "got: {:?}", r.err());
|
|
let s = r.unwrap();
|
|
let goals = s.goals.unwrap();
|
|
assert_eq!(goals.len(), 5);
|
|
let home_goals: Vec<_> = goals.iter().filter(|g| g.team == "GNU United").collect();
|
|
let away_goals: Vec<_> = goals.iter().filter(|g| g.team == "BSD Athletic").collect();
|
|
assert_eq!(home_goals.len(), 3);
|
|
assert_eq!(away_goals.len(), 2);
|
|
assert_eq!(home_goals[0].player, "Richard Stallman");
|
|
assert_eq!(home_goals[0].minute, 12);
|
|
}
|
|
|
|
#[test]
|
|
fn script_variable_ref_in_players() {
|
|
let r = parse(r#"
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_ok(), "got: {:?}", r.err());
|
|
let s = r.unwrap();
|
|
assert!(s.roster.contains_key("Team A"));
|
|
assert!(s.roster.contains_key("Team B"));
|
|
}
|
|
|
|
#[test]
|
|
fn script_mismatch_roster_team_name() {
|
|
let r = parse(r#"
|
|
string h = "Linux City";
|
|
string a = "Libre Pool";
|
|
players["P1"] = "Man Page City";
|
|
players["P2"] = a;
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_err());
|
|
let err = r.unwrap_err();
|
|
assert!(err.contains("not a match team"), "got: {}", err);
|
|
assert!(err.contains("Man Page City"), "got: {}", err);
|
|
}
|
|
|
|
#[test]
|
|
fn script_duplicate_player() {
|
|
let r = parse(r#"
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_err());
|
|
let err = r.unwrap_err();
|
|
assert!(err.contains("duplicate player"), "got: {}", err);
|
|
assert!(err.contains("P1"), "got: {}", err);
|
|
}
|
|
|
|
#[test]
|
|
fn script_duplicate_variable() {
|
|
let r = parse(r#"
|
|
string home = "Team A";
|
|
string home = "Team B";
|
|
players["P1"] = home;
|
|
players["P2"] = home;
|
|
match(home, home);
|
|
"#);
|
|
assert!(r.is_err());
|
|
let err = r.unwrap_err();
|
|
assert!(err.contains("redefined"), "got: {}", err);
|
|
assert!(err.contains("home"), "got: {}", err);
|
|
}
|
|
|
|
#[test]
|
|
fn script_no_match_directive() {
|
|
let r = parse(r#"
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
"#);
|
|
assert!(r.is_err());
|
|
let err = r.unwrap_err();
|
|
assert!(err.contains("no match() directive found"), "got: {}", err);
|
|
}
|
|
|
|
#[test]
|
|
fn script_same_team_in_match() {
|
|
let r = parse(r#"
|
|
string h = "Team A";
|
|
string a = "Team A";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_err());
|
|
let err = r.unwrap_err();
|
|
assert!(err.contains("same team"), "got: {}", err);
|
|
assert!(err.contains("Team A"), "got: {}", err);
|
|
}
|
|
|
|
#[test]
|
|
fn script_no_players_for_team() {
|
|
let r = parse(r#"
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_err());
|
|
let err = r.unwrap_err();
|
|
assert!(err.contains("no players assigned"), "got: {}", err);
|
|
}
|
|
|
|
#[test]
|
|
fn define_default_is_unicode_table() {
|
|
let r = parse(r#"
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_ok(), "got: {:?}", r.err());
|
|
assert_eq!(r.unwrap().output_mode, tssr::tsrc::OutputMode::UnicodeTable);
|
|
}
|
|
|
|
#[test]
|
|
fn define_json() {
|
|
let r = parse(r#"
|
|
#define JSON
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_ok(), "got: {:?}", r.err());
|
|
assert_eq!(r.unwrap().output_mode, tssr::tsrc::OutputMode::Json);
|
|
}
|
|
|
|
#[test]
|
|
fn define_ascii_table() {
|
|
let r = parse(r#"
|
|
#define ASCII_TABLE
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_ok(), "got: {:?}", r.err());
|
|
assert_eq!(r.unwrap().output_mode, tssr::tsrc::OutputMode::AsciiTable);
|
|
}
|
|
|
|
#[test]
|
|
fn define_unicode_table_explicit() {
|
|
let r = parse(r#"
|
|
#define UNICODE_TABLE
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_ok(), "got: {:?}", r.err());
|
|
assert_eq!(r.unwrap().output_mode, tssr::tsrc::OutputMode::UnicodeTable);
|
|
}
|
|
|
|
#[test]
|
|
fn define_duplicate_error() {
|
|
let r = parse(r#"
|
|
#define JSON
|
|
#define ASCII_TABLE
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_err());
|
|
let err = r.unwrap_err();
|
|
assert!(err.contains("duplicate #define"), "got: {}", err);
|
|
}
|
|
|
|
#[test]
|
|
fn define_unknown_error() {
|
|
let r = parse(r#"
|
|
#define FOO_BAR
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_err());
|
|
let err = r.unwrap_err();
|
|
assert!(err.contains("unknown #define"), "got: {}", err);
|
|
assert!(err.contains("FOO_BAR"), "got: {}", err);
|
|
}
|
|
|
|
#[test]
|
|
fn situation_valid_with_goals() {
|
|
let r = parse(r#"
|
|
#define SITUATION
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
players["P3"] = h;
|
|
players["P4"] = a;
|
|
goal(10, h, "P1");
|
|
goal(45, a, "P2");
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_ok(), "got: {:?}", r.err());
|
|
let s = r.unwrap();
|
|
assert!(s.situation_mode);
|
|
assert!(s.goals.is_some());
|
|
assert_eq!(s.goals.unwrap().len(), 2);
|
|
}
|
|
|
|
#[test]
|
|
fn situation_requires_goals_error() {
|
|
let r = parse(r#"
|
|
#define SITUATION
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_err());
|
|
let err = r.unwrap_err();
|
|
assert!(err.contains("SITUATION"), "got: {}", err);
|
|
assert!(err.contains("goal()"), "got: {}", err);
|
|
}
|
|
|
|
#[test]
|
|
fn situation_combinable_with_output_mode() {
|
|
let r = parse(r#"
|
|
#define SITUATION
|
|
#define ASCII_TABLE
|
|
string h = "Team A";
|
|
string a = "Team B";
|
|
players["P1"] = h;
|
|
players["P2"] = a;
|
|
players["P3"] = h;
|
|
players["P4"] = a;
|
|
goal(10, h, "P1");
|
|
match(h, a);
|
|
"#);
|
|
assert!(r.is_ok(), "got: {:?}", r.err());
|
|
let s = r.unwrap();
|
|
assert!(s.situation_mode);
|
|
assert_eq!(s.output_mode, tssr::tsrc::OutputMode::AsciiTable);
|
|
}
|