From 056be03158051e1cd05db94f599dade30fdaf7f3 Mon Sep 17 00:00:00 2001 From: Peter Etelej Date: Sat, 3 Mar 2018 08:03:54 +0300 Subject: [PATCH 1/5] Add tests for cmd package Adds testing for cmd package. Adds a setup and teardown main test with a cmd test db as well as tests for account, add and update. Closes #19 --- cmd/account.go | 12 +++--- cmd/account_test.go | 49 ++++++++++++++++++++++++ cmd/add_test.go | 73 ++++++++++++++++++++++++++++++++++++ cmd/cmd_test.go | 28 ++++++++++++++ cmd/update_test.go | 91 +++++++++++++++++++++++++++++++++++++++++++++ database/sqlite.go | 8 ++-- main.go | 2 +- 7 files changed, 253 insertions(+), 10 deletions(-) create mode 100644 cmd/account_test.go create mode 100644 cmd/add_test.go create mode 100644 cmd/cmd_test.go create mode 100644 cmd/update_test.go diff --git a/cmd/account.go b/cmd/account.go index 08a9aea4..5f096955 100644 --- a/cmd/account.go +++ b/cmd/account.go @@ -2,6 +2,8 @@ package cmd import ( "fmt" + "io" + "os" "syscall" "github.com/spf13/cobra" @@ -45,7 +47,7 @@ var ( Args: cobra.NoArgs, Run: func(cmd *cobra.Command, args []string) { keyword, _ := cmd.Flags().GetString("search") - err := printAccounts(keyword) + err := printAccounts(keyword, os.Stdout) if err != nil { cError.Println(err) return @@ -103,7 +105,7 @@ func init() { func addAccount(username, password string) error { if username == "" { - return fmt.Errorf("Username must not empty") + return fmt.Errorf("Username must not be empty") } if len(password) < 8 { @@ -118,15 +120,15 @@ func addAccount(username, password string) error { return nil } -func printAccounts(keyword string) error { +func printAccounts(keyword string, wr io.Writer) error { accounts, err := DB.GetAccounts(keyword, false) if err != nil { return err } for _, account := range accounts { - cIndex.Print("- ") - fmt.Println(account.Username) + cIndex.Fprint(wr, "- ") + fmt.Fprintln(wr, account.Username) } return nil diff --git a/cmd/account_test.go b/cmd/account_test.go new file mode 100644 index 00000000..5fc5827d --- /dev/null +++ b/cmd/account_test.go @@ -0,0 +1,49 @@ +package cmd + +import ( + "strings" + "testing" +) + +func TestAddAccount(t *testing.T) { + tests := []struct { + username string + password string + want string + }{ + {"", "", "Username must not be empty"}, + {"abc", "abc", "Password must be at least"}, + {"abc", "fooBar123", ""}, + } + for _, tt := range tests { + err := addAccount(tt.username, tt.password) + if err != nil { + if tt.want == "" { + t.Errorf("got unexpected error: %v", err) + } + if !strings.Contains(err.Error(), tt.want) { + t.Errorf("expected error containing '%s', got error '%v'", err, tt.want) + } + continue + } + if tt.want != "" { + t.Errorf("expected error '%s', got no error", tt.want) + } + } +} + +func TestPrintAccounts(t *testing.T) { + if err := addAccount("foo", "fooBar123"); err != nil { + t.Errorf("failed to add test account: %v", err) + return + } + var b strings.Builder + err := printAccounts("", &b) + if err != nil { + t.Errorf("got unexpected error: %v", err) + } + got := b.String() + if !strings.Contains(got, "foo") { + t.Errorf("expected string containing 'foo', got '%s'", got) + } +} diff --git a/cmd/add_test.go b/cmd/add_test.go new file mode 100644 index 00000000..84444f7e --- /dev/null +++ b/cmd/add_test.go @@ -0,0 +1,73 @@ +package cmd + +import ( + "strings" + "testing" + + "github.com/RadhiFadlillah/shiori/model" +) + +func TestAddBookMark(t *testing.T) { + tests := []struct { + bookmark model.Bookmark + offline bool + want string + }{ + { + model.Bookmark{}, + true, "URL must not be empty", + }, + { + model.Bookmark{ + URL: "https://github.com/RadhiFadlillah/shiori", + }, + true, "Title must not be empty", + }, + {model.Bookmark{URL: "foo", Title: "Foo"}, true, ""}, + { + model.Bookmark{ + URL: "https://github.com/RadhiFadlillah/shiori", + Title: "Shiori", + }, + true, "", + }, + { + model.Bookmark{ + URL: "https://github.com/RadhiFadlillah/shiori/issues", + }, + false, "", + }, + } + for _, tt := range tests { + bk, err := addBookmark(tt.bookmark, tt.offline) + if err != nil { + if tt.want == "" { + t.Errorf("got unexpected error: '%v'", err) + continue + } + if !strings.Contains(err.Error(), tt.want) { + t.Errorf("expected error '%s', got '%v'", tt.want, err) + } + continue + } + if tt.bookmark.URL == "" { + t.Errorf("expected error '%s', got '%v'", tt.want, err) + continue + } + if tt.offline && tt.bookmark.Title == "" { + t.Error("expected error 'Title must not be empty', got no error") + continue + } + + if tt.want != "" { + t.Errorf("expected error '%s', got no error", tt.want) + continue + } + if tt.offline && bk.Title != tt.bookmark.Title { + t.Errorf("expected title '%s', got '%s'", tt.bookmark.Title, bk.Title) + } + if !tt.offline && bk.Title == "" { + t.Error("expected title, got empty string ''") + } + } +} diff --git a/cmd/cmd_test.go b/cmd/cmd_test.go new file mode 100644 index 00000000..b9926bae --- /dev/null +++ b/cmd/cmd_test.go @@ -0,0 +1,28 @@ +package cmd + +import ( + "fmt" + "os" + "testing" + + db "github.com/RadhiFadlillah/shiori/database" + _ "github.com/mattn/go-sqlite3" +) + +func TestMain(m *testing.M) { + testDBFile := "shiori_test.db" + sqliteDB, err := db.OpenSQLiteDatabase(testDBFile) + if err != nil { + fmt.Printf("failed to create tests DB: %v", err) + os.Exit(1) + } + DB = sqliteDB + + code := m.Run() + + if err := os.Remove(testDBFile); err != nil { + fmt.Printf("failed to delete tests DB: %v", err) + } + os.Exit(code) + +} diff --git a/cmd/update_test.go b/cmd/update_test.go new file mode 100644 index 00000000..3ca6a264 --- /dev/null +++ b/cmd/update_test.go @@ -0,0 +1,91 @@ +package cmd + +import ( + "fmt" + "strings" + "testing" + + "github.com/RadhiFadlillah/shiori/model" +) + +func TestUpdateBookMark(t *testing.T) { + testbks := []model.Bookmark{ + { + URL: "https://github.com/RadhiFadlillah/shiori/releases", + Title: "Releases", + }, + { + URL: "https://github.com/RadhiFadlillah/shiori/projects", + Title: "Projects", + }, + } + for i, tb := range testbks { + bk, err := addBookmark(tb, true) + if err != nil { + t.Fatalf("failed to create testing bookmarks: %v", err) + } + testbks[i].ID = bk.ID + } + + tests := []struct { + indices []string + url string + title string + excerpt string + tags []string + offline bool + want string + }{ + { + indices: []string{"9000"}, + want: "No matching index found", + }, + { + indices: []string{"-1"}, + want: "Index is not valid", + }, + { + indices: []string{"3", "-1"}, + want: "Index is not valid", + }, + { + indices: []string{fmt.Sprintf("%d", testbks[0].ID)}, + url: testbks[0].URL, + title: testbks[0].Title + " updated", + offline: true, + }, + { + indices: []string{fmt.Sprintf("%d", testbks[0].ID)}, + offline: false, + }, + { + indices: []string{fmt.Sprintf("%d", testbks[1].ID)}, + offline: true, + }, + } + for _, tt := range tests { + bks, err := updateBookmarks(tt.indices, tt.url, tt.title, tt.excerpt, tt.tags, tt.offline) + if err != nil { + if tt.want == "" { + t.Errorf("got unexpected error: '%v'", err) + continue + } + if !strings.Contains(err.Error(), tt.want) { + t.Errorf("expected error '%s', got '%v'", tt.want, err) + } + continue + } + if tt.want != "" { + t.Errorf("expected error '%s', got no errors", tt.want) + continue + } + if len(bks) == 0 { + t.Error("expected at least 1 bookmark, got 0") + continue + } + bk := bks[0] + if tt.title == "" && bk.Title == tt.title { + t.Errorf("expected title as '%s', got '%s'", tt.title, bk.Title) + } + } +} diff --git a/database/sqlite.go b/database/sqlite.go index 21baeda8..b831bd60 100644 --- a/database/sqlite.go +++ b/database/sqlite.go @@ -18,10 +18,10 @@ type SQLiteDatabase struct { } // OpenSQLiteDatabase creates and open connection to new SQLite3 database. -func OpenSQLiteDatabase() (*SQLiteDatabase, error) { +func OpenSQLiteDatabase(dbFile string) (*SQLiteDatabase, error) { // Open database and start transaction var err error - db := sqlx.MustConnect("sqlite3", "shiori.db") + db := sqlx.MustConnect("sqlite3", dbFile) tx := db.MustBegin() // Make sure to rollback if panic ever happened @@ -81,11 +81,11 @@ func OpenSQLiteDatabase() (*SQLiteDatabase, error) { func (db *SQLiteDatabase) CreateBookmark(bookmark model.Bookmark) (bookmarkID int64, err error) { // Check URL and title if bookmark.URL == "" { - return -1, fmt.Errorf("URL must not empty") + return -1, fmt.Errorf("URL must not be empty") } if bookmark.Title == "" { - return -1, fmt.Errorf("Title must not empty") + return -1, fmt.Errorf("Title must not be empty") } if bookmark.Modified == "" { diff --git a/main.go b/main.go index c44a6aad..0e7e8644 100644 --- a/main.go +++ b/main.go @@ -8,7 +8,7 @@ import ( ) func main() { - sqliteDB, err := db.OpenSQLiteDatabase() + sqliteDB, err := db.OpenSQLiteDatabase("shiori.db") checkError(err) cmd.DB = sqliteDB From 5f790c705c7efd00d226f3023fa08b86d44c2da4 Mon Sep 17 00:00:00 2001 From: Radhi Fadlillah Date: Tue, 6 Mar 2018 15:33:29 +0700 Subject: [PATCH 2/5] Replace strings.Builder for backward Go compability --- cmd/account_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmd/account_test.go b/cmd/account_test.go index 5fc5827d..151b11f2 100644 --- a/cmd/account_test.go +++ b/cmd/account_test.go @@ -1,6 +1,7 @@ package cmd import ( + "bytes" "strings" "testing" ) @@ -37,8 +38,8 @@ func TestPrintAccounts(t *testing.T) { t.Errorf("failed to add test account: %v", err) return } - var b strings.Builder - err := printAccounts("", &b) + b := bytes.NewBufferString("") + err := printAccounts("", b) if err != nil { t.Errorf("got unexpected error: %v", err) } From 5bea3de59b89b0981be812580ab545cd77653c4a Mon Sep 17 00:00:00 2001 From: Radhi Fadlillah Date: Tue, 6 Mar 2018 16:05:08 +0700 Subject: [PATCH 3/5] Fix: error scan on Go 1.8 --- database/sqlite.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/sqlite.go b/database/sqlite.go index 0fdb056f..459c6217 100644 --- a/database/sqlite.go +++ b/database/sqlite.go @@ -466,7 +466,7 @@ func (db *SQLiteDatabase) UpdateBookmarks(bookmarks []model.Bookmark) (result [] stmtUpdateBookmarkContent.MustExec( book.Title, book.Content, - book.HTML, + string(book.HTML), book.ID) newTags := []model.Tag{} From 8b31568eaf3f4956778adcb72cc6fa44704e83c7 Mon Sep 17 00:00:00 2001 From: Radhi Fadlillah Date: Tue, 6 Mar 2018 16:30:47 +0700 Subject: [PATCH 4/5] Revert unneeded change --- database/sqlite.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/sqlite.go b/database/sqlite.go index 459c6217..0fdb056f 100644 --- a/database/sqlite.go +++ b/database/sqlite.go @@ -466,7 +466,7 @@ func (db *SQLiteDatabase) UpdateBookmarks(bookmarks []model.Bookmark) (result [] stmtUpdateBookmarkContent.MustExec( book.Title, book.Content, - string(book.HTML), + book.HTML, book.ID) newTags := []model.Tag{} From b16c5cc363e5f06abaedfbf996fffcebddbe2788 Mon Sep 17 00:00:00 2001 From: Radhi Fadlillah Date: Tue, 6 Mar 2018 16:48:06 +0700 Subject: [PATCH 5/5] Convert template.HTML to string --- cmd/add.go | 3 +-- cmd/update.go | 3 +-- model/model.go | 26 ++++++++++++-------------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/cmd/add.go b/cmd/add.go index 0497b17e..9e004fdd 100644 --- a/cmd/add.go +++ b/cmd/add.go @@ -1,7 +1,6 @@ package cmd import ( - "html/template" nurl "net/url" "strings" "time" @@ -81,7 +80,7 @@ func addBookmark(base model.Bookmark, offline bool) (book model.Bookmark, err er book.MinReadTime = article.Meta.MinReadTime book.MaxReadTime = article.Meta.MaxReadTime book.Content = article.Content - book.HTML = template.HTML(article.RawContent) + book.HTML = article.RawContent if book.Title == "" { book.Title = article.Meta.Title diff --git a/cmd/update.go b/cmd/update.go index 75baba74..9d47bbb9 100644 --- a/cmd/update.go +++ b/cmd/update.go @@ -2,7 +2,6 @@ package cmd import ( "fmt" - "html/template" "strconv" "strings" "sync" @@ -121,7 +120,7 @@ func updateBookmarks(indices []string, url, title, excerpt string, tags []string book.MinReadTime = article.Meta.MinReadTime book.MaxReadTime = article.Meta.MaxReadTime book.Content = article.Content - book.HTML = template.HTML(article.RawContent) + book.HTML = article.RawContent mutex.Lock() bookmarks[pos] = book diff --git a/model/model.go b/model/model.go index 4a7954a1..f6d2a8eb 100644 --- a/model/model.go +++ b/model/model.go @@ -1,7 +1,5 @@ package model -import "html/template" - // Tag is tag for the bookmark type Tag struct { ID int64 `db:"id" json:"id"` @@ -11,18 +9,18 @@ type Tag struct { // Bookmark is record of a specified URL type Bookmark struct { - ID int64 `db:"id" json:"id"` - URL string `db:"url" json:"url"` - Title string `db:"title" json:"title"` - ImageURL string `db:"image_url" json:"imageURL"` - Excerpt string `db:"excerpt" json:"excerpt"` - Author string `db:"author" json:"author"` - MinReadTime int `db:"min_read_time" json:"minReadTime"` - MaxReadTime int `db:"max_read_time" json:"maxReadTime"` - Modified string `db:"modified" json:"modified"` - Content string `db:"content" json:"-"` - HTML template.HTML `db:"html" json:"-"` - Tags []Tag `json:"tags"` + ID int64 `db:"id" json:"id"` + URL string `db:"url" json:"url"` + Title string `db:"title" json:"title"` + ImageURL string `db:"image_url" json:"imageURL"` + Excerpt string `db:"excerpt" json:"excerpt"` + Author string `db:"author" json:"author"` + MinReadTime int `db:"min_read_time" json:"minReadTime"` + MaxReadTime int `db:"max_read_time" json:"maxReadTime"` + Modified string `db:"modified" json:"modified"` + Content string `db:"content" json:"-"` + HTML string `db:"html" json:"-"` + Tags []Tag `json:"tags"` } // Account is account for accessing bookmarks from web interface