tests are now autogenerated from the readme, this makes test names DRY

I want to reduce friction of adding new tests as much as possible

Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
Jakub Doka 2024-12-25 21:17:03 +01:00
parent 5c8f7c9c79
commit 51bfbdf7ae
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
6 changed files with 69 additions and 158 deletions

1
.gitignore vendored
View file

@ -12,3 +12,4 @@ db.sqlite-journal
/depell/src/static-pages/*.html
#**/*-sv.rs
/bytecode/src/instrs.rs
/lang/src/testcases.rs

View file

@ -736,28 +736,6 @@ main := fn(): uint {
### Incomplete Examples
#### string_array
```hb
main := fn(): uint {
strings := (^u8).["abcdefshijklmnop\0".ptr, "abcdefghijklnnop\0".ptr, "abcdefshijklmnop\0".ptr, "abcdefghijklmnop\0".ptr, "abcdefghijflmnop\0".ptr, "dbcdefghijklmnop\0".ptr, "abcdefghijklmnop\0".ptr]
return *strings[0]
}
```
#### comptime_pointers
```hb
main := fn(): uint {
$integer := 7
modify(&integer)
return integer
}
modify := fn($num: ^uint): void {
$: *num = 0
}
```
#### fb_driver
```hb
arm_fb_ptr := fn(): uint return 100
@ -798,6 +776,30 @@ main := fn(): uint {
### Purely Testing Examples
#### string_array
```hb
main := fn(): uint {
strings := (^u8).["abcdefshijklmnop\0".ptr, "abcdefghijklnnop\0".ptr, "abcdefshijklmnop\0".ptr, "abcdefghijklmnop\0".ptr, "abcdefghijflmnop\0".ptr, "dbcdefghijklmnop\0".ptr, "abcdefghijklmnop\0".ptr]
return *strings[0]
}
```
#### generic_function_in_struct
```hb
A := struct {
a: uint,
b := fn(self: ^Self, $T: type, c: T): T {
return c
}
}
main := fn(): uint {
a := A.(100)
return a.b(uint, 100)
}
```
#### len_never_goes_down
```hb
chars := fn(iter: []u8): struct {

35
lang/build.rs Normal file
View file

@ -0,0 +1,35 @@
use std::{fmt::Write, iter};
fn main() {
const TEST_FILE: &str = "src/testcases.rs";
const INPUT: &str = include_str!("./README.md");
let mut out = String::new();
for (name, code) in block_iter(INPUT) {
let name = name.replace(' ', "_");
_ = writeln!(
out,
"#[test] fn {name}() {{ run_codegen_test(\"{name}\", r##\"{code}\"##) }}"
);
}
std::fs::write(TEST_FILE, out).unwrap();
}
fn block_iter(mut input: &str) -> impl Iterator<Item = (&str, &str)> {
const CASE_PREFIX: &str = "#### ";
const CASE_SUFFIX: &str = "\n```hb";
iter::from_fn(move || loop {
let pos = input.find(CASE_PREFIX)?;
input = unsafe { input.get_unchecked(pos + CASE_PREFIX.len()..) };
let Some((test_name, rest)) = input.split_once(CASE_SUFFIX) else { continue };
if !test_name.chars().all(|c| c.is_alphanumeric() || c == '_') {
continue;
}
input = rest;
let (body, rest) = input.split_once("```").unwrap_or((input, ""));
input = rest;
break Some((test_name, body));
})
}

View file

@ -401,10 +401,10 @@ impl Default for FnvHasher {
#[cfg(test)]
pub fn run_test(
name: &'static str,
ident: &'static str,
input: &'static str,
test: fn(&'static str, &'static str, &mut alloc::string::String),
name: &str,
ident: &str,
input: &str,
test: fn(&str, &str, &mut alloc::string::String),
) {
use std::{
io::Write,
@ -483,31 +483,6 @@ fn test_parse_files(
std::{borrow::ToOwned, string::ToString},
};
fn find_block<'a>(mut input: &'a str, test_name: &str) -> &'a str {
const CASE_PREFIX: &str = "#### ";
const CASE_SUFFIX: &str = "\n```hb";
loop {
let Some(pos) = input.find(CASE_PREFIX) else {
unreachable!("test {test_name} not found");
};
input = unsafe { input.get_unchecked(pos + CASE_PREFIX.len()..) };
if !input.starts_with(test_name) {
continue;
}
input = unsafe { input.get_unchecked(test_name.len()..) };
if !input.starts_with(CASE_SUFFIX) {
continue;
}
input = unsafe { input.get_unchecked(CASE_SUFFIX.len()..) };
let end = input.find("```").unwrap_or(input.len());
break unsafe { input.get_unchecked(..end) };
}
}
let input = find_block(input, ident);
let mut module_map = Vec::new();
let mut embed_map = Vec::new();
let mut last_start = 0;

View file

@ -4389,7 +4389,7 @@ mod tests {
core::fmt::Write,
};
fn generate(ident: &'static str, input: &'static str, output: &mut String) {
fn generate(ident: &str, input: &str, output: &mut String) {
_ = log::set_logger(&crate::fs::Logger);
log::set_max_level(log::LevelFilter::Info);
//log::set_max_level(log::LevelFilter::Trace);
@ -4423,111 +4423,9 @@ mod tests {
}
}
crate::run_tests! { generate:
// Tour Examples
main_fn;
arithmetic;
floating_point_arithmetic;
functions;
comments;
if_statements;
variables;
hex_octal_binary_literals;
loops;
pointers;
structs;
tuples;
struct_scopes;
enums;
unions;
nullable_types;
struct_operators;
global_variables;
constants;
directives;
c_strings;
struct_patterns;
arrays;
slices;
inline;
idk;
generic_functions;
die;
defer;
unrolled_loops;
// Incomplete Examples;
//comptime_pointers;
generic_types;
fb_driver;
// Purely Testing Examples;
len_never_goes_down;
slice_to_global_pointer;
subsclice_bug;
string_array;
proper_ident_propagation;
method_receiver_by_value;
comparing_floating_points;
pointer_comparison;
different_function_destinations;
triggering_store_in_divergent_branch;
wrong_dead_code_elimination;
memory_swap;
very_nested_loops;
generic_type_mishap;
storing_into_nullable_struct;
scheduling_block_did_dirty;
null_check_returning_small_global;
null_check_in_the_loop;
stack_provenance;
advanced_floating_point_arithmetic;
nullable_structure;
needless_unwrap;
inlining_issues;
null_check_test;
only_break_loop;
reading_idk;
nonexistent_ident_import;
big_array_crash;
returning_global_struct;
small_struct_bitcast;
small_struct_assignment;
intcast_store;
string_flip;
signed_to_unsigned_upcast;
wide_ret;
comptime_min_reg_leak;
different_types;
struct_return_from_module_function;
sort_something_viredly;
struct_in_register;
comptime_function_from_another_file;
inline_test;
inlined_generic_functions;
some_generic_code;
integer_inference_issues;
writing_into_string;
request_page;
tests_ptr_to_ptr_copy;
global_variable_wiredness;
inline_return_stack;
// Just Testing Optimizations;
elide_stack_offsets_for_parameters_correctly;
const_folding_with_arg;
branch_assignments;
exhaustive_loop_testing;
pointer_opts;
conditional_stores;
loop_stores;
dead_code_in_loop;
infinite_loop_after_peephole;
aliasing_overoptimization;
global_aliasing_overptimization;
overwrite_aliasing_overoptimization;
more_if_opts;
optional_from_eca;
returning_optional_issues;
fn run_codegen_test(name: &str, input: &str) {
crate::run_test(&format!("{}::{}", module_path!(), name), name, input, generate);
}
include!("./testcases.rs");
}