146 lines
5.2 KiB
Rust
146 lines
5.2 KiB
Rust
use super::*;
|
|
|
|
#[test]
|
|
fn enums_and_local_decode_use_shared_cmd_http_and_json_codecs() {
|
|
let directory = Directory::new();
|
|
let root = directory.0.join("module/demo/input");
|
|
std::fs::create_dir_all(root.join("app")).unwrap();
|
|
std::fs::write(root.join("app/read.dever"), r#"type State { Ready
|
|
Busy }
|
|
type Packet { state: State
|
|
optional: State?
|
|
states: List<State>
|
|
payload: Json }
|
|
type Decoded { Ready(value: Packet)
|
|
error Invalid(cause: dever.json.JsonResult) }
|
|
echo(value: State) (output: State) { output = value }
|
|
packet(value: Packet) (output: Packet) { output = value }
|
|
decode(payload: Json) (output: Packet) {
|
|
value: Packet = dever.json.decode(payload)
|
|
output = value
|
|
}
|
|
capture(payload: Json) (valid: Bool) {
|
|
value: Decoded = result(dever.json.decode(payload))
|
|
valid = accepted(value)
|
|
}
|
|
accepted(value: Decoded.Ready(packet)) (valid: Bool) recover("无效输入返回 false") { valid = packet.state == State.Ready }
|
|
accepted(value: Decoded.Invalid(cause)) (valid: Bool) recover("无效输入返回 false") { valid = false }
|
|
encode(value: State) (output: Json) { output = dever.json.encode(value) }
|
|
fault(divisor: Int) (valid: Bool) {
|
|
value: Decoded = result(dever.json.decode(dever.json.encode(10 // divisor)))
|
|
valid = accepted(value)
|
|
}
|
|
"#).unwrap();
|
|
std::fs::write(root.join("api.dever"), "cmd echo = app.echo\ncmd packet = app.packet\ncmd decode = app.decode\ncmd capture = app.capture\ncmd encode = app.encode\ncmd fault = app.fault\npublic get echo = app.echo\npublic post packet = app.packet\npublic post decode = app.decode\npublic post capture = app.capture\n").unwrap();
|
|
let project = Project::load(&directory.0).unwrap();
|
|
let program = project.check().unwrap();
|
|
let binary =
|
|
build::build(&program, &project.sources, "main", &directory.0.join("app")).unwrap();
|
|
let packet = r#"{"state":"Ready","optional":null,"states":["Busy"],"payload":{"x":1}}"#;
|
|
for (name, input, data) in [
|
|
("echo", r#"{"value":"Ready"}"#.to_owned(), r#""Ready""#),
|
|
("packet", format!(r#"{{"value":{packet}}}"#), packet),
|
|
("decode", format!(r#"{{"payload":{packet}}}"#), packet),
|
|
("capture", format!(r#"{{"payload":{packet}}}"#), "true"),
|
|
(
|
|
"capture",
|
|
r#"{"payload":{"state":"Wrong"}}"#.into(),
|
|
"false",
|
|
),
|
|
("encode", r#"{"value":"Busy"}"#.into(), r#""Busy""#),
|
|
] {
|
|
let output = execute(&binary, &format!("demo.input.{name}"), &input);
|
|
assert!(
|
|
output.status.success(),
|
|
"{name}: {}",
|
|
String::from_utf8_lossy(&output.stderr)
|
|
);
|
|
assert_eq!(
|
|
String::from_utf8(output.stdout).unwrap(),
|
|
format!("{{\"code\":0,\"message\":\"ok\",\"data\":{data}}}\n")
|
|
);
|
|
}
|
|
for input in [
|
|
r#"{"value":"Wrong"}"#,
|
|
r#"{"value":0}"#,
|
|
r#"{"value":{"Ready":null}}"#,
|
|
] {
|
|
assert!(!execute(&binary, "demo.input.echo", input).status.success());
|
|
}
|
|
let fault = execute(&binary, "demo.input.fault", r#"{"divisor":0}"#);
|
|
assert!(!fault.status.success());
|
|
let error = String::from_utf8_lossy(&fault.stderr);
|
|
assert!(error.contains("integer arithmetic fault"), "{error}");
|
|
let listener = TcpListener::bind("127.0.0.1:0").unwrap();
|
|
let port = listener.local_addr().unwrap().port();
|
|
drop(listener);
|
|
let config = directory.0.join("setting.json");
|
|
std::fs::write(&config, format!(r#"{{"http":{{"host":"127.0.0.1","port":{port}}},"sites":{{"public":{{"path":"","hosts":["fixture.test"]}}}}}}"#)).unwrap();
|
|
let mut server = Server(
|
|
Command::new(&binary)
|
|
.args(["--config", config.to_str().unwrap()])
|
|
.stdout(std::process::Stdio::null())
|
|
.spawn()
|
|
.unwrap(),
|
|
);
|
|
let deadline = Instant::now() + Duration::from_secs(5);
|
|
while TcpStream::connect(("127.0.0.1", port)).is_err() {
|
|
assert!(server.0.try_wait().unwrap().is_none());
|
|
assert!(Instant::now() < deadline);
|
|
std::thread::sleep(Duration::from_millis(10));
|
|
}
|
|
for (method, path, body, status, data) in [
|
|
(
|
|
"GET",
|
|
"/demo/input/echo?value=Busy",
|
|
"".into(),
|
|
200,
|
|
r#""Busy""#,
|
|
),
|
|
(
|
|
"GET",
|
|
"/demo/input/echo?value=Wrong",
|
|
"".into(),
|
|
400,
|
|
"null",
|
|
),
|
|
(
|
|
"POST",
|
|
"/demo/input/packet",
|
|
format!(r#"{{"value":{packet}}}"#),
|
|
200,
|
|
packet,
|
|
),
|
|
(
|
|
"POST",
|
|
"/demo/input/decode",
|
|
format!(r#"{{"payload":{packet}}}"#),
|
|
200,
|
|
packet,
|
|
),
|
|
(
|
|
"POST",
|
|
"/demo/input/capture",
|
|
r#"{"payload":null}"#.into(),
|
|
200,
|
|
"false",
|
|
),
|
|
] {
|
|
let (actual, output) = request(
|
|
port,
|
|
method,
|
|
path,
|
|
"fixture.test",
|
|
"Content-Type: application/json\r\n",
|
|
&body,
|
|
);
|
|
assert_eq!(actual, status, "{path}: {output}");
|
|
if status == 200 {
|
|
assert_eq!(
|
|
output,
|
|
format!("{{\"code\":0,\"message\":\"ok\",\"data\":{data}}}")
|
|
);
|
|
}
|
|
}
|
|
}
|