package rss import ( "fmt" "net/http" "net/http/httptest" "testing" "git.lxtend.com/lixiangwuxian/qqbot/config" . "github.com/bytedance/mockey" . "github.com/smartystreets/goconvey/convey" ) func init() { Mock((*config.Config).LoadConfig).Return(nil).Build() } // 模拟RSS XML数据 const mockRSSXML = ` 测试RSS源 https://example.com 这是一个测试RSS源 测试文章1 https://example.com/article1 这是第一篇测试文章的描述 Mon, 01 Jan 2024 12:00:00 +0800 https://example.com/article1 测试作者 技术 测试文章2 https://example.com/article2 这是第二篇测试文章的描述 Tue, 02 Jan 2024 14:30:00 +0800 https://example.com/article2 测试作者2 生活 ` func TestParseRssFeed(t *testing.T) { Convey("TestParseRssFeed", t, func() { Convey("测试正常RSS解析", func() { // 创建模拟HTTP服务器 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method == "HEAD" { w.Header().Set("Content-Type", "application/rss+xml") w.Header().Set("Content-Length", fmt.Sprintf("%d", len(mockRSSXML))) w.WriteHeader(http.StatusOK) return } if r.Method == "GET" { w.Header().Set("Content-Type", "application/rss+xml") w.WriteHeader(http.StatusOK) w.Write([]byte(mockRSSXML)) return } })) defer server.Close() // 测试解析功能 items, err := ParseRssFeed(server.URL) So(err, ShouldBeNil) So(len(items), ShouldEqual, 2) // 验证第一个条目 So(items[0].Title, ShouldEqual, "测试文章1") So(items[0].Link, ShouldEqual, "https://example.com/article1") So(items[0].Description, ShouldEqual, "这是第一篇测试文章的描述") So(items[0].GUID, ShouldEqual, "https://example.com/article1") So(items[0].Author, ShouldEqual, "测试作者") So(items[0].Category, ShouldEqual, "技术") So(items[0].Hash, ShouldNotBeEmpty) // 验证第二个条目 So(items[1].Title, ShouldEqual, "测试文章2") So(items[1].Link, ShouldEqual, "https://example.com/article2") So(items[1].Description, ShouldEqual, "这是第二篇测试文章的描述") So(items[1].GUID, ShouldEqual, "https://example.com/article2") So(items[1].Author, ShouldEqual, "测试作者2") So(items[1].Category, ShouldEqual, "生活") So(items[1].Hash, ShouldNotBeEmpty) // 验证哈希值不同 So(items[0].Hash, ShouldNotEqual, items[1].Hash) fmt.Printf("成功解析RSS源,共%d个条目\n", len(items)) for i, item := range items { fmt.Printf("条目%d: %s - %s\n", i+1, item.Title, item.Link) } }) Convey("测试RSS源大小限制", func() { // 创建超大内容的模拟服务器 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method == "HEAD" { w.Header().Set("Content-Type", "application/rss+xml") w.Header().Set("Content-Length", "20971520") // 20MB w.WriteHeader(http.StatusOK) return } })) defer server.Close() _, err := ParseRssFeed(server.URL) So(err, ShouldNotBeNil) So(err.Error(), ShouldContainSubstring, "超出限制") }) Convey("测试无效RSS源状态码", func() { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNotFound) })) defer server.Close() _, err := ParseRssFeed(server.URL) So(err, ShouldNotBeNil) So(err.Error(), ShouldContainSubstring, "RSS源无效: 404") }) Convey("测试无效XML格式", func() { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.Method == "HEAD" { w.Header().Set("Content-Type", "application/rss+xml") w.Header().Set("Content-Length", "100") w.WriteHeader(http.StatusOK) return } if r.Method == "GET" { w.Header().Set("Content-Type", "application/rss+xml") w.WriteHeader(http.StatusOK) w.Write([]byte("这不是有效的XML")) return } })) defer server.Close() _, err := ParseRssFeed(server.URL) So(err, ShouldNotBeNil) So(err.Error(), ShouldContainSubstring, "解析RSS数据失败") }) }) } func TestCheckRssFeed(t *testing.T) { Convey("TestCheckRssFeed", t, func() { Convey("测试有效RSS源检查", func() { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/rss+xml") w.WriteHeader(http.StatusOK) })) defer server.Close() err := CheckRssFeed(server.URL) So(err, ShouldBeNil) }) Convey("测试无效Content-Type", func() { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "text/html") w.WriteHeader(http.StatusOK) })) defer server.Close() err := CheckRssFeed(server.URL) So(err, ShouldNotBeNil) So(err.Error(), ShouldContainSubstring, "RSS源无效: text/html") }) Convey("测试无效状态码", func() { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) })) defer server.Close() err := CheckRssFeed(server.URL) So(err, ShouldNotBeNil) So(err.Error(), ShouldContainSubstring, "RSS源无效: 500") }) }) } func TestRssItemHash(t *testing.T) { Convey("TestRssItemHash", t, func() { Convey("测试相同内容生成相同哈希", func() { content1 := "测试标题测试链接测试描述" content2 := "测试标题测试链接测试描述" // 模拟哈希生成过程 hash1 := fmt.Sprintf("%x", []byte(content1)) hash2 := fmt.Sprintf("%x", []byte(content2)) So(hash1, ShouldEqual, hash2) }) Convey("测试不同内容生成不同哈希", func() { content1 := "测试标题1测试链接1测试描述1" content2 := "测试标题2测试链接2测试描述2" hash1 := fmt.Sprintf("%x", []byte(content1)) hash2 := fmt.Sprintf("%x", []byte(content2)) So(hash1, ShouldNotEqual, hash2) }) }) }