02-Loops and if.md
03-Functions and scopes.md
04-Structs.md
05-Imports and namespaces.md
06-Enums and switch.md
07-Debugging.md
08-Macros and preprocessor.md
10-Annotations.md
11-Operator overloading.md
15-Polymorphism.md
16-Maps and arrays.md
17-Constructors and destructors.md
18-Platforms.md
19-Testing.md
20-Type information.md
21-Inline assembly.md
22-Libraries.md
23-Style conventions.md
24-Exceptions.md
25-Bytecode and VM.md
26-Targeting ARM.md
27-Compile time execution.md
28-Compiler functions.md
29-Importing C headers.md
100-Standard libraries.md
101-OpenSSL.md
102-Logger.md
README.md
19-Testing.md
The language/compiler has a builtin testing feature, mainly meant for testing the compiler while relying on as few features as possible. It can be used to selectively run tests from a directory, file or individual tests within a file.
There is one flaw which is that failed and succeded tests are printed to stdout which means that you can't use stdout for other things. We may use stderr in the future or write to a temporary file
You can always develop your own testing environment if the testing system doesn't suit your needs.
The basics
WARNING: The syntax and behaviour is not set in stone and may change in the future!
First of all, this is what you type in the terminal to tell the compiler to run tests.
btb --test your_file.btb
# Wildcard is also allowed, see 'btb --help' for more information
btb --test tests/*
There are two key components to testing. Specifying a test case and tests to perform within the case as seen below.
@TEST_CASE(my_first_test) // <- The test case
_test 1; 1; // will always succeed <- The tests
_test 1; 0; // will always fail
// _test takes two expressions that evaluates to a 64-bit
// value on a 64-bit machine.
_test expr_a; expr_b;
// Yes, separating the expressions with semi-colon is a little strange. Syntax is work in progress.
Here is an example with two test cases.
@TEST_CASE(test_func)
expectations: i32[] { 2, 7, 12, 17 }
for expectations {
expected := it
actual := func(nr)
_test expected; actual;
}
fn func(x: i32) -> i32 { return x * 5 + 2 }
@TEST_CASE(test_diamond)
expectations: i32[] { 2, 7, 12, 17 }
for expectations {
expected := it
actual := func(nr)
_test expected; actual;
}
fn func(x: i32) -> i32 { return x * 5 + 2 }
Implementation details
TODO: Provide more information and clarify things.
The compiler tests code with these steps:
- 1. Find
@TEST_CASE within the files and divide them up into substrings. - 2. Compile the substrings.
- 3. Execute the compiled program.
- 4. Read stdout from the program,
x means success,_ means failure - 5. Summarize compile errors and the result from stdout.
- 16777215 (24 bits)
_test(0, 4, 4) _test(1, 4, 4) _test(2, 4, 4)
The machine code `_test` is converted to can be found by searching for BC_TEST_VALUE in this file `x64_gen_extra.cpp`.
`TestSuite.cpp` controls the steps during testing.
# Future features
- Improve test time by reusing compiled imports for multiple tests cases. Especially those from the standard library. This should be an optional feature since it could have unforseen side effects.
- Ability to write a section of code that is included in all test cases within a file. Currently, you have to create a separate file and import it to reuse code like that for testing.