package java

import (
	"testing"

	"github.com/stretchr/testify/assert"

	"github.com/anchore/syft/syft/pkg"
)

func Test_packageURL(t *testing.T) {
	tests := []struct {
		name   string
		pkg    pkg.Package
		expect string
	}{
		{
			name: "maven",
			pkg: pkg.Package{
				Name:     "example-java-app-maven",
				Version:  "0.1.0",
				Language: pkg.Java,
				Type:     pkg.JavaPkg,
				Metadata: pkg.JavaArchive{
					VirtualPath: "testdata/java-builds/packages/example-java-app-maven-0.1.0.jar",
					Manifest: &pkg.JavaManifest{
						Main: []pkg.KeyValue{
							{
								Key:   "Manifest-Version",
								Value: "1.0",
							},
						},
					},
					PomProperties: &pkg.JavaPomProperties{
						Path:       "META-INF/maven/org.anchore/example-java-app-maven/pom.properties",
						GroupID:    "org.anchore",
						ArtifactID: "example-java-app-maven",
						Version:    "0.1.0",
						Extra:      make(map[string]string),
					},
				},
			},
			expect: "pkg:maven/org.anchore/example-java-app-maven@0.1.0",
		},
		{
			name: "POM properties have explicit group ID without . in it",
			pkg: pkg.Package{
				Name:     "example-java-app-maven",
				Version:  "0.1.0",
				Language: pkg.Java,
				Type:     pkg.JavaPkg,
				Metadata: pkg.JavaArchive{
					VirtualPath: "testdata/java-builds/packages/example-java-app-maven-0.1.0.jar",
					Manifest: &pkg.JavaManifest{
						Main: []pkg.KeyValue{
							{
								Key:   "Manifest-Version",
								Value: "1.0",
							},
						},
					},
					PomProperties: &pkg.JavaPomProperties{
						Path:       "META-INF/maven/org.anchore/example-java-app-maven/pom.properties",
						GroupID:    "commons",
						ArtifactID: "example-java-app-maven",
						Version:    "0.1.0",
						Extra:      make(map[string]string),
					},
				},
			},
			expect: "pkg:maven/commons/example-java-app-maven@0.1.0",
		},
		{
			name: "POM project has explicit group ID without . in it",
			pkg: pkg.Package{
				Name:     "example-java-app-maven",
				Version:  "0.1.0",
				Language: pkg.Java,
				Type:     pkg.JavaPkg,
				Metadata: pkg.JavaArchive{
					VirtualPath: "testdata/java-builds/packages/example-java-app-maven-0.1.0.jar",
					Manifest: &pkg.JavaManifest{
						Main: []pkg.KeyValue{
							{
								Key:   "Manifest-Version",
								Value: "1.0",
							},
						},
					},
					PomProperties: &pkg.JavaPomProperties{
						Path:       "META-INF/maven/org.anchore/example-java-app-maven/pom.properties",
						ArtifactID: "example-java-app-maven",
						Version:    "0.1.0",
						Extra:      make(map[string]string),
					},
					PomProject: &pkg.JavaPomProject{
						GroupID: "commons",
					},
				},
			},
			expect: "pkg:maven/commons/example-java-app-maven@0.1.0",
		},
		{
			name: "POM project has explicit group ID without . in it",
			pkg: pkg.Package{
				Name:     "example-java-app-maven",
				Version:  "0.1.0",
				Language: pkg.Java,
				Type:     pkg.JavaPkg,
				Metadata: pkg.JavaArchive{
					VirtualPath: "testdata/java-builds/packages/example-java-app-maven-0.1.0.jar",
					Manifest: &pkg.JavaManifest{
						Main: []pkg.KeyValue{
							{
								Key:   "Manifest-Version",
								Value: "1.0",
							},
						},
					},
					PomProperties: &pkg.JavaPomProperties{
						Path:       "META-INF/maven/org.anchore/example-java-app-maven/pom.properties",
						ArtifactID: "example-java-app-maven",
						Version:    "0.1.0",
						Extra:      make(map[string]string),
					},
					PomProject: &pkg.JavaPomProject{
						Parent: &pkg.JavaPomParent{
							GroupID: "parent",
						},
					},
				},
			},
			expect: "pkg:maven/parent/example-java-app-maven@0.1.0",
		},
	}
	for _, tt := range tests {
		t.Run(tt.expect, func(t *testing.T) {
			assert.Equal(t, tt.expect, packageURL(tt.pkg.Name, tt.pkg.Version, tt.pkg.Metadata.(pkg.JavaArchive)))
		})
	}
}

func Test_groupIDFromJavaMetadata(t *testing.T) {
	tests := []struct {
		name     string
		pkgName  string
		metadata pkg.JavaArchive
		expect   string
	}{
		{
			name: "pom properties",
			metadata: pkg.JavaArchive{
				PomProperties: &pkg.JavaPomProperties{
					GroupID: "org.anchore",
				},
			},
			expect: "org.anchore",
		},
		{
			name: "pom project",
			metadata: pkg.JavaArchive{
				PomProject: &pkg.JavaPomProject{
					GroupID: "org.anchore",
				},
			},
			expect: "org.anchore",
		},
		{
			name:     "known package list",
			pkgName:  "ant-antlr",
			metadata: pkg.JavaArchive{},
			expect:   "org.apache.ant",
		},
		{
			// regression for github.com/anchore/syft/issues/4030: spring-ldap artifacts
			// live under org.springframework.ldap, not org.springframework
			name:     "known package list spring-ldap-core",
			pkgName:  "spring-ldap-core",
			metadata: pkg.JavaArchive{},
			expect:   "org.springframework.ldap",
		},
		{
			name:     "known package list spring-ldap",
			pkgName:  "spring-ldap",
			metadata: pkg.JavaArchive{},
			expect:   "org.springframework.ldap",
		},
		{
			// regression for github.com/anchore/syft/issues/4598: legacy Jackson 1.x ("-asl")
			// jars built before ~2014 have no embedded pom.properties, so without the known
			// package list the group ID falls back to the artifact name itself, producing a
			// purl that doesn't match the vulnerability database's namespace (e.g. the correct
			// group for jackson-mapper-asl is org.codehaus.jackson, not jackson-mapper-asl).
			name:     "known package list jackson-mapper-asl",
			pkgName:  "jackson-mapper-asl",
			metadata: pkg.JavaArchive{},
			expect:   "org.codehaus.jackson",
		},
		{
			name:     "known package list jackson-core-asl",
			pkgName:  "jackson-core-asl",
			metadata: pkg.JavaArchive{},
			expect:   "org.codehaus.jackson",
		},
		{
			name: "java manifest",
			metadata: pkg.JavaArchive{
				Manifest: &pkg.JavaManifest{
					Main: []pkg.KeyValue{
						{
							Key:   "Implementation-Vendor",
							Value: "org.anchore",
						},
					},
				},
			},
			expect: "org.anchore",
		},
		{
			name:     "no group id",
			metadata: pkg.JavaArchive{},
			expect:   "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			assert.Equal(t, tt.expect, groupIDFromJavaMetadata(tt.pkgName, tt.metadata))
		})
	}
}
