mirror of
https://github.com/lune-org/lune.git
synced 2025-01-05 19:09:10 +00:00
Migrate away from tokio & reqwest, use smol & ureq
This commit is contained in:
parent
e5e96dfd54
commit
06339a2699
10 changed files with 394 additions and 717 deletions
811
Cargo.lock
generated
811
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
12
Cargo.toml
12
Cargo.toml
|
@ -23,12 +23,12 @@ lto = true # Enable link-time optimization
|
||||||
panic = "abort" # Remove extra panic info
|
panic = "abort" # Remove extra panic info
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = { version = "1.0.68" }
|
anyhow = "1.0.68"
|
||||||
clap = { version = "4.1.1", features = ["derive"] }
|
clap = { version = "4.1.1", features = ["derive"] }
|
||||||
mlua = { version = "0.8.7", features = ["luau", "async", "serialize"] }
|
mlua = { version = "0.8.7", features = ["luau", "async", "serialize"] }
|
||||||
once_cell = { version = "1.17.0" }
|
once_cell = "1.17.0"
|
||||||
os_str_bytes = { version = "6.4.1" }
|
os_str_bytes = "6.4.1"
|
||||||
reqwest = { version = "0.11.13", features = ["gzip", "deflate"] }
|
|
||||||
serde = { version = "1.0.152", features = ["derive"] }
|
serde = { version = "1.0.152", features = ["derive"] }
|
||||||
serde_json = { version = "1.0.91" }
|
serde_json = "1.0.91"
|
||||||
tokio = { version = "1.24.2", features = ["full"] }
|
smol = "1.3.0"
|
||||||
|
ureq = "2.6.2"
|
||||||
|
|
|
@ -57,7 +57,7 @@ impl Cli {
|
||||||
// Download definition files, if wanted
|
// Download definition files, if wanted
|
||||||
let download_types_requested = self.download_selene_types || self.download_luau_types;
|
let download_types_requested = self.download_selene_types || self.download_luau_types;
|
||||||
if download_types_requested {
|
if download_types_requested {
|
||||||
let client = GithubClient::new().map_err(mlua::Error::external)?;
|
let client = GithubClient::new();
|
||||||
let release = client
|
let release = client
|
||||||
.fetch_release_for_this_version()
|
.fetch_release_for_this_version()
|
||||||
.await
|
.await
|
||||||
|
|
|
@ -10,9 +10,10 @@ mod utils;
|
||||||
|
|
||||||
use cli::Cli;
|
use cli::Cli;
|
||||||
|
|
||||||
#[tokio::main]
|
fn main() -> Result<()> {
|
||||||
async fn main() -> Result<()> {
|
smol::block_on(async {
|
||||||
let cli = Cli::parse();
|
let cli = Cli::parse();
|
||||||
cli.run().await?;
|
cli.run().await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use std::env::current_dir;
|
use std::env::current_dir;
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{bail, Context, Result};
|
||||||
use reqwest::header::{HeaderMap, HeaderValue};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use lune::utils::net::{get_github_owner_and_repo, get_request_user_agent_header};
|
use lune::utils::net::{get_github_owner_and_repo, get_request_user_agent_header};
|
||||||
|
use smol::unblock;
|
||||||
|
|
||||||
#[derive(Clone, Deserialize, Serialize)]
|
#[derive(Clone, Deserialize, Serialize)]
|
||||||
pub struct ReleaseAsset {
|
pub struct ReleaseAsset {
|
||||||
|
@ -29,35 +29,28 @@ pub struct Release {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
client: reqwest::Client,
|
|
||||||
github_owner: String,
|
github_owner: String,
|
||||||
github_repo: String,
|
github_repo: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub fn new() -> Result<Self> {
|
pub fn new() -> Self {
|
||||||
let (github_owner, github_repo) = get_github_owner_and_repo();
|
let (github_owner, github_repo) = get_github_owner_and_repo();
|
||||||
let mut headers = HeaderMap::new();
|
Self {
|
||||||
headers.insert(
|
|
||||||
"User-Agent",
|
|
||||||
HeaderValue::from_str(&get_request_user_agent_header())?,
|
|
||||||
);
|
|
||||||
headers.insert(
|
|
||||||
"Accept",
|
|
||||||
HeaderValue::from_static("application/vnd.github+json"),
|
|
||||||
);
|
|
||||||
headers.insert(
|
|
||||||
"X-GitHub-Api-Version",
|
|
||||||
HeaderValue::from_static("2022-11-28"),
|
|
||||||
);
|
|
||||||
let client = reqwest::Client::builder()
|
|
||||||
.default_headers(headers)
|
|
||||||
.build()?;
|
|
||||||
Ok(Self {
|
|
||||||
client,
|
|
||||||
github_owner,
|
github_owner,
|
||||||
github_repo,
|
github_repo,
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get(&self, url: &str, headers: &[(&str, &str)]) -> Result<String> {
|
||||||
|
let mut request = ureq::get(url)
|
||||||
|
.set("User-Agent", &get_request_user_agent_header())
|
||||||
|
.set("Accept", "application/vnd.github+json")
|
||||||
|
.set("X-GitHub-Api-Version", "2022-11-28");
|
||||||
|
for (header, value) in headers {
|
||||||
|
request = request.set(header, value);
|
||||||
|
}
|
||||||
|
unblock(|| Ok(request.send_string("")?.into_string()?)).await
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fetch_releases(&self) -> Result<Vec<Release>> {
|
pub async fn fetch_releases(&self) -> Result<Vec<Release>> {
|
||||||
|
@ -65,17 +58,8 @@ impl Client {
|
||||||
"https://api.github.com/repos/{}/{}/releases",
|
"https://api.github.com/repos/{}/{}/releases",
|
||||||
&self.github_owner, &self.github_repo
|
&self.github_owner, &self.github_repo
|
||||||
);
|
);
|
||||||
let response_bytes = self
|
let response_string = self.get(&release_api_url, &[]).await?;
|
||||||
.client
|
Ok(serde_json::from_str(&response_string)?)
|
||||||
.get(release_api_url)
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
.context("Failed to send releases request")?
|
|
||||||
.bytes()
|
|
||||||
.await
|
|
||||||
.context("Failed to get releases response bytes")?;
|
|
||||||
let response_body: Vec<Release> = serde_json::from_slice(&response_bytes)?;
|
|
||||||
Ok(response_body)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn fetch_release_for_this_version(&self) -> Result<Release> {
|
pub async fn fetch_release_for_this_version(&self) -> Result<Release> {
|
||||||
|
@ -95,17 +79,8 @@ impl Client {
|
||||||
.find(|asset| matches!(&asset.name, Some(name) if name == asset_name))
|
.find(|asset| matches!(&asset.name, Some(name) if name == asset_name))
|
||||||
{
|
{
|
||||||
let file_path = current_dir()?.join(asset_name);
|
let file_path = current_dir()?.join(asset_name);
|
||||||
let file_bytes = self
|
let file_string = self.get(&asset.url, &[]).await?;
|
||||||
.client
|
smol::fs::write(&file_path, &file_string)
|
||||||
.get(&asset.url)
|
|
||||||
.header("Accept", "application/octet-stream")
|
|
||||||
.send()
|
|
||||||
.await
|
|
||||||
.context("Failed to send asset download request")?
|
|
||||||
.bytes()
|
|
||||||
.await
|
|
||||||
.context("Failed to get asset download response bytes")?;
|
|
||||||
tokio::fs::write(&file_path, &file_bytes)
|
|
||||||
.await
|
.await
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
format!("Failed to write file at path '{}'", &file_path.display())
|
format!("Failed to write file at path '{}'", &file_path.display())
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::path::{PathBuf, MAIN_SEPARATOR};
|
use std::path::{PathBuf, MAIN_SEPARATOR};
|
||||||
|
|
||||||
use mlua::{Lua, Result};
|
use mlua::{Lua, Result};
|
||||||
use tokio::fs;
|
use smol::{fs, prelude::*};
|
||||||
|
|
||||||
use crate::utils::table_builder::TableBuilder;
|
use crate::utils::table_builder::TableBuilder;
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ async fn fs_read_file(_: &Lua, path: String) -> Result<String> {
|
||||||
async fn fs_read_dir(_: &Lua, path: String) -> Result<Vec<String>> {
|
async fn fs_read_dir(_: &Lua, path: String) -> Result<Vec<String>> {
|
||||||
let mut dir_strings = Vec::new();
|
let mut dir_strings = Vec::new();
|
||||||
let mut dir = fs::read_dir(&path).await.map_err(mlua::Error::external)?;
|
let mut dir = fs::read_dir(&path).await.map_err(mlua::Error::external)?;
|
||||||
while let Some(dir_entry) = dir.next_entry().await.map_err(mlua::Error::external)? {
|
while let Some(dir_entry) = dir.try_next().await.map_err(mlua::Error::external)? {
|
||||||
if let Some(dir_path_str) = dir_entry.path().to_str() {
|
if let Some(dir_path_str) = dir_entry.path().to_str() {
|
||||||
dir_strings.push(dir_path_str.to_owned());
|
dir_strings.push(dir_path_str.to_owned());
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,10 +1,6 @@
|
||||||
use std::{collections::HashMap, str::FromStr};
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use mlua::{Error, Lua, LuaSerdeExt, Result, Table, Value};
|
use mlua::{Error, Lua, LuaSerdeExt, Result, Table, Value};
|
||||||
use reqwest::{
|
|
||||||
header::{HeaderMap, HeaderName, HeaderValue},
|
|
||||||
Method,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::utils::{net::get_request_user_agent_header, table_builder::TableBuilder};
|
use crate::utils::{net::get_request_user_agent_header, table_builder::TableBuilder};
|
||||||
|
|
||||||
|
@ -38,7 +34,7 @@ async fn net_request<'lua>(lua: &'lua Lua, config: Value<'lua>) -> Result<Table<
|
||||||
Value::String(s) => {
|
Value::String(s) => {
|
||||||
let url = s.to_string_lossy().to_string();
|
let url = s.to_string_lossy().to_string();
|
||||||
let method = "GET".to_string();
|
let method = "GET".to_string();
|
||||||
(url, method, None, None)
|
(url, method, HashMap::new(), None)
|
||||||
}
|
}
|
||||||
Value::Table(tab) => {
|
Value::Table(tab) => {
|
||||||
// Extract url
|
// Extract url
|
||||||
|
@ -58,17 +54,14 @@ async fn net_request<'lua>(lua: &'lua Lua, config: Value<'lua>) -> Result<Table<
|
||||||
// Extract headers
|
// Extract headers
|
||||||
let headers = match tab.raw_get::<&str, mlua::Table>("headers") {
|
let headers = match tab.raw_get::<&str, mlua::Table>("headers") {
|
||||||
Ok(config_headers) => {
|
Ok(config_headers) => {
|
||||||
let mut lua_headers = HeaderMap::new();
|
let mut lua_headers = HashMap::new();
|
||||||
for pair in config_headers.pairs::<mlua::String, mlua::String>() {
|
for pair in config_headers.pairs::<mlua::String, mlua::String>() {
|
||||||
let (key, value) = pair?;
|
let (key, value) = pair?.to_owned();
|
||||||
lua_headers.insert(
|
lua_headers.insert(key, value);
|
||||||
HeaderName::from_str(key.to_str()?).map_err(Error::external)?,
|
|
||||||
HeaderValue::from_str(value.to_str()?).map_err(Error::external)?,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Some(lua_headers)
|
lua_headers
|
||||||
}
|
}
|
||||||
Err(_) => None,
|
Err(_) => HashMap::new(),
|
||||||
};
|
};
|
||||||
// Extract body
|
// Extract body
|
||||||
let body = match tab.raw_get::<&str, mlua::String>("body") {
|
let body = match tab.raw_get::<&str, mlua::String>("body") {
|
||||||
|
@ -85,58 +78,46 @@ async fn net_request<'lua>(lua: &'lua Lua, config: Value<'lua>) -> Result<Table<
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Convert method string into proper enum
|
// Convert method string into proper enum
|
||||||
let method = match Method::from_str(&method) {
|
let method = method.trim().to_ascii_uppercase();
|
||||||
Ok(meth) => meth,
|
let method = match method.as_ref() {
|
||||||
Err(_) => {
|
"GET" | "POST" | "PUT" | "DELETE" | "HEAD" | "OPTIONS" | "PATCH" => &method,
|
||||||
|
_ => {
|
||||||
return Err(Error::RuntimeError(format!(
|
return Err(Error::RuntimeError(format!(
|
||||||
"Invalid request config method '{}'",
|
"Invalid request config method '{}'",
|
||||||
&method
|
&method
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// Extract headers from config, force user agent
|
|
||||||
let mut header_map = if let Some(headers) = headers {
|
|
||||||
headers
|
|
||||||
} else {
|
|
||||||
HeaderMap::new()
|
|
||||||
};
|
|
||||||
header_map.insert(
|
|
||||||
"User-Agent",
|
|
||||||
HeaderValue::from_str(&get_request_user_agent_header()).map_err(Error::external)?,
|
|
||||||
);
|
|
||||||
// Create a client to send a request with
|
|
||||||
// FUTURE: Try to reuse this client
|
|
||||||
let client = reqwest::Client::builder()
|
|
||||||
.build()
|
|
||||||
.map_err(Error::external)?;
|
|
||||||
// Create and send the request
|
// Create and send the request
|
||||||
let mut request = client.request(method, url).headers(header_map);
|
let mut request = ureq::request(method, &url);
|
||||||
if let Some(body) = body {
|
for (header, value) in headers {
|
||||||
request = request.body(body);
|
request = request.set(header.to_str()?, value.to_str()?);
|
||||||
}
|
}
|
||||||
let response = request.send().await.map_err(Error::external)?;
|
let response = request
|
||||||
// Extract status, headers, body
|
.set("User-Agent", &get_request_user_agent_header()) // Always force user agent
|
||||||
let res_status = response.status();
|
.send_bytes(&body.unwrap_or_default());
|
||||||
let res_headers = response.headers().clone();
|
match response {
|
||||||
let res_bytes = response.bytes().await.map_err(Error::external)?;
|
Ok(res) | Err(ureq::Error::Status(_, res)) => {
|
||||||
// Construct and return a readonly lua table with results
|
// Extract status, headers
|
||||||
TableBuilder::new(lua)?
|
let res_status = res.status();
|
||||||
.with_value("ok", res_status.is_success())?
|
let res_status_text = res.status_text().to_owned();
|
||||||
.with_value("statusCode", res_status.as_u16())?
|
let res_header_names = &res.headers_names();
|
||||||
.with_value(
|
let res_headers = res_header_names
|
||||||
"statusMessage",
|
|
||||||
res_status.canonical_reason().unwrap_or("?"),
|
|
||||||
)?
|
|
||||||
.with_value(
|
|
||||||
"headers",
|
|
||||||
res_headers
|
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|(key, value)| match value.to_str() {
|
.map(|name| (name.to_owned(), res.header(name).unwrap().to_owned()))
|
||||||
Ok(value) => Some((key.as_str(), value)),
|
.collect::<HashMap<String, String>>();
|
||||||
Err(_) => None,
|
// Read response bytes
|
||||||
})
|
let mut res_bytes = Vec::new();
|
||||||
.collect::<HashMap<_, _>>(),
|
res.into_reader().read_to_end(&mut res_bytes)?;
|
||||||
)?
|
// Construct and return a readonly lua table with results
|
||||||
.with_value("body", lua.create_string(&res_bytes)?)?
|
TableBuilder::new(lua)?
|
||||||
.build_readonly()
|
.with_value("ok", (200..300).contains(&res_status))?
|
||||||
|
.with_value("statusCode", res_status)?
|
||||||
|
.with_value("statusMessage", res_status_text)?
|
||||||
|
.with_value("headers", res_headers)?
|
||||||
|
.with_value("body", lua.create_string(&res_bytes)?)?
|
||||||
|
.build_readonly()
|
||||||
|
}
|
||||||
|
Err(e) => Err(Error::external(e)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ use std::{
|
||||||
|
|
||||||
use mlua::{Error, Function, Lua, MetaMethod, Result, Table, Value};
|
use mlua::{Error, Function, Lua, MetaMethod, Result, Table, Value};
|
||||||
use os_str_bytes::RawOsString;
|
use os_str_bytes::RawOsString;
|
||||||
use tokio::process::Command;
|
use smol::process::Command;
|
||||||
|
|
||||||
use crate::utils::table_builder::TableBuilder;
|
use crate::utils::table_builder::TableBuilder;
|
||||||
|
|
||||||
|
@ -113,10 +113,7 @@ async fn process_spawn(lua: &Lua, (program, args): (String, Option<Vec<String>>)
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
.map_err(mlua::Error::external)?;
|
.map_err(mlua::Error::external)?;
|
||||||
let output = child
|
let output = child.output().await.map_err(mlua::Error::external)?;
|
||||||
.wait_with_output()
|
|
||||||
.await
|
|
||||||
.map_err(mlua::Error::external)?;
|
|
||||||
// NOTE: If an exit code was not given by the child process,
|
// NOTE: If an exit code was not given by the child process,
|
||||||
// we default to 1 if it yielded any error output, otherwise 0
|
// we default to 1 if it yielded any error output, otherwise 0
|
||||||
let code = output
|
let code = output
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::time::Duration;
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
use mlua::{Error, Function, Lua, Result, Table, Thread, Value, Variadic};
|
use mlua::{Error, Function, Lua, Result, Table, Thread, Value, Variadic};
|
||||||
use tokio::time::{self, Instant};
|
use smol::Timer;
|
||||||
|
|
||||||
use crate::utils::table_builder::TableBuilder;
|
use crate::utils::table_builder::TableBuilder;
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ async fn task_spawn<'a>(lua: &'a Lua, (tof, args): (Value<'a>, Vararg<'a>)) -> R
|
||||||
// the async wait function inside of a coroutine
|
// the async wait function inside of a coroutine
|
||||||
async fn task_wait(_: &Lua, duration: Option<f32>) -> Result<f32> {
|
async fn task_wait(_: &Lua, duration: Option<f32>) -> Result<f32> {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
time::sleep(
|
Timer::after(
|
||||||
duration
|
duration
|
||||||
.map(Duration::from_secs_f32)
|
.map(Duration::from_secs_f32)
|
||||||
.unwrap_or(Duration::ZERO),
|
.unwrap_or(Duration::ZERO),
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use mlua::Lua;
|
use mlua::prelude::*;
|
||||||
use tokio::task;
|
|
||||||
|
|
||||||
pub mod globals;
|
pub mod globals;
|
||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
@ -62,46 +61,33 @@ impl Lune {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn run(&self, name: &str, chunk: &str) -> Result<()> {
|
pub async fn run(&self, name: &str, chunk: &str) -> Result<()> {
|
||||||
let run_name = name.to_owned();
|
smol::block_on(async {
|
||||||
let run_chunk = chunk.to_owned();
|
let lua = Lua::new();
|
||||||
let run_globals = self.globals.to_owned();
|
for global in &self.globals {
|
||||||
let run_args = self.args.to_owned();
|
match &global {
|
||||||
// Spawn a thread-local task so that we can then spawn
|
LuneGlobal::Console => create_console(&lua).await?,
|
||||||
// more tasks in our globals without the Send requirement
|
LuneGlobal::Fs => create_fs(&lua).await?,
|
||||||
let local = task::LocalSet::new();
|
LuneGlobal::Net => create_net(&lua).await?,
|
||||||
local
|
LuneGlobal::Process => create_process(&lua, self.args.clone()).await?,
|
||||||
.run_until(async move {
|
LuneGlobal::Task => create_task(&lua).await?,
|
||||||
task::spawn_local(async move {
|
}
|
||||||
let lua = Lua::new();
|
}
|
||||||
for global in &run_globals {
|
let result = lua.load(chunk).set_name(name)?.exec_async().await;
|
||||||
match &global {
|
match result {
|
||||||
LuneGlobal::Console => create_console(&lua).await?,
|
Ok(_) => Ok(()),
|
||||||
LuneGlobal::Fs => create_fs(&lua).await?,
|
Err(e) => {
|
||||||
LuneGlobal::Net => create_net(&lua).await?,
|
if cfg!(test) {
|
||||||
LuneGlobal::Process => create_process(&lua, run_args.clone()).await?,
|
bail!(pretty_format_luau_error(&e))
|
||||||
LuneGlobal::Task => create_task(&lua).await?,
|
} else {
|
||||||
}
|
bail!(
|
||||||
|
"\n{}\n{}",
|
||||||
|
format_label("ERROR"),
|
||||||
|
pretty_format_luau_error(&e)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
let result = lua.load(&run_chunk).set_name(&run_name)?.exec_async().await;
|
}
|
||||||
match result {
|
}
|
||||||
Ok(_) => Ok(()),
|
})
|
||||||
Err(e) => {
|
|
||||||
if cfg!(test) {
|
|
||||||
bail!(pretty_format_luau_error(&e))
|
|
||||||
} else {
|
|
||||||
bail!(
|
|
||||||
"\n{}\n{}",
|
|
||||||
format_label("ERROR"),
|
|
||||||
pretty_format_luau_error(&e)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
})
|
|
||||||
.await
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,26 +95,28 @@ impl Lune {
|
||||||
mod tests {
|
mod tests {
|
||||||
use crate::Lune;
|
use crate::Lune;
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use smol::fs::read_to_string;
|
||||||
use std::env::current_dir;
|
use std::env::current_dir;
|
||||||
use tokio::fs::read_to_string;
|
|
||||||
|
|
||||||
const ARGS: &[&str] = &["Foo", "Bar"];
|
const ARGS: &[&str] = &["Foo", "Bar"];
|
||||||
|
|
||||||
macro_rules! run_tests {
|
macro_rules! run_tests {
|
||||||
($($name:ident: $value:expr,)*) => {
|
($($name:ident: $value:expr,)*) => {
|
||||||
$(
|
$(
|
||||||
#[tokio::test]
|
#[test]
|
||||||
async fn $name() -> Result<()> {
|
fn $name() -> Result<()> {
|
||||||
let path = current_dir()
|
smol::block_on(async {
|
||||||
.unwrap()
|
let path = current_dir()
|
||||||
.join(format!("src/tests/{}.luau", $value));
|
.unwrap()
|
||||||
let script = read_to_string(&path)
|
.join(format!("src/tests/{}.luau", $value));
|
||||||
.await
|
let script = read_to_string(&path)
|
||||||
.unwrap();
|
.await
|
||||||
let lune = Lune::new()
|
.unwrap();
|
||||||
.with_args(ARGS.clone().iter().map(ToString::to_string).collect())
|
let lune = Lune::new()
|
||||||
.with_all_globals();
|
.with_args(ARGS.clone().iter().map(ToString::to_string).collect())
|
||||||
lune.run($value, &script).await
|
.with_all_globals();
|
||||||
|
lune.run($value, &script).await
|
||||||
|
})
|
||||||
}
|
}
|
||||||
)*
|
)*
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue