314 lines
10 KiB
Rust
314 lines
10 KiB
Rust
use std::{
|
|
env,
|
|
ffi::OsStr,
|
|
fs,
|
|
path::{Path, PathBuf},
|
|
process::{Command, Output},
|
|
sync::atomic::{AtomicUsize, Ordering},
|
|
};
|
|
|
|
static NEXT_TEMP_ID: AtomicUsize = AtomicUsize::new(0);
|
|
|
|
const EXPECTED_TEST_OUTPUT: &str = concat!(
|
|
"test \"explicit std json document scalar string\" ... ok\n",
|
|
"test \"explicit std json document scalar bool\" ... ok\n",
|
|
"test \"explicit std json document scalar integer\" ... ok\n",
|
|
"test \"explicit std json document scalar float null\" ... ok\n",
|
|
"test \"explicit std json document scalar failures\" ... ok\n",
|
|
"test \"explicit std json document scalar all\" ... ok\n",
|
|
"6 test(s) passed\n",
|
|
);
|
|
|
|
const STANDARD_JSON_DOCUMENT_SCALAR_BETA21: &[&str] = &[
|
|
"parse_string_document_result",
|
|
"parse_bool_document_result",
|
|
"parse_i32_document_result",
|
|
"parse_u32_document_result",
|
|
"parse_i64_document_result",
|
|
"parse_u64_document_result",
|
|
"parse_f64_document_result",
|
|
"parse_null_document_result",
|
|
];
|
|
|
|
#[test]
|
|
fn explicit_std_json_document_scalar_helpers_check_and_test() {
|
|
let project = write_project(
|
|
"std-json-document-scalar-beta21",
|
|
r#"
|
|
(module main)
|
|
|
|
(import std.json (parse_string_document_result parse_bool_document_result parse_i32_document_result parse_u32_document_result parse_i64_document_result parse_u64_document_result parse_f64_document_result parse_null_document_result))
|
|
|
|
(fn imported_json_document_string_ok () -> bool
|
|
(if (= (std.result.unwrap_ok (parse_string_document_result " \"slovo\" ")) "slovo")
|
|
(= (std.result.unwrap_ok (parse_string_document_result "\n\t\"slo\\\"vo\"\t")) "slo\"vo")
|
|
false))
|
|
|
|
(fn imported_json_document_bool_ok () -> bool
|
|
(if (std.result.unwrap_ok (parse_bool_document_result " true "))
|
|
(= (std.result.unwrap_ok (parse_bool_document_result "\nfalse\t")) false)
|
|
false))
|
|
|
|
(fn imported_json_document_integer_ok () -> bool
|
|
(if (= (std.result.unwrap_ok (parse_i32_document_result " -7 ")) -7)
|
|
(if (= (std.result.unwrap_ok (parse_u32_document_result "\n7\t")) 7u32)
|
|
(if (= (std.result.unwrap_ok (parse_i64_document_result " -8 ")) -8i64)
|
|
(= (std.result.unwrap_ok (parse_u64_document_result "9 ")) 9u64)
|
|
false)
|
|
false)
|
|
false))
|
|
|
|
(fn imported_json_document_float_null_ok () -> bool
|
|
(if (= (std.result.unwrap_ok (parse_f64_document_result " 1e2 ")) 100.0)
|
|
(std.result.unwrap_ok (parse_null_document_result "\nnull\t"))
|
|
false))
|
|
|
|
(fn imported_json_document_failures_ok () -> bool
|
|
(if (= (std.result.unwrap_err (parse_string_document_result "\"slovo\" x")) 1)
|
|
(if (= (std.result.unwrap_err (parse_bool_document_result " TRUE ")) 1)
|
|
(if (= (std.result.unwrap_err (parse_i32_document_result " 01 ")) 1)
|
|
(if (= (std.result.unwrap_err (parse_u32_document_result " -1 ")) 1)
|
|
(if (= (std.result.unwrap_err (parse_i64_document_result " 8i64 ")) 1)
|
|
(if (= (std.result.unwrap_err (parse_u64_document_result " ")) 1)
|
|
(if (= (std.result.unwrap_err (parse_f64_document_result " 01.0 ")) 1)
|
|
(= (std.result.unwrap_err (parse_null_document_result " NULL ")) 1)
|
|
false)
|
|
false)
|
|
false)
|
|
false)
|
|
false)
|
|
false)
|
|
false))
|
|
|
|
(fn imported_json_document_scalar_all_ok () -> bool
|
|
(if (imported_json_document_string_ok)
|
|
(if (imported_json_document_bool_ok)
|
|
(if (imported_json_document_integer_ok)
|
|
(if (imported_json_document_float_null_ok)
|
|
(imported_json_document_failures_ok)
|
|
false)
|
|
false)
|
|
false)
|
|
false))
|
|
|
|
(fn main () -> i32
|
|
(if (imported_json_document_scalar_all_ok)
|
|
42
|
|
1))
|
|
|
|
(test "explicit std json document scalar string"
|
|
(imported_json_document_string_ok))
|
|
|
|
(test "explicit std json document scalar bool"
|
|
(imported_json_document_bool_ok))
|
|
|
|
(test "explicit std json document scalar integer"
|
|
(imported_json_document_integer_ok))
|
|
|
|
(test "explicit std json document scalar float null"
|
|
(imported_json_document_float_null_ok))
|
|
|
|
(test "explicit std json document scalar failures"
|
|
(imported_json_document_failures_ok))
|
|
|
|
(test "explicit std json document scalar all"
|
|
(= (main) 42))
|
|
"#,
|
|
);
|
|
|
|
let source = read(&project.join("src/main.slo"));
|
|
let std_json = read(&std_json_path());
|
|
|
|
assert!(
|
|
!project.join("src/json.slo").exists(),
|
|
"beta21 fixture must exercise repo-root std.json, not a local module copy"
|
|
);
|
|
assert!(
|
|
source.starts_with("(module main)\n\n(import std.json ("),
|
|
"beta21 fixture must use an explicit std.json import"
|
|
);
|
|
assert_json_document_scalar_helpers_are_source_authored(&std_json);
|
|
|
|
let fmt = run_glagol([
|
|
OsStr::new("fmt"),
|
|
OsStr::new("--check"),
|
|
project.as_os_str(),
|
|
]);
|
|
assert_success("std json document scalar fmt --check", &fmt);
|
|
|
|
let check = run_glagol([OsStr::new("check"), project.as_os_str()]);
|
|
assert_success_stdout(check, "", "std json document scalar check");
|
|
|
|
let test = run_glagol([OsStr::new("test"), project.as_os_str()]);
|
|
assert_success_stdout(test, EXPECTED_TEST_OUTPUT, "std json document scalar test");
|
|
}
|
|
|
|
#[test]
|
|
fn json_document_scalar_helpers_are_not_compiler_known_runtime_calls() {
|
|
let std_json = read(&std_json_path());
|
|
assert_json_document_scalar_helpers_are_source_authored(&std_json);
|
|
|
|
for helper in STANDARD_JSON_DOCUMENT_SCALAR_BETA21 {
|
|
let fixture = write_fixture(
|
|
helper,
|
|
&format!(
|
|
"(module main)\n\n(fn main () -> i32\n (std.result.unwrap_err (std.json.{} \"invalid\")))\n",
|
|
helper
|
|
),
|
|
);
|
|
let output = run_glagol([fixture.as_os_str()]);
|
|
assert_failure_stderr_contains(
|
|
&format!("direct std.json.{} runtime call", helper),
|
|
&output,
|
|
&format!(
|
|
"standard library call `std.json.{}` is not supported",
|
|
helper
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
fn assert_json_document_scalar_helpers_are_source_authored(std_json: &str) {
|
|
assert!(
|
|
std_json.starts_with("(module json (export "),
|
|
"lib/std/json.slo must stay a source-authored module export"
|
|
);
|
|
|
|
for helper in STANDARD_JSON_DOCUMENT_SCALAR_BETA21 {
|
|
assert!(
|
|
std_json.contains(&format!("(fn {} ", helper)),
|
|
"lib/std/json.slo is missing source facade `{}`",
|
|
helper
|
|
);
|
|
assert!(
|
|
!std_json.contains(&format!("std.json.{}", helper)),
|
|
"std.json.{} must remain source-authored, not a compiler-known runtime call",
|
|
helper
|
|
);
|
|
}
|
|
|
|
for private_prefix in [
|
|
"__glagol_json_parse_string_document",
|
|
"__glagol_json_parse_bool_document",
|
|
"__glagol_json_parse_i32_document",
|
|
"__glagol_json_parse_u32_document",
|
|
"__glagol_json_parse_i64_document",
|
|
"__glagol_json_parse_u64_document",
|
|
"__glagol_json_parse_f64_document",
|
|
"__glagol_json_parse_null_document",
|
|
] {
|
|
assert!(
|
|
!std_json.contains(private_prefix),
|
|
"lib/std/json.slo must not introduce private JSON document runtime symbol `{}`",
|
|
private_prefix
|
|
);
|
|
}
|
|
}
|
|
|
|
fn run_glagol<I, S>(args: I) -> Output
|
|
where
|
|
I: IntoIterator<Item = S>,
|
|
S: AsRef<OsStr>,
|
|
{
|
|
Command::new(env!("CARGO_BIN_EXE_glagol"))
|
|
.args(args)
|
|
.current_dir(Path::new(env!("CARGO_MANIFEST_DIR")))
|
|
.output()
|
|
.expect("run glagol")
|
|
}
|
|
|
|
fn write_project(name: &str, source: &str) -> PathBuf {
|
|
let root = temp_root(name);
|
|
let src = root.join("src");
|
|
fs::create_dir_all(&src).unwrap_or_else(|err| panic!("create `{}`: {}", src.display(), err));
|
|
fs::write(
|
|
root.join("slovo.toml"),
|
|
format!(
|
|
"[project]\nname = \"{}\"\nsource_root = \"src\"\nentry = \"main\"\n",
|
|
name
|
|
),
|
|
)
|
|
.unwrap_or_else(|err| panic!("write project manifest: {}", err));
|
|
fs::write(src.join("main.slo"), source.trim_start())
|
|
.unwrap_or_else(|err| panic!("write project main.slo: {}", err));
|
|
root
|
|
}
|
|
|
|
fn write_fixture(name: &str, source: &str) -> PathBuf {
|
|
let mut path = env::temp_dir();
|
|
path.push(format!(
|
|
"glagol-standard-json-document-scalar-beta21-{}-{}-{}.slo",
|
|
name,
|
|
std::process::id(),
|
|
NEXT_TEMP_ID.fetch_add(1, Ordering::Relaxed)
|
|
));
|
|
fs::write(&path, source.trim_start())
|
|
.unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
|
|
path
|
|
}
|
|
|
|
fn temp_root(name: &str) -> PathBuf {
|
|
let root = env::temp_dir().join(format!(
|
|
"glagol-standard-json-document-scalar-beta21-{}-{}-{}",
|
|
name,
|
|
std::process::id(),
|
|
NEXT_TEMP_ID.fetch_add(1, Ordering::Relaxed)
|
|
));
|
|
let _ = fs::remove_dir_all(&root);
|
|
fs::create_dir_all(&root).unwrap_or_else(|err| panic!("create `{}`: {}", root.display(), err));
|
|
root
|
|
}
|
|
|
|
fn std_json_path() -> PathBuf {
|
|
Path::new(env!("CARGO_MANIFEST_DIR")).join("../lib/std/json.slo")
|
|
}
|
|
|
|
fn read(path: &Path) -> String {
|
|
fs::read_to_string(path).unwrap_or_else(|err| panic!("read `{}`: {}", path.display(), err))
|
|
}
|
|
|
|
fn assert_success(context: &str, output: &Output) {
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(
|
|
output.status.success(),
|
|
"{} failed\nstatus: {:?}\nstdout:\n{}\nstderr:\n{}",
|
|
context,
|
|
output.status.code(),
|
|
stdout,
|
|
stderr
|
|
);
|
|
assert!(stderr.is_empty(), "{} wrote stderr:\n{}", context, stderr);
|
|
}
|
|
|
|
fn assert_success_stdout(output: Output, expected: &str, context: &str) {
|
|
assert_success(context, &output);
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
assert_eq!(stdout, expected, "{}", context);
|
|
}
|
|
|
|
fn assert_failure_stderr_contains(context: &str, output: &Output, needle: &str) {
|
|
let stdout = String::from_utf8_lossy(&output.stdout);
|
|
let stderr = String::from_utf8_lossy(&output.stderr);
|
|
assert!(
|
|
!output.status.success(),
|
|
"{} unexpectedly passed\nstdout:\n{}\nstderr:\n{}",
|
|
context,
|
|
stdout,
|
|
stderr
|
|
);
|
|
assert!(
|
|
stdout.is_empty(),
|
|
"{} rejected compile wrote stdout:\n{}",
|
|
context,
|
|
stdout
|
|
);
|
|
assert!(
|
|
stderr.contains(needle),
|
|
"{} stderr did not contain `{}`:\n{}",
|
|
context,
|
|
needle,
|
|
stderr
|
|
);
|
|
}
|