| package testkit |
|
|
| import ( |
| "fmt" |
| "io" |
| "math/rand" |
| "net/http" |
| "os" |
| "reflect" |
| "strconv" |
| "testing" |
| "time" |
|
|
| "github.com/stretchr/testify/assert" |
| "github.com/stretchr/testify/require" |
|
|
| "github.com/metatube-community/metatube-sdk-go/model" |
| mt "github.com/metatube-community/metatube-sdk-go/provider" |
| ) |
|
|
| type internalTestSuite struct { |
| t *testing.T |
| } |
|
|
| func (s *internalTestSuite) T() *testing.T { |
| return s.t |
| } |
|
|
| func (s *internalTestSuite) testItems(items []string, call func(*testing.T, string)) { |
| for i, item := range items { |
| s.T().Run(item, func(t *testing.T) { |
| call(t, item) |
| }) |
| if i < len(items)-1 { |
| |
| time.Sleep(time.Duration(rand.Intn(500)+500) * time.Millisecond) |
| } |
| } |
| } |
|
|
| func (s *internalTestSuite) testGetInfo(f any, items []string, vfs ...ValidateFunc) { |
| ff := func(item string) (info interface{ IsValid() bool }, err error) { |
| switch v := f.(type) { |
| case func(string) (*model.ActorInfo, error): |
| info, err = v(item) |
| case func(string) (*model.MovieInfo, error): |
| info, err = v(item) |
| default: |
| return nil, fmt.Errorf("invalid function type: %T", v) |
| } |
| return |
| } |
| s.testItems(items, func(t *testing.T, item string) { |
| info, err := ff(item) |
| require.NoError(t, err) |
| require.NotNil(t, info) |
| for _, vf := range append([]ValidateFunc{ |
| logJSONContent(), |
| assertIsValid(), |
| }, vfs...) { |
| vf(t, info) |
| } |
| }) |
| } |
|
|
| func (s *internalTestSuite) TestGetActorInfoByID(p mt.ActorProvider, items []string, vfs ...ValidateFunc) { |
| s.testGetInfo(p.GetActorInfoByID, items, vfs...) |
| } |
|
|
| func (s *internalTestSuite) TestGetActorInfoByURL(p mt.ActorProvider, items []string, vfs ...ValidateFunc) { |
| s.testGetInfo(p.GetActorInfoByURL, items, vfs...) |
| } |
|
|
| func (s *internalTestSuite) TestGetMovieInfoByID(p mt.MovieProvider, items []string, vfs ...ValidateFunc) { |
| s.testGetInfo(p.GetMovieInfoByID, items, vfs...) |
| } |
|
|
| func (s *internalTestSuite) TestGetMovieInfoByURL(p mt.MovieProvider, items []string, vfs ...ValidateFunc) { |
| s.testGetInfo(p.GetMovieInfoByURL, items, vfs...) |
| } |
|
|
| func (s *internalTestSuite) testGetMovieReviews(f func(string) ([]*model.MovieReviewDetail, error), items []string, vfs ...ValidateFunc) { |
| s.testItems(items, func(t *testing.T, item string) { |
| reviews, err := f(item) |
| require.NoError(t, err) |
| require.NotEmpty(t, reviews) |
| for _, vf := range append([]ValidateFunc{ |
| logJSONContent(), |
| assertIsValid(), |
| }, vfs...) { |
| vf(t, reviews) |
| } |
| }) |
| } |
|
|
| func (s *internalTestSuite) TestGetMovieReviewsByID(p mt.MovieReviewer, items []string, vfs ...ValidateFunc) { |
| s.testGetMovieReviews(p.GetMovieReviewsByID, items, vfs...) |
| } |
|
|
| func (s *internalTestSuite) TestGetMovieReviewsByURL(p mt.MovieReviewer, items []string, vfs ...ValidateFunc) { |
| s.testGetMovieReviews(p.GetMovieReviewsByURL, items, vfs...) |
| } |
|
|
| func (s *internalTestSuite) TestSearchActor(p mt.ActorSearcher, items []string, vfs ...ValidateFunc) { |
| s.testItems(items, func(t *testing.T, item string) { |
| results, err := p.SearchActor(item) |
| require.NoError(t, err) |
| require.NotEmpty(t, results) |
| for _, vf := range append([]ValidateFunc{ |
| logJSONContent(), |
| assertIsValid(), |
| }, vfs...) { |
| vf(t, results) |
| } |
| }) |
| } |
|
|
| func (s *internalTestSuite) TestSearchMovie(p mt.MovieSearcher, items []string, vfs ...ValidateFunc) { |
| s.testItems(items, func(t *testing.T, item string) { |
| results, err := p.SearchMovie(p.NormalizeMovieKeyword(item)) |
| require.NoError(t, err) |
| require.NotEmpty(t, results) |
| for _, vf := range append([]ValidateFunc{ |
| logJSONContent(), |
| assertIsValid(), |
| }, vfs...) { |
| vf(t, results) |
| } |
| }) |
| } |
|
|
| func (s *internalTestSuite) TestFetch(p mt.Fetcher, items []string, vfs ...ValidateFunc) { |
| s.testItems(items, func(t *testing.T, item string) { |
| resp, err := p.Fetch(item) |
| require.NoError(t, err) |
| require.NotNil(t, resp) |
| require.Equal(t, http.StatusOK, resp.StatusCode) |
| data, err := io.ReadAll(resp.Body) |
| require.NoError(t, err) |
| require.NoError(t, resp.Body.Close()) |
| assert.NotEmpty(t, data) |
| for _, vf := range append([]ValidateFunc{ |
| logJSONContent(), |
| }, vfs...) { |
| vf(t, data) |
| } |
| }) |
| } |
|
|
| func Test[T mt.Provider](t *testing.T, new func() T, items []string, vfs ...ValidateFunc) { |
| if ci, _ := strconv.ParseBool(os.Getenv("GITHUB_ACTIONS")); ci { |
| t.SkipNow() |
| } |
|
|
| functionName := getFrame(1).Function |
| providerName, testMethod, err := parseTestFunction(functionName) |
| require.NoError(t, err) |
|
|
| provider := new() |
| structName := reflect.TypeOf(provider).Elem().Name() |
| require.Equal(t, providerName, structName) |
|
|
| s := &internalTestSuite{t} |
| m := reflect.ValueOf(s).MethodByName("Test" + testMethod) |
| require.Truef(t, m.IsValid(), "invalid test method: %s", testMethod) |
|
|
| |
| args := []reflect.Value{ |
| reflect.ValueOf(provider), |
| reflect.ValueOf(items), |
| } |
| for _, vf := range vfs { |
| args = append(args, reflect.ValueOf(vf)) |
| } |
|
|
| |
| results := m.Call(args) |
| require.Empty(t, results) |
| } |
|
|