mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-07 19:14:19 +00:00
Port tests\core\net
This commit is contained in:
committed by
Feoramund
parent
dacb0f7786
commit
62b7d8de97
@@ -81,7 +81,7 @@ noise_test:
|
||||
$(ODIN) test math/noise $(COMMON) -out:test_noise
|
||||
|
||||
net_test:
|
||||
$(ODIN) run net $(COMMON) -out:test_core_net
|
||||
$(ODIN) test net $(COMMON) -out:test_core_net
|
||||
|
||||
os_exit_test:
|
||||
$(ODIN) run os/test_core_os_exit.odin -file -out:test_core_os_exit && exit 1 || exit 0
|
||||
|
||||
@@ -81,7 +81,7 @@ echo ---
|
||||
echo ---
|
||||
echo Running core:net
|
||||
echo ---
|
||||
%PATH_TO_ODIN% run net %COMMON% -out:test_core_net.exe || exit /b
|
||||
%PATH_TO_ODIN% test net %COMMON% -out:test_core_net.exe || exit /b
|
||||
|
||||
echo ---
|
||||
echo Running core:odin tests
|
||||
|
||||
@@ -11,71 +11,12 @@
|
||||
package test_core_net
|
||||
|
||||
import "core:testing"
|
||||
import "core:mem"
|
||||
import "core:fmt"
|
||||
import "core:net"
|
||||
import "core:strconv"
|
||||
import "core:sync"
|
||||
import "core:time"
|
||||
import "core:thread"
|
||||
import "core:os"
|
||||
|
||||
_, _ :: time, thread
|
||||
|
||||
TEST_count := 0
|
||||
TEST_fail := 0
|
||||
|
||||
t := &testing.T{}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
_tracking_allocator := mem.Tracking_Allocator{}
|
||||
|
||||
print_tracking_allocator_report :: proc() {
|
||||
for _, leak in _tracking_allocator.allocation_map {
|
||||
fmt.printf("%v leaked %v bytes\n", leak.location, leak.size)
|
||||
}
|
||||
|
||||
for bf in _tracking_allocator.bad_free_array {
|
||||
fmt.printf("%v allocation %p was freed badly\n", bf.location, bf.memory)
|
||||
}
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
mem.tracking_allocator_init(&_tracking_allocator, context.allocator)
|
||||
context.allocator = mem.tracking_allocator(&_tracking_allocator)
|
||||
|
||||
address_parsing_test(t)
|
||||
|
||||
tcp_tests(t)
|
||||
|
||||
split_url_test(t)
|
||||
join_url_test(t)
|
||||
|
||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||
|
||||
print_tracking_allocator_report()
|
||||
|
||||
if TEST_fail > 0 {
|
||||
os.exit(1)
|
||||
}
|
||||
}
|
||||
import "core:fmt"
|
||||
|
||||
@test
|
||||
address_parsing_test :: proc(t: ^testing.T) {
|
||||
@@ -89,127 +30,66 @@ address_parsing_test :: proc(t: ^testing.T) {
|
||||
}
|
||||
|
||||
valid := len(vector.binstr) > 0
|
||||
|
||||
fmt.printf("%v %v\n", kind, vector.input)
|
||||
|
||||
msg := "-set a proper message-"
|
||||
switch vector.family {
|
||||
case .IP4, .IP4_Alt:
|
||||
/*
|
||||
Does `net.parse_ip4_address` think we parsed the address properly?
|
||||
*/
|
||||
// Does `net.parse_ip4_address` think we parsed the address properly?
|
||||
non_decimal := vector.family == .IP4_Alt
|
||||
any_addr := net.parse_address(vector.input, non_decimal)
|
||||
parsed_ok := any_addr != nil
|
||||
parsed: net.IP4_Address
|
||||
|
||||
any_addr := net.parse_address(vector.input, non_decimal)
|
||||
parsed_ok := any_addr != nil
|
||||
parsed: net.IP4_Address
|
||||
|
||||
/*
|
||||
Ensure that `parse_address` doesn't parse IPv4 addresses into IPv6 addreses by mistake.
|
||||
*/
|
||||
// Ensure that `parse_address` doesn't parse IPv4 addresses into IPv6 addreses by mistake.
|
||||
switch addr in any_addr {
|
||||
case net.IP4_Address:
|
||||
parsed = addr
|
||||
case net.IP6_Address:
|
||||
parsed_ok = false
|
||||
msg = fmt.tprintf("parse_address mistook %v as IPv6 address %04x", vector.input, addr)
|
||||
expect(t, false, msg)
|
||||
testing.expectf(t, false, "parse_address mistook %v as IPv6 address %04x", vector.input, addr)
|
||||
}
|
||||
|
||||
if !parsed_ok && valid {
|
||||
msg = fmt.tprintf("parse_ip4_address failed to parse %v, expected %v", vector.input, binstr_to_address(vector.binstr))
|
||||
testing.expectf(t, parsed_ok == valid, "parse_ip4_address failed to parse %v, expected %v", vector.input, binstr_to_address(t, vector.binstr))
|
||||
|
||||
} else if parsed_ok && !valid {
|
||||
msg = fmt.tprintf("parse_ip4_address parsed %v into %v, expected failure", vector.input, parsed)
|
||||
testing.expectf(t, parsed_ok == valid, "parse_ip4_address parsed %v into %v, expected failure", vector.input, parsed)
|
||||
}
|
||||
expect(t, parsed_ok == valid, msg)
|
||||
|
||||
if valid && parsed_ok {
|
||||
actual_binary := address_to_binstr(parsed)
|
||||
msg = fmt.tprintf("parse_ip4_address parsed %v into %v, expected %v", vector.input, actual_binary, vector.binstr)
|
||||
expect(t, actual_binary == vector.binstr, msg)
|
||||
testing.expectf(t, actual_binary == vector.binstr, "parse_ip4_address parsed %v into %v, expected %v", vector.input, actual_binary, vector.binstr)
|
||||
|
||||
/*
|
||||
Do we turn an address back into the same string properly?
|
||||
No point in testing the roundtrip if the first part failed.
|
||||
*/
|
||||
// Do we turn an address back into the same string properly? No point in testing the roundtrip if the first part failed.
|
||||
if len(vector.output) > 0 && actual_binary == vector.binstr {
|
||||
stringified := net.address_to_string(parsed)
|
||||
msg = fmt.tprintf("address_to_string turned %v into %v, expected %v", parsed, stringified, vector.output)
|
||||
expect(t, stringified == vector.output, msg)
|
||||
testing.expectf(t, stringified == vector.output, "address_to_string turned %v into %v, expected %v", parsed, stringified, vector.output)
|
||||
}
|
||||
}
|
||||
|
||||
case .IP6:
|
||||
/*
|
||||
Do we parse the address properly?
|
||||
*/
|
||||
// Do we parse the address properly?
|
||||
parsed, parsed_ok := net.parse_ip6_address(vector.input)
|
||||
|
||||
if !parsed_ok && valid {
|
||||
msg = fmt.tprintf("parse_ip6_address failed to parse %v, expected %04x", vector.input, binstr_to_address(vector.binstr))
|
||||
testing.expectf(t, parsed_ok == valid, "parse_ip6_address failed to parse %v, expected %04x", vector.input, binstr_to_address(t, vector.binstr))
|
||||
|
||||
} else if parsed_ok && !valid {
|
||||
msg = fmt.tprintf("parse_ip6_address parsed %v into %04x, expected failure", vector.input, parsed)
|
||||
testing.expectf(t, parsed_ok == valid, "parse_ip6_address parsed %v into %04x, expected failure", vector.input, parsed)
|
||||
}
|
||||
expect(t, parsed_ok == valid, msg)
|
||||
|
||||
if valid && parsed_ok {
|
||||
actual_binary := address_to_binstr(parsed)
|
||||
msg = fmt.tprintf("parse_ip6_address parsed %v into %v, expected %v", vector.input, actual_binary, vector.binstr)
|
||||
expect(t, actual_binary == vector.binstr, msg)
|
||||
testing.expectf(t, actual_binary == vector.binstr, "parse_ip6_address parsed %v into %v, expected %v", vector.input, actual_binary, vector.binstr)
|
||||
|
||||
/*
|
||||
Do we turn an address back into the same string properly?
|
||||
No point in testing the roundtrip if the first part failed.
|
||||
*/
|
||||
// Do we turn an address back into the same string properly? No point in testing the roundtrip if the first part failed.
|
||||
if len(vector.output) > 0 && actual_binary == vector.binstr {
|
||||
stringified := net.address_to_string(parsed)
|
||||
msg = fmt.tprintf("address_to_string turned %v into %v, expected %v", parsed, stringified, vector.output)
|
||||
expect(t, stringified == vector.output, msg)
|
||||
testing.expectf(t, stringified == vector.output, "address_to_string turned %v into %v, expected %v", parsed, stringified, vector.output)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
address_to_binstr :: proc(address: net.Address) -> (binstr: string) {
|
||||
switch t in address {
|
||||
case net.IP4_Address:
|
||||
b := transmute(u32be)t
|
||||
return fmt.tprintf("%08x", b)
|
||||
case net.IP6_Address:
|
||||
b := transmute(u128be)t
|
||||
return fmt.tprintf("%32x", b)
|
||||
case:
|
||||
return ""
|
||||
}
|
||||
unreachable()
|
||||
}
|
||||
|
||||
binstr_to_address :: proc(binstr: string) -> (address: net.Address) {
|
||||
switch len(binstr) {
|
||||
case 8: // IPv4
|
||||
a, ok := strconv.parse_u64_of_base(binstr, 16)
|
||||
expect(t, ok, "failed to parse test case bin string")
|
||||
|
||||
ipv4 := u32be(a)
|
||||
return net.IP4_Address(transmute([4]u8)ipv4)
|
||||
|
||||
|
||||
case 32: // IPv6
|
||||
a, ok := strconv.parse_u128_of_base(binstr, 16)
|
||||
expect(t, ok, "failed to parse test case bin string")
|
||||
|
||||
ipv4 := u128be(a)
|
||||
return net.IP6_Address(transmute([8]u16be)ipv4)
|
||||
|
||||
case 0:
|
||||
return nil
|
||||
}
|
||||
panic("Invalid test case")
|
||||
}
|
||||
|
||||
Kind :: enum {
|
||||
IP4, // Decimal IPv4
|
||||
IP4_Alt, // Non-decimal address
|
||||
@@ -223,10 +103,7 @@ IP_Address_Parsing_Test_Vector :: struct {
|
||||
// Input address to try and parse.
|
||||
input: string,
|
||||
|
||||
/*
|
||||
Hexadecimal representation of the expected numeric value of the address.
|
||||
Zero length means input is invalid and the parser should report failure.
|
||||
*/
|
||||
// Hexadecimal representation of the expected numeric value of the address. Zero length means input is invalid and the parser should report failure.
|
||||
binstr: string,
|
||||
|
||||
// Expected `address_to_string` output, if a valid input and this string is non-empty.
|
||||
@@ -335,38 +212,30 @@ IP_Address_Parsing_Test_Vectors :: []IP_Address_Parsing_Test_Vector{
|
||||
{ .IP6, "c0a8", "", ""},
|
||||
}
|
||||
|
||||
tcp_tests :: proc(t: ^testing.T) {
|
||||
fmt.println("Testing two servers trying to bind to the same endpoint...")
|
||||
two_servers_binding_same_endpoint(t)
|
||||
fmt.println("Testing client connecting to a closed port...")
|
||||
client_connects_to_closed_port(t)
|
||||
fmt.println("Testing client sending server data...")
|
||||
client_sends_server_data(t)
|
||||
}
|
||||
|
||||
ENDPOINT := net.Endpoint{
|
||||
net.IP4_Address{127, 0, 0, 1},
|
||||
9999,
|
||||
}
|
||||
ENDPOINT_TWO_SERVERS := net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 9991}
|
||||
ENDPOINT_CLOSED_PORT := net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 9992}
|
||||
ENDPOINT_SERVER_SENDS := net.Endpoint{net.IP4_Address{127, 0, 0, 1}, 9993}
|
||||
|
||||
@(test)
|
||||
two_servers_binding_same_endpoint :: proc(t: ^testing.T) {
|
||||
skt1, err1 := net.listen_tcp(ENDPOINT)
|
||||
skt1, err1 := net.listen_tcp(ENDPOINT_TWO_SERVERS)
|
||||
defer net.close(skt1)
|
||||
skt2, err2 := net.listen_tcp(ENDPOINT)
|
||||
skt2, err2 := net.listen_tcp(ENDPOINT_TWO_SERVERS)
|
||||
defer net.close(skt2)
|
||||
|
||||
expect(t, err1 == nil, "expected first server binding to endpoint to do so without error")
|
||||
expect(t, err2 == net.Bind_Error.Address_In_Use, "expected second server to bind to an endpoint to return .Address_In_Use")
|
||||
testing.expect(t, err1 == nil, "expected first server binding to endpoint to do so without error")
|
||||
testing.expect(t, err2 == net.Bind_Error.Address_In_Use, "expected second server to bind to an endpoint to return .Address_In_Use")
|
||||
}
|
||||
|
||||
@(test)
|
||||
client_connects_to_closed_port :: proc(t: ^testing.T) {
|
||||
skt, err := net.dial_tcp(ENDPOINT)
|
||||
|
||||
skt, err := net.dial_tcp(ENDPOINT_CLOSED_PORT)
|
||||
defer net.close(skt)
|
||||
expect(t, err == net.Dial_Error.Refused, "expected dial of a closed endpoint to return .Refused")
|
||||
testing.expect(t, err == net.Dial_Error.Refused, "expected dial of a closed endpoint to return .Refused")
|
||||
}
|
||||
|
||||
|
||||
@(test)
|
||||
client_sends_server_data :: proc(t: ^testing.T) {
|
||||
CONTENT: string: "Hellope!"
|
||||
@@ -390,8 +259,8 @@ client_sends_server_data :: proc(t: ^testing.T) {
|
||||
|
||||
defer sync.wait_group_done(r.wg)
|
||||
|
||||
if r.skt, r.err = net.dial_tcp(ENDPOINT); r.err != nil {
|
||||
log(r.t, r.err)
|
||||
if r.skt, r.err = net.dial_tcp(ENDPOINT_SERVER_SENDS); r.err != nil {
|
||||
testing.expectf(r.t, false, "[tcp_client:dial_tcp] %v", r.err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -405,19 +274,17 @@ client_sends_server_data :: proc(t: ^testing.T) {
|
||||
|
||||
defer sync.wait_group_done(r.wg)
|
||||
|
||||
log(r.t, "tcp_server listen")
|
||||
if r.skt, r.err = net.listen_tcp(ENDPOINT); r.err != nil {
|
||||
if r.skt, r.err = net.listen_tcp(ENDPOINT_SERVER_SENDS); r.err != nil {
|
||||
sync.wait_group_done(r.wg)
|
||||
log(r.t, r.err)
|
||||
testing.expectf(r.t, false, "[tcp_server:listen_tcp] %v", r.err)
|
||||
return
|
||||
}
|
||||
|
||||
sync.wait_group_done(r.wg)
|
||||
|
||||
log(r.t, "tcp_server accept")
|
||||
client: net.TCP_Socket
|
||||
if client, _, r.err = net.accept_tcp(r.skt.(net.TCP_Socket)); r.err != nil {
|
||||
log(r.t, r.err)
|
||||
testing.expectf(r.t, false, "[tcp_server:accept_tcp] %v", r.err)
|
||||
return
|
||||
}
|
||||
defer net.close(client)
|
||||
@@ -437,10 +304,7 @@ client_sends_server_data :: proc(t: ^testing.T) {
|
||||
thread_data[0].wg = &wg
|
||||
thread_data[0].tid = thread.create_and_start_with_data(&thread_data[0], tcp_server, context)
|
||||
|
||||
log(t, "waiting for server to start listening")
|
||||
sync.wait_group_wait(&wg)
|
||||
log(t, "starting up client")
|
||||
|
||||
sync.wait_group_add(&wg, 2)
|
||||
|
||||
thread_data[1].t = t
|
||||
@@ -454,20 +318,15 @@ client_sends_server_data :: proc(t: ^testing.T) {
|
||||
net.close(thread_data[1].skt)
|
||||
thread.destroy(thread_data[1].tid)
|
||||
}
|
||||
|
||||
log(t, "waiting for threads to finish")
|
||||
sync.wait_group_wait(&wg)
|
||||
log(t, "threads finished")
|
||||
|
||||
okay := thread_data[0].err == nil && thread_data[1].err == nil
|
||||
msg := fmt.tprintf("Expected client and server to return `nil`, got %v and %v", thread_data[0].err, thread_data[1].err)
|
||||
expect(t, okay, msg)
|
||||
testing.expectf(t, okay, "Expected client and server to return `nil`, got %v and %v", thread_data[0].err, thread_data[1].err)
|
||||
|
||||
received := string(thread_data[0].data[:thread_data[0].length])
|
||||
|
||||
okay = received == CONTENT
|
||||
msg = fmt.tprintf("Expected client to send \"{}\", got \"{}\"", CONTENT, received)
|
||||
expect(t, okay, msg)
|
||||
testing.expectf(t, okay, "Expected client to send \"{}\", got \"{}\"", CONTENT, received)
|
||||
}
|
||||
|
||||
URL_Test :: struct {
|
||||
@@ -559,22 +418,15 @@ split_url_test :: proc(t: ^testing.T) {
|
||||
delete(test.queries)
|
||||
}
|
||||
|
||||
msg := fmt.tprintf("Expected `net.split_url` to return %s, got %s", test.scheme, scheme)
|
||||
expect(t, scheme == test.scheme, msg)
|
||||
msg = fmt.tprintf("Expected `net.split_url` to return %s, got %s", test.host, host)
|
||||
expect(t, host == test.host, msg)
|
||||
msg = fmt.tprintf("Expected `net.split_url` to return %s, got %s", test.path, path)
|
||||
expect(t, path == test.path, msg)
|
||||
msg = fmt.tprintf("Expected `net.split_url` to return %d queries, got %d queries", len(test.queries), len(queries))
|
||||
expect(t, len(queries) == len(test.queries), msg)
|
||||
testing.expectf(t, scheme == test.scheme, "Expected `net.split_url` to return %s, got %s", test.scheme, scheme)
|
||||
testing.expectf(t, host == test.host, "Expected `net.split_url` to return %s, got %s", test.host, host)
|
||||
testing.expectf(t, path == test.path, "Expected `net.split_url` to return %s, got %s", test.path, path)
|
||||
testing.expectf(t, len(queries) == len(test.queries), "Expected `net.split_url` to return %d queries, got %d queries", len(test.queries), len(queries))
|
||||
for k, v in queries {
|
||||
expected := test.queries[k]
|
||||
msg = fmt.tprintf("Expected `net.split_url` to return %s, got %s", expected, v)
|
||||
expect(t, v == expected, msg)
|
||||
testing.expectf(t, v == expected, "Expected `net.split_url` to return %s, got %s", expected, v)
|
||||
}
|
||||
msg = fmt.tprintf("Expected `net.split_url` to return %s, got %s", test.fragment, fragment)
|
||||
expect(t, fragment == test.fragment, msg)
|
||||
|
||||
testing.expectf(t, fragment == test.fragment, "Expected `net.split_url` to return %s, got %s", test.fragment, fragment)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -659,7 +511,45 @@ join_url_test :: proc(t: ^testing.T) {
|
||||
for test_url in test.url {
|
||||
pass |= url == test_url
|
||||
}
|
||||
msg := fmt.tprintf("Expected `net.join_url` to return one of %s, got %s", test.url, url)
|
||||
expect(t, pass, msg)
|
||||
testing.expectf(t, pass, "Expected `net.join_url` to return one of %s, got %s", test.url, url)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
address_to_binstr :: proc(address: net.Address) -> (binstr: string) {
|
||||
switch t in address {
|
||||
case net.IP4_Address:
|
||||
b := transmute(u32be)t
|
||||
return fmt.tprintf("%08x", b)
|
||||
case net.IP6_Address:
|
||||
b := transmute(u128be)t
|
||||
return fmt.tprintf("%32x", b)
|
||||
case:
|
||||
return ""
|
||||
}
|
||||
unreachable()
|
||||
}
|
||||
|
||||
@(private)
|
||||
binstr_to_address :: proc(t: ^testing.T, binstr: string) -> (address: net.Address) {
|
||||
switch len(binstr) {
|
||||
case 8: // IPv4
|
||||
a, ok := strconv.parse_u64_of_base(binstr, 16)
|
||||
testing.expect(t, ok, "failed to parse test case bin string")
|
||||
|
||||
ipv4 := u32be(a)
|
||||
return net.IP4_Address(transmute([4]u8)ipv4)
|
||||
|
||||
|
||||
case 32: // IPv6
|
||||
a, ok := strconv.parse_u128_of_base(binstr, 16)
|
||||
testing.expect(t, ok, "failed to parse test case bin string")
|
||||
|
||||
ipv4 := u128be(a)
|
||||
return net.IP6_Address(transmute([8]u16be)ipv4)
|
||||
|
||||
case 0:
|
||||
return nil
|
||||
}
|
||||
panic("Invalid test case")
|
||||
}
|
||||
Reference in New Issue
Block a user