Files
core/test/rust/native/application/http/choice.rs
T
2026-11-03 03:32:07 +00:00

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}}}")
);
}
}
}