package proto

import (
	"testing"

	"code.justin.tv/dta/rockpaperscissors/internal/testutil"
	"github.com/golang/protobuf/proto"
	"google.golang.org/genproto/protobuf/field_mask"
)

var (
	src = &ProjectMetadata{
		TeamName: proto.String("new_team_name"),
		Rollbar: &Rollbar{
			Project: proto.String("new_rollbar_project"),
		},
		BuildService: []*BuildService{
			&BuildService{
				Service: &BuildService_JenkinsJob{
					JenkinsJob: &JenkinsJob{
						Name: proto.String("new_jenkins_job"),
					},
				},
			},
		},
	}
	dst = &ProjectMetadata{
		ProjectId: proto.String("project_id"),
		TeamName:  proto.String("old_team_name"),
		Rollbar: &Rollbar{
			Project: proto.String("old_rollbar_project"),
		},
		BuildService: []*BuildService{
			&BuildService{
				Service: &BuildService_JenkinsJob{
					JenkinsJob: &JenkinsJob{
						Name: proto.String("old_jenkins_job"),
					},
				},
			},
		},
	}
)

func TestProtoMaskedMerge(t *testing.T) {
	fieldMask := &field_mask.FieldMask{
		Paths: []string{"team_name", "rollbar.project", "build_service"},
	}

	expectedProjectMetadata := &ProjectMetadata{
		ProjectId: proto.String("project_id"),
		TeamName:  proto.String("new_team_name"),
		Rollbar: &Rollbar{
			Project: proto.String("new_rollbar_project"),
		},
		BuildService: []*BuildService{
			&BuildService{
				Service: &BuildService_JenkinsJob{
					JenkinsJob: &JenkinsJob{
						Name: proto.String("new_jenkins_job"),
					},
				},
			},
		},
	}

	err := MaskedMerge(dst, src, fieldMask)
	testutil.AssertNil(t, "ProtoMaskedMerge returned a nil error", err)
	testutil.AssertEquals(t, "ProtoMaskedMerge correctly merged protobuffers",
		dst.String(), expectedProjectMetadata.String())
}

func TestProtoMaskedMergeTypeMismatch(t *testing.T) {
	fieldMask := &field_mask.FieldMask{}
	err := MaskedMerge(dst, &BuildService{}, fieldMask)
	testutil.AssertNotNil(t, "ProtoMaskedMerge returned an error", err)
	testutil.AssertEquals(t, "ProtoMaskedMerge returned an ErrTypeMismatch error",
		err, ErrTypeMismatch)
}

func TestProtoMaskedMergeRepeatedField(t *testing.T) {
	fieldMask := &field_mask.FieldMask{
		Paths: []string{"build_service.description"},
	}
	err := MaskedMerge(dst, src, fieldMask)
	testutil.AssertNotNil(t, "ProtoMaskedMerge returned an error", err)
	testutil.AssertEquals(t, "ProtoMaskedMerge returned an ErrNonLastRepeatedField error",
		err, ErrNonLastRepeatedField)
}

func TestProtoMaskedMergeSubField(t *testing.T) {
	fieldMask := &field_mask.FieldMask{
		Paths: []string{"team_name.foo"},
	}
	err := MaskedMerge(dst, src, fieldMask)
	testutil.AssertNotNil(t, "ProtoMaskedMerge returned an error", err)
	testutil.AssertEquals(t, "ProtoMaskedMerge returned an ErrNonMessageSubField error",
		err, ErrNonMessageSubField)
}
