github.com/CycloneDX/sbom-utility@v0.16.0/cmd/component_test.go (about) 1 // SPDX-License-Identifier: Apache-2.0 2 /* 3 * Licensed to the Apache Software Foundation (ASF) under one or more 4 * contributor license agreements. See the NOTICE file distributed with 5 * this work for additional information regarding copyright ownership. 6 * The ASF licenses this file to You under the Apache License, Version 2.0 7 * (the "License"); you may not use this file except in compliance with 8 * the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 package cmd 20 21 import ( 22 "bufio" 23 "bytes" 24 "io/fs" 25 "log" 26 "os" 27 "testing" 28 29 "github.com/CycloneDX/sbom-utility/common" 30 "github.com/CycloneDX/sbom-utility/utils" 31 ) 32 33 // Test "resource list" command 34 const ( 35 // test/cyclonedx/cdx-1-3-resource-list.json 36 TEST_COMPONENT_LIST_CDX_1_3 = TEST_RESOURCE_LIST_CDX_1_3 37 // test/cyclonedx/cdx-1-5-mature-example-1.json 38 TEST_COMPONENT_LIST_CDX_1_5_MATURE = TEST_CDX_1_5_MATURE_EXAMPLE_1_BASE 39 // test/cyclonedx/1.6/cdx-1-6-valid-cbom-full-1.6.json 40 TEST_COMPONENT_LIST_CDX_1_6_CBOM = TEST_CDX_1_6_CRYPTO_BOM 41 // test/cyclonedx/1.6/cdx-1-6-valid-mlbom-environmental-considerations.json 42 TEST_COMPONENT_LIST_CDX_1_6_MLBOM = TEST_CDX_1_6_MACHINE_LEARNING_BOM 43 ) 44 45 var COMPONENT_TEST_DEFAULT_FLAGS utils.ComponentCommandFlags 46 47 type ComponentTestInfo struct { 48 CommonTestInfo 49 } 50 51 func (ti *ComponentTestInfo) String() string { 52 buffer, _ := utils.EncodeAnyToDefaultIndentedJSONStr(ti) 53 return buffer.String() 54 } 55 56 func NewComponentTestInfo(inputFile string, outputFormat string, listSummary bool, whereClause string, 57 resultExpectedLineCount int) *ComponentTestInfo { 58 59 var ti = new(ComponentTestInfo) 60 var pCommon = &ti.CommonTestInfo 61 // initialize common fields 62 pCommon.Init(inputFile, outputFormat, listSummary, whereClause, 63 nil, resultExpectedLineCount, nil) 64 return ti 65 } 66 67 func NewComponentTestInfoBasic(inputFile string, listFormat string, resultExpectedError error) *ComponentTestInfo { 68 var ti = new(ComponentTestInfo) 69 var pCommon = &ti.CommonTestInfo 70 pCommon.InitBasic(inputFile, listFormat, resultExpectedError) 71 return ti 72 } 73 74 // ------------------------------------------- 75 // resource list test helper functions 76 // ------------------------------------------- 77 func innerBufferedTestComponentList(testInfo *ComponentTestInfo, whereFilters []common.WhereFilter, flags utils.ComponentCommandFlags) (outputBuffer bytes.Buffer, err error) { 78 // Declare an output outputBuffer/outputWriter to use used during tests 79 var outputWriter = bufio.NewWriter(&outputBuffer) 80 // ensure all data is written to buffer before further validation 81 defer outputWriter.Flush() 82 83 var persistentFlags utils.PersistentCommandFlags 84 persistentFlags.OutputFormat = testInfo.OutputFormat 85 86 err = ListComponents(outputWriter, persistentFlags, flags, whereFilters) 87 return 88 } 89 90 func innerTestComponentList(t *testing.T, testInfo *ComponentTestInfo, flags utils.ComponentCommandFlags) (outputBuffer bytes.Buffer, basicTestInfo string, err error) { 91 getLogger().Tracef("TestInfo: %s", testInfo) 92 93 // Parse out --where filters and exit out if error detected 94 whereFilters, err := prepareWhereFilters(t, &testInfo.CommonTestInfo) 95 if err != nil { 96 return 97 } 98 99 // The command looks for the input filename in global flags struct 100 utils.GlobalFlags.PersistentFlags.InputFile = testInfo.InputFile 101 102 // Mock stdin if requested 103 if testInfo.MockStdin == true { 104 utils.GlobalFlags.PersistentFlags.InputFile = INPUT_TYPE_STDIN 105 file, err := os.Open(testInfo.InputFile) // For read access. 106 if err != nil { 107 log.Fatal(err) 108 } 109 110 // convert byte slice to io.Reader 111 savedStdIn := os.Stdin 112 // !!!Important restore stdin 113 defer func() { os.Stdin = savedStdIn }() 114 os.Stdin = file 115 } 116 117 // invoke resource list command with a byte buffer 118 outputBuffer, err = innerBufferedTestComponentList(testInfo, whereFilters, flags) 119 120 // Run all common tests against "result" values in the CommonTestInfo struct 121 err = innerRunReportResultTests(t, &testInfo.CommonTestInfo, outputBuffer, err) 122 123 return 124 } 125 126 // ------------------------------------------- 127 // Test format unsupported (SPDX) 128 // ------------------------------------------- 129 func TestComponentListFormatUnsupportedSPDXMinReq(t *testing.T) { 130 ti := NewComponentTestInfoBasic( 131 TEST_INPUT_FILE_NON_EXISTENT, 132 FORMAT_DEFAULT, 133 &fs.PathError{}, 134 ) 135 // verify correct error is returned 136 innerTestComponentList(t, ti, COMPONENT_TEST_DEFAULT_FLAGS) 137 } 138 139 // ------------------------------------------- 140 // Format variants 141 // ------------------------------------------- 142 143 func TestComponentListCdx13Text(t *testing.T) { 144 ti := NewComponentTestInfoBasic(TEST_RESOURCE_LIST_CDX_1_3, FORMAT_TEXT, nil) 145 ti.ResultExpectedLineCount = 14 // title + separator + 11 data + EOF LF 146 ti.ResultLineContainsValuesAtLineNum = 6 147 ti.ResultLineContainsValues = []string{"Library G"} 148 innerTestComponentList(t, ti, COMPONENT_TEST_DEFAULT_FLAGS) 149 } 150 151 func TestComponentListCdx13Csv(t *testing.T) { 152 ti := NewComponentTestInfoBasic(TEST_RESOURCE_LIST_CDX_1_3, FORMAT_CSV, nil) 153 ti.ResultExpectedLineCount = 13 // title + 11 data + EOF LF 154 ti.ResultLineContainsValuesAtLineNum = 5 155 ti.ResultLineContainsValues = []string{"Library G"} 156 innerTestComponentList(t, ti, COMPONENT_TEST_DEFAULT_FLAGS) 157 } 158 159 func TestComponentListCdx13Markdown(t *testing.T) { 160 ti := NewComponentTestInfoBasic(TEST_RESOURCE_LIST_CDX_1_3, FORMAT_MARKDOWN, nil) 161 ti.ResultExpectedLineCount = 14 // title + separator + 11 data + EOF LF 162 ti.ResultLineContainsValuesAtLineNum = 6 163 ti.ResultLineContainsValues = []string{"Library G"} 164 innerTestComponentList(t, ti, COMPONENT_TEST_DEFAULT_FLAGS) 165 } 166 167 // ------------------------------------------- 168 // CDX variants 169 // ------------------------------------------- 170 171 func TestComponentListCdx15MatureCsv(t *testing.T) { 172 ti := NewComponentTestInfoBasic(TEST_COMPONENT_LIST_CDX_1_5_MATURE, FORMAT_CSV, nil) 173 //ti.ListSummary = false 174 //ti.WhereClause = "version=2.0" 175 ti.ResultExpectedLineCount = 5 // title + 3 data + EOF LF 176 ti.ResultLineContainsValuesAtLineNum = 3 177 ti.ResultLineContainsValues = []string{"sample"} 178 innerTestComponentList(t, ti, COMPONENT_TEST_DEFAULT_FLAGS) 179 } 180 181 func TestComponentListCdx16CryptoBOMCsv(t *testing.T) { 182 ti := NewComponentTestInfoBasic(TEST_COMPONENT_LIST_CDX_1_6_CBOM, FORMAT_CSV, nil) 183 ti.ResultExpectedLineCount = 6 // title + 4 data + EOF LF 184 ti.ResultLineContainsValuesAtLineNum = 2 185 ti.ResultLineContainsValues = []string{"asset-2"} 186 innerTestComponentList(t, ti, COMPONENT_TEST_DEFAULT_FLAGS) 187 } 188 189 func TestComponentListCdx16MachineLearningBOMCsv(t *testing.T) { 190 ti := NewComponentTestInfoBasic(TEST_COMPONENT_LIST_CDX_1_6_MLBOM, FORMAT_CSV, nil) 191 ti.ResultExpectedLineCount = 3 // title + 1 data + EOF LF 192 ti.ResultLineContainsValuesAtLineNum = 1 193 ti.ResultLineContainsValues = []string{"Llama-2-7b"} 194 innerTestComponentList(t, ti, COMPONENT_TEST_DEFAULT_FLAGS) 195 } 196 197 // ./sbom-utility component list -i test/cyclonedx/cdx-1-3-resource-list.json --where "number-licenses=0" --quiet --format=txt 198 // 199 // library Library NoLicense 1.0.0 Library "NoLicense" description. pkg:lib/libraryNoLicense@1.0.0 0 0 200 func TestComponentListCdx13WhereNumLicensesCsv(t *testing.T) { 201 ti := NewComponentTestInfoBasic(TEST_RESOURCE_LIST_CDX_1_3, FORMAT_CSV, nil) 202 ti.WhereClause = "number-licenses=0" 203 ti.ResultExpectedLineCount = 3 // title + 1 data + EOF LF 204 ti.ResultLineContainsValuesAtLineNum = 1 205 ti.ResultLineContainsValues = []string{"NoLicense"} 206 innerTestComponentList(t, ti, COMPONENT_TEST_DEFAULT_FLAGS) 207 } 208 209 func TestComponentListCdx16ValidBom(t *testing.T) { 210 ti := NewComponentTestInfoBasic(TEST_CDX_SPEC_1_6_VALID_BOM, FORMAT_CSV, nil) 211 innerTestComponentList(t, ti, COMPONENT_TEST_DEFAULT_FLAGS) 212 } 213 214 func TestComponentListCdx16ValidComponentIds(t *testing.T) { 215 ti := NewComponentTestInfoBasic(TEST_CDX_SPEC_1_6_VALID_COMPONENT_IDS, FORMAT_CSV, nil) 216 innerTestComponentList(t, ti, COMPONENT_TEST_DEFAULT_FLAGS) 217 } 218 219 func TestComponentListCdx16ValidComponentSwid(t *testing.T) { 220 ti := NewComponentTestInfoBasic(TEST_CDX_SPEC_1_6_VALID_SWID, FORMAT_CSV, nil) 221 innerTestComponentList(t, ti, COMPONENT_TEST_DEFAULT_FLAGS) 222 } 223 224 func TestComponentListCdx16ValidComponentTypes(t *testing.T) { 225 ti := NewComponentTestInfoBasic(TEST_CDX_SPEC_1_6_VALID_COMPONENT_TYPES, FORMAT_CSV, nil) 226 innerTestComponentList(t, ti, COMPONENT_TEST_DEFAULT_FLAGS) 227 }