///|
pub struct PathExpectation {
path : String
allowed : Bool
} derive(Debug, Eq)
///|
pub struct Scenario {
name : String
robots : String
agent : String
expectations : Array[PathExpectation]
} derive(Debug, Eq)
///|
pub fn expect_path(path : String, allowed : Bool) -> PathExpectation {
{ path, allowed }
}
///|
pub fn scenario(
name : String,
robots : String,
agent : String,
expectations : Array[PathExpectation],
) -> Scenario {
{ name, robots, agent, expectations }
}
///|
pub fn run_scenario(case : Scenario) -> Array[String] {
let failures : Array[String] = []
let robots = parse(case.robots)
for item in case.expectations {
let actual = decide(robots, case.agent, item.path).allowed
if actual != item.allowed {
failures.push(
case.name +
" " +
item.path +
" expected " +
bool_word(item.allowed) +
" got " +
bool_word(actual),
)
}
}
failures
}
///|
pub fn scenario_report(case : Scenario) -> String {
let failures = run_scenario(case)
if failures.is_empty() {
case.name + ": ok"
} else {
join_lines(failures)
}
}
///|
pub fn run_scenarios(cases : Array[Scenario]) -> Array[String] {
let failures : Array[String] = []
for case in cases {
for failure in run_scenario(case) {
failures.push(failure)
}
}
failures
}
///|
pub fn scenarios_report(cases : Array[Scenario]) -> String {
let failures = run_scenarios(cases)
if failures.is_empty() {
"ok"
} else {
join_lines(failures)
}
}
///|
pub fn scenario_matrix(case : Scenario) -> String {
let lines : Array[String] = ["path,expected,actual"]
let robots = parse(case.robots)
for item in case.expectations {
lines.push(
item.path +
"," +
bool_word(item.allowed) +
"," +
bool_word(decide(robots, case.agent, item.path).allowed),
)
}
join_lines(lines)
}
///|
pub fn built_in_scenarios() -> Array[Scenario] {
[
scenario(
"private-with-public-hole",
"User-agent: *\nDisallow: /private\nAllow: /private/public\n",
"bot",
[
expect_path("/", true),
expect_path("/private/a", false),
expect_path("/private/public/a", true),
],
),
scenario(
"specific-agent",
"User-agent: *\nDisallow: /\n\nUser-agent: goodbot\nAllow: /\n",
"goodbot",
[expect_path("/", true), expect_path("/anything", true)],
),
]
}
///|
pub fn built_in_scenarios_report() -> String {
scenarios_report(built_in_scenarios())
}
///|
pub fn scenario_markdown(case : Scenario) -> String {
"# Scenario: " +
case.name +
"\n\n" +
fenced(scenario_matrix(case)) +
"\n\n" +
fenced(scenario_report(case))
}