github.com/anchore/syft@v1.38.2/test/cli/trait_assertions_test.go (about) 1 package cli 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "regexp" 8 "sort" 9 "strings" 10 "testing" 11 12 "github.com/acarl005/stripansi" 13 "github.com/stretchr/testify/assert" 14 "github.com/stretchr/testify/require" 15 16 "github.com/anchore/syft/syft/format/syftjson/model" 17 ) 18 19 type traitAssertion func(tb testing.TB, stdout, stderr string, rc int) 20 21 func assertFileOutput(tb testing.TB, path string, assertions ...traitAssertion) traitAssertion { 22 tb.Helper() 23 24 return func(tb testing.TB, _, stderr string, rc int) { 25 content, err := os.ReadFile(path) 26 require.NoError(tb, err) 27 contentStr := string(content) 28 29 for _, assertion := range assertions { 30 // treat the file content as stdout 31 assertion(tb, contentStr, stderr, rc) 32 } 33 } 34 } 35 36 func assertJsonReport(tb testing.TB, stdout, _ string, _ int) { 37 tb.Helper() 38 var data interface{} 39 40 if err := json.Unmarshal([]byte(stdout), &data); err != nil { 41 tb.Errorf("expected to find a JSON report, but was unmarshalable: %+v", err) 42 } 43 } 44 45 func assertTableReport(tb testing.TB, stdout, _ string, _ int) { 46 tb.Helper() 47 if !strings.Contains(stdout, "NAME") || !strings.Contains(stdout, "VERSION") || !strings.Contains(stdout, "TYPE") { 48 tb.Errorf("expected to find a table report, but did not") 49 } 50 } 51 52 //func assertScope(scope source.Scope) traitAssertion { 53 // return func(tb testing.TB, stdout, stderr string, rc int) { 54 // tb.Helper() 55 // // we can only verify source with the json report 56 // assertJsonReport(tb, stdout, stderr, rc) 57 // 58 // if !strings.Contains(stdout, fmt.Sprintf(`"scope": "%s"`, scope.String())) { 59 // tb.Errorf("JSON report did not indicate the %q scope", scope) 60 // } 61 // } 62 //} 63 64 func assertLoggingLevel(level string) traitAssertion { 65 // match examples: 66 // "[0000] INFO" 67 // "[0012] DEBUG" 68 logPattern := regexp.MustCompile(`(?m)^\[\d\d\d\d\]\s+` + strings.ToUpper(level)) 69 return func(tb testing.TB, _, stderr string, _ int) { 70 tb.Helper() 71 if !logPattern.MatchString(stripansi.Strip(stderr)) { 72 tb.Errorf("output did not indicate the %q logging level", level) 73 } 74 } 75 } 76 77 func assertNotInOutput(data string) traitAssertion { 78 return func(tb testing.TB, stdout, stderr string, _ int) { 79 tb.Helper() 80 if strings.Contains(stripansi.Strip(stderr), data) { 81 tb.Errorf("data=%q was found in stderr, but should not have been there", data) 82 } 83 if strings.Contains(stripansi.Strip(stdout), data) { 84 tb.Errorf("data=%q was found in stdout, but should not have been there", data) 85 } 86 } 87 } 88 89 func assertNoStderr(tb testing.TB, _, stderr string, _ int) { 90 tb.Helper() 91 if len(stderr) > 0 { 92 tb.Errorf("expected stderr to be empty, but wasn't") 93 if showOutput != nil && *showOutput { 94 tb.Errorf("STDERR:%s", stderr) 95 } 96 } 97 } 98 99 func assertInOutput(data string) traitAssertion { 100 return func(tb testing.TB, stdout, stderr string, _ int) { 101 tb.Helper() 102 stdout = stripansi.Strip(stdout) 103 stderr = stripansi.Strip(stderr) 104 if !strings.Contains(stdout, data) && !strings.Contains(stderr, data) { 105 tb.Errorf("data=%q was NOT found in any output, but should have been there", data) 106 if showOutput != nil && *showOutput { 107 tb.Errorf("STDOUT:%s\nSTDERR:%s", stdout, stderr) 108 } 109 } 110 } 111 } 112 113 func assertStdoutLengthGreaterThan(length uint) traitAssertion { 114 return func(tb testing.TB, stdout, _ string, _ int) { 115 tb.Helper() 116 if uint(len(stdout)) < length { 117 tb.Errorf("not enough output (expected at least %d, got %d)", length, len(stdout)) 118 } 119 } 120 } 121 122 func assertPackageCount(length uint) traitAssertion { 123 return func(tb testing.TB, stdout, _ string, _ int) { 124 tb.Helper() 125 type NameAndVersion struct { 126 Name string `json:"name"` 127 Version string `json:"version"` 128 Type string `json:"type"` 129 } 130 type partial struct { 131 Artifacts []NameAndVersion `json:"artifacts"` 132 } 133 var data partial 134 135 if err := json.Unmarshal([]byte(stdout), &data); err != nil { 136 tb.Errorf("expected to find a JSON report, but was unmarshalable: %+v", err) 137 } 138 139 if uint(len(data.Artifacts)) != length { 140 tb.Errorf("expected package count of %d, but found %d", length, len(data.Artifacts)) 141 debugArtifacts := make([]string, len(data.Artifacts)) 142 for i, a := range data.Artifacts { 143 debugArtifacts[i] = fmt.Sprintf("%s@%s (%s)", a.Name, a.Version, a.Type) 144 } 145 sort.Strings(debugArtifacts) 146 for i, a := range debugArtifacts { 147 tb.Errorf("package %d: %s", i+1, a) 148 } 149 150 } 151 } 152 } 153 154 func assertUnknownLicenseContent(required bool) traitAssertion { 155 return func(tb testing.TB, stdout, _ string, _ int) { 156 tb.Helper() 157 type NameAndLicense struct { 158 Name string `json:"name"` 159 Licenses []model.License `json:"Licenses"` 160 } 161 type partial struct { 162 Artifacts []NameAndLicense `json:"artifacts"` 163 } 164 165 var data partial 166 if err := json.Unmarshal([]byte(stdout), &data); err != nil { 167 tb.Errorf("expected to find a JSON report, but was unmarshalable: %+v", err) 168 } 169 170 for _, pkg := range data.Artifacts { 171 for _, lic := range pkg.Licenses { 172 if strings.Contains(lic.Value, "sha256") && required { 173 assert.NotZero(tb, len(lic.Contents)) 174 } else { 175 assert.Empty(tb, lic.Contents) 176 } 177 } 178 } 179 } 180 } 181 182 func assertFailingReturnCode(tb testing.TB, _, _ string, rc int) { 183 tb.Helper() 184 if rc == 0 { 185 tb.Errorf("expected a failure but got rc=%d", rc) 186 } 187 } 188 189 func assertSuccessfulReturnCode(tb testing.TB, _, _ string, rc int) { 190 tb.Helper() 191 if rc != 0 { 192 tb.Errorf("expected no failure but got rc=%d", rc) 193 } 194 } 195 196 func assertFileExists(file string) traitAssertion { 197 return func(tb testing.TB, _, _ string, _ int) { 198 tb.Helper() 199 if _, err := os.Stat(file); err != nil { 200 tb.Errorf("expected file to exist %s", file) 201 } 202 } 203 }