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