Browse Source

Port `tests\core\encoding\json`

Jeroen van Rijn 1 year ago
parent
commit
601df0e8f7

+ 2 - 2
core/encoding/json/marshal.odin

@@ -62,8 +62,8 @@ Marshal_Options :: struct {
 	mjson_skipped_first_braces_end: bool,
 }
 
-marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) {
-	b := strings.builder_make(allocator)
+marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator, loc := #caller_location) -> (data: []byte, err: Marshal_Error) {
+	b := strings.builder_make(allocator, loc)
 	defer if err != nil {
 		strings.builder_destroy(&b)
 	}

+ 33 - 32
core/encoding/json/parser.odin

@@ -28,27 +28,27 @@ make_parser_from_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, par
 }
 
 
-parse :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator) -> (Value, Error) {
-	return parse_string(string(data), spec, parse_integers, allocator)
+parse :: proc(data: []byte, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator, loc := #caller_location) -> (Value, Error) {
+	return parse_string(string(data), spec, parse_integers, allocator, loc)
 }
 
-parse_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator) -> (Value, Error) {
+parse_string :: proc(data: string, spec := DEFAULT_SPECIFICATION, parse_integers := false, allocator := context.allocator, loc := #caller_location) -> (Value, Error) {
 	context.allocator = allocator
 	p := make_parser_from_string(data, spec, parse_integers, allocator)
 
 	switch p.spec {
 	case .JSON:
-		return parse_object(&p)
+		return parse_object(&p, loc)
 	case .JSON5:
-		return parse_value(&p)
+		return parse_value(&p, loc)
 	case .SJSON:
 		#partial switch p.curr_token.kind {
 		case .Ident, .String:
-			return parse_object_body(&p, .EOF)
+			return parse_object_body(&p, .EOF, loc)
 		}
-		return parse_value(&p)
+		return parse_value(&p, loc)
 	}
-	return parse_object(&p)
+	return parse_object(&p, loc)
 }
 
 token_end_pos :: proc(tok: Token) -> Pos {
@@ -106,7 +106,7 @@ parse_comma :: proc(p: ^Parser) -> (do_break: bool) {
 	return false
 }
 
-parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) {
+parse_value :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err: Error) {
 	err = .None
 	token := p.curr_token
 	#partial switch token.kind {
@@ -142,13 +142,13 @@ parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) {
 		
 	case .String:
 		advance_token(p)
-		return unquote_string(token, p.spec, p.allocator)
+		return unquote_string(token, p.spec, p.allocator, loc)
 
 	case .Open_Brace:
-		return parse_object(p)
+		return parse_object(p, loc)
 
 	case .Open_Bracket:
-		return parse_array(p)
+		return parse_array(p, loc)
 
 	case:
 		if p.spec != .JSON {
@@ -176,7 +176,7 @@ parse_value :: proc(p: ^Parser) -> (value: Value, err: Error) {
 	return
 }
 
-parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) {
+parse_array :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err: Error) {
 	err = .None
 	expect_token(p, .Open_Bracket) or_return
 
@@ -184,14 +184,14 @@ parse_array :: proc(p: ^Parser) -> (value: Value, err: Error) {
 	array.allocator = p.allocator
 	defer if err != nil {
 		for elem in array {
-			destroy_value(elem)
+			destroy_value(elem, loc=loc)
 		}
-		delete(array)
+		delete(array, loc)
 	}
 
 	for p.curr_token.kind != .Close_Bracket {
-		elem := parse_value(p) or_return
-		append(&array, elem)
+		elem := parse_value(p, loc) or_return
+		append(&array, elem, loc)
 		
 		if parse_comma(p) {
 			break
@@ -228,38 +228,39 @@ clone_string :: proc(s: string, allocator: mem.Allocator, loc := #caller_locatio
 	return
 }
 
-parse_object_key :: proc(p: ^Parser, key_allocator: mem.Allocator) -> (key: string, err: Error) {
+parse_object_key :: proc(p: ^Parser, key_allocator: mem.Allocator, loc := #caller_location) -> (key: string, err: Error) {
 	tok := p.curr_token
 	if p.spec != .JSON {
 		if allow_token(p, .Ident) {
-			return clone_string(tok.text, key_allocator)
+			return clone_string(tok.text, key_allocator, loc)
 		}
 	}
 	if tok_err := expect_token(p, .String); tok_err != nil {
 		err = .Expected_String_For_Object_Key
 		return
 	}
-	return unquote_string(tok, p.spec, key_allocator)
+	return unquote_string(tok, p.spec, key_allocator, loc)
 }
 
-parse_object_body :: proc(p: ^Parser, end_token: Token_Kind) -> (obj: Object, err: Error) {
-	obj.allocator = p.allocator
+parse_object_body :: proc(p: ^Parser, end_token: Token_Kind, loc := #caller_location) -> (obj: Object, err: Error) {
+	obj = make(Object, allocator=p.allocator, loc=loc)
+
 	defer if err != nil {
 		for key, elem in obj {
-			delete(key, p.allocator)
-			destroy_value(elem)
+			delete(key, p.allocator, loc)
+			destroy_value(elem, loc=loc)
 		}
-		delete(obj)
+		delete(obj, loc)
 	}
 
 	for p.curr_token.kind != end_token {
-		key := parse_object_key(p, p.allocator) or_return
+		key := parse_object_key(p, p.allocator, loc) or_return
 		parse_colon(p) or_return
-		elem := parse_value(p) or_return
+		elem := parse_value(p, loc) or_return
 
 		if key in obj {
 			err = .Duplicate_Object_Key
-			delete(key, p.allocator)
+			delete(key, p.allocator, loc)
 			return
 		}
 
@@ -267,7 +268,7 @@ parse_object_body :: proc(p: ^Parser, end_token: Token_Kind) -> (obj: Object, er
 		// inserting empty key/values into the object and for those we do not
 		// want to allocate anything
 		if key != "" {
-			reserve_error := reserve(&obj, len(obj) + 1)
+			reserve_error := reserve(&obj, len(obj) + 1, loc)
 			if reserve_error == mem.Allocator_Error.Out_Of_Memory {
 				return nil, .Out_Of_Memory
 			}
@@ -281,9 +282,9 @@ parse_object_body :: proc(p: ^Parser, end_token: Token_Kind) -> (obj: Object, er
 	return obj, .None
 }
 
-parse_object :: proc(p: ^Parser) -> (value: Value, err: Error) {
+parse_object :: proc(p: ^Parser, loc := #caller_location) -> (value: Value, err: Error) {
 	expect_token(p, .Open_Brace) or_return
-	obj := parse_object_body(p, .Close_Brace) or_return
+	obj := parse_object_body(p, .Close_Brace, loc) or_return
 	expect_token(p, .Close_Brace) or_return
 	return obj, .None
 }
@@ -480,4 +481,4 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a
 	}
 
 	return string(b[:w]), nil
-}
+}

+ 7 - 7
core/encoding/json/types.odin

@@ -89,22 +89,22 @@ Error :: enum {
 
 
 
-destroy_value :: proc(value: Value, allocator := context.allocator) {
+destroy_value :: proc(value: Value, allocator := context.allocator, loc := #caller_location) {
 	context.allocator = allocator
 	#partial switch v in value {
 	case Object:
 		for key, elem in v {
-			delete(key)
-			destroy_value(elem)
+			delete(key, loc=loc)
+			destroy_value(elem, loc=loc)
 		}
-		delete(v)
+		delete(v, loc=loc)
 	case Array:
 		for elem in v {
-			destroy_value(elem)
+			destroy_value(elem, loc=loc)
 		}
-		delete(v)
+		delete(v, loc=loc)
 	case String:
-		delete(v)
+		delete(v, loc=loc)
 	}
 }
 

+ 1 - 1
tests/core/Makefile

@@ -49,7 +49,7 @@ encoding_test:
 	$(ODIN) test encoding/cbor   $(COMMON) -out:test_cbor
 	$(ODIN) test encoding/hex    $(COMMON) -out:test_hex
 	$(ODIN) test encoding/hxa    $(COMMON) -out:test_hxa
-	$(ODIN) run encoding/json    $(COMMON) -out:test_json
+	$(ODIN) test encoding/json   $(COMMON) -out:test_json
 	$(ODIN) run encoding/varint  $(COMMON) -out:test_varint
 	$(ODIN) run encoding/xml     $(COMMON) -out:test_xml
 

+ 1 - 1
tests/core/build.bat

@@ -30,7 +30,7 @@ echo ---
 %PATH_TO_ODIN% test encoding/cbor   %COMMON% -out:test_cbor.exe   || exit /b
 %PATH_TO_ODIN% test encoding/hex    %COMMON% -out:test_hex.exe    || exit /b
 %PATH_TO_ODIN% test encoding/hxa    %COMMON% -out:test_hxa.exe    || exit /b
-%PATH_TO_ODIN% run encoding/json   %COMMON% -out:test_json.exe    || exit /b
+%PATH_TO_ODIN% test encoding/json   %COMMON% -out:test_json.exe   || exit /b
 %PATH_TO_ODIN% run encoding/varint %COMMON% -out:test_varint.exe  || exit /b
 %PATH_TO_ODIN% run encoding/xml    %COMMON% -out:test_xml.exe     || exit /b
 

+ 23 - 65
tests/core/encoding/json/test_core_json.odin

@@ -2,46 +2,8 @@ package test_core_json
 
 import "core:encoding/json"
 import "core:testing"
-import "core:fmt"
-import "core:os"
 import "core:mem/virtual"
 
-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{}
-
-	parse_json(&t)
-	marshal_json(&t)
-	unmarshal_json(&t)
-	surrogate(&t)
-	utf8_string_of_multibyte_characters(&t)
-
-	fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
-	if TEST_fail > 0 {
-		os.exit(1)
-	}
-}
-
 @test
 parse_json :: proc(t: ^testing.T) {
    
@@ -72,10 +34,9 @@ parse_json :: proc(t: ^testing.T) {
 	}
 	`
    
-	_, err := json.parse(transmute([]u8)json_data)
-
-	msg := fmt.tprintf("Expected `json.parse` to return nil, got %v", err)
-	expect(t, err == nil, msg)
+	val, err := json.parse(transmute([]u8)json_data)
+	json.destroy_value(val)
+	testing.expectf(t, err == nil, "Expected `json.parse` to return nil, got %v", err)
 }
 
 @test
@@ -83,7 +44,7 @@ out_of_memory_in_parse_json :: proc(t: ^testing.T) {
 	arena: virtual.Arena
 	arena_buffer: [256]byte
 	arena_init_error := virtual.arena_init_buffer(&arena, arena_buffer[:])
-	testing.expect(t, arena_init_error == nil, fmt.tprintf("Expected arena initialization to not return error, got: %v\n", arena_init_error))
+	testing.expectf(t, arena_init_error == nil, "Expected arena initialization to not return error, got: %v\n", arena_init_error)
 
 	context.allocator = virtual.arena_allocator(&arena)
 	
@@ -114,11 +75,11 @@ out_of_memory_in_parse_json :: proc(t: ^testing.T) {
 	}
 	`
 
-	_, err := json.parse(transmute([]u8)json_data)
+	val, err := json.parse(transmute([]u8)json_data)
+	json.destroy_value(val)
 
 	expected_error := json.Error.Out_Of_Memory
-	msg := fmt.tprintf("Expected `json.parse` to fail with %v, got %v", expected_error, err)
-	expect(t, err == json.Error.Out_Of_Memory, msg)
+	testing.expectf(t, err == json.Error.Out_Of_Memory, "Expected `json.parse` to fail with %v, got %v", expected_error, err)
 }
 
 @test
@@ -134,9 +95,9 @@ marshal_json :: proc(t: ^testing.T) {
 		b = 5,
 	}
    
-	_, err := json.marshal(my_struct)
-	msg := fmt.tprintf("Expected `json.marshal` to return nil, got %v", err)
-	expect(t, err == nil, msg)
+	data, err := json.marshal(my_struct)
+	defer delete(data)
+	testing.expectf(t, err == nil, "Expected `json.marshal` to return nil, got %v", err)
 }
 
 PRODUCTS := `
@@ -378,17 +339,12 @@ unmarshal_json :: proc(t: ^testing.T) {
 	err := json.unmarshal(transmute([]u8)PRODUCTS, &g, json.DEFAULT_SPECIFICATION)
 	defer cleanup(g)
 
-	msg := fmt.tprintf("Expected `json.unmarshal` to return nil, got %v", err)
-	expect(t, err == nil, msg)
-
-	msg = fmt.tprintf("Expected %v products to have been unmarshaled, got %v", len(original_data.products), len(g.products))
-	expect(t, len(g.products) == len(original_data.products), msg)
-
-	msg = fmt.tprintf("Expected cash to have been unmarshaled as %v, got %v", original_data.cash, g.cash)
-	expect(t, original_data.cash == g.cash, msg)
+	testing.expectf(t, err == nil,                                     "Expected `json.unmarshal` to return nil, got %v", err)
+	testing.expectf(t, len(g.products) == len(original_data.products), "Expected %v products to have been unmarshaled, got %v", len(original_data.products), len(g.products))
+	testing.expectf(t, original_data.cash == g.cash,                   "Expected cash to have been unmarshaled as %v, got %v", original_data.cash, g.cash)
 
 	for p, i in g.products {
-		expect(t, p == original_data.products[i], "Producted unmarshaled improperly")
+		testing.expect(t, p == original_data.products[i], "Producted unmarshaled improperly")
 	}
 }
 
@@ -397,17 +353,19 @@ surrogate :: proc(t: ^testing.T) {
 	input := `+ + * 😃 - /`
 
 	out, err := json.marshal(input)
-	expect(t, err == nil, fmt.tprintf("Expected `json.marshal(%q)` to return a nil error, got %v", input, err))
+	defer delete(out)
+	testing.expectf(t, err == nil,    "Expected `json.marshal(%q)` to return a nil error, got %v", input, err)
 
 	back: string
 	uerr := json.unmarshal(out, &back)
-	expect(t, uerr == nil, fmt.tprintf("Expected `json.unmarshal(%q)` to return a nil error, got %v", string(out), uerr))
-	expect(t, back == input, fmt.tprintf("Expected `json.unmarshal(%q)` to return %q, got %v", string(out), input, uerr))
+	defer delete(back)
+	testing.expectf(t, uerr == nil,   "Expected `json.unmarshal(%q)` to return a nil error, got %v", string(out), uerr)
+	testing.expectf(t, back == input, "Expected `json.unmarshal(%q)` to return %q, got %v", string(out), input, uerr)
 }
 
 @test
 utf8_string_of_multibyte_characters :: proc(t: ^testing.T) {
-	_, err := json.parse_string(`"🐛✅"`)
-	msg := fmt.tprintf("Expected `json.parse` to return nil, got %v", err)
-	expect(t, err == nil, msg)
-}
+	val, err := json.parse_string(`"🐛✅"`)
+	defer json.destroy_value(val)
+	testing.expectf(t, err == nil, "Expected `json.parse` to return nil, got %v", err)
+}