Skip to content

Commit a8d1d3c

Browse files
committed
test/added unit tests for PrintProjects() and ListProjectCommand()
Signed-off-by: Rayyan Khan <rayyanrehman101@gmail.com>
1 parent 3254929 commit a8d1d3c

File tree

1 file changed

+224
-3
lines changed

1 file changed

+224
-3
lines changed

cmd/harbor/root/project/list_test.go

Lines changed: 224 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,50 @@
1515
package project
1616

1717
import (
18+
"bytes"
19+
"encoding/json"
1820
"fmt"
21+
"io"
22+
"os"
1923
"reflect"
2024
"runtime"
25+
"strings"
2126
"testing"
2227

2328
"github.com/goharbor/go-client/pkg/sdk/v2.0/client/project"
2429
"github.com/goharbor/go-client/pkg/sdk/v2.0/models"
2530
"github.com/goharbor/harbor-cli/pkg/api"
31+
log "github.com/sirupsen/logrus"
32+
"github.com/spf13/viper"
2633
"github.com/stretchr/testify/assert"
34+
"go.yaml.in/yaml/v4"
2735
)
2836

29-
// api.ListProject, api.ListAllProjects
30-
// -> take care of public and private
31-
// -> project store and return projects according to pagination similar to user pagination,
37+
func captureOutput(f func() error) (string, error) {
38+
origStdout := os.Stdout
39+
defer func() { os.Stdout = origStdout }()
40+
r, w, err := os.Pipe()
41+
if err != nil {
42+
return "", err
43+
}
44+
defer func() {
45+
_ = w.Close()
46+
_ = r.Close()
47+
}()
48+
os.Stdout = w
49+
if err := f(); err != nil {
50+
return "", err
51+
}
52+
if err := w.Close(); err != nil {
53+
return "", err
54+
}
55+
var buf bytes.Buffer
56+
if _, err := io.Copy(&buf, r); err != nil {
57+
return "", err
58+
}
59+
return buf.String(), nil
60+
}
61+
3262
type MockProjectLister struct {
3363
projectsCnt int
3464
projects []*models.Project
@@ -385,3 +415,194 @@ func TestFetchProjects(t *testing.T) {
385415
})
386416
}
387417
}
418+
func TestPrintProjects(t *testing.T) {
419+
var logBuf bytes.Buffer
420+
log.SetOutput(&logBuf)
421+
defer log.SetOutput(os.Stderr)
422+
423+
testProjects := func() []*models.Project {
424+
return []*models.Project{
425+
{
426+
ProjectID: 1,
427+
Name: "testProject1",
428+
RegistryID: 0,
429+
RepoCount: 5,
430+
Metadata: &models.ProjectMetadata{
431+
Public: "true",
432+
},
433+
},
434+
{
435+
ProjectID: 2,
436+
Name: "testProject2",
437+
RegistryID: 10,
438+
RepoCount: 3,
439+
Metadata: &models.ProjectMetadata{
440+
Public: "false",
441+
},
442+
},
443+
{
444+
ProjectID: 3,
445+
Name: "testProject3",
446+
RegistryID: 0,
447+
RepoCount: 0,
448+
Metadata: &models.ProjectMetadata{
449+
Public: "false",
450+
},
451+
},
452+
}
453+
}
454+
tests := []struct {
455+
name string
456+
setup func() []*models.Project
457+
outputFormat string
458+
}{
459+
{
460+
name: "Number of projects not zero and output format is json",
461+
setup: func() []*models.Project {
462+
return testProjects()
463+
},
464+
outputFormat: "json",
465+
},
466+
{
467+
name: "Number of projects not zero and output format yaml",
468+
setup: func() []*models.Project {
469+
return testProjects()
470+
},
471+
outputFormat: "yaml",
472+
},
473+
{
474+
name: "Number of projects not zero and output format default",
475+
setup: func() []*models.Project {
476+
return testProjects()
477+
},
478+
outputFormat: "",
479+
},
480+
{
481+
name: "Number of projects is zero",
482+
setup: func() []*models.Project {
483+
return []*models.Project{}
484+
},
485+
outputFormat: "default",
486+
},
487+
}
488+
for _, tt := range tests {
489+
t.Run(tt.name, func(t *testing.T) {
490+
allProjects := tt.setup()
491+
492+
logBuf.Reset()
493+
494+
originalFormatFlag := viper.GetString("output-format")
495+
viper.Set("output-format", tt.outputFormat)
496+
defer viper.Set("output-format", originalFormatFlag)
497+
498+
output, err := captureOutput(func() error {
499+
return PrintProjects(allProjects)
500+
})
501+
if err != nil {
502+
t.Fatalf("PrintProjects() returned error: %v", err)
503+
}
504+
505+
switch {
506+
case len(allProjects) == 0:
507+
if !strings.Contains(logBuf.String(), "No projects found") {
508+
t.Errorf(`Expected logs to contain "No projects found" but got: %s`, logBuf.String())
509+
}
510+
case tt.outputFormat == "json":
511+
if len(output) == 0 {
512+
t.Fatal("Expected JSON output, but output was empty")
513+
}
514+
var decoded []*models.Project
515+
if err := json.Unmarshal([]byte(output), &decoded); err != nil {
516+
t.Fatalf("Output is not valid JSON: %v. Output:\n%s", err, output)
517+
}
518+
if len(decoded) != len(allProjects) {
519+
t.Errorf("Expected %d projects in JSON, got %d", len(allProjects), len(decoded))
520+
}
521+
if len(decoded) > 0 {
522+
if decoded[0].Name != allProjects[0].Name {
523+
t.Errorf("Expected name '%s', got '%s'", allProjects[0].Name, decoded[0].Name)
524+
}
525+
if decoded[0].ProjectID != allProjects[0].ProjectID {
526+
t.Errorf("Expected ProjectID %d, got %d", allProjects[0].ProjectID, decoded[0].ProjectID)
527+
}
528+
}
529+
case tt.outputFormat == "yaml":
530+
if len(output) == 0 {
531+
t.Fatal("Expected YAML output, but output was empty")
532+
}
533+
var decoded []*models.Project
534+
if err := yaml.Unmarshal([]byte(output), &decoded); err != nil {
535+
t.Fatalf("Output is not valid YAML: %v. Output:\n%s", err, output)
536+
}
537+
if len(decoded) != len(allProjects) {
538+
t.Errorf("Expected %d projects in YAML, got %d", len(allProjects), len(decoded))
539+
}
540+
if len(decoded) > 0 {
541+
if decoded[0].Name != allProjects[0].Name {
542+
t.Errorf("Expected name '%s', got '%s'", allProjects[0].Name, decoded[0].Name)
543+
}
544+
if decoded[0].ProjectID != allProjects[0].ProjectID {
545+
t.Errorf("Expected ProjectID %d, got %d", allProjects[0].ProjectID, decoded[0].ProjectID)
546+
}
547+
}
548+
default:
549+
if len(output) == 0 {
550+
t.Fatal("Expected TUI table output, but output was empty")
551+
}
552+
if !strings.Contains(output, "ID") || !strings.Contains(output, "Project Name") || !strings.Contains(output, "Access Level") {
553+
t.Error("Expected table output to contain headers 'ID', 'Project Name' and 'Access Level' among other headers")
554+
}
555+
if !strings.Contains(output, "testProject1") {
556+
t.Errorf("Expected table to contain project name 'testProject1'")
557+
}
558+
}
559+
})
560+
}
561+
}
562+
func TestListProjectCommand(t *testing.T) {
563+
cmd := ListProjectCommand()
564+
565+
assert.Equal(t, "list", cmd.Use, "Expected command use to be 'list'")
566+
assert.NotEmpty(t, cmd.Short, "Expected a short description for the command")
567+
assert.NotNil(t, cmd.Args, "Expected Args validator to be set")
568+
569+
flags := cmd.Flags()
570+
571+
nameFlag := flags.Lookup("name")
572+
assert.NotNil(t, nameFlag, "Expected 'name' flag to exist")
573+
assert.Equal(t, "", nameFlag.DefValue, "Expected 'name' flag default value to be empty string")
574+
575+
pageFlag := flags.Lookup("page")
576+
assert.NotNil(t, pageFlag, "Expected 'page' flag to exist")
577+
assert.Equal(t, "1", pageFlag.DefValue, "Expected 'page' flag default value to be 1")
578+
579+
pageSizeFlag := flags.Lookup("page-size")
580+
assert.NotNil(t, pageSizeFlag, "Expected 'page-size' flag to exist")
581+
assert.Equal(t, "0", pageSizeFlag.DefValue, "Expected 'page-size' flag default value to be 0")
582+
583+
privateFlag := flags.Lookup("private")
584+
assert.NotNil(t, privateFlag, "Expected 'private' flag to exist")
585+
assert.Equal(t, "false", privateFlag.DefValue, "Expected 'private' flag default value to be false")
586+
587+
publicFlag := flags.Lookup("public")
588+
assert.NotNil(t, publicFlag, "Expected 'public' flag to exist")
589+
assert.Equal(t, "false", publicFlag.DefValue, "Expected 'public' flag default value to be false")
590+
591+
sortFlag := flags.Lookup("sort")
592+
assert.NotNil(t, sortFlag, "Expected 'sort' flag to exist")
593+
assert.Equal(t, "", sortFlag.DefValue, "Expected 'sort' flag default value to be empty string")
594+
595+
fuzzyFlag := flags.Lookup("fuzzy")
596+
assert.NotNil(t, fuzzyFlag, "Expected 'fuzzy' flag to exist")
597+
assert.Equal(t, "[]", fuzzyFlag.DefValue, "Expected 'fuzzy' flag default value to be empty slice")
598+
599+
matchFlag := flags.Lookup("match")
600+
assert.NotNil(t, matchFlag, "Expected 'match' flag to exist")
601+
assert.Equal(t, "[]", matchFlag.DefValue, "Expected 'match' flag default value to be empty slice")
602+
603+
rangeFlag := flags.Lookup("range")
604+
assert.NotNil(t, rangeFlag, "Expected 'range' flag to exist")
605+
assert.Equal(t, "[]", rangeFlag.DefValue, "Expected 'range' flag default value to be empty slice")
606+
607+
assert.NotNil(t, cmd.RunE, "Expected RunE to be not nil")
608+
}

0 commit comments

Comments
 (0)