Repository: datreeio/datree
Pull request #133 (2021-08-11 08:12:11)

staging


Patch:
diff --git a/README.md b/README.md
index a4d49a3..86dbcb8 100644
--- a/README.md
+++ b/README.md
@@ -16,7 +16,7 @@ The CLI integration provides a policy enforcement solution for Kubernetes to run
 ## Quick start in two steps
 #### 1. Install the latest release on your CLI  
 **Linux & MacOS:** `curl https://get.datree.io | /bin/bash`  
-**Windows:** `not supported yet :(`  
+**Windows:** `iwr -useb https://get.datree.io/windows_install.ps1 | iex`  
 
 #### 2. Pass datree a Kuberntes manifest file to scan
 `datree test <k8s-manifest-file>`  
diff --git a/bl/evaluation/printer.go b/bl/evaluation/printer.go
index 425d6e7..8aec229 100644
--- a/bl/evaluation/printer.go
+++ b/bl/evaluation/printer.go
@@ -83,23 +83,29 @@ func textOutput(results *EvaluationResults, invalidYamlFiles []*validation.Inval
 	return nil
 }
 
-func parseToPrinterWarnings(results *EvaluationResults, invalidYamlFiles []*validation.InvalidYamlFile, invalidK8sFiles []*validation.InvalidK8sFile, pwd string, k8sVersion string) ([]printer.Warning, error) {
-	var warnings = []printer.Warning{}
+func parseInvalidYamlFilesToWarnings(invalidYamlFiles []*validation.InvalidYamlFile) []printer.Warning {
+	var warnings []printer.Warning
 
 	for _, invalidFile := range invalidYamlFiles {
 		warnings = append(warnings, printer.Warning{
-			Title:   fmt.Sprintf(">>  File: %s\n", invalidFile.Path),
-			Details: []printer.WarningInfo{},
+			Title:       fmt.Sprintf(">>  File: %s\n", invalidFile.Path),
+			FailedRules: []printer.FailedRule{},
 			InvalidYamlInfo: printer.InvalidYamlInfo{
 				ValidationErrors: invalidFile.ValidationErrors,
 			},
 		})
 	}
 
+	return warnings
+}
+
+func parseInvalidK8sFilesToWarnings(invalidK8sFiles []*validation.InvalidK8sFile, k8sVersion string) []printer.Warning {
+	var warnings []printer.Warning
+
 	for _, invalidFile := range invalidK8sFiles {
 		warnings = append(warnings, printer.Warning{
-			Title:   fmt.Sprintf(">>  File: %s\n", invalidFile.Path),
-			Details: []printer.WarningInfo{},
+			Title:       fmt.Sprintf(">>  File: %s\n", invalidFile.Path),
+			FailedRules: []printer.FailedRule{},
 			InvalidK8sInfo: printer.InvalidK8sInfo{
 				ValidationErrors: invalidFile.ValidationErrors,
 				K8sVersion:       k8sVersion,
@@ -107,17 +113,27 @@ func parseToPrinterWarnings(results *EvaluationResults, invalidYamlFiles []*vali
 		})
 	}
 
+	return warnings
+}
+
+func parseToPrinterWarnings(results *EvaluationResults, invalidYamlFiles []*validation.InvalidYamlFile, invalidK8sFiles []*validation.InvalidK8sFile, pwd string, k8sVersion string) ([]printer.Warning, error) {
+	var warnings = []printer.Warning{}
+
+	warnings = append(warnings, parseInvalidYamlFilesToWarnings(invalidYamlFiles)...)
+
+	warnings = append(warnings, parseInvalidK8sFilesToWarnings(invalidK8sFiles, k8sVersion)...)
+
 	if results != nil {
 
-		filesKeys := []string{}
+		filenames := []string{}
 		for key := range results.FileNameRuleMapper {
-			filesKeys = append(filesKeys, key)
+			filenames = append(filenames, key)
 		}
-		sort.Strings(filesKeys)
+		sort.Strings(filenames)
 
-		for _, filename := range filesKeys {
+		for _, filename := range filenames {
 			rules := results.FileNameRuleMapper[filename]
-			var warningDetails = []printer.WarningInfo{}
+			var failedRules = []printer.FailedRule{}
 
 			rulesIds := []int{}
 			for ruleId := range rules {
@@ -127,27 +143,27 @@ func parseToPrinterWarnings(results *EvaluationResults, invalidYamlFiles []*vali
 
 			for _, ruleId := range rulesIds {
 				rule := rules[ruleId]
-				details := printer.WarningInfo{
-					Caption:            rule.Name,
+				failedRule := printer.FailedRule{
+					Name:               rule.Name,
 					Occurrences:        rule.GetCount(),
 					Suggestion:         rule.FailSuggestion,
 					OccurrencesDetails: []printer.OccurrenceDetails{},
 				}
 				for _, occurrenceDetails := range rule.OccurrencesDetails {
-					details.OccurrencesDetails = append(
-						details.OccurrencesDetails,
+					failedRule.OccurrencesDetails = append(
+						failedRule.OccurrencesDetails,
 						printer.OccurrenceDetails{MetadataName: occurrenceDetails.MetadataName, Kind: occurrenceDetails.Kind},
 					)
 				}
 
-				warningDetails = append(warningDetails, details)
+				failedRules = append(failedRules, failedRule)
 			}
 
 			relativePath, _ := filepath.Rel(pwd, filename)
 
 			warnings = append(warnings, printer.Warning{
 				Title:           fmt.Sprintf(">>  File: %s\n", relativePath),
-				Details:         warningDetails,
+				FailedRules:     failedRules,
 				InvalidYamlInfo: printer.InvalidYamlInfo{},
 				InvalidK8sInfo:  printer.InvalidK8sInfo{},
 			})
diff --git a/install.sh b/install.sh
index 7f8d4ff..2f0d356 100755
--- a/install.sh
+++ b/install.sh
@@ -40,4 +40,6 @@ echo -e "\033[35m Usage: $ datree test ~/.datree/k8s-demo.yaml"
 
 echo -e " Using Helm? => https://hub.datree.io/helm-plugin"
 
+tput init
+
 echo
diff --git a/pkg/printer/printer.go b/pkg/printer/printer.go
index 2ef7ae9..aa3e4f2 100644
--- a/pkg/printer/printer.go
+++ b/pkg/printer/printer.go
@@ -2,25 +2,28 @@ package printer
 
 import (
 	"fmt"
+	"io"
 	"os"
 
 	"github.com/fatih/color"
 	"github.com/olekukonko/tablewriter"
 )
 
+var out io.Writer = os.Stdout
+
 type Printer struct {
-	theme *theme
+	Theme *Theme
 }
 
 func CreateNewPrinter() *Printer {
-	theme := createTheme()
+	theme := createDefaultTheme()
 	return &Printer{
-		theme: theme,
+		Theme: theme,
 	}
 }
 
-type WarningInfo struct {
-	Caption            string
+type FailedRule struct {
+	Name               string
 	Occurrences        int
 	Suggestion         string
 	OccurrencesDetails []OccurrenceDetails
@@ -40,72 +43,84 @@ type InvalidK8sInfo struct {
 }
 type Warning struct {
 	Title           string
-	Details         []WarningInfo
+	FailedRules     []FailedRule
 	InvalidYamlInfo InvalidYamlInfo
 	InvalidK8sInfo  InvalidK8sInfo
 }
 
+func (p *Printer) SetTheme(theme *Theme) {
+	p.Theme = theme
+}
+
+func (p *Printer) printYamlValidationWarning(warning Warning) {
+	p.printInColor("[X] YAML validation\n", p.Theme.Colors.White)
+	fmt.Fprintln(out)
+	for _, validationError := range warning.InvalidYamlInfo.ValidationErrors {
+		validationError := p.Theme.Colors.RedBold.Sprint(validationError.Error())
+		fmt.Fprintf(out, "%v %v\n", p.Theme.Emoji.Error, validationError)
+	}
+	fmt.Fprintln(out)
+
+	p.printInColor("[?] Kubernetes schema validation didn't run for this file\n", p.Theme.Colors.White)
+	p.printSkippedPolicyCheck()
+	fmt.Fprintln(out)
+}
+
+func (p *Printer) printK8sValidationWarning(warning Warning) {
+	p.printPassedYamlValidation()
+	p.printInColor("[X] Kubernetes schema validation\n", p.Theme.Colors.White)
+	fmt.Fprintln(out)
+
+	for _, validationError := range warning.InvalidK8sInfo.ValidationErrors {
+		validationError := p.Theme.Colors.RedBold.Sprint(validationError.Error())
+		fmt.Fprintf(out, "%v %v\n", p.Theme.Emoji.Error, validationError)
+	}
+	fmt.Fprintln(out)
+	p.printSkippedPolicyCheck()
+	fmt.Fprintln(out)
+}
+
 func (p *Printer) PrintWarnings(warnings []Warning) {
 	for _, warning := range warnings {
-		p.printInColor(warning.Title, p.theme.Colors.Yellow)
-		fmt.Println()
+		p.printInColor(warning.Title, p.Theme.Colors.Yellow)
+		fmt.Fprintln(out)
 
 		if len(warning.InvalidYamlInfo.ValidationErrors) > 0 {
-			p.printInColor("[X] YAML validation\n", p.theme.Colors.White)
-			fmt.Println()
-			for _, validationError := range warning.InvalidYamlInfo.ValidationErrors {
-				validationError := p.theme.Colors.Red.Sprint(validationError.Error())
-				fmt.Printf("%v %v\n", p.theme.Emoji.Error, validationError)
-			}
-			fmt.Println()
-
-			p.printInColor("[?] Kubernetes schema validation didn’t run for this file\n", p.theme.Colors.White)
-			p.printSkippedPolicyCheck()
-			fmt.Println()
+			p.printYamlValidationWarning(warning)
 		} else if len(warning.InvalidK8sInfo.ValidationErrors) > 0 {
-			p.printPassedYamlValidation()
-			p.printInColor("[X] Kubernetes schema validation\n", p.theme.Colors.White)
-			fmt.Println()
-
-			for _, validationError := range warning.InvalidK8sInfo.ValidationErrors {
-				validationError := p.theme.Colors.Red.Sprint(validationError.Error())
-				fmt.Printf("%v %v\n", p.theme.Emoji.Error, validationError)
-			}
-			fmt.Println()
-			p.printSkippedPolicyCheck()
-			fmt.Println()
+			p.printK8sValidationWarning(warning)
 		} else {
 			p.printPassedYamlValidation()
-			p.printInColor("[V] Kubernetes schema validation\n", p.theme.Colors.Green)
+			p.printInColor("[V] Kubernetes schema validation\n", p.Theme.Colors.Green)
 
-			fmt.Println()
-			p.printInColor("[X] Policy check\n", p.theme.Colors.White)
-			fmt.Println()
+			fmt.Fprintln(out)
+			p.printInColor("[X] Policy check\n", p.Theme.Colors.White)
+			fmt.Fprintln(out)
 
-			for _, details := range warning.Details {
+			for _, failedRule := range warning.FailedRules {
 				var occurrencesPostfix string
-				if details.Occurrences > 1 {
+				if failedRule.Occurrences > 1 {
 					occurrencesPostfix = "s"
 				} else {
 					occurrencesPostfix = ""
 				}
-				formattedOccurrences := fmt.Sprintf(" [%d occurrence%v]", details.Occurrences, occurrencesPostfix)
-				occurrences := p.theme.Colors.White.Sprintf(formattedOccurrences)
+				formattedOccurrences := fmt.Sprintf(" [%d occurrence%v]", failedRule.Occurrences, occurrencesPostfix)
+				occurrences := p.Theme.Colors.White.Sprintf(formattedOccurrences)
 
-				caption := p.theme.Colors.Red.Sprint(details.Caption)
+				ruleName := p.Theme.Colors.RedBold.Sprint(failedRule.Name)
 
-				fmt.Printf("%v %v %v\n", p.theme.Emoji.Error, caption, occurrences)
-				for _, occurrenceDetails := range details.OccurrencesDetails {
-					fmt.Printf("    — metadata.name: %v (kind: %v)\n", p.getStringOrNotAvailable(occurrenceDetails.MetadataName), p.getStringOrNotAvailable(occurrenceDetails.Kind))
+				fmt.Fprintf(out, "%v %v %v\n", p.Theme.Emoji.Error, ruleName, occurrences)
+				for _, occurrenceDetails := range failedRule.OccurrencesDetails {
+					fmt.Fprintf(out, "    — metadata.name: %v (kind: %v)\n", p.getStringOrNotAvailable(occurrenceDetails.MetadataName), p.getStringOrNotAvailable(occurrenceDetails.Kind))
 				}
-				fmt.Printf("%v %v\n", p.theme.Emoji.Suggestion, details.Suggestion)
+				fmt.Fprintf(out, "%v %v\n", p.Theme.Emoji.Suggestion, failedRule.Suggestion)
 
-				fmt.Println()
+				fmt.Fprintln(out)
 			}
 		}
 	}
 
-	fmt.Println()
+	fmt.Fprintln(out)
 }
 
 type SummaryItem struct {
@@ -130,15 +145,15 @@ type EvaluationSummary struct {
 }
 
 func (p *Printer) PrintEvaluationSummary(summary EvaluationSummary, k8sVersion string) {
-	p.printInColor("(Summary)\n", p.theme.Colors.White)
-	fmt.Println()
+	p.printInColor("(Summary)\n", p.Theme.Colors.White)
+	fmt.Fprintln(out)
 
-	fmt.Printf("- Passing YAML validation: %v/%v\n", summary.PassedYamlValidationCount, summary.FilesCount)
-	fmt.Println()
-	fmt.Printf("- Passing Kubernetes (%s) schema validation: %v/%v\n", k8sVersion, summary.PassedK8sValidationCount, summary.FilesCount)
-	fmt.Println()
-	fmt.Printf("- Passing policy check: %v/%v\n", summary.PassedPolicyCheckCount, summary.FilesCount)
-	fmt.Println()
+	fmt.Fprintf(out, "- Passing YAML validation: %v/%v\n", summary.PassedYamlValidationCount, summary.FilesCount)
+	fmt.Fprintln(out)
+	fmt.Fprintf(out, "- Passing Kubernetes (%s) schema validation: %v/%v\n", k8sVersion, summary.PassedK8sValidationCount, summary.FilesCount)
+	fmt.Fprintln(out)
+	fmt.Fprintf(out, "- Passing policy check: %v/%v\n", summary.PassedPolicyCheckCount, summary.FilesCount)
+	fmt.Fprintln(out)
 }
 
 func (p *Printer) PrintSummaryTable(summary Summary) {
@@ -157,11 +172,11 @@ func (p *Printer) PrintSummaryTable(summary Summary) {
 	}
 
 	errorRow := []string{summary.ErrorRow.LeftCol, summary.ErrorRow.RightCol}
-	summaryTable.Rich(errorRow, []tablewriter.Colors{{tablewriter.FgHiRedColor}, {tablewriter.FgHiRedColor}})
+	summaryTable.Rich(errorRow, []tablewriter.Colors{{int(p.Theme.ColorsAttributes.Red)}, {int(p.Theme.ColorsAttributes.Red)}})
 	rowIndex++
 
 	successRow := []string{summary.SuccessRow.LeftCol, summary.SuccessRow.RightCol}
-	summaryTable.Rich(successRow, []tablewriter.Colors{{tablewriter.Normal, tablewriter.FgGreenColor}, {tablewriter.Normal, tablewriter.FgGreenColor}})
+	summaryTable.Rich(successRow, []tablewriter.Colors{{int(p.Theme.ColorsAttributes.Green)}, {int(p.Theme.ColorsAttributes.Green)}})
 	rowIndex++
 
 	for plainRowsIndex < len(summary.PlainRows) && summary.PlainRows[plainRowsIndex].RowIndex >= rowIndex {
@@ -173,22 +188,22 @@ func (p *Printer) PrintSummaryTable(summary Summary) {
 }
 
 func (p *Printer) printInColor(title string, color *color.Color) {
-	colorPrintFn := color.PrintfFunc()
-	colorPrintFn(title)
+	colorPrintFn := color.FprintfFunc()
+	colorPrintFn(out, title)
 }
 
 func (p *Printer) createNewColor(clr string) *color.Color {
 	switch clr {
 	case "error":
-		return p.theme.Colors.Error
+		return p.Theme.Colors.Error
 	case "red":
-		return p.theme.Colors.Red
+		return p.Theme.Colors.RedBold
 	case "yellow":
-		return p.theme.Colors.Yellow
+		return p.Theme.Colors.Yellow
 	case "green":
-		return p.theme.Colors.Green
+		return p.Theme.Colors.Green
 	default:
-		return p.theme.Colors.White
+		return p.Theme.Colors.White
 	}
 }
 
@@ -198,11 +213,11 @@ func (p *Printer) PrintMessage(messageText string, messageColor string) {
 }
 
 func (p *Printer) printPassedYamlValidation() {
-	p.printInColor("[V] YAML validation\n", p.theme.Colors.Green)
+	p.printInColor("[V] YAML validation\n", p.Theme.Colors.Green)
 }
 
 func (p *Printer) printSkippedPolicyCheck() {
-	p.printInColor("[?] Policy check didn’t run for this file\n", p.theme.Colors.White)
+	p.printInColor("[?] Policy check didn't run for this file\n", p.Theme.Colors.White)
 }
 
 func (p *Printer) getStringOrNotAvailable(str string) string {
diff --git a/pkg/printer/theme.go b/pkg/printer/theme.go
index 5977e2e..46d2c01 100644
--- a/pkg/printer/theme.go
+++ b/pkg/printer/theme.go
@@ -7,13 +7,17 @@ import (
 	"github.com/kyokomi/emoji"
 )
 
-type theme struct {
+type Theme struct {
 	Colors struct {
-		Green  *color.Color
-		Yellow *color.Color
-		Red    *color.Color
-		White  *color.Color
-		Error  *color.Color
+		Green   *color.Color
+		Yellow  *color.Color
+		RedBold *color.Color
+		White   *color.Color
+		Error   *color.Color
+	}
+	ColorsAttributes struct {
+		Green color.Attribute
+		Red   color.Attribute
 	}
 	Spacing struct {
 		Default string
@@ -24,20 +28,27 @@ type theme struct {
 	}
 }
 
-func createTheme() *theme {
-	return &theme{
+func createDefaultTheme() *Theme {
+	return &Theme{
 		Colors: struct {
-			Green  *color.Color
-			Yellow *color.Color
-			Red    *color.Color
-			White  *color.Color
-			Error  *color.Color
+			Green   *color.Color
+			Yellow  *color.Color
+			RedBold *color.Color
+			White   *color.Color
+			Error   *color.Color
+		}{
+			Green:   color.New(color.FgGreen),
+			Yellow:  color.New(color.FgYellow),
+			RedBold: color.New(color.FgHiRed, color.Bold),
+			Error:   color.New(color.FgHiRed),
+			White:   color.New(color.FgHiWhite),
+		},
+		ColorsAttributes: struct {
+			Green color.Attribute
+			Red   color.Attribute
 		}{
-			Green:  color.New(color.FgGreen),
-			Yellow: color.New(color.FgYellow),
-			Red:    color.New(color.FgHiRed, color.Bold),
-			Error:  color.New(color.FgHiRed),
-			White:  color.New(color.FgHiWhite),
+			Green: color.FgGreen,
+			Red:   color.FgHiRed,
 		},
 		Spacing: struct{ Default string }{
 			Default: strings.Join([]string{" "}, ""),
@@ -51,3 +62,37 @@ func createTheme() *theme {
 		},
 	}
 }
+func CreateSimpleTheme() *Theme {
+	return &Theme{
+		Colors: struct {
+			Green   *color.Color
+			Yellow  *color.Color
+			RedBold *color.Color
+			White   *color.Color
+			Error   *color.Color
+		}{
+			Green:   color.New(),
+			Yellow:  color.New(),
+			RedBold: color.New(),
+			Error:   color.New(),
+			White:   color.New(),
+		},
+		ColorsAttributes: struct {
+			Green color.Attribute
+			Red   color.Attribute
+		}{
+			Green: color.Reset,
+			Red:   color.Reset,
+		},
+		Spacing: struct{ Default string }{
+			Default: strings.Join([]string{" "}, ""),
+		},
+		Emoji: struct {
+			Error      string
+			Suggestion string
+		}{
+			Error:      "[X] ",
+			Suggestion: "[*] ",
+		},
+	}
+}


Test patch:
diff --git a/cmd/test/main.go b/cmd/test/main.go
index 8ab7b4e..d725608 100644
--- a/cmd/test/main.go
+++ b/cmd/test/main.go
@@ -48,6 +48,7 @@ type EvaluationPrinter interface {
 	PrintSummaryTable(summary printer.Summary)
 	PrintMessage(messageText string, messageColor string)
 	PrintEvaluationSummary(evaluationSummary printer.EvaluationSummary, k8sVersion string)
+	SetTheme(theme *printer.Theme)
 }
 
 type Reader interface {
@@ -150,6 +151,9 @@ func test(ctx *TestCommandContext, paths []string, flags TestCommandFlags) error
 		paths = []string{tempFile.Name()}
 	}
 
+	if flags.Output == "simple" {
+		ctx.Printer.SetTheme(printer.CreateSimpleTheme())
+	}
 	isInteractiveMode := (flags.Output != "json") && (flags.Output != "yaml")
 
 	if isInteractiveMode == true {
@@ -175,7 +179,11 @@ func test(ctx *TestCommandContext, paths []string, flags TestCommandFlags) error
 
 	var _spinner *spinner.Spinner
 	if isInteractiveMode == true {
-		_spinner = createSpinner(" Loading...", "cyan")
+		color := "cyan"
+		if flags.Output == "simple" {
+			color = ""
+		}
+		_spinner = createSpinner(" Loading...", color)
 		_spinner.Start()
 	}
 
diff --git a/cmd/test/main_test.go b/cmd/test/main_test.go
index 858477c..c016dd2 100644
--- a/cmd/test/main_test.go
+++ b/cmd/test/main_test.go
@@ -86,12 +86,16 @@ func (p *PrinterMock) PrintSummaryTable(summary printer.Summary) {
 	p.Called(summary)
 }
 
+func (p *PrinterMock) PrintEvaluationSummary(evaluationSummary printer.EvaluationSummary, k8sVersion string) {
+	p.Called(evaluationSummary)
+}
+
 func (p *PrinterMock) PrintMessage(messageText string, messageColor string) {
 	p.Called(messageText, messageColor)
 }
 
-func (p *PrinterMock) PrintEvaluationSummary(evaluationSummary printer.EvaluationSummary, k8sVersion string) {
-	p.Called(evaluationSummary)
+func (p *PrinterMock) SetTheme(theme *printer.Theme) {
+	p.Called(theme)
 }
 
 type ReaderMock struct {
@@ -145,8 +149,8 @@ func TestTestCommand(t *testing.T) {
 	printerMock := &PrinterMock{}
 	printerMock.On("PrintWarnings", mock.Anything)
 	printerMock.On("PrintSummaryTable", mock.Anything)
-	printerMock.On("PrintMessage", mock.Anything, mock.Anything)
 	printerMock.On("PrintEvaluationSummary", mock.Anything, mock.Anything)
+	printerMock.On("PrintMessage", mock.Anything, mock.Anything)
 
 	readerMock := &ReaderMock{}
 	readerMock.On("FilterFiles", mock.Anything).Return([]string{"file/path"}, nil)
diff --git a/pkg/printer/printer_test.go b/pkg/printer/printer_test.go
new file mode 100644
index 0000000..c5e37e3
--- /dev/null
+++ b/pkg/printer/printer_test.go
@@ -0,0 +1,151 @@
+package printer
+
+import (
+	"bytes"
+	"fmt"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestPrintWarnings(t *testing.T) {
+	printer := CreateNewPrinter()
+
+	warnings := []Warning{
+		Warning{
+			Title: "Failed with Occurrences",
+			FailedRules: []FailedRule{
+				FailedRule{
+					Name:               "Caption",
+					Occurrences:        1,
+					Suggestion:         "Suggestion",
+					OccurrencesDetails: []OccurrenceDetails{OccurrenceDetails{MetadataName: "yishay", Kind: "Pod"}},
+				},
+			},
+		},
+		Warning{
+			Title:           "Failed with yaml validation",
+			FailedRules:     []FailedRule{},
+			InvalidYamlInfo: InvalidYamlInfo{ValidationErrors: []error{fmt.Errorf("yaml validation error")}},
+		},
+		Warning{
+			Title:          "Failed with k8s validation",
+			FailedRules:    []FailedRule{},
+			InvalidK8sInfo: InvalidK8sInfo{ValidationErrors: []error{fmt.Errorf("K8S validation error")}, K8sVersion: "1.18.0"},
+		},
+	}
+
+	t.Run("Test PrintWarnings", func(t *testing.T) {
+
+		out = new(bytes.Buffer)
+
+		printer.PrintWarnings(warnings)
+
+		got := out.(*bytes.Buffer).Bytes()
+
+		expected := []byte(
+			`Failed with Occurrences
+[V] YAML validation
+[V] Kubernetes schema validation
+
+[X] Policy check
+
+❌  Caption  [1 occurrence]
+    — metadata.name: yishay (kind: Pod)
+💡  Suggestion
+
+Failed with yaml validation
+[X] YAML validation
+
+❌  yaml validation error
+
+[?] Kubernetes schema validation didn't run for this file
+[?] Policy check didn't run for this file
+
+Failed with k8s validation
+[V] YAML validation
+[X] Kubernetes schema validation
+
+❌  K8S validation error
+
+[?] Policy check didn't run for this file
+
+
+`)
+		assert.Equal(t, string(expected), string(got))
+	})
+
+	t.Run("Test PrintWarnings simple output", func(t *testing.T) {
+
+		out = new(bytes.Buffer)
+
+		printer.SetTheme(CreateSimpleTheme())
+
+		printer.PrintWarnings(warnings)
+
+		got := out.(*bytes.Buffer).Bytes()
+
+		expected := []byte(
+			`Failed with Occurrences
+[V] YAML validation
+[V] Kubernetes schema validation
+
+[X] Policy check
+
+[X]  Caption  [1 occurrence]
+    — metadata.name: yishay (kind: Pod)
+[*]  Suggestion
+
+Failed with yaml validation
+[X] YAML validation
+
+[X]  yaml validation error
+
+[?] Kubernetes schema validation didn't run for this file
+[?] Policy check didn't run for this file
+
+Failed with k8s validation
+[V] YAML validation
+[X] Kubernetes schema validation
+
+[X]  K8S validation error
+
+[?] Policy check didn't run for this file
+
+
+`)
+		assert.Equal(t, string(expected), string(got))
+	})
+}
+
+func TestPrintEvaluationSummary(t *testing.T) {
+	t.Run("Test PrintEvaluationSummary", func(t *testing.T) {
+		out = new(bytes.Buffer)
+		printer := CreateNewPrinter()
+		summary := EvaluationSummary{
+			ConfigsCount:              6,
+			RulesCount:                21,
+			FilesCount:                5,
+			PassedYamlValidationCount: 4,
+			PassedK8sValidationCount:  3,
+			PassedPolicyCheckCount:    2,
+		}
+		k8sVersion := "1.2.3"
+
+		printer.PrintEvaluationSummary(summary, k8sVersion)
+		expected := []byte(`(Summary)
+
+- Passing YAML validation: 4/5
+
+- Passing Kubernetes (1.2.3) schema validation: 3/5
+
+- Passing policy check: 2/5
+
+`)
+
+		got := out.(*bytes.Buffer).Bytes()
+
+		assert.Equal(t, string(expected), string(got))
+
+	})
+}