Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@

# .env files
.env

# Generated CSV files
*.csv
143 changes: 143 additions & 0 deletions examples/functional/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
package main

import (
"log"

qascsv "github.com/hypersequent/qasphere-csv"
)

func main() {
if err := generateFolderComments(); err != nil {
log.Fatal(err)
}
if err := generateEmptyFolders(); err != nil {
log.Fatal(err)
}
if err := generateEscaping(); err != nil {
log.Fatal(err)
}
}

func generateFolderComments() error {
q := qascsv.NewQASphereCSV()

if err := q.AddFolder(qascsv.Folder{
FolderPath: []string{"Commented Folder"},
Comment: "This folder has a comment but also contains test cases",
}); err != nil {
return err
}
if err := q.AddTestCase(qascsv.TestCase{
Title: "Test inside commented folder",
Folder: []string{"Commented Folder"},
Priority: qascsv.PriorityHigh,
}); err != nil {
return err
}

if err := q.AddFolder(qascsv.Folder{
FolderPath: []string{"Another Folder"},
Comment: "Standalone comment on a folder with no test cases",
}); err != nil {
return err
}

if err := q.AddFolder(qascsv.Folder{
FolderPath: []string{"Parent", "Child With Comment"},
Comment: "Nested folder comment",
}); err != nil {
return err
}
if err := q.AddTestCase(qascsv.TestCase{
Title: "Test in parent folder",
Folder: []string{"Parent"},
Priority: qascsv.PriorityMedium,
}); err != nil {
return err
}

if err := q.WriteCSVToFile("folder_comments.csv"); err != nil {
return err
}
log.Println("wrote folder_comments.csv")
return nil
}

func generateEmptyFolders() error {
q := qascsv.NewQASphereCSV()

if err := q.AddFolder(qascsv.Folder{
FolderPath: []string{"Empty Root Folder"},
}); err != nil {
return err
}
if err := q.AddFolder(qascsv.Folder{
FolderPath: []string{"Parent", "Empty Child"},
}); err != nil {
return err
}
if err := q.AddFolder(qascsv.Folder{
FolderPath: []string{"Parent", "Another Empty Child"},
}); err != nil {
return err
}
if err := q.AddTestCase(qascsv.TestCase{
Title: "Test in parent alongside empty children",
Folder: []string{"Parent"},
Priority: qascsv.PriorityLow,
}); err != nil {
return err
}

if err := q.AddFolder(qascsv.Folder{
FolderPath: []string{"Deep", "Nested", "Empty"},
}); err != nil {
return err
}

if err := q.WriteCSVToFile("empty_folders.csv"); err != nil {
return err
}
log.Println("wrote empty_folders.csv")
return nil
}

func generateEscaping() error {
q := qascsv.NewQASphereCSV()

if err := q.AddTestCase(qascsv.TestCase{
Title: "Test in folder with slash",
Folder: []string{"Features/Bugs", "Login"},
Priority: qascsv.PriorityHigh,
}); err != nil {
return err
}
if err := q.AddTestCase(qascsv.TestCase{
Title: "Test in folder with multiple slashes",
Folder: []string{"A/B/C", "D/E"},
Priority: qascsv.PriorityMedium,
}); err != nil {
return err
}

if err := q.AddFolder(qascsv.Folder{
FolderPath: []string{"Empty/Slash/Folder"},
Comment: "This empty folder name contains slashes",
}); err != nil {
return err
}

if err := q.AddTestCase(qascsv.TestCase{
Title: "Test in normal folder for comparison",
Folder: []string{"Normal Folder", "Subfolder"},
Priority: qascsv.PriorityLow,
}); err != nil {
return err
}

if err := q.WriteCSVToFile("escaping.csv"); err != nil {
return err
}
log.Println("wrote escaping.csv")
return nil
}
181 changes: 166 additions & 15 deletions qacsv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,11 @@ var successTestCases = []TestCase{
},
}

const successTestCasesCSV = `Folder,Type,Name,Legacy ID,Draft,Priority,Tags,Requirements,Links,Files,Preconditions,Parameter Values,Template Suffix Params,Step 1,Expected 1,Step 2,Expected 2
root,standalone,tc-with-minimal-fields,,false,high,,,,,,,,,,,
root,standalone,tc-with-partial-fields,,true,low,,[](http://req1),,"[{""fileName"":""file-1.csv"",""id"":""file-id"",""url"":""http://file1"",""mimeType"":""text/csv"",""size"":10},{""fileName"":""file-1.csv"",""id"":""file-id"",""url"":""http://file1"",""mimeType"":""text/csv"",""size"":10}]",,,,action-1,,,expected-2
root/child,standalone,tc-with-all-fields,legacy-id,false,high,"tag1,tag2",[req1](http://req1),"[link-1](http://link1),[link-2](http://link2)","[{""fileName"":""file-1.csv"",""id"":""file-id"",""url"":""http://file1"",""mimeType"":""text/csv"",""size"":10},{""fileName"":""file-1.csv"",""id"":""file-id"",""url"":""http://file1"",""mimeType"":""text/csv"",""size"":10}]",preconditions,,,action-1,expected-1,action-2,expected-2
root/child,standalone,"tc-with-special-chars.,<>/@$%""""''*&()[]{}+-[BACKTICK]!~;",legacy-id,false,high,"tag1.,<>/@$%""""''*&()[]{}+-[BACKTICK]!~;","[req.,<>/@$%""""''*&()[]{}+-[BACKTICK]!~;]()","[link-1.,<>/@$%""""''*&()[]{}+-[BACKTICK]!~;](http://link1)","[{""fileName"":""file-1.csv"",""id"":""file-id"",""url"":""http://file1"",""mimeType"":""text/csv"",""size"":10}]","preconditions.,<>/@$%""""''*&()[]{}+-[BACKTICK]!~;",,,"action.,<>/@$%""""''*&()[]{}+-[BACKTICK]!~;","expected.,<>/@$%""""''*&()[]{}+-[BACKTICK]!~;",,
const successTestCasesCSV = `Folder,Folder Comment,Type,Name,Legacy ID,Draft,Priority,Tags,Requirements,Links,Files,Preconditions,Parameter Values,Template Suffix Params,Step 1,Expected 1,Step 2,Expected 2
root/child,,standalone,tc-with-all-fields,legacy-id,false,high,"tag1,tag2",[req1](http://req1),"[link-1](http://link1),[link-2](http://link2)","[{""fileName"":""file-1.csv"",""id"":""file-id"",""url"":""http://file1"",""mimeType"":""text/csv"",""size"":10},{""fileName"":""file-1.csv"",""id"":""file-id"",""url"":""http://file1"",""mimeType"":""text/csv"",""size"":10}]",preconditions,,,action-1,expected-1,action-2,expected-2
root/child,,standalone,"tc-with-special-chars.,<>/@$%""""''*&()[]{}+-[BACKTICK]!~;",legacy-id,false,high,"tag1.,<>/@$%""""''*&()[]{}+-[BACKTICK]!~;","[req.,<>/@$%""""''*&()[]{}+-[BACKTICK]!~;]()","[link-1.,<>/@$%""""''*&()[]{}+-[BACKTICK]!~;](http://link1)","[{""fileName"":""file-1.csv"",""id"":""file-id"",""url"":""http://file1"",""mimeType"":""text/csv"",""size"":10}]","preconditions.,<>/@$%""""''*&()[]{}+-[BACKTICK]!~;",,,"action.,<>/@$%""""''*&()[]{}+-[BACKTICK]!~;","expected.,<>/@$%""""''*&()[]{}+-[BACKTICK]!~;",,
root,,standalone,tc-with-minimal-fields,,false,high,,,,,,,,,,,
root,,standalone,tc-with-partial-fields,,true,low,,[](http://req1),,"[{""fileName"":""file-1.csv"",""id"":""file-id"",""url"":""http://file1"",""mimeType"":""text/csv"",""size"":10},{""fileName"":""file-1.csv"",""id"":""file-id"",""url"":""http://file1"",""mimeType"":""text/csv"",""size"":10}]",,,,action-1,,,expected-2
`

var failureTestCases = []TestCase{
Expand All @@ -146,12 +146,12 @@ var failureTestCases = []TestCase{
Folder: []string{},
Priority: "high",
}, {
Title: "folder with empty title",
Folder: []string{"root/child"},
Title: "folder with empty segment",
Folder: []string{"root", ""},
Priority: "high",
}, {
Title: "folder title with slash",
Folder: []string{"root/child"},
Title: "folder segment ending with backslash",
Folder: []string{"root\\"},
Priority: "high",
}, {
Title: "wrong priority",
Expand Down Expand Up @@ -353,12 +353,12 @@ var customFieldSuccessTestCases = []TestCase{
},
}

const customFieldSuccessTestCasesCSV = `Folder,Type,Name,Legacy ID,Draft,Priority,Tags,Requirements,Links,Files,Preconditions,Parameter Values,Template Suffix Params,Step 1,Expected 1,custom_field_dropdown_test_env,custom_field_dropdown_automation,custom_field_text_notes
custom-fields,standalone,tc-with-single-custom-field,,false,medium,,,,,,,,,,"{""value"":""staging"",""isDefault"":false}",,
custom-fields,standalone,tc-with-multiple-custom-fields,,false,high,"regression,smoke",,,,,,,Execute test,Test passes,"{""value"":""production"",""isDefault"":false}","{""value"":""Automated"",""isDefault"":false}","{""value"":""This is a test note with special chars: !@#$%^\u0026*()"",""isDefault"":false}"
custom-fields,standalone,tc-with-empty-custom-field-value,,false,low,,,,,,,,,,,,"{""value"":"""",""isDefault"":false}"
custom-fields,standalone,tc-with-default-custom-field,,false,medium,,,,,,,,,,,"{""value"":"""",""isDefault"":false}",
custom-fields/comprehensive,standalone,tc-with-all-fields-and-custom-fields,CF-001,false,high,"custom,comprehensive",[CF Requirements](http://cf-req),[CF Link](http://cf-link),"[{""fileName"":""cf-test.txt"",""id"":""cf-file-id"",""url"":""http://cf-file"",""mimeType"":""text/plain"",""size"":100}]",Custom field test setup,,,Step 1,Result 1,"{""value"":""development"",""isDefault"":false}","{""value"":""In Progress"",""isDefault"":false}",
const customFieldSuccessTestCasesCSV = `Folder,Folder Comment,Type,Name,Legacy ID,Draft,Priority,Tags,Requirements,Links,Files,Preconditions,Parameter Values,Template Suffix Params,Step 1,Expected 1,custom_field_dropdown_test_env,custom_field_dropdown_automation,custom_field_text_notes
custom-fields,,standalone,tc-with-single-custom-field,,false,medium,,,,,,,,,,"{""value"":""staging"",""isDefault"":false}",,
custom-fields,,standalone,tc-with-multiple-custom-fields,,false,high,"regression,smoke",,,,,,,Execute test,Test passes,"{""value"":""production"",""isDefault"":false}","{""value"":""Automated"",""isDefault"":false}","{""value"":""This is a test note with special chars: !@#$%^&*()"",""isDefault"":false}"
custom-fields,,standalone,tc-with-empty-custom-field-value,,false,low,,,,,,,,,,,,"{""value"":"""",""isDefault"":false}"
custom-fields,,standalone,tc-with-default-custom-field,,false,medium,,,,,,,,,,,"{""value"":"""",""isDefault"":false}",
custom-fields/comprehensive,,standalone,tc-with-all-fields-and-custom-fields,CF-001,false,high,"custom,comprehensive",[CF Requirements](http://cf-req),[CF Link](http://cf-link),"[{""fileName"":""cf-test.txt"",""id"":""cf-file-id"",""url"":""http://cf-file"",""mimeType"":""text/plain"",""size"":100}]",Custom field test setup,,,Step 1,Result 1,"{""value"":""development"",""isDefault"":false}","{""value"":""In Progress"",""isDefault"":false}",
`

var customFieldFailureTestCases = []TestCase{
Expand Down Expand Up @@ -456,3 +456,154 @@ func TestCustomFieldFailureTestCases(t *testing.T) {
})
}
}

func TestFolderSlashEscaping(t *testing.T) {
qasCSV := NewQASphereCSV()

err := qasCSV.AddTestCase(TestCase{
Title: "tc-in-slash-folder",
Folder: []string{"root/parent", "child/leaf"},
Priority: "high",
})
require.NoError(t, err)

csv, err := qasCSV.GenerateCSV()
require.NoError(t, err)

expected := `Folder,Folder Comment,Type,Name,Legacy ID,Draft,Priority,Tags,Requirements,Links,Files,Preconditions,Parameter Values,Template Suffix Params
root\/parent/child\/leaf,,standalone,tc-in-slash-folder,,false,high,,,,,,,
`
require.Equal(t, expected, csv)
}

func TestFolderSegmentEndingWithBackslash(t *testing.T) {
qasCSV := NewQASphereCSV()

err := qasCSV.AddTestCase(TestCase{
Title: "tc-bad-backslash",
Folder: []string{"root\\"},
Priority: "high",
})
require.Error(t, err)
require.Contains(t, err.Error(), "must not end with '\\'")
}

func TestAddFolderEmpty(t *testing.T) {
qasCSV := NewQASphereCSV()

err := qasCSV.AddFolder(Folder{FolderPath: []string{"empty-folder"}})
require.NoError(t, err)

csv, err := qasCSV.GenerateCSV()
require.NoError(t, err)

expected := `Folder,Folder Comment,Type,Name,Legacy ID,Draft,Priority,Tags,Requirements,Links,Files,Preconditions,Parameter Values,Template Suffix Params
empty-folder,,,,,,,,,,,,,
`
require.Equal(t, expected, csv)
}

func TestAddFolderWithComment(t *testing.T) {
qasCSV := NewQASphereCSV()

err := qasCSV.AddFolder(Folder{
FolderPath: []string{"commented-folder"},
Comment: "This is a folder comment",
})
require.NoError(t, err)

csv, err := qasCSV.GenerateCSV()
require.NoError(t, err)

expected := `Folder,Folder Comment,Type,Name,Legacy ID,Draft,Priority,Tags,Requirements,Links,Files,Preconditions,Parameter Values,Template Suffix Params
commented-folder,This is a folder comment,,,,,,,,,,,,
`
require.Equal(t, expected, csv)
}

func TestAddFolderWithCommentAndTestCases(t *testing.T) {
qasCSV := NewQASphereCSV()

err := qasCSV.AddFolder(Folder{
FolderPath: []string{"my-folder"},
Comment: "Folder description",
})
require.NoError(t, err)

err = qasCSV.AddTestCase(TestCase{
Title: "tc-in-commented-folder",
Folder: []string{"my-folder"},
Priority: "high",
})
require.NoError(t, err)

csv, err := qasCSV.GenerateCSV()
require.NoError(t, err)

expected := `Folder,Folder Comment,Type,Name,Legacy ID,Draft,Priority,Tags,Requirements,Links,Files,Preconditions,Parameter Values,Template Suffix Params
my-folder,Folder description,,,,,,,,,,,,
my-folder,,standalone,tc-in-commented-folder,,false,high,,,,,,,
`
require.Equal(t, expected, csv)
}

func TestAddFolderValidation(t *testing.T) {
t.Run("empty folder path", func(t *testing.T) {
qasCSV := NewQASphereCSV()
err := qasCSV.AddFolder(Folder{Comment: "comment"})
require.Error(t, err)
})

t.Run("empty folder segment", func(t *testing.T) {
qasCSV := NewQASphereCSV()
err := qasCSV.AddFolder(Folder{FolderPath: []string{"root", ""}, Comment: "comment"})
require.Error(t, err)
})

t.Run("folder segment ending with backslash", func(t *testing.T) {
qasCSV := NewQASphereCSV()
err := qasCSV.AddFolder(Folder{FolderPath: []string{"root\\"}, Comment: "comment"})
require.Error(t, err)
require.Contains(t, err.Error(), "must not end with '\\'")
})

t.Run("duplicate folder", func(t *testing.T) {
qasCSV := NewQASphereCSV()
err := qasCSV.AddFolder(Folder{FolderPath: []string{"root"}, Comment: "comment"})
require.NoError(t, err)
err = qasCSV.AddFolder(Folder{FolderPath: []string{"root"}, Comment: "another comment"})
require.Error(t, err)
require.Contains(t, err.Error(), "already exists")
})

t.Run("folder already has test cases", func(t *testing.T) {
qasCSV := NewQASphereCSV()
err := qasCSV.AddTestCase(TestCase{
Title: "tc",
Folder: []string{"root"},
Priority: "high",
})
require.NoError(t, err)
err = qasCSV.AddFolder(Folder{FolderPath: []string{"root"}, Comment: "comment"})
require.Error(t, err)
require.Contains(t, err.Error(), "already exists")
})
}

func TestAddFolderWithSlashInName(t *testing.T) {
qasCSV := NewQASphereCSV()

err := qasCSV.AddFolder(Folder{
FolderPath: []string{"folder/with/slashes", "child"},
Comment: "slash comment",
})
require.NoError(t, err)

csv, err := qasCSV.GenerateCSV()
require.NoError(t, err)

expected := `Folder,Folder Comment,Type,Name,Legacy ID,Draft,Priority,Tags,Requirements,Links,Files,Preconditions,Parameter Values,Template Suffix Params
folder\/with\/slashes/child,slash comment,,,,,,,,,,,,
`
require.Equal(t, expected, csv)
}
Loading