github.com/kastenhq/syft@v0.0.0-20230821225854-0710af25cdbe/syft/pkg/cataloger/java/parse_pom_xml_test.go (about)

     1  package java
     2  
     3  import (
     4  	"os"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  	"github.com/vifraa/gopom"
     9  
    10  	"github.com/kastenhq/syft/syft/file"
    11  	"github.com/kastenhq/syft/syft/pkg"
    12  	"github.com/kastenhq/syft/syft/pkg/cataloger/internal/pkgtest"
    13  )
    14  
    15  func Test_parserPomXML(t *testing.T) {
    16  	tests := []struct {
    17  		input    string
    18  		expected []pkg.Package
    19  	}{
    20  		{
    21  			input: "test-fixtures/pom/pom.xml",
    22  			expected: []pkg.Package{
    23  				{
    24  					Name:         "joda-time",
    25  					Version:      "2.9.2",
    26  					PURL:         "pkg:maven/com.joda/joda-time@2.9.2",
    27  					Language:     pkg.Java,
    28  					Type:         pkg.JavaPkg,
    29  					MetadataType: pkg.JavaMetadataType,
    30  					Metadata: pkg.JavaMetadata{
    31  						PomProperties: &pkg.PomProperties{
    32  							GroupID:    "com.joda",
    33  							ArtifactID: "joda-time",
    34  						},
    35  					},
    36  				},
    37  				{
    38  					Name:         "junit",
    39  					Version:      "4.12",
    40  					PURL:         "pkg:maven/junit/junit@4.12",
    41  					Language:     pkg.Java,
    42  					Type:         pkg.JavaPkg,
    43  					MetadataType: pkg.JavaMetadataType,
    44  					Metadata: pkg.JavaMetadata{
    45  						PomProperties: &pkg.PomProperties{
    46  							GroupID:    "junit",
    47  							ArtifactID: "junit",
    48  							Scope:      "test",
    49  						},
    50  					},
    51  				},
    52  			},
    53  		},
    54  	}
    55  
    56  	for _, test := range tests {
    57  		t.Run(test.input, func(t *testing.T) {
    58  			for i := range test.expected {
    59  				test.expected[i].Locations.Add(file.NewLocation(test.input))
    60  			}
    61  			pkgtest.TestFileParser(t, test.input, parserPomXML, test.expected, nil)
    62  		})
    63  	}
    64  }
    65  
    66  func Test_parseCommonsTextPomXMLProject(t *testing.T) {
    67  	tests := []struct {
    68  		input    string
    69  		expected []pkg.Package
    70  	}{
    71  		{
    72  			input: "test-fixtures/pom/commons-text.pom.xml",
    73  			expected: []pkg.Package{
    74  				{
    75  					Name:         "commons-lang3",
    76  					Version:      "3.12.0",
    77  					PURL:         "pkg:maven/org.apache.commons/commons-lang3@3.12.0",
    78  					Language:     pkg.Java,
    79  					Type:         pkg.JavaPkg,
    80  					MetadataType: pkg.JavaMetadataType,
    81  					Metadata: pkg.JavaMetadata{
    82  						PomProperties: &pkg.PomProperties{
    83  							GroupID:    "org.apache.commons",
    84  							ArtifactID: "commons-lang3",
    85  						},
    86  					},
    87  				},
    88  				{
    89  					Name:         "junit-jupiter",
    90  					Version:      "",
    91  					PURL:         "pkg:maven/org.junit.jupiter/junit-jupiter",
    92  					Language:     pkg.Java,
    93  					Type:         pkg.JavaPkg,
    94  					MetadataType: pkg.JavaMetadataType,
    95  					Metadata: pkg.JavaMetadata{
    96  						PomProperties: &pkg.PomProperties{
    97  							GroupID:    "org.junit.jupiter",
    98  							ArtifactID: "junit-jupiter",
    99  							Scope:      "test",
   100  						},
   101  					},
   102  				},
   103  				{
   104  					Name:         "assertj-core",
   105  					Version:      "3.23.1",
   106  					PURL:         "pkg:maven/org.assertj/assertj-core@3.23.1",
   107  					Language:     pkg.Java,
   108  					Type:         pkg.JavaPkg,
   109  					MetadataType: pkg.JavaMetadataType,
   110  					Metadata: pkg.JavaMetadata{
   111  						PomProperties: &pkg.PomProperties{
   112  							GroupID:    "org.assertj",
   113  							ArtifactID: "assertj-core",
   114  							Scope:      "test",
   115  						},
   116  					},
   117  				},
   118  				{
   119  					Name:         "commons-io",
   120  					Version:      "2.11.0",
   121  					PURL:         "pkg:maven/commons-io/commons-io@2.11.0",
   122  					Language:     pkg.Java,
   123  					Type:         pkg.JavaPkg,
   124  					MetadataType: pkg.JavaMetadataType,
   125  					Metadata: pkg.JavaMetadata{
   126  						PomProperties: &pkg.PomProperties{
   127  							GroupID:    "commons-io",
   128  							ArtifactID: "commons-io",
   129  							Scope:      "test",
   130  						},
   131  					},
   132  				},
   133  				{
   134  					Name:         "mockito-inline",
   135  					Version:      "4.8.0",
   136  					PURL:         "pkg:maven/org.mockito/mockito-inline@4.8.0",
   137  					Language:     pkg.Java,
   138  					Type:         pkg.JavaPkg,
   139  					MetadataType: pkg.JavaMetadataType,
   140  					Metadata: pkg.JavaMetadata{
   141  						PomProperties: &pkg.PomProperties{
   142  							GroupID:    "org.mockito",
   143  							ArtifactID: "mockito-inline",
   144  							Scope:      "test",
   145  						},
   146  					},
   147  				},
   148  				{
   149  					Name:         "js",
   150  					Version:      "22.0.0.2",
   151  					PURL:         "pkg:maven/org.graalvm.js/js@22.0.0.2",
   152  					Language:     pkg.Java,
   153  					Type:         pkg.JavaPkg,
   154  					MetadataType: pkg.JavaMetadataType,
   155  					Metadata: pkg.JavaMetadata{
   156  						PomProperties: &pkg.PomProperties{
   157  							GroupID:    "org.graalvm.js",
   158  							ArtifactID: "js",
   159  							Scope:      "test",
   160  						},
   161  					},
   162  				},
   163  				{
   164  					Name:         "js-scriptengine",
   165  					Version:      "22.0.0.2",
   166  					PURL:         "pkg:maven/org.graalvm.js/js-scriptengine@22.0.0.2",
   167  					Language:     pkg.Java,
   168  					Type:         pkg.JavaPkg,
   169  					MetadataType: pkg.JavaMetadataType,
   170  					Metadata: pkg.JavaMetadata{
   171  						PomProperties: &pkg.PomProperties{
   172  							GroupID:    "org.graalvm.js",
   173  							ArtifactID: "js-scriptengine",
   174  							Scope:      "test",
   175  						},
   176  					},
   177  				},
   178  				{
   179  					Name:         "commons-rng-simple",
   180  					Version:      "1.4",
   181  					PURL:         "pkg:maven/org.apache.commons/commons-rng-simple@1.4",
   182  					Language:     pkg.Java,
   183  					Type:         pkg.JavaPkg,
   184  					MetadataType: pkg.JavaMetadataType,
   185  					Metadata: pkg.JavaMetadata{
   186  						PomProperties: &pkg.PomProperties{
   187  							GroupID:    "org.apache.commons",
   188  							ArtifactID: "commons-rng-simple",
   189  							Scope:      "test",
   190  						},
   191  					},
   192  				},
   193  				{
   194  					Name:         "jmh-core",
   195  					Version:      "1.35",
   196  					PURL:         "pkg:maven/org.openjdk.jmh/jmh-core@1.35",
   197  					Language:     pkg.Java,
   198  					Type:         pkg.JavaPkg,
   199  					MetadataType: pkg.JavaMetadataType,
   200  					Metadata: pkg.JavaMetadata{
   201  						PomProperties: &pkg.PomProperties{
   202  							GroupID:    "org.openjdk.jmh",
   203  							ArtifactID: "jmh-core",
   204  							Scope:      "test",
   205  						},
   206  					},
   207  				},
   208  				{
   209  					Name:         "jmh-generator-annprocess",
   210  					Version:      "1.35",
   211  					PURL:         "pkg:maven/org.openjdk.jmh/jmh-generator-annprocess@1.35",
   212  					Language:     pkg.Java,
   213  					Type:         pkg.JavaPkg,
   214  					MetadataType: pkg.JavaMetadataType,
   215  					Metadata: pkg.JavaMetadata{
   216  						PomProperties: &pkg.PomProperties{
   217  							GroupID:    "org.openjdk.jmh",
   218  							ArtifactID: "jmh-generator-annprocess",
   219  							Scope:      "test",
   220  						},
   221  					},
   222  				},
   223  			},
   224  		},
   225  	}
   226  
   227  	for _, test := range tests {
   228  		t.Run(test.input, func(t *testing.T) {
   229  			for i := range test.expected {
   230  				test.expected[i].Locations.Add(file.NewLocation(test.input))
   231  			}
   232  			pkgtest.TestFileParser(t, test.input, parserPomXML, test.expected, nil)
   233  		})
   234  	}
   235  }
   236  
   237  func Test_parsePomXMLProject(t *testing.T) {
   238  	tests := []struct {
   239  		expected pkg.PomProject
   240  	}{
   241  		{
   242  			expected: pkg.PomProject{
   243  				Path: "test-fixtures/pom/commons-codec.pom.xml",
   244  				Parent: &pkg.PomParent{
   245  					GroupID:    "org.apache.commons",
   246  					ArtifactID: "commons-parent",
   247  					Version:    "42",
   248  				},
   249  				GroupID:     "commons-codec",
   250  				ArtifactID:  "commons-codec",
   251  				Version:     "1.11",
   252  				Name:        "Apache Commons Codec",
   253  				Description: "The Apache Commons Codec package contains simple encoder and decoders for various formats such as Base64 and Hexadecimal.  In addition to these widely used encoders and decoders, the codec package also maintains a collection of phonetic encoding utilities.",
   254  				URL:         "http://commons.apache.org/proper/commons-codec/",
   255  			},
   256  		},
   257  	}
   258  
   259  	for _, test := range tests {
   260  		t.Run(test.expected.Path, func(t *testing.T) {
   261  			fixture, err := os.Open(test.expected.Path)
   262  			assert.NoError(t, err)
   263  
   264  			actual, err := parsePomXMLProject(fixture.Name(), fixture)
   265  			assert.NoError(t, err)
   266  
   267  			assert.Equal(t, &test.expected, actual)
   268  		})
   269  	}
   270  }
   271  
   272  func Test_pomParent(t *testing.T) {
   273  	tests := []struct {
   274  		name     string
   275  		input    gopom.Parent
   276  		expected *pkg.PomParent
   277  	}{
   278  		{
   279  			name: "only group ID",
   280  			input: gopom.Parent{
   281  				GroupID: "org.something",
   282  			},
   283  			expected: &pkg.PomParent{
   284  				GroupID: "org.something",
   285  			},
   286  		},
   287  		{
   288  			name: "only artifact ID",
   289  			input: gopom.Parent{
   290  				ArtifactID: "something",
   291  			},
   292  			expected: &pkg.PomParent{
   293  				ArtifactID: "something",
   294  			},
   295  		},
   296  		{
   297  			name: "only Version",
   298  			input: gopom.Parent{
   299  				Version: "something",
   300  			},
   301  			expected: &pkg.PomParent{
   302  				Version: "something",
   303  			},
   304  		},
   305  		{
   306  			name:     "empty",
   307  			input:    gopom.Parent{},
   308  			expected: nil,
   309  		},
   310  		{
   311  			name: "unused field",
   312  			input: gopom.Parent{
   313  				RelativePath: "something",
   314  			},
   315  			expected: nil,
   316  		},
   317  	}
   318  
   319  	for _, test := range tests {
   320  		t.Run(test.name, func(t *testing.T) {
   321  			assert.Equal(t, test.expected, pomParent(gopom.Project{}, test.input))
   322  		})
   323  	}
   324  }
   325  
   326  func Test_cleanDescription(t *testing.T) {
   327  	tests := []struct {
   328  		name     string
   329  		input    string
   330  		expected string
   331  	}{
   332  		{
   333  			name: "indent + multiline",
   334  			input: `        The Apache Commons Codec package contains simple encoder and decoders for
   335          various formats such as Base64 and Hexadecimal.  In addition to these
   336          widely used encoders and decoders, the codec package also maintains a
   337          collection of phonetic encoding utilities.`,
   338  			expected: "The Apache Commons Codec package contains simple encoder and decoders for various formats such as Base64 and Hexadecimal.  In addition to these widely used encoders and decoders, the codec package also maintains a collection of phonetic encoding utilities.",
   339  		},
   340  	}
   341  
   342  	for _, test := range tests {
   343  		t.Run(test.name, func(t *testing.T) {
   344  			assert.Equal(t, test.expected, cleanDescription(test.input))
   345  		})
   346  	}
   347  }
   348  
   349  func Test_resolveProperty(t *testing.T) {
   350  	tests := []struct {
   351  		name     string
   352  		property string
   353  		pom      gopom.Project
   354  		expected string
   355  	}{
   356  		{
   357  			name:     "property",
   358  			property: "${version.number}",
   359  			pom: gopom.Project{
   360  				Properties: gopom.Properties{
   361  					Entries: map[string]string{
   362  						"version.number": "12.5.0",
   363  					},
   364  				},
   365  			},
   366  			expected: "12.5.0",
   367  		},
   368  		{
   369  			name:     "groupId",
   370  			property: "${project.groupId}",
   371  			pom: gopom.Project{
   372  				GroupID: "org.some.group",
   373  			},
   374  			expected: "org.some.group",
   375  		},
   376  		{
   377  			name:     "parent groupId",
   378  			property: "${project.parent.groupId}",
   379  			pom: gopom.Project{
   380  				Parent: gopom.Parent{
   381  					GroupID: "org.some.parent",
   382  				},
   383  			},
   384  			expected: "org.some.parent",
   385  		},
   386  	}
   387  
   388  	for _, test := range tests {
   389  		t.Run(test.name, func(t *testing.T) {
   390  			resolved := resolveProperty(test.pom, test.property)
   391  			assert.Equal(t, test.expected, resolved)
   392  		})
   393  	}
   394  }