diff --git a/core/core/list.go b/core/core/list.go index d00a2376..9818e7a2 100644 --- a/core/core/list.go +++ b/core/core/list.go @@ -159,8 +159,21 @@ func generateControlRows(policies []string) [][]string { rows := [][]string{} for _, control := range policies { + idAndControlAndFrameworks := strings.Split(control, "|") - id, control, framework := idAndControlAndFrameworks[0], idAndControlAndFrameworks[1], idAndControlAndFrameworks[2] + + var id, control, framework string + + switch len(idAndControlAndFrameworks) { + case 0: + continue + case 1: + id = idAndControlAndFrameworks[0] + case 2: + id, control = idAndControlAndFrameworks[0], idAndControlAndFrameworks[1] + default: + id, control, framework = idAndControlAndFrameworks[0], idAndControlAndFrameworks[1], idAndControlAndFrameworks[2] + } docs := cautils.GetControlLink(id) diff --git a/core/core/list_test.go b/core/core/list_test.go index d309eb63..81ead3c3 100644 --- a/core/core/list_test.go +++ b/core/core/list_test.go @@ -201,6 +201,33 @@ func TestGenerateControlRowsWithAllFields(t *testing.T) { assert.Equal(t, want, got) } +// Handles policies with no '|' characters in the string +func TestGenerateControlRowsHandlesPoliciesWithEmptyStringOrNoPipesOrOnePipeMissing(t *testing.T) { + policies := []string{ + "", + "1", + "2|Control 2|Framework 2", + "3|Control 3|Framework 3|Extra 3", + "4||Framework 4", + "|", + "5|Control 5||Extra 5", + } + + expectedRows := [][]string{ + {"", "", "https://hub.armosec.io/docs/", ""}, + {"1", "", "https://hub.armosec.io/docs/1", ""}, + {"2", "Control 2", "https://hub.armosec.io/docs/2", "Framework\n2"}, + {"3", "Control 3", "https://hub.armosec.io/docs/3", "Framework\n3"}, + {"4", "", "https://hub.armosec.io/docs/4", "Framework\n4"}, + {"", "", "https://hub.armosec.io/docs/", ""}, + {"5", "Control 5", "https://hub.armosec.io/docs/5", ""}, + } + + rows := generateControlRows(policies) + + assert.Equal(t, expectedRows, rows) +} + // The function generates a table with the correct headers and rows based on the input policies. func TestGenerateTableWithCorrectHeadersAndRows(t *testing.T) { // Arrange @@ -240,6 +267,56 @@ func TestGenerateTableWithCorrectHeadersAndRows(t *testing.T) { assert.Equal(t, want, string(got)) } +func TestGenerateTableWithMalformedPoliciesAndPrettyPrintHeadersAndRows(t *testing.T) { + // Arrange + ctx := context.Background() + policies := []string{ + "", + "1", + "2|Control 2|Framework 2", + "3|Control 3|Framework 3|Extra 3", + "4||Framework 4", + "|", + "5|Control 5||Extra 5", + } + + // Redirect stdout to a buffer + rescueStdout := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + + prettyPrintControls(ctx, policies) + + w.Close() + got, _ := io.ReadAll(r) + + os.Stdout = rescueStdout + + want := `┌────────────┬──────────────┬───────────────────────────────┬────────────┐ +│ Control ID │ Control name │ Docs │ Frameworks │ +├────────────┼──────────────┼───────────────────────────────┼────────────┤ +│ │ │ https://hub.armosec.io/docs/ │ │ +├────────────┼──────────────┼───────────────────────────────┼────────────┤ +│ 1 │ │ https://hub.armosec.io/docs/1 │ │ +├────────────┼──────────────┼───────────────────────────────┼────────────┤ +│ 2 │ Control 2 │ https://hub.armosec.io/docs/2 │ Framework │ +│ │ │ │ 2 │ +├────────────┼──────────────┼───────────────────────────────┼────────────┤ +│ 3 │ Control 3 │ https://hub.armosec.io/docs/3 │ Framework │ +│ │ │ │ 3 │ +├────────────┼──────────────┼───────────────────────────────┼────────────┤ +│ 4 │ │ https://hub.armosec.io/docs/4 │ Framework │ +│ │ │ │ 4 │ +├────────────┼──────────────┼───────────────────────────────┼────────────┤ +│ │ │ https://hub.armosec.io/docs/ │ │ +├────────────┼──────────────┼───────────────────────────────┼────────────┤ +│ 5 │ Control 5 │ https://hub.armosec.io/docs/5 │ │ +└────────────┴──────────────┴───────────────────────────────┴────────────┘ +` + + assert.Equal(t, want, string(got)) +} + // Returns a non-empty list of supported actions when 'ListSupportActions' is called. func TestListSupportActionsNotEmpty(t *testing.T) { actions := ListSupportActions()