use std::{fs::File, io::Read, path::PathBuf};
use insta::assert_debug_snapshot;
use rested::{interpreter::environment::Environment, parser::ast::Program};
fn new_env_with_vars(vars: &[(&str, &str)]) -> Environment {
let mut env = Environment::new(PathBuf::from(".env.rd.json")).unwrap();
for (key, value) in vars {
env.set_variable(key.to_string(), value.to_string())
.unwrap();
}
return env;
}
macro_rules! run {
($code:expr, $env:ident) => {
let program = Program::from($code);
let program = program.interpret(&$env).unwrap();
println!("{:#}", program.source);
println!("{:#?}", program);
program.run_ureq(None);
};
($code:ident, $env:ident, $names:expr) => {
let program = Program::from($code);
let program = program.interpret(&$env).unwrap();
println!("{:#}", program.source);
println!("{:#?}", program);
program.run_ureq($names);
};
}
#[test]
fn requests_work() {
let mut server = mockito::Server::new();
let url = server.url();
let token = "asl236ap9sdhf";
let env = new_env_with_vars(&[("b_url", &url), ("token", token)]);
let get_api = server.mock("GET", "/api").with_status(200).create();
let get_api_v2 = server
.mock("GET", "/api/v2")
.with_status(200)
.with_header("Authorization", token)
.create();
let post_api = server
.mock("POST", "/api")
.with_status(200)
.with_header("Authorization", token)
.with_body("data")
.create();
let put_api = server
.mock("PUT", "/api")
.with_status(200)
.with_header("Authorization", token)
.with_body("data")
.create();
let patch_api = server
.mock("PATCH", "/api")
.with_status(200)
.with_header("Authorization", token)
.with_body("data")
.create();
let delete_api = server
.mock("DELETE", "/api")
.with_status(200)
.with_header("Authorization", token)
.create();
let code = r#"
set BASE_URL env("b_url")
get /api
get /api/v2 {
header "Authorization" env("token")
}
post /api {
header "Authorization" env("token")
body "data"
}
put /api {
header "Authorization" env("token")
body "data"
}
patch /api {
header "Authorization" env("token")
body "data"
}
delete /api {
header "Authorization" env("token")
}
"#;
run!(code, env);
get_api.assert();
get_api_v2.assert();
post_api.assert();
put_api.assert();
patch_api.assert();
delete_api.assert();
}
#[test]
fn comments_are_ignored() {
let mut server = mockito::Server::new();
let url = server.url();
let env = Environment::new(PathBuf::from(".env.rd.json")).unwrap();
let get_api = server
.mock("GET", "/api")
.with_status(200)
.expect(0)
.create();
let get_api_v2 = server.mock("GET", "/api/v2").with_status(200).create();
let code = format!(
r#"
// set BASE_URL env("b_url")
// get /api
// @skip
get {url}/api/v2 {{
// header Aas "test"
}}
"#
);
run!(&code, env);
get_api.assert();
get_api_v2.assert();
}
#[test]
fn requests_are_skippable() {
let mut server = mockito::Server::new();
let url = server.url();
let mut env = Environment::new(PathBuf::from(".env.rd.json")).unwrap();
env.set_variable("b_url".to_string(), url).unwrap();
let mocks = ["GET", "POST", "PUT", "PATCH", "DELETE"]
.map(|method| server.mock(method, "/api").with_status(200).create());
let code = r#"
set BASE_URL env("b_url")
get /api
@skip
get /api
post /api
@skip
post /api
put /api
@skip
put /api
patch /api
@skip
patch /api
delete /api
@skip
delete /api
"#;
run!(code, env);
for mock in mocks {
mock.assert();
}
}
#[test]
fn responses_can_be_logged() {
let mut server = mockito::Server::new();
let url = server.url();
let mut env = Environment::new(PathBuf::from(".env.rd.json")).unwrap();
env.set_variable("b_url".to_string(), url).unwrap();
let mocks = ["POST"].map(|method| {
server
.mock(method, "/api")
.with_status(200)
.with_body_from_file("tests/files/test_data.json")
.create()
});
let code = r#"
set BASE_URL env("b_url")
@log("tests/output/test_data_echo.json")
post /api
"#;
run!(code, env);
let mut input_file = File::open("tests/files/test_data.json").unwrap();
let mut output_file = File::open("tests/output/test_data_echo.json").unwrap();
let mut req_body = String::new();
input_file.read_to_string(&mut req_body).unwrap();
let mut res_body = String::new();
output_file.read_to_string(&mut res_body).unwrap();
assert_eq!(req_body, res_body);
for mock in mocks {
mock.assert();
}
}
#[test]
fn let_bindings_work() {
let mut server = mockito::Server::new();
let url = server.url();
let mut env = Environment::new(PathBuf::from(".env.rd.json")).unwrap();
env.set_variable("test".to_string(), "12345".to_string())
.unwrap();
env.set_variable("b_url".to_string(), url).unwrap();
let mocks = ["POST"].map(|method| {
server
.mock(method, "/api")
.with_status(200)
.with_header("test", env.get_variable_value(&"test".to_string()).unwrap())
.with_header("test1", "asdf")
.create()
});
let code = r#"
set BASE_URL env("b_url")
let variable = env("test")
let o_variable = "asdf"
post /api {
header "test" variable
header "test1" o_variable
}
"#;
run!(code, env);
for mock in mocks {
mock.assert();
}
}
#[test]
fn running_specific_requests_by_name() {
let mut server = mockito::Server::new();
let url = server.url();
let env = new_env_with_vars(&[("b_url", &url)]);
let mocks =
["GET", "POST", "PUT"].map(|method| server.mock(method, "/api").with_status(200).create());
let del = server
.mock("DELETE", "/api")
.with_status(200)
.expect(0)
.create();
let code = r#"
set BASE_URL env("b_url")
get /api
post /api
put /api
@name("test")
get /api
@name("test")
post /api
@name("test")
put /api
@name("nope")
delete /api
"#;
run!(code, env, Some(&["test".to_string()]));
for mock in mocks {
mock.assert();
}
del.assert();
}
#[test]
fn name_attribute_requires_value() {
let mut env = Environment::new(PathBuf::from(".env.rd.json")).unwrap();
env.set_variable("b_url".to_string(), "asdfasdf".to_string())
.unwrap();
let code = r#"
set BASE_URL env("b_url")
@name
get /api {}
"#;
let name_att_without_arg_err = Program::from(code).interpret(&env).unwrap_err();
assert_debug_snapshot!(name_att_without_arg_err);
}
#[test]
fn prevents_duplicate_attributes() {
let code = r#"
set BASE_URL env("b_url")
@log("file.json")
@log("otherfile.json")
get /api {}
"#;
let env = new_env_with_vars(&[("b_url", "asdfasdf")]);
let duped_att_err = Program::from(code).interpret(&env).unwrap_err();
assert_debug_snapshot!(duped_att_err);
let code = r#"
set BASE_URL env("b_url")
@name("a")
@name("b")
get /api {}
"#;
let env = new_env_with_vars(&[("b_url", "asdfasdf")]);
let duped_att_err = Program::from(code).interpret(&env).unwrap_err();
assert_debug_snapshot!(duped_att_err);
}
#[test]
fn request_with_json_like_data() {
let code = r#"
set BASE_URL env("b_url")
let ident = {
t: 123,
test: "ing"
}
post /test {
body json(ident)
}
post /api {
header "Content-Type" "application/json"
body json({
neet: 1337,
nothing: null,
arr: ["yo", {h: "i"}],
"hello": {
w: env("hello"),
warudo: env(env("hi")),
"fun": true,
notFun: false,
e: {},
em: []
},
})
}
"#;
let mut server = mockito::Server::new();
let url = server.url();
let env = new_env_with_vars(&[("b_url", &url), ("hello", "world"), ("hi", "hello")]);
let mock = server
.mock("POST", "/test")
.match_body(mockito::Matcher::PartialJsonString(
r#"{"t": 123.0, "test": "ing"}"#.to_string(),
))
.with_status(200)
.create();
let mock1 = server
.mock("POST", "/api")
.match_header("Content-Type", "application/json")
.match_body(mockito::Matcher::PartialJsonString(
r#"{"neet": 1337.0, "nothing": null, "arr": ["yo", {"h": "i"}], "hello": {"w": "world", "warudo": "world", "fun": true, "notFun": false, "e": {}, "em": []}}"#.to_string(),
))
.with_status(200)
.create();
run!(code, env);
mock.assert();
mock1.assert();
}
#[test]
fn ignores_expression_items() {
let code = r#"
env("test")
read("file")
// obj literal
{
key: "value",
oKey: ["1", "2"]
}
// string literal expression
"adsf"
"#;
let env = new_env_with_vars(&[]);
run!(code, env);
}