package keeper_test

import (
	"context"
	"testing"

    <%= for (goImport) in mergeGoImports(Fields) { %>
    <%= goImport.Alias %> "<%= goImport.Name %>"<% } %>
	"github.com/cosmos/cosmos-sdk/types/query"
	"github.com/stretchr/testify/require"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"

	"<%= ModulePath %>/x/<%= ModuleName %>/keeper"
	"<%= ModulePath %>/x/<%= ModuleName %>/types"
)

func createN<%= TypeName.PascalCase %>(keeper keeper.Keeper, ctx context.Context, n int) []types.<%= TypeName.PascalCase %> {
	items := make([]types.<%= TypeName.PascalCase %>, n)
	for i := range items {
		items[i].<%= Index.Name.UpperCamel %> = <%= Index.ValueLoop() %><%= for (field) in Fields { %>
		items[i].<%= field.Name.UpperCamel %> = <%= field.ValueLoop() %><% } %>
		_ = keeper.<%= TypeName.UpperCamel %>.Set(ctx, items[i].<%= Index.Name.UpperCamel %>, items[i])
	}
	return items
}

func Test<%= TypeName.PascalCase %>QuerySingle(t *testing.T) {
	f := initFixture(t)
	qs := keeper.NewQueryServerImpl(f.keeper)
	msgs := createN<%= TypeName.PascalCase %>(f.keeper, f.ctx, 2)
	tests := []struct {
		desc     string
		request  *types.QueryGet<%= TypeName.PascalCase %>Request
		response *types.QueryGet<%= TypeName.PascalCase %>Response
		err      error
	}{
		{
			desc:     "First",
			request:  &types.QueryGet<%= TypeName.PascalCase %>Request{
			    <%= Index.Name.UpperCamel %>: msgs[0].<%= Index.Name.UpperCamel %>,
			},
			response: &types.QueryGet<%= TypeName.PascalCase %>Response{<%= TypeName.UpperCamel %>: msgs[0]},
		},
		{
			desc:     "Second",
			request:  &types.QueryGet<%= TypeName.PascalCase %>Request{
			    <%= Index.Name.UpperCamel %>: msgs[1].<%= Index.Name.UpperCamel %>,
			},
			response: &types.QueryGet<%= TypeName.PascalCase %>Response{<%= TypeName.UpperCamel %>: msgs[1]},
		},
		{
			desc:    "KeyNotFound",
			request: &types.QueryGet<%= TypeName.PascalCase %>Request{
				<%= Index.Name.UpperCamel %>: <%= Index.ValueInvalidIndex() %>,
			},
			err:     status.Error(codes.NotFound, "not found"),
		},
		{
			desc: "InvalidRequest",
			err:  status.Error(codes.InvalidArgument, "invalid request"),
		},
	}
	for _, tc := range tests {
		t.Run(tc.desc, func(t *testing.T) {
			response, err := qs.Get<%= TypeName.PascalCase %>(f.ctx, tc.request)
			if tc.err != nil {
				require.ErrorIs(t, err, tc.err)
			} else {
				require.NoError(t, err)
				require.EqualExportedValues(t, tc.response, response)
			}
		})
	}
}

func Test<%= TypeName.PascalCase %>QueryPaginated(t *testing.T) {
	f := initFixture(t)
	qs := keeper.NewQueryServerImpl(f.keeper)
	msgs := createN<%= TypeName.PascalCase %>(f.keeper, f.ctx, 5)

	request := func(next []byte, offset, limit uint64, total bool) *types.QueryAll<%= TypeName.PascalCase %>Request {
		return &types.QueryAll<%= TypeName.PascalCase %>Request{
			Pagination: &query.PageRequest{
				Key:        next,
				Offset:     offset,
				Limit:      limit,
				CountTotal: total,
			},
		}
	}
	t.Run("ByOffset", func(t *testing.T) {
		step := 2
		for i := 0; i < len(msgs); i += step {
			resp, err := qs.List<%= TypeName.PascalCase %>(f.ctx, request(nil, uint64(i), uint64(step), false))
			require.NoError(t, err)
			require.LessOrEqual(t, len(resp.<%= TypeName.UpperCamel %>), step)
			require.Subset(t, msgs, resp.<%= TypeName.UpperCamel %>)
		}
	})
	t.Run("ByKey", func(t *testing.T) {
		step := 2
		var next []byte
		for i := 0; i < len(msgs); i += step {
			resp, err := qs.List<%= TypeName.PascalCase %>(f.ctx, request(next, 0, uint64(step), false))
			require.NoError(t, err)
			require.LessOrEqual(t, len(resp.<%= TypeName.UpperCamel %>), step)
			require.Subset(t, msgs, resp.<%= TypeName.UpperCamel %>)
			next = resp.Pagination.NextKey
		}
	})
	t.Run("Total", func(t *testing.T) {
		resp, err := qs.List<%= TypeName.PascalCase %>(f.ctx, request(nil, 0, 0, true))
		require.NoError(t, err)
		require.Equal(t, len(msgs), int(resp.Pagination.Total))
		require.EqualExportedValues(t, msgs, resp.<%= TypeName.UpperCamel %>)
	})
	t.Run("InvalidRequest", func(t *testing.T) {
		_, err := qs.List<%= TypeName.PascalCase %>(f.ctx, nil)
		require.ErrorIs(t, err, status.Error(codes.InvalidArgument, "invalid request"))
	})
}
