// Process transforms Template object into List object. It generates
// Parameter values using the defined set of generators first, and then it
// substitutes all Parameter expression occurrences with their corresponding
// values (currently in the containers' Environment variables only).
func (p *Processor) Process(template *api.Template) fielderrors.ValidationErrorList {
	templateErrors := fielderrors.ValidationErrorList{}

	if err := p.GenerateParameterValues(template); err != nil {
		return append(templateErrors.Prefix("Template"), fielderrors.NewFieldInvalid("parameters", err, "failure to generate parameter value"))
	}

	for i, item := range template.Objects {
		if obj, ok := item.(*runtime.Unknown); ok {
			// TODO: use runtime.DecodeList when it returns ValidationErrorList
			obj, err := runtime.UnstructuredJSONScheme.Decode(obj.RawJSON)
			if err != nil {
				util.ReportError(&templateErrors, i, *fielderrors.NewFieldInvalid("objects", err, "unable to handle object"))
				continue
			}
			item = obj
		}

		newItem, err := p.SubstituteParameters(template.Parameters, item)
		if err != nil {
			util.ReportError(&templateErrors, i, *fielderrors.NewFieldNotSupported("parameters", err))
		}
		stripNamespace(newItem)
		if err := util.AddObjectLabels(newItem, template.ObjectLabels); err != nil {
			util.ReportError(&templateErrors, i, *fielderrors.NewFieldInvalid("labels", err, "label could not be applied"))
		}
		template.Objects[i] = newItem
	}

	return templateErrors
}
func TestNewInvalid(t *testing.T) {
	testCases := []struct {
		Err     *fielderrors.ValidationError
		Details *api.StatusDetails
	}{
		{
			fielderrors.NewFieldDuplicate("field[0].name", "bar"),
			&api.StatusDetails{
				Kind: "kind",
				ID:   "name",
				Causes: []api.StatusCause{{
					Type:  api.CauseTypeFieldValueDuplicate,
					Field: "field[0].name",
				}},
			},
		},
		{
			fielderrors.NewFieldInvalid("field[0].name", "bar", "detail"),
			&api.StatusDetails{
				Kind: "kind",
				ID:   "name",
				Causes: []api.StatusCause{{
					Type:  api.CauseTypeFieldValueInvalid,
					Field: "field[0].name",
				}},
			},
		},
		{
			fielderrors.NewFieldNotFound("field[0].name", "bar"),
			&api.StatusDetails{
				Kind: "kind",
				ID:   "name",
				Causes: []api.StatusCause{{
					Type:  api.CauseTypeFieldValueNotFound,
					Field: "field[0].name",
				}},
			},
		},
		{
			fielderrors.NewFieldNotSupported("field[0].name", "bar"),
			&api.StatusDetails{
				Kind: "kind",
				ID:   "name",
				Causes: []api.StatusCause{{
					Type:  api.CauseTypeFieldValueNotSupported,
					Field: "field[0].name",
				}},
			},
		},
		{
			fielderrors.NewFieldRequired("field[0].name"),
			&api.StatusDetails{
				Kind: "kind",
				ID:   "name",
				Causes: []api.StatusCause{{
					Type:  api.CauseTypeFieldValueRequired,
					Field: "field[0].name",
				}},
			},
		},
	}
	for i, testCase := range testCases {
		vErr, expected := testCase.Err, testCase.Details
		expected.Causes[0].Message = vErr.Error()
		err := NewInvalid("kind", "name", fielderrors.ValidationErrorList{vErr})
		status := err.(*StatusError).ErrStatus
		if status.Code != 422 || status.Reason != api.StatusReasonInvalid {
			t.Errorf("%d: unexpected status: %#v", i, status)
		}
		if !reflect.DeepEqual(expected, status.Details) {
			t.Errorf("%d: expected %#v, got %#v", i, expected, status.Details)
		}
	}
}