1package testing
2
3import (
4 "bytes"
5 "encoding/hex"
6 "encoding/json"
7 "fmt"
8 "io"
9 "os"
10 "testing"
11
12 comatproto "github.com/bluesky-social/indigo/api/atproto"
13 appbsky "github.com/bluesky-social/indigo/api/bsky"
14 bsky "github.com/bluesky-social/indigo/api/bsky"
15 lexutil "github.com/bluesky-social/indigo/lex/util"
16 "github.com/ipfs/go-cid"
17
18 "github.com/stretchr/testify/assert"
19)
20
21func TestFeedPostParse(t *testing.T) {
22 assert := assert.New(t)
23
24 // this is a post-lex-refactor app.bsky.feed.post record
25 inFile, err := os.Open("testdata/feedpost_record.cbor")
26 assert.NoError(err)
27 cborBytes, err := io.ReadAll(inFile)
28 assert.NoError(err)
29
30 var fp appbsky.FeedPost
31 assert.NoError(fp.UnmarshalCBOR(bytes.NewReader(cborBytes)))
32
33 assert.Equal("app.bsky.feed.post", fp.LexiconTypeID)
34 assert.Equal("Who the hell do you think you are", fp.Text)
35 assert.Equal("2023-03-29T20:59:19.417Z", fp.CreatedAt)
36 assert.Nil(fp.Entities)
37 assert.Nil(fp.Facets)
38 assert.Nil(fp.Reply)
39 assert.Nil(fp.Embed.EmbedImages)
40 assert.Nil(fp.Embed.EmbedExternal)
41 assert.Nil(fp.Embed.EmbedRecord)
42 assert.NotNil(fp.Embed.EmbedRecordWithMedia)
43 assert.Equal("app.bsky.embed.recordWithMedia", fp.Embed.EmbedRecordWithMedia.LexiconTypeID)
44
45 cc, err := cid.Decode("bafkreieqq463374bbcbeq7gpmet5rvrpeqow6t4rtjzrkhnlumdylagaqa")
46 if err != nil {
47 t.Fatal(err)
48 }
49
50 assert.Equal(
51 &appbsky.EmbedRecordWithMedia{
52 LexiconTypeID: "app.bsky.embed.recordWithMedia",
53 Media: &appbsky.EmbedRecordWithMedia_Media{
54 EmbedImages: &appbsky.EmbedImages{
55 LexiconTypeID: "app.bsky.embed.images",
56 Images: []*appbsky.EmbedImages_Image{
57 &appbsky.EmbedImages_Image{
58 Image: &lexutil.LexBlob{
59 //LexiconTypeID: "blob",
60 Ref: lexutil.LexLink(cc), // 000155122090873DBDFF810882487CCF6127D8D62F241D6F4F919A73151DABA3078580C080
61 Size: 751473,
62 MimeType: "image/jpeg",
63 },
64 },
65 },
66 },
67 },
68 Record: &appbsky.EmbedRecord{
69 LexiconTypeID: "app.bsky.embed.record",
70 Record: &comatproto.RepoStrongRef{
71 Cid: "bafyreiaku7udekkiijxcuue3sn6esz7qijqj637rigz4xqdw57fk5houji",
72 Uri: "at://did:plc:rbtury4cp2sdk4tvnedaqu54/app.bsky.feed.post/3jilislho4s2k",
73 },
74 },
75 },
76 fp.Embed.EmbedRecordWithMedia,
77 )
78
79 // re-encode as CBOR, check against input bytes
80 outCborBytes := new(bytes.Buffer)
81 assert.NoError(fp.MarshalCBOR(outCborBytes))
82 assert.Equal(cborBytes, outCborBytes.Bytes())
83
84 fmt.Printf("OUTPUT: %x\n", outCborBytes.Bytes())
85
86 // marshal as JSON, compare against expected
87 expectedJson := `{
88 "$type": "app.bsky.feed.post",
89 "createdAt": "2023-03-29T20:59:19.417Z",
90 "embed": {
91 "$type": "app.bsky.embed.recordWithMedia",
92 "media": {
93 "$type": "app.bsky.embed.images",
94 "images": [
95 {
96 "alt": "",
97 "image": {
98 "$type": "blob",
99 "ref": {
100 "$link": "bafkreieqq463374bbcbeq7gpmet5rvrpeqow6t4rtjzrkhnlumdylagaqa"
101 },
102 "mimeType": "image/jpeg",
103 "size": 751473
104 }
105 }
106 ]
107 },
108 "record": {
109 "$type": "app.bsky.embed.record",
110 "record": {
111 "cid": "bafyreiaku7udekkiijxcuue3sn6esz7qijqj637rigz4xqdw57fk5houji",
112 "uri": "at://did:plc:rbtury4cp2sdk4tvnedaqu54/app.bsky.feed.post/3jilislho4s2k"
113 }
114 }
115 },
116 "text": "Who the hell do you think you are"
117 }`
118
119 outJsonBytes, err := json.Marshal(fp)
120 assert.NoError(err)
121 fmt.Println(string(outJsonBytes))
122 var outJsonObj map[string]interface{}
123 assert.NoError(json.Unmarshal(outJsonBytes, &outJsonObj))
124 var expectedJsonObj map[string]interface{}
125 assert.NoError(json.Unmarshal([]byte(expectedJson), &expectedJsonObj))
126 assert.Equal(expectedJsonObj, outJsonObj)
127}
128
129func TestPostToJson(t *testing.T) {
130 raw := "a464746578747834e38282e38186e38193e381a3e381a1e3818ce69cace5aeb654776974746572e381a7e38184e38184e381aee381a7e381afefbc9f652474797065726170702e62736b792e666565642e706f737465656d626564a2652474797065756170702e62736b792e656d6265642e696d6167657366696d6167657381a263616c746065696d616765a463726566d82a5825000155122071e37fa09ed1814412a06d4dcd4f9462500b2992c267b9dea11884c52f6bacce6473697a6519ef2e65247479706564626c6f62686d696d65547970656a696d6167652f6a706567696372656174656441747818323032332d30342d30335432323a34363a31392e3438375a"
131
132 b, err := hex.DecodeString(raw)
133 if err != nil {
134 t.Fatal(err)
135 }
136
137 var fp bsky.FeedPost
138 if err := fp.UnmarshalCBOR(bytes.NewReader(b)); err != nil {
139 t.Fatal(err)
140 }
141
142 outb, err := json.Marshal(&fp)
143 if err != nil {
144 t.Fatal(err)
145 }
146
147 fmt.Println(string(outb))
148}
149
150// checks a corner-case with $type: "app.bsky.richtext.facet#link"
151func TestFeedPostRichtextLink(t *testing.T) {
152 assert := assert.New(t)
153 cidBuilder := cid.V1Builder{Codec: 0x71, MhType: 0x12, MhLength: 0}
154
155 // this is a app.bsky.feed.post with richtext link
156 inFile, err := os.Open("testdata/post_richtext_link.cbor")
157 if err != nil {
158 t.Fatal(err)
159 }
160 cborBytes, err := io.ReadAll(inFile)
161 if err != nil {
162 t.Fatal(err)
163 }
164 fmt.Println("=== typescript CBOR bytes (hex)")
165 fmt.Println(hex.EncodeToString(cborBytes))
166 origCID, err := cidBuilder.Sum(cborBytes)
167 if err != nil {
168 t.Fatal(err)
169 }
170
171 recordCBOR := new(bytes.Buffer)
172 var recordOrig appbsky.FeedPost
173 var recordRepro appbsky.FeedPost
174 assert.NoError(recordOrig.UnmarshalCBOR(bytes.NewReader(cborBytes)))
175 assert.Equal("app.bsky.feed.post", recordOrig.LexiconTypeID)
176
177 recordJSON, err := json.Marshal(recordOrig)
178 fmt.Println(string(recordJSON))
179 assert.NoError(err)
180 assert.NoError(json.Unmarshal(recordJSON, &recordRepro))
181 assert.Equal(recordOrig, recordRepro)
182 assert.NoError(recordRepro.MarshalCBOR(recordCBOR))
183 fmt.Println("=== golang cbor-gen bytes (hex)")
184 fmt.Println(hex.EncodeToString(recordCBOR.Bytes()))
185 reproCID, err := cidBuilder.Sum(recordCBOR.Bytes())
186 assert.NoError(err)
187 assert.Equal(origCID.String(), reproCID.String())
188
189}