From c4c4ebeda80ae1159c3d6438c7cce55367644aa3 Mon Sep 17 00:00:00 2001 From: Tnze Date: Fri, 2 Apr 2021 01:16:43 +0800 Subject: [PATCH] Add tests and examples for pk.Opt and pk.Tuple. --- net/packet/packet_test.go | 21 ------- net/packet/util.go | 23 ++++---- net/packet/util_test.go | 120 +++++++++++++++++++++++++++++++++++++- 3 files changed, 131 insertions(+), 33 deletions(-) diff --git a/net/packet/packet_test.go b/net/packet/packet_test.go index f38736f..9998bda 100644 --- a/net/packet/packet_test.go +++ b/net/packet/packet_test.go @@ -99,27 +99,6 @@ func TestVarLong_ReadFrom(t *testing.T) { } } -func TestAry_ReadFrom(t *testing.T) { - var num pk.Int = 2 - var ary []pk.String - var bin = []byte{ - 4, 'T', 'n', 'z', 'e', - 0, - } - var data = pk.Ary{Len: &num, Ary: &ary} - if _, err := data.ReadFrom(bytes.NewReader(bin)); err != nil { - t.Fatal(err) - } - if len(ary) != int(num) { - t.Fatalf("length not match: %d != %d", len(ary), num) - } - for i, v := range []string{"Tnze", ""} { - if string(ary[i]) != v { - t.Errorf("want %q, get %q", v, ary[i]) - } - } -} - //go:embed joingame_test.bin var testJoinGameData []byte diff --git a/net/packet/util.go b/net/packet/util.go index d7e08a4..6fe3163 100644 --- a/net/packet/util.go +++ b/net/packet/util.go @@ -70,20 +70,23 @@ func (a Ary) ReadFrom(r io.Reader) (n int64, err error) { } type Opt struct { - Has interface{} // Boolean, *Boolean or func() bool + Has interface{} // Pointer of bool, or `func() bool` Field interface{} // FieldEncoder, FieldDecoder or both (Field) } func (o Opt) has() bool { - switch o.Has.(type) { - case Boolean: - return bool(o.Has.(Boolean)) - case *Boolean: - return bool(*o.Has.(*Boolean)) - case func() bool: - return o.Has.(func() bool)() - default: - panic(errors.New("unsupported Has value")) + v := reflect.ValueOf(o.Has) + for { + switch v.Kind() { + case reflect.Ptr: + v = v.Elem() + case reflect.Bool: + return v.Bool() + case reflect.Func: + return v.Interface().(func() bool)() + default: + panic(errors.New("unsupported Has value")) + } } } diff --git a/net/packet/util_test.go b/net/packet/util_test.go index e6057fe..03ea4dc 100644 --- a/net/packet/util_test.go +++ b/net/packet/util_test.go @@ -2,9 +2,9 @@ package packet_test import ( "bytes" - "testing" - + "fmt" pk "github.com/Tnze/go-mc/net/packet" + "testing" ) func ExampleAry_WriteTo() { @@ -42,6 +42,27 @@ func ExampleAry_ReadFrom() { } } +func TestAry_ReadFrom(t *testing.T) { + var num pk.Int = 2 + var ary []pk.String + var bin = []byte{ + 4, 'T', 'n', 'z', 'e', + 0, + } + var data = pk.Ary{Len: &num, Ary: &ary} + if _, err := data.ReadFrom(bytes.NewReader(bin)); err != nil { + t.Fatal(err) + } + if len(ary) != int(num) { + t.Fatalf("length not match: %d != %d", len(ary), num) + } + for i, v := range []string{"Tnze", ""} { + if string(ary[i]) != v { + t.Errorf("want %q, get %q", v, ary[i]) + } + } +} + func TestAry_WriteTo(t *testing.T) { var buf bytes.Buffer want := []byte{ @@ -51,6 +72,7 @@ func TestAry_WriteTo(t *testing.T) { } int3, long3, varint3, varlong3 := pk.Int(3), pk.Long(3), pk.VarInt(3), pk.VarLong(3) for _, item := range [...]pk.Ary{ + {Len: 3, Ary: []pk.Int{1, 2, 3}}, {Len: int3, Ary: []pk.Int{1, 2, 3}}, {Len: long3, Ary: []pk.Int{1, 2, 3}}, {Len: varint3, Ary: []pk.Int{1, 2, 3}}, @@ -70,3 +92,97 @@ func TestAry_WriteTo(t *testing.T) { buf.Reset() } } + +func ExampleOpt_ReadFrom() { + var has pk.Boolean + + var data pk.String + p1 := pk.Packet{Data: []byte{ + 0x01, // pk.Boolean(true) + 4, 'T', 'n', 'z', 'e', // pk.String + }} + if err := p1.Scan( + &has, + pk.Opt{ + Has: &has, Field: &data, + }, + ); err != nil { + panic(err) + } + fmt.Println(data) + + var data2 pk.String = "WILL NOT BE READ, WILL NOT BE COVERED" + p2 := pk.Packet{Data: []byte{ + 0x00, // pk.Boolean(false) + // empty + }} + if err := p2.Scan( + &has, + pk.Opt{ + Has: &has, Field: &data2, + }, + ); err != nil { + panic(err) + } + fmt.Println(data2) + + // Output: + // Tnze + // WILL NOT BE READ, WILL NOT BE COVERED +} + +func ExampleOpt_ReadFrom_func() { + // As an example, we define this packet as this: + // +------+-----------------+----------------------------------+ + // | Name | Type | Notes | + // +------+-----------------+----------------------------------+ + // | Flag | Unsigned Byte | Odd if the following is present. | + // +------+-----------------+----------------------------------+ + // | User | Optional String | The player's name. | + // +------+-----------------+----------------------------------+ + // So we need a function to decide if the User field is present. + var flag pk.Byte + var data pk.String + p := pk.Packet{Data: []byte{ + 0b_0010_0011, // pk.Byte(flag) + 4, 'T', 'n', 'z', 'e', // pk.String + }} + if err := p.Scan( + &flag, + pk.Opt{ + Has: func() bool { + return flag&1 != 0 + }, + Field: &data, + }, + ); err != nil { + panic(err) + } + fmt.Println(data) + + // Output: Tnze +} + +func ExampleTuple_ReadFrom() { + // When you need to read an "Optional Array of X": + var has pk.Boolean + var arylen pk.Int + var ary []pk.String + + var p pk.Packet // = conn.ReadPacket() + if err := p.Scan( + &has, + pk.Opt{ + Has: &has, + Field: pk.Tuple{ + &arylen, + pk.Ary{ + Len: &arylen, + Ary: &ary, + }, + }, + }, + ); err != nil { + panic(err) + } +}