rust example

This commit is contained in:
Andras Bacsai
2024-07-19 14:50:47 +02:00
parent 1e571dbb76
commit 374ed812ca
5 changed files with 1712 additions and 0 deletions

1
rust/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
target/*

1551
rust/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

8
rust/Cargo.toml Normal file
View File

@@ -0,0 +1,8 @@
[package]
name = "hello"
version = "0.0.0"
edition = "2021"
publish = false
[dependencies]
rocket = "0.5.1"

81
rust/src/main.rs Normal file
View File

@@ -0,0 +1,81 @@
#[macro_use] extern crate rocket;
#[cfg(test)] mod tests;
#[derive(FromFormField)]
enum Lang {
#[field(value = "en")]
English,
#[field(value = "ru")]
#[field(value = "ру")]
Russian
}
#[derive(FromForm)]
struct Options<'r> {
emoji: bool,
name: Option<&'r str>,
}
// Try visiting:
// http://127.0.0.1:8000/hello/world
#[get("/world")]
fn world() -> &'static str {
"Hello, world!"
}
// Try visiting:
// http://127.0.0.1:8000/hello/мир
#[get("/мир")]
fn mir() -> &'static str {
"Привет, мир!"
}
// Try visiting:
// http://127.0.0.1:8000/wave/Rocketeer/100
#[get("/<name>/<age>")]
fn wave(name: &str, age: u8) -> String {
format!("👋 Hello, {} year old named {}!", age, name)
}
// Note: without the `..` in `opt..`, we'd need to pass `opt.emoji`, `opt.name`.
//
// Try visiting:
// http://127.0.0.1:8000/?emoji
// http://127.0.0.1:8000/?name=Rocketeer
// http://127.0.0.1:8000/?lang=ру
// http://127.0.0.1:8000/?lang=ру&emoji
// http://127.0.0.1:8000/?emoji&lang=en
// http://127.0.0.1:8000/?name=Rocketeer&lang=en
// http://127.0.0.1:8000/?emoji&name=Rocketeer
// http://127.0.0.1:8000/?name=Rocketeer&lang=en&emoji
// http://127.0.0.1:8000/?lang=ru&emoji&name=Rocketeer
#[get("/?<lang>&<opt..>")]
fn hello(lang: Option<Lang>, opt: Options<'_>) -> String {
let mut greeting = String::new();
if opt.emoji {
greeting.push_str("👋 ");
}
match lang {
Some(Lang::Russian) => greeting.push_str("Привет"),
Some(Lang::English) => greeting.push_str("Hello"),
None => greeting.push_str("Hi"),
}
if let Some(name) = opt.name {
greeting.push_str(", ");
greeting.push_str(name);
}
greeting.push('!');
greeting
}
#[launch]
fn rocket() -> _ {
rocket::build()
.mount("/", routes![hello])
.mount("/hello", routes![world, mir])
.mount("/wave", routes![wave])
}

71
rust/src/tests.rs Normal file
View File

@@ -0,0 +1,71 @@
use rocket::local::blocking::Client;
use rocket::http::{RawStr, Status};
#[test]
fn hello() {
let langs = &["", "ru", "%D1%80%D1%83", "en", "unknown"];
let ex_lang = &["Hi", "Привет", "Привет", "Hello", "Hi"];
let emojis = &["", "on", "true", "false", "no", "yes", "off"];
let ex_emoji = &["", "👋 ", "👋 ", "", "", "👋 ", ""];
let names = &["", "Bob", "Bob+Smith"];
let ex_name = &["!", ", Bob!", ", Bob Smith!"];
let client = Client::tracked(super::rocket()).unwrap();
for n in 0..(langs.len() * emojis.len() * names.len()) {
let i = n / (emojis.len() * names.len());
let j = n % (emojis.len() * names.len()) / names.len();
let k = n % (emojis.len() * names.len()) % names.len();
let (lang, ex_lang) = (langs[i], ex_lang[i]);
let (emoji, ex_emoji) = (emojis[j], ex_emoji[j]);
let (name, ex_name) = (names[k], ex_name[k]);
let expected = format!("{}{}{}", ex_emoji, ex_lang, ex_name);
let q = |name, s: &str| match s.is_empty() {
true => "".into(),
false => format!("&{}={}", name, s)
};
let uri = format!("/?{}{}{}", q("lang", lang), q("emoji", emoji), q("name", name));
let response = client.get(uri).dispatch();
assert_eq!(response.into_string().unwrap(), expected);
let uri = format!("/?{}{}{}", q("emoji", emoji), q("name", name), q("lang", lang));
let response = client.get(uri).dispatch();
assert_eq!(response.into_string().unwrap(), expected);
}
}
#[test]
fn hello_world() {
let client = Client::tracked(super::rocket()).unwrap();
let response = client.get("/hello/world").dispatch();
assert_eq!(response.into_string(), Some("Hello, world!".into()));
}
#[test]
fn hello_mir() {
let client = Client::tracked(super::rocket()).unwrap();
let response = client.get("/hello/%D0%BC%D0%B8%D1%80").dispatch();
assert_eq!(response.into_string(), Some("Привет, мир!".into()));
}
#[test]
fn wave() {
let client = Client::tracked(super::rocket()).unwrap();
for &(name, age) in &[("Bob%20Smith", 22), ("Michael", 80), ("A", 0), ("a", 127)] {
let uri = format!("/wave/{}/{}", name, age);
let real_name = RawStr::new(name).percent_decode_lossy();
let expected = format!("👋 Hello, {} year old named {}!", age, real_name);
let response = client.get(uri).dispatch();
assert_eq!(response.into_string().unwrap(), expected);
for bad_age in &["1000", "-1", "bird"] {
let bad_uri = format!("/wave/{}/{}", name, bad_age);
let response = client.get(bad_uri).dispatch();
assert_eq!(response.status(), Status::UnprocessableEntity);
}
}
}