(fix): finalize v2 contracts (tests): cover v2 migration (doc): prepare release guidance
This commit is contained in:
+93
-15
@@ -3,6 +3,7 @@ package tgapi
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@@ -233,23 +234,98 @@ func TestRichBlockDividerHasNoContent(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRichBlockUnknownTypeWithTextIsForwardCompat(t *testing.T) {
|
||||
raw := []byte(`{"type":"future_tag","text":"hello"}`)
|
||||
b, err := UnmarshalRichBlock(raw)
|
||||
if err != nil {
|
||||
t.Fatalf("forward-compat failed: %v", err)
|
||||
func TestUnknownRichObjectsRoundTripLosslessly(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
raw string
|
||||
parse func([]byte) (any, error)
|
||||
}{
|
||||
{
|
||||
name: "text",
|
||||
raw: `{"type":"future_text","text":"hello","metadata":{"flag":true},"items":[1,2]}`,
|
||||
parse: func(data []byte) (any, error) {
|
||||
return UnmarshalRichText(data)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "block",
|
||||
raw: `{"type":"future_block","value":42,"metadata":{"flag":true},"items":[1,2]}`,
|
||||
parse: func(data []byte) (any, error) {
|
||||
return UnmarshalRichBlock(data)
|
||||
},
|
||||
},
|
||||
}
|
||||
w, ok := b.(RichBlockWrap)
|
||||
if !ok || w.Tag != "future_tag" {
|
||||
t.Fatalf("expected RichBlockWrap{future_tag}, got %T", b)
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
input := []byte(tt.raw)
|
||||
value, err := tt.parse(input)
|
||||
if err != nil {
|
||||
t.Fatalf("parse failed: %v", err)
|
||||
}
|
||||
for i := range input {
|
||||
input[i] = ' '
|
||||
}
|
||||
encoded, err := json.Marshal(value)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal failed: %v", err)
|
||||
}
|
||||
var got, want any
|
||||
if err := json.Unmarshal(encoded, &got); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := json.Unmarshal([]byte(tt.raw), &want); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Fatalf("unknown object changed: got %s want %s", encoded, tt.raw)
|
||||
}
|
||||
switch v := value.(type) {
|
||||
case RichTextUnknown:
|
||||
if len(v.Raw) == 0 {
|
||||
t.Fatal("empty preserved rich text")
|
||||
}
|
||||
case RichBlockUnknown:
|
||||
if len(v.Raw) == 0 {
|
||||
t.Fatal("empty preserved rich block")
|
||||
}
|
||||
default:
|
||||
t.Fatalf("unexpected fallback type %T", value)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRichBlockUnknownTypeWithoutTextIsError(t *testing.T) {
|
||||
raw := []byte(`{"type":"mystery_leaf","value":42}`)
|
||||
_, err := UnmarshalRichBlock(raw)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for unknown type without text")
|
||||
func TestUnknownRichObjectsRoundTripInsideMessage(t *testing.T) {
|
||||
raw := []byte(`{"blocks":[{"type":"future_block","metadata":{"version":2}},{"type":"paragraph","text":{"type":"future_text","payload":[1,2,3]}}],"is_rtl":true}`)
|
||||
message, err := UnmarshalRichMessage(raw)
|
||||
if err != nil {
|
||||
t.Fatalf("UnmarshalRichMessage failed: %v", err)
|
||||
}
|
||||
if _, ok := message.Blocks[0].(RichBlockUnknown); !ok {
|
||||
t.Fatalf("first block type = %T, want RichBlockUnknown", message.Blocks[0])
|
||||
}
|
||||
paragraph, ok := message.Blocks[1].(RichBlockWrap)
|
||||
if !ok {
|
||||
t.Fatalf("second block type = %T, want RichBlockWrap", message.Blocks[1])
|
||||
}
|
||||
if _, ok := paragraph.Text.(RichTextUnknown); !ok {
|
||||
t.Fatalf("paragraph text type = %T, want RichTextUnknown", paragraph.Text)
|
||||
}
|
||||
|
||||
encoded, err := json.Marshal(message)
|
||||
if err != nil {
|
||||
t.Fatalf("Marshal failed: %v", err)
|
||||
}
|
||||
var got, want any
|
||||
if err := json.Unmarshal(encoded, &got); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := json.Unmarshal(raw, &want); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(got, want) {
|
||||
t.Fatalf("message changed: got %s want %s", encoded, raw)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,8 +347,10 @@ func TestUnmarshalRichBlockRejectsMalformedFields(t *testing.T) {
|
||||
func TestUnmarshalRichMessageStrict(t *testing.T) {
|
||||
for _, raw := range []string{`null`, `{}`, `{"blocks":null}`, `{"blocks":{}}`} {
|
||||
t.Run(raw, func(t *testing.T) {
|
||||
if _, err := UnmarshalRichMessageStrict([]byte(raw)); err == nil {
|
||||
t.Fatal("expected strict decoder error")
|
||||
for _, parse := range []func([]byte) (RichMessage, error){UnmarshalRichMessage, UnmarshalRichMessageStrict} {
|
||||
if _, err := parse([]byte(raw)); err == nil {
|
||||
t.Fatal("expected strict decoder error")
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user