//
// Copyright 2021 The Sigstore Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package app

import (
	"context"
	"errors"
	"net/http"
	"net/http/httptest"
	"os"
	"testing"

	"github.com/spf13/cobra"
	"github.com/spf13/viper"

	"github.com/sigstore/rekor/pkg/types"
)

func TestArtifactPFlags(t *testing.T) {
	type test struct {
		caseDesc              string
		typeStr               string
		entry                 string
		artifact              string
		signature             string
		publicKey             string
		multiPublicKey        []string
		uuid                  string
		aad                   string
		uuidRequired          bool
		logIndex              string
		logIndexRequired      bool
		expectParseSuccess    bool
		expectValidateSuccess bool
	}

	testServer := httptest.NewServer(http.HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			file := []byte{}
			var err error

			switch r.URL.Path {
			case "/artifact":
				file, err = os.ReadFile("tests/test_file.txt")
			case "/signature":
				file, err = os.ReadFile("tests/test_file.sig")
			case "/publicKey":
				file, err = os.ReadFile("tests/test_public_key.key")
			case "/rekord":
				file, err = os.ReadFile("tests/rekor.json")
			case "/rpmEntry":
				file, err = os.ReadFile("tests/rpm.json")
			case "/rpm":
				file, err = os.ReadFile("tests/test.rpm")
			case "/rpmPublicKey":
				file, err = os.ReadFile("tests/test_rpm_public_key.key")
			case "/alpine":
				file, err = os.ReadFile("tests/test_alpine.apk")
			case "/alpinePublicKey":
				file, err = os.ReadFile("tests/test_alpine.pub")
			case "/alpineEntry":
				file, err = os.ReadFile("tests/alpine.json")
			case "/helmEntry":
				file, err = os.ReadFile("tests/helm.json")
			case "/not_found":
				err = errors.New("file not found")
			}
			if err != nil {
				w.WriteHeader(http.StatusNotFound)
				return
			}
			w.WriteHeader(http.StatusOK)
			_, _ = w.Write(file)
		}))
	defer testServer.Close()

	tests := []test{
		{
			caseDesc:              "valid rekord file",
			entry:                 "tests/rekor.json",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid rekord URL",
			entry:                 testServer.URL + "/rekord",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid rekord file, wrong type",
			typeStr:               "rpm",
			entry:                 "tests/rekor.json",
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "valid rpm file",
			entry:                 "tests/rpm.json",
			typeStr:               "rpm",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid rpm URL",
			entry:                 testServer.URL + "/rpmEntry",
			typeStr:               "rpm",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid alpine URL",
			entry:                 testServer.URL + "/alpineEntry",
			typeStr:               "alpine",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid helm URL",
			entry:                 testServer.URL + "/helmEntry",
			typeStr:               "helm",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},

		{
			caseDesc:              "valid rpm file, wrong type",
			typeStr:               "rekord",
			entry:                 "tests/rpm.json",
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "non-existent rekord file",
			entry:                 "tests/not_there.json",
			expectParseSuccess:    false,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "non-existent rekord url",
			entry:                 testServer.URL + "/not_found",
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "valid rekord - local artifact with required flags",
			artifact:              "tests/test_file.txt",
			signature:             "tests/test_file.sig",
			publicKey:             "tests/test_public_key.key",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid rpm - local artifact with required flags",
			typeStr:               "rpm",
			artifact:              "tests/test.rpm",
			publicKey:             "tests/test_rpm_public_key.key",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid alpine - local artifact with required flags",
			typeStr:               "alpine",
			artifact:              "tests/test_alpine.apk",
			publicKey:             "tests/test_alpine.pub",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "nonexistent local artifact",
			artifact:              "tests/not_a_file",
			signature:             "tests/test_file.sig",
			publicKey:             "tests/test_public_key.key",
			expectParseSuccess:    false,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "nonexistent remote artifact",
			artifact:              testServer.URL + "/not_found",
			signature:             "tests/test_file.sig",
			publicKey:             "tests/test_public_key.key",
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "local artifact without required local signature",
			artifact:              "tests/test_file.txt",
			publicKey:             "tests/test_public_key.key",
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "local artifact with missing remote signature",
			artifact:              "tests/test_file.txt",
			publicKey:             "tests/test_public_key.key",
			signature:             testServer.URL + "/not_found",
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "local artifact with invalid local signature",
			artifact:              "tests/test_file.txt",
			signature:             "tests/not_a_file",
			publicKey:             "tests/test_public_key.key",
			expectParseSuccess:    false,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "local artifact with invalid remote signature",
			artifact:              "tests/test_file.txt",
			signature:             testServer.URL + "/artifact",
			publicKey:             "tests/test_public_key.key",
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "local artifact without required public key",
			artifact:              "tests/test_file.txt",
			signature:             "tests/test_file.sig",
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "local artifact with invalid local public key",
			artifact:              "tests/test_file.txt",
			signature:             "tests/test_file.sig",
			publicKey:             "tests/not_a_file",
			expectParseSuccess:    false,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "local artifact with invalid remote public key",
			artifact:              "tests/test_file.txt",
			signature:             "tests/test_file.sig",
			publicKey:             testServer.URL + "/artifact",
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "valid rekord - remote artifact with required flags",
			artifact:              testServer.URL + "/artifact",
			signature:             "tests/test_file.sig",
			publicKey:             "tests/test_public_key.key",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid rpm - remote artifact with required flags",
			typeStr:               "rpm",
			artifact:              testServer.URL + "/rpm",
			publicKey:             "tests/test_rpm_public_key.key",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid alpine - remote artifact with required flags",
			typeStr:               "alpine",
			artifact:              testServer.URL + "/alpine",
			publicKey:             "tests/test_alpine.pub",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "remote artifact with invalid URL",
			artifact:              "hteeteep%**/test_file.txt",
			signature:             "tests/test_file.sig",
			publicKey:             "tests/test_public_key.key",
			expectParseSuccess:    false,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "valid uuid",
			uuid:                  "3030303030303030303030303030303030303030303030303030303030303030",
			uuidRequired:          true,
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "invalid uuid",
			uuid:                  "not_a_uuid",
			uuidRequired:          true,
			expectParseSuccess:    false,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "unwanted uuid",
			uuid:                  "3030303030303030303030303030303030303030303030303030303030303030",
			uuidRequired:          false,
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "valid log index",
			logIndex:              "1",
			logIndexRequired:      true,
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "invalid log index",
			logIndex:              "not_a_int",
			logIndexRequired:      true,
			expectParseSuccess:    false,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "invalid log index - less than 0",
			logIndex:              "-1",
			logIndexRequired:      true,
			expectParseSuccess:    false,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "unwanted log index",
			logIndex:              "1",
			logIndexRequired:      false,
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "no flags when either uuid, rekord, or artifact++ are needed",
			uuidRequired:          false,
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "missing uuid flag when it is needed",
			uuidRequired:          true,
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "missing log index flag when it is needed",
			logIndexRequired:      true,
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "valid cose, with aad",
			typeStr:               "cose",
			artifact:              "tests/test_cose.cbor",
			publicKey:             "tests/test_cose.pub",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
			aad:                   "dGVzdCBhYWQ=",
		},
		{
			caseDesc:              "valid cose, malformed base64 aad",
			typeStr:               "cose",
			artifact:              "tests/test_cose.cbor",
			publicKey:             "tests/test_cose.pub",
			expectParseSuccess:    false,
			expectValidateSuccess: true,
			aad:                   "dGVzdCBhYWQ]",
		},
		{
			caseDesc:              "valid cose, missing aad",
			typeStr:               "cose",
			artifact:              "tests/test_cose.cbor",
			publicKey:             "tests/test_cose.pub",
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "valid intoto - one keys",
			typeStr:               "intoto",
			artifact:              "tests/intoto_dsse.json",
			publicKey:             "tests/intoto_dsse.pem",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid intoto - multi keys",
			typeStr:               "intoto",
			artifact:              "tests/intoto_multi_dsse.json",
			multiPublicKey:        []string{"tests/intoto_dsse.pem", "tests/intoto_multi_pub2.pem"},
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
	}

	for _, tc := range tests {
		initializePFlagMap()
		var blankCmd = &cobra.Command{}
		if err := addArtifactPFlags(blankCmd); err != nil {
			t.Fatalf("unexpected error adding flags in '%v': %v", tc.caseDesc, err)
		}
		if err := addUUIDPFlags(blankCmd, tc.uuidRequired); err != nil {
			t.Fatalf("unexpected error adding uuid flags in '%v': %v", tc.caseDesc, err)
		}
		if err := addLogIndexFlag(blankCmd, tc.logIndexRequired); err != nil {
			t.Fatalf("unexpected error adding log index flags in '%v': %v", tc.caseDesc, err)
		}

		args := []string{}

		if tc.entry != "" {
			args = append(args, "--entry", tc.entry)
		}
		if tc.typeStr != "" {
			args = append(args, "--type", tc.typeStr)
		}
		if tc.artifact != "" {
			args = append(args, "--artifact", tc.artifact)
		}
		if tc.signature != "" {
			args = append(args, "--signature", tc.signature)
		}
		if tc.publicKey != "" {
			args = append(args, "--public-key", tc.publicKey)
		}
		if len(tc.multiPublicKey) > 0 {
			for _, key := range tc.multiPublicKey {
				args = append(args, "--public-key", key)
			}
		}
		if tc.uuid != "" {
			args = append(args, "--uuid", tc.uuid)
		}
		if tc.logIndex != "" {
			args = append(args, "--log-index", tc.logIndex)
		}
		if tc.aad != "" {
			args = append(args, "--aad", tc.aad)
		}

		if err := blankCmd.ParseFlags(args); (err == nil) != tc.expectParseSuccess {
			t.Errorf("unexpected result parsing '%v': %v", tc.caseDesc, err)
			continue
		}

		if tc.expectValidateSuccess {
			if err := viper.BindPFlags(blankCmd.Flags()); err != nil {
				t.Fatalf("unexpected result initializing viper in '%v': %v", tc.caseDesc, err)
			}
			if err := validateArtifactPFlags(tc.uuidRequired, tc.logIndexRequired); (err == nil) != tc.expectValidateSuccess {
				t.Errorf("unexpected result validating '%v': %v", tc.caseDesc, err)
				continue
			}
			if !tc.uuidRequired && !tc.logIndexRequired && tc.entry == "" {
				typeStr, versionStr, err := ParseTypeFlag(viper.GetString("type"))
				if err != nil {
					t.Fatalf("error parsing typeStr: %v", err)
				}
				props := CreatePropsFromPflags()
				if _, err := types.NewProposedEntry(context.Background(), typeStr, versionStr, *props); err != nil {
					t.Errorf("unexpected result in '%v' building entry: %v", tc.caseDesc, err)
				}
			}
		}
	}
}

func TestValidateRekorServerURL(t *testing.T) {
	type test struct {
		caseDesc      string
		rekorServer   string
		expectSuccess bool
	}

	tests := []test{
		{
			caseDesc:      "value not specified",
			expectSuccess: false,
		},
		{
			caseDesc:      "valid rekor_server value",
			rekorServer:   "http://localhost:3000",
			expectSuccess: true,
		},
		{
			caseDesc:      "valid URL, invalid scheme",
			rekorServer:   "ldap://localhost:3000",
			expectSuccess: false,
		},
		{
			caseDesc:      "invalid URL",
			rekorServer:   "hteeteepeeColonSlashSlashlocalhost:3000",
			expectSuccess: false,
		},
		{
			caseDesc:      "local path",
			rekorServer:   "/localhost",
			expectSuccess: false,
		},
	}

	for _, tc := range tests {
		if err := rootCmd.PersistentFlags().Set("rekor_server", tc.rekorServer); (err == nil) != tc.expectSuccess {
			t.Errorf("unexpected result in '%v': %v", tc.caseDesc, err)
		}
	}
}

// TestValidateRetryCount tests the validation of the retry count flag
func TestValidateRetryCount(t *testing.T) {
	type test struct {
		caseDesc      string
		retryCount    string
		expectSuccess bool
	}

	tests := []test{
		{
			caseDesc:      "value not specified",
			expectSuccess: false,
		},
		{
			caseDesc:      "valid retry_count value: 0",
			retryCount:    "0",
			expectSuccess: true,
		},
		{
			caseDesc:      "valid retry_count value: 1",
			retryCount:    "1",
			expectSuccess: true,
		},
		{
			caseDesc:      "invalid retry_count value: asdf",
			retryCount:    "asdf",
			expectSuccess: false,
		},
		{
			caseDesc:      "invalid retry_count value: -1",
			retryCount:    "-1",
			expectSuccess: false,
		},
	}

	for _, tc := range tests {
		if err := rootCmd.PersistentFlags().Set("retry", tc.retryCount); (err == nil) != tc.expectSuccess {
			t.Errorf("unexpected result in '%v': %v", tc.caseDesc, err)
		}
	}
}

func TestSearchPFlags(t *testing.T) {
	type test struct {
		caseDesc              string
		artifact              string
		publicKey             string
		sha                   string
		email                 string
		pkiFormat             string
		expectParseSuccess    bool
		expectValidateSuccess bool
	}

	testServer := httptest.NewServer(http.HandlerFunc(
		func(w http.ResponseWriter, r *http.Request) {
			file := []byte{}
			var err error

			switch r.URL.Path {
			case "/artifact":
				file, err = os.ReadFile("tests/test_file.txt")
			case "/publicKey":
				file, err = os.ReadFile("tests/test_public_key.key")
			case "/not_found":
				err = errors.New("file not found")
			}
			if err != nil {
				w.WriteHeader(http.StatusNotFound)
				return
			}
			w.WriteHeader(http.StatusOK)
			_, _ = w.Write(file)
		}))
	defer testServer.Close()

	tests := []test{
		{
			caseDesc:              "valid local artifact",
			artifact:              "tests/test_file.txt",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid remote artifact",
			artifact:              testServer.URL + "/artifact",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "nonexistent local artifact",
			artifact:              "tests/not_a_file",
			expectParseSuccess:    false,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "nonexistent remote artifact",
			artifact:              testServer.URL + "/not_found",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid local public key",
			publicKey:             "tests/test_public_key.key",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid local minisign public key",
			publicKey:             "../../../pkg/pki/minisign/testdata/minisign.pub",
			pkiFormat:             "minisign",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid remote public key",
			publicKey:             testServer.URL + "/publicKey",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "nonexistent local public key",
			publicKey:             "tests/not_a_file",
			expectParseSuccess:    false,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "nonexistent remote public key",
			publicKey:             testServer.URL + "/not_found",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid SHA1",
			sha:                   "84374135959eacf60cf3fed7520a01b336332efe",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid SHA1 with prefix",
			sha:                   "sha1:84374135959eacf60cf3fed7520a01b336332efe",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid SHA256",
			sha:                   "45c7b11fcbf07dec1694adecd8c5b85770a12a6c8dfdcf2580a2db0c47c31779",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid SHA256 with prefix",
			sha:                   "sha256:45c7b11fcbf07dec1694adecd8c5b85770a12a6c8dfdcf2580a2db0c47c31779",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid SHA512",
			sha:                   "a5d575f245588b64bcec78a1bb9d92a66bfb4d68d7de1aea4162ad0b232753860cb764fd0645ada1f5d935163522987359e515e0594068d7bc108f0584d6da29",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "valid SHA512 with prefix",
			sha:                   "sha512:a5d575f245588b64bcec78a1bb9d92a66bfb4d68d7de1aea4162ad0b232753860cb764fd0645ada1f5d935163522987359e515e0594068d7bc108f0584d6da29",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "invalid SHA prefix",
			sha:                   "sha257:45c7b11fcbf07dec1694adecd8c5b85770a12a6c8dfdcf2580a2db0c47c31779",
			expectParseSuccess:    false,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "invalid SHA",
			sha:                   "45c7b11fcbf",
			expectParseSuccess:    false,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "invalid hash alg",
			sha:                   "md5:d408f34c27cf5930be6394a455f23d40",
			expectParseSuccess:    false,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "valid email",
			email:                 "cat@foo.com",
			expectParseSuccess:    true,
			expectValidateSuccess: true,
		},
		{
			caseDesc:              "invalid email",
			email:                 "SignaMeseCat",
			expectParseSuccess:    false,
			expectValidateSuccess: false,
		},
		{
			caseDesc:              "no flags when either artifact, sha, public key, or email are needed",
			expectParseSuccess:    true,
			expectValidateSuccess: false,
		},
	}

	for _, tc := range tests {
		initializePFlagMap()
		var blankCmd = &cobra.Command{}
		if err := addSearchPFlags(blankCmd); err != nil {
			t.Fatalf("unexpected error adding flags in '%v': %v", tc.caseDesc, err)
		}

		args := []string{}

		if tc.artifact != "" {
			args = append(args, "--artifact", tc.artifact)
		}
		if tc.publicKey != "" {
			args = append(args, "--public-key", tc.publicKey)
		}
		if tc.pkiFormat != "" {
			args = append(args, "--pki-format", tc.pkiFormat)
		}
		if tc.sha != "" {
			args = append(args, "--sha", tc.sha)
		}
		if tc.email != "" {
			args = append(args, "--email", tc.email)
		}

		if err := blankCmd.ParseFlags(args); (err == nil) != tc.expectParseSuccess {
			t.Errorf("unexpected result parsing '%v': %v", tc.caseDesc, err)
			continue
		}

		if err := viper.BindPFlags(blankCmd.Flags()); err != nil {
			t.Fatalf("unexpected result initializing viper in '%v': %v", tc.caseDesc, err)
		}
		if err := validateSearchPFlags(); (err == nil) != tc.expectValidateSuccess {
			t.Errorf("unexpected result validating '%v': %v", tc.caseDesc, err)
			continue
		}
	}
}

func TestParseTypeFlag(t *testing.T) {
	type test struct {
		caseDesc      string
		typeStr       string
		expectSuccess bool
	}

	tests := []test{
		{
			caseDesc:      "bogus",
			typeStr:       "bogus",
			expectSuccess: false,
		},
		{
			caseDesc:      "rekord",
			typeStr:       "rekord",
			expectSuccess: true,
		},
		{
			caseDesc:      "explicit rekord v0.0.1",
			typeStr:       "rekord:0.0.1",
			expectSuccess: true,
		},
		{
			caseDesc:      "non-existent rekord v0.0.0",
			typeStr:       "rekord:0.0.0",
			expectSuccess: false,
		},
		{
			caseDesc:      "hashedrekord",
			typeStr:       "hashedrekord",
			expectSuccess: true,
		},
		{
			caseDesc:      "explicit hashedrekord v0.0.1",
			typeStr:       "hashedrekord:0.0.1",
			expectSuccess: true,
		},
		{
			caseDesc:      "non-existent hashedrekord v0.0.0",
			typeStr:       "hashedrekord:0.0.0",
			expectSuccess: false,
		},
		{
			caseDesc:      "alpine",
			typeStr:       "alpine",
			expectSuccess: true,
		},
		{
			caseDesc:      "explicit alpine v0.0.1",
			typeStr:       "alpine:0.0.1",
			expectSuccess: true,
		},
		{
			caseDesc:      "non-existent alpine v0.0.0",
			typeStr:       "alpine:0.0.0",
			expectSuccess: false,
		},
		{
			caseDesc:      "cose",
			typeStr:       "cose",
			expectSuccess: true,
		},
		{
			caseDesc:      "explicit cose v0.0.1",
			typeStr:       "cose:0.0.1",
			expectSuccess: true,
		},
		{
			caseDesc:      "non-existent cose v0.0.0",
			typeStr:       "cose:0.0.0",
			expectSuccess: false,
		},
		{
			caseDesc:      "helm",
			typeStr:       "helm",
			expectSuccess: true,
		},
		{
			caseDesc:      "explicit helm v0.0.1",
			typeStr:       "helm:0.0.1",
			expectSuccess: true,
		},
		{
			caseDesc:      "non-existent helm v0.0.0",
			typeStr:       "helm:0.0.0",
			expectSuccess: false,
		},
		{
			caseDesc:      "intoto",
			typeStr:       "intoto",
			expectSuccess: true,
		},
		{
			caseDesc:      "explicit intoto v0.0.1",
			typeStr:       "intoto:0.0.1",
			expectSuccess: true,
		},
		{
			caseDesc:      "explicit intoto v0.0.2",
			typeStr:       "intoto:0.0.2",
			expectSuccess: true,
		},
		{
			caseDesc:      "non-existent intoto v0.0.0",
			typeStr:       "intoto:0.0.0",
			expectSuccess: false,
		},
		{
			caseDesc:      "jar",
			typeStr:       "jar",
			expectSuccess: true,
		},
		{
			caseDesc:      "explicit jar v0.0.1",
			typeStr:       "jar:0.0.1",
			expectSuccess: true,
		},
		{
			caseDesc:      "non-existent jar v0.0.0",
			typeStr:       "jar:0.0.0",
			expectSuccess: false,
		},
		{
			caseDesc:      "rfc3161",
			typeStr:       "rfc3161",
			expectSuccess: true,
		},
		{
			caseDesc:      "explicit rfc3161 v0.0.1",
			typeStr:       "rfc3161:0.0.1",
			expectSuccess: true,
		},
		{
			caseDesc:      "non-existent rfc3161 v0.0.0",
			typeStr:       "rfc3161:0.0.0",
			expectSuccess: false,
		},
		{
			caseDesc:      "rpm",
			typeStr:       "rpm",
			expectSuccess: true,
		},
		{
			caseDesc:      "explicit rpm v0.0.1",
			typeStr:       "rpm:0.0.1",
			expectSuccess: true,
		},
		{
			caseDesc:      "non-existent rpm v0.0.0",
			typeStr:       "rpm:0.0.0",
			expectSuccess: false,
		},
		{
			caseDesc:      "tuf",
			typeStr:       "tuf",
			expectSuccess: true,
		},
		{
			caseDesc:      "explicit tuf v0.0.1",
			typeStr:       "tuf:0.0.1",
			expectSuccess: true,
		},
		{
			caseDesc:      "non-existent tuf v0.0.0",
			typeStr:       "tuf:0.0.0",
			expectSuccess: false,
		},
	}

	for _, tc := range tests {
		if _, _, err := ParseTypeFlag(tc.typeStr); (err == nil) != tc.expectSuccess {
			t.Fatalf("unexpected error parsing type flag in '%v': %v", tc.caseDesc, err)
		}
	}
}
