mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-13 01:21:38 -07:00
[varint] Add LEB128 decoding + tests
Also make tests in general less spammy: Don't print [PASS] for each successful test, only report failures and progress.
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright 2022 Jeroen van Rijn <nom@duclavier.com>.
|
||||
Made available under Odin's BSD-3 license.
|
||||
|
||||
List of contributors:
|
||||
Jeroen van Rijn: Initial implementation.
|
||||
*/
|
||||
|
||||
// package varint implements variable length integer encoding and decoding
|
||||
// using the LEB128 format as used by DWARF debug and other file formats
|
||||
package varint
|
||||
|
||||
// Decode a slice of bytes encoding an unsigned LEB128 integer into value and number of bytes used.
|
||||
// Returns `size` == 0 for an invalid value, empty slice, or a varint > 16 bytes.
|
||||
// In theory we should use the bigint package. In practice, varints bigger than this indicate a corrupted file.
|
||||
decode_uleb128 :: proc(buf: []u8) -> (val: u128, size: int) {
|
||||
more := true
|
||||
|
||||
for v, i in buf {
|
||||
size = i + 1
|
||||
|
||||
if size > size_of(u128) {
|
||||
return
|
||||
}
|
||||
|
||||
val |= u128(v & 0x7f) << uint(i * 7)
|
||||
|
||||
if v < 128 {
|
||||
more = false
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If the buffer runs out before the number ends, return an error.
|
||||
if more {
|
||||
return 0, 0
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Decode a slice of bytes encoding a signed LEB128 integer into value and number of bytes used.
|
||||
// Returns `size` == 0 for an invalid value, empty slice, or a varint > 16 bytes.
|
||||
// In theory we should use the bigint package. In practice, varints bigger than this indicate a corrupted file.
|
||||
decode_ileb128 :: proc(buf: []u8) -> (val: i128, size: int) {
|
||||
shift: uint
|
||||
|
||||
if len(buf) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
for v in buf {
|
||||
size += 1
|
||||
if size > size_of(i128) {
|
||||
return
|
||||
}
|
||||
|
||||
val |= i128(v & 0x7f) << shift
|
||||
shift += 7
|
||||
|
||||
if v < 128 { break }
|
||||
}
|
||||
|
||||
if buf[size - 1] & 0x40 == 0x40 {
|
||||
val |= max(i128) << shift
|
||||
}
|
||||
return
|
||||
}
|
||||
+6
-2
@@ -1,7 +1,7 @@
|
||||
ODIN=../../odin
|
||||
PYTHON=$(shell which python3)
|
||||
|
||||
all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test
|
||||
all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test
|
||||
|
||||
download_test_assets:
|
||||
$(PYTHON) download_assets.py
|
||||
@@ -22,4 +22,8 @@ crypto_test:
|
||||
$(ODIN) run crypto -out=crypto_hash -o:speed -no-bounds-check
|
||||
|
||||
noise_test:
|
||||
$(ODIN) run math/noise -out=test_noise
|
||||
$(ODIN) run math/noise -out=test_noise
|
||||
|
||||
encoding_test:
|
||||
$(ODIN) run encoding/json -out=test_json
|
||||
$(ODIN) run encoding/varint -out=test_varint
|
||||
@@ -35,7 +35,8 @@ echo ---
|
||||
echo ---
|
||||
echo Running core:encoding tests
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run encoding %COMMON%
|
||||
%PATH_TO_ODIN% run encoding/json %COMMON%
|
||||
%PATH_TO_ODIN% run encoding/varint %COMMON%
|
||||
|
||||
echo ---
|
||||
echo Running core:math/noise tests
|
||||
|
||||
@@ -30,14 +30,12 @@ when ODIN_TEST {
|
||||
log :: testing.log
|
||||
} else {
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.println(message)
|
||||
fmt.printf("[%v] %v\n", loc, message)
|
||||
return
|
||||
}
|
||||
fmt.println(" PASS")
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
+17
-19
@@ -9,32 +9,30 @@ TEST_count := 0
|
||||
TEST_fail := 0
|
||||
|
||||
when ODIN_TEST {
|
||||
expect :: testing.expect
|
||||
log :: testing.log
|
||||
expect :: testing.expect
|
||||
log :: testing.log
|
||||
} else {
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.println(message)
|
||||
return
|
||||
}
|
||||
fmt.println(" PASS")
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
fmt.printf("log: %v\n", v)
|
||||
}
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.printf("[%v] %v\n", loc, message)
|
||||
return
|
||||
}
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
fmt.printf("log: %v\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
t := testing.T{}
|
||||
|
||||
t := testing.T{}
|
||||
|
||||
parse_json(&t)
|
||||
marshal_json(&t)
|
||||
|
||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||
if TEST_fail > 0 {
|
||||
os.exit(1)
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package test_core_varint
|
||||
|
||||
import "core:encoding/varint"
|
||||
import "core:testing"
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
|
||||
TEST_count := 0
|
||||
TEST_fail := 0
|
||||
|
||||
when ODIN_TEST {
|
||||
expect :: testing.expect
|
||||
log :: testing.log
|
||||
} else {
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.printf("[%v] %v\n", loc, message)
|
||||
return
|
||||
}
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
fmt.printf("log: %v\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
t := testing.T{}
|
||||
|
||||
test_dwarf(&t)
|
||||
|
||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||
if TEST_fail > 0 {
|
||||
os.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@(test)
|
||||
test_dwarf :: proc(t: ^testing.T) {
|
||||
for vector in ULEB_Vectors {
|
||||
val, size := varint.decode_uleb128(vector.encoded)
|
||||
|
||||
msg := fmt.tprintf("Expected %02x to decode to %v consuming %v bytes, got %v and %v", vector.encoded, vector.value, vector.size, val, size)
|
||||
expect(t, size == vector.size && val == vector.value, msg)
|
||||
}
|
||||
|
||||
for vector in ILEB_Vectors {
|
||||
val, size := varint.decode_ileb128(vector.encoded)
|
||||
|
||||
msg := fmt.tprintf("Expected %02x to decode to %v consuming %v bytes, got %v and %v", vector.encoded, vector.value, vector.size, val, size)
|
||||
expect(t, size == vector.size && val == vector.value, msg)
|
||||
}
|
||||
}
|
||||
|
||||
ULEB_Test_Vector :: struct {
|
||||
encoded: []u8,
|
||||
value: u128,
|
||||
size: int,
|
||||
}
|
||||
|
||||
ULEB_Vectors :: []ULEB_Test_Vector{
|
||||
{ []u8{0x00}, 0, 1 },
|
||||
{ []u8{0x7f}, 127, 1 },
|
||||
{ []u8{0xE5, 0x8E, 0x26}, 624485, 3 },
|
||||
{ []u8{0x80}, 0, 0 },
|
||||
{ []u8{}, 0, 0 },
|
||||
}
|
||||
|
||||
ILEB_Test_Vector :: struct {
|
||||
encoded: []u8,
|
||||
value: i128,
|
||||
size: int,
|
||||
}
|
||||
|
||||
ILEB_Vectors :: []ILEB_Test_Vector{
|
||||
{ []u8{0x00}, 0, 1 },
|
||||
{ []u8{0xC0, 0xBB, 0x78}, -123456, 3 },
|
||||
{ []u8{}, 0, 0 },
|
||||
}
|
||||
@@ -15,14 +15,12 @@ when ODIN_TEST {
|
||||
log :: testing.log
|
||||
} else {
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.println(" FAIL:", message)
|
||||
fmt.printf("[%v] %v\n", loc, message)
|
||||
return
|
||||
}
|
||||
fmt.println(" PASS")
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
|
||||
@@ -32,23 +32,21 @@ TEST_count := 0
|
||||
TEST_fail := 0
|
||||
|
||||
when ODIN_TEST {
|
||||
expect :: testing.expect
|
||||
log :: testing.log
|
||||
expect :: testing.expect
|
||||
log :: testing.log
|
||||
} else {
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.println(message)
|
||||
return
|
||||
}
|
||||
fmt.println(" PASS")
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
fmt.printf("log: %v\n", v)
|
||||
}
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.printf("[%v] %v\n", loc, message)
|
||||
return
|
||||
}
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
fmt.printf("log: %v\n", v)
|
||||
}
|
||||
}
|
||||
I_Error :: image.Error
|
||||
|
||||
|
||||
@@ -13,23 +13,21 @@ V3 :: noise.Vec3
|
||||
V4 :: noise.Vec4
|
||||
|
||||
when ODIN_TEST {
|
||||
expect :: testing.expect
|
||||
log :: testing.log
|
||||
expect :: testing.expect
|
||||
log :: testing.log
|
||||
} else {
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.println(message)
|
||||
return
|
||||
}
|
||||
fmt.println(" PASS")
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
fmt.printf("log: %v\n", v)
|
||||
}
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.printf("[%v] %v\n", loc, message)
|
||||
return
|
||||
}
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
fmt.printf("log: %v\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
|
||||
@@ -10,34 +10,31 @@ TEST_count := 0
|
||||
TEST_fail := 0
|
||||
|
||||
when ODIN_TEST {
|
||||
expect :: testing.expect
|
||||
log :: testing.log
|
||||
expect :: testing.expect
|
||||
log :: testing.log
|
||||
} else {
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.println(message)
|
||||
return
|
||||
}
|
||||
fmt.println(" PASS")
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
fmt.printf("log: %v\n", v)
|
||||
}
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.printf("[%v] %v\n", loc, message)
|
||||
return
|
||||
}
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
fmt.printf("log: %v\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
main :: proc() {
|
||||
t := testing.T{}
|
||||
test_parse_demo(&t)
|
||||
t := testing.T{}
|
||||
test_parse_demo(&t)
|
||||
|
||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||
if TEST_fail > 0 {
|
||||
os.exit(1)
|
||||
}
|
||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||
if TEST_fail > 0 {
|
||||
os.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -50,4 +47,4 @@ test_parse_demo :: proc(t: ^testing.T) {
|
||||
for key, value in pkg.files {
|
||||
expect(t, value.syntax_error_count == 0, fmt.tprintf("%v should contain zero errors", key))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,59 +9,57 @@ TEST_count := 0
|
||||
TEST_fail := 0
|
||||
|
||||
when ODIN_TEST {
|
||||
expect :: testing.expect
|
||||
log :: testing.log
|
||||
expect :: testing.expect
|
||||
log :: testing.log
|
||||
} else {
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.println(message)
|
||||
return
|
||||
}
|
||||
fmt.println(" PASS")
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
fmt.printf("log: %v\n", v)
|
||||
}
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.printf("[%v] %v\n", loc, message)
|
||||
return
|
||||
}
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
fmt.printf("log: %v\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
t := testing.T{}
|
||||
test_index_any_small_string_not_found(&t)
|
||||
test_index_any_larger_string_not_found(&t)
|
||||
test_index_any_small_string_found(&t)
|
||||
test_index_any_larger_string_found(&t)
|
||||
t := testing.T{}
|
||||
test_index_any_small_string_not_found(&t)
|
||||
test_index_any_larger_string_not_found(&t)
|
||||
test_index_any_small_string_found(&t)
|
||||
test_index_any_larger_string_found(&t)
|
||||
|
||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||
if TEST_fail > 0 {
|
||||
os.exit(1)
|
||||
}
|
||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||
if TEST_fail > 0 {
|
||||
os.exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
@test
|
||||
test_index_any_small_string_not_found :: proc(t: ^testing.T) {
|
||||
index := strings.index_any(".", "/:\"")
|
||||
log(t, index)
|
||||
expect(t, index == -1, "index_any should be negative")
|
||||
index := strings.index_any(".", "/:\"")
|
||||
log(t, index)
|
||||
expect(t, index == -1, "index_any should be negative")
|
||||
}
|
||||
|
||||
@test
|
||||
test_index_any_larger_string_not_found :: proc(t: ^testing.T) {
|
||||
index := strings.index_any("aaaaaaaa.aaaaaaaa", "/:\"")
|
||||
expect(t, index == -1, "index_any should be negative")
|
||||
index := strings.index_any("aaaaaaaa.aaaaaaaa", "/:\"")
|
||||
expect(t, index == -1, "index_any should be negative")
|
||||
}
|
||||
|
||||
@test
|
||||
test_index_any_small_string_found :: proc(t: ^testing.T) {
|
||||
index := strings.index_any(".", "/:.\"")
|
||||
expect(t, index == 0, "index_any should be 0")
|
||||
index := strings.index_any(".", "/:.\"")
|
||||
expect(t, index == 0, "index_any should be 0")
|
||||
}
|
||||
|
||||
@test
|
||||
test_index_any_larger_string_found :: proc(t: ^testing.T) {
|
||||
index := strings.index_any("aaaaaaaa:aaaaaaaa", "/:\"")
|
||||
expect(t, index == 8, "index_any should be 8")
|
||||
index := strings.index_any("aaaaaaaa:aaaaaaaa", "/:\"")
|
||||
expect(t, index == 8, "index_any should be 8")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user