generic: parse string representation of integer

This makes the data easier to handle down the pipeline.

Signed-off-by: Yonah <contrib@gensokyo.uk>
This commit is contained in:
Yonah 2025-09-17 05:41:40 +09:00
parent bddce42723
commit 5b9d1e4fe8
Signed by: yonah
SSH Key Fingerprint: SHA256:vnQvK8+XXH9Tbni2AV1a/8qdVK/zPcXw52GM0ruQvwA
2 changed files with 83 additions and 0 deletions

23
generic.go Normal file
View File

@ -0,0 +1,23 @@
package monstersirenfetch
import (
"encoding/json"
"strconv"
)
// StringInt is a JSON string representing an integer.
type StringInt int
func (i *StringInt) MarshalJSON() ([]byte, error) { return json.Marshal(strconv.Itoa(int(*i))) }
func (i *StringInt) UnmarshalJSON(data []byte) (err error) {
var v string
err = json.Unmarshal(data, &v)
if err == nil {
var n int
n, err = strconv.Atoi(v)
if err == nil {
*i = StringInt(n)
}
}
return
}

60
generic_test.go Normal file
View File

@ -0,0 +1,60 @@
package monstersirenfetch_test
import (
"encoding/json"
"reflect"
"strconv"
"testing"
"unsafe"
. "git.gensokyo.uk/yonah/monstersirenfetch"
)
func TestStringInt(t *testing.T) {
testCases := []struct {
name string
wantErr error
data string
val int
}{
{"valid", nil, `"3735928559"`, 0xdeadbeef},
{"invalid json", newSyntaxError("unexpected end of JSON input", 11), `"3735928559`, -1},
{"invalid number", &strconv.NumError{Func: "Atoi", Num: ":3735928559", Err: strconv.ErrSyntax}, `":3735928559"`, -1},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
if tc.wantErr == nil {
t.Run("marshal", func(t *testing.T) {
v := StringInt(tc.val)
if got, err := json.Marshal(&v); err != nil {
t.Fatalf("Marshal: error = %v", err)
} else if string(got) != tc.data {
t.Errorf("Marshal: %s, want %s", string(got), tc.data)
}
})
}
t.Run("unmarshal", func(t *testing.T) {
var got StringInt
err := json.Unmarshal([]byte(tc.data), &got)
if !reflect.DeepEqual(err, tc.wantErr) {
t.Errorf("Unmarshal: error = %v, want %v", err, tc.wantErr)
}
if tc.wantErr == nil {
if int(got) != tc.val {
t.Errorf("Unmarshal: %d, want %d", got, tc.val)
}
}
})
})
}
}
func newSyntaxError(msg string, offset int64) *json.SyntaxError {
e := &json.SyntaxError{Offset: offset}
msgV := reflect.ValueOf(e).Elem().FieldByName("msg")
reflect.NewAt(msgV.Type(), unsafe.Pointer(msgV.UnsafeAddr())).Elem().SetString(msg)
return e
}