mirror of
https://github.com/dnote/dnote
synced 2026-03-14 14:35:50 +01:00
Restructure packages to reduce duplication
This commit is contained in:
parent
5feed29df7
commit
d476fa02f8
15 changed files with 228 additions and 131 deletions
51
pkg/cli/context/files.go
Normal file
51
pkg/cli/context/files.go
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/* Copyright (C) 2019, 2020, 2021, 2022, 2023, 2024, 2025 Dnote contributors
|
||||
*
|
||||
* This file is part of Dnote.
|
||||
*
|
||||
* Dnote is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Dnote is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package context
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/dnote/dnote/pkg/cli/consts"
|
||||
"github.com/dnote/dnote/pkg/cli/utils"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// InitDnoteDirs creates the dnote directories if they don't already exist.
|
||||
func InitDnoteDirs(paths Paths) error {
|
||||
if paths.Config != "" {
|
||||
configDir := filepath.Join(paths.Config, consts.DnoteDirName)
|
||||
if err := utils.EnsureDir(configDir); err != nil {
|
||||
return errors.Wrap(err, "initializing config dir")
|
||||
}
|
||||
}
|
||||
if paths.Data != "" {
|
||||
dataDir := filepath.Join(paths.Data, consts.DnoteDirName)
|
||||
if err := utils.EnsureDir(dataDir); err != nil {
|
||||
return errors.Wrap(err, "initializing data dir")
|
||||
}
|
||||
}
|
||||
if paths.Cache != "" {
|
||||
cacheDir := filepath.Join(paths.Cache, consts.DnoteDirName)
|
||||
if err := utils.EnsureDir(cacheDir); err != nil {
|
||||
return errors.Wrap(err, "initializing cache dir")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
65
pkg/cli/context/files_test.go
Normal file
65
pkg/cli/context/files_test.go
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
/* Copyright (C) 2019, 2020, 2021, 2022, 2023, 2024, 2025 Dnote contributors
|
||||
*
|
||||
* This file is part of Dnote.
|
||||
*
|
||||
* Dnote is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Dnote is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package context
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/dnote/dnote/pkg/assert"
|
||||
"github.com/dnote/dnote/pkg/cli/consts"
|
||||
)
|
||||
|
||||
func assertDirsExist(t *testing.T, paths Paths) {
|
||||
configDir := filepath.Join(paths.Config, consts.DnoteDirName)
|
||||
info, err := os.Stat(configDir)
|
||||
assert.Equal(t, err, nil, "config dir should exist")
|
||||
assert.Equal(t, info.IsDir(), true, "config should be a directory")
|
||||
|
||||
dataDir := filepath.Join(paths.Data, consts.DnoteDirName)
|
||||
info, err = os.Stat(dataDir)
|
||||
assert.Equal(t, err, nil, "data dir should exist")
|
||||
assert.Equal(t, info.IsDir(), true, "data should be a directory")
|
||||
|
||||
cacheDir := filepath.Join(paths.Cache, consts.DnoteDirName)
|
||||
info, err = os.Stat(cacheDir)
|
||||
assert.Equal(t, err, nil, "cache dir should exist")
|
||||
assert.Equal(t, info.IsDir(), true, "cache should be a directory")
|
||||
}
|
||||
|
||||
func TestInitDnoteDirs(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
paths := Paths{
|
||||
Config: filepath.Join(tmpDir, "config"),
|
||||
Data: filepath.Join(tmpDir, "data"),
|
||||
Cache: filepath.Join(tmpDir, "cache"),
|
||||
}
|
||||
|
||||
// Initialize directories
|
||||
err := InitDnoteDirs(paths)
|
||||
assert.Equal(t, err, nil, "InitDnoteDirs should succeed")
|
||||
assertDirsExist(t, paths)
|
||||
|
||||
// Call again - should be idempotent
|
||||
err = InitDnoteDirs(paths)
|
||||
assert.Equal(t, err, nil, "InitDnoteDirs should succeed when dirs already exist")
|
||||
assertDirsExist(t, paths)
|
||||
}
|
||||
|
|
@ -19,7 +19,6 @@
|
|||
package context
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
|
|
@ -40,34 +39,16 @@ func getDefaultTestPaths(t *testing.T) Paths {
|
|||
}
|
||||
}
|
||||
|
||||
// createTestDirectories creates test directories for the given paths
|
||||
func createTestDirectories(t *testing.T, paths Paths) {
|
||||
if paths.Config != "" {
|
||||
configDir := filepath.Join(paths.Config, consts.DnoteDirName)
|
||||
if err := os.MkdirAll(configDir, 0755); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "creating test config directory"))
|
||||
}
|
||||
}
|
||||
if paths.Data != "" {
|
||||
dataDir := filepath.Join(paths.Data, consts.DnoteDirName)
|
||||
if err := os.MkdirAll(dataDir, 0755); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "creating test data directory"))
|
||||
}
|
||||
}
|
||||
if paths.Cache != "" {
|
||||
cacheDir := filepath.Join(paths.Cache, consts.DnoteDirName)
|
||||
if err := os.MkdirAll(cacheDir, 0755); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "creating test cache directory"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// InitTestCtx initializes a test context with an in-memory database
|
||||
// and a temporary directory for all paths
|
||||
func InitTestCtx(t *testing.T) DnoteCtx {
|
||||
paths := getDefaultTestPaths(t)
|
||||
db := database.InitTestMemoryDB(t)
|
||||
createTestDirectories(t, paths)
|
||||
|
||||
if err := InitDnoteDirs(paths); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "creating test directories"))
|
||||
}
|
||||
|
||||
return DnoteCtx{
|
||||
DB: db,
|
||||
|
|
@ -81,7 +62,10 @@ func InitTestCtx(t *testing.T) DnoteCtx {
|
|||
// Used when you need full control over database initialization (e.g. migration tests).
|
||||
func InitTestCtxWithDB(t *testing.T, db *database.DB) DnoteCtx {
|
||||
paths := getDefaultTestPaths(t)
|
||||
createTestDirectories(t, paths)
|
||||
|
||||
if err := InitDnoteDirs(paths); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "creating test directories"))
|
||||
}
|
||||
|
||||
return DnoteCtx{
|
||||
DB: db,
|
||||
|
|
@ -94,7 +78,10 @@ func InitTestCtxWithDB(t *testing.T, db *database.DB) DnoteCtx {
|
|||
// at the expected path.
|
||||
func InitTestCtxWithFileDB(t *testing.T) DnoteCtx {
|
||||
paths := getDefaultTestPaths(t)
|
||||
createTestDirectories(t, paths)
|
||||
|
||||
if err := InitDnoteDirs(paths); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "creating test directories"))
|
||||
}
|
||||
|
||||
dbPath := filepath.Join(paths.Data, consts.DnoteDirName, consts.DnoteDBFileName)
|
||||
db, err := database.Open(dbPath)
|
||||
|
|
@ -106,7 +93,6 @@ func InitTestCtxWithFileDB(t *testing.T) DnoteCtx {
|
|||
t.Fatal(errors.Wrap(err, "running schema sql"))
|
||||
}
|
||||
|
||||
database.MarkMigrationComplete(t, db)
|
||||
t.Cleanup(func() { db.Close() })
|
||||
|
||||
return DnoteCtx{
|
||||
|
|
|
|||
|
|
@ -110,7 +110,6 @@ func TestNoteInsert(t *testing.T) {
|
|||
func() {
|
||||
// Setup
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
n := Note{
|
||||
UUID: tc.uuid,
|
||||
|
|
@ -244,7 +243,6 @@ func TestNoteUpdate(t *testing.T) {
|
|||
func() {
|
||||
// Setup
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
n1 := Note{
|
||||
UUID: tc.uuid,
|
||||
|
|
@ -267,8 +265,8 @@ func TestNoteUpdate(t *testing.T) {
|
|||
Dirty: false,
|
||||
}
|
||||
|
||||
MustExec(t, fmt.Sprintf("inserting n1 for test case %d", idx), db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", n1.UUID, n1.BookUUID, n1.USN, n1.AddedOn, n1.EditedOn, n1.Body, n1.Deleted, n1.Dirty)
|
||||
MustExec(t, fmt.Sprintf("inserting n2 for test case %d", idx), db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", n2.UUID, n2.BookUUID, n2.USN, n2.AddedOn, n2.EditedOn, n2.Body, n2.Deleted, n2.Dirty)
|
||||
MustExec(t, fmt.Sprintf("inserting n1 for test case %d", idx), db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", n1.UUID, n1.BookUUID, n1.USN, n1.AddedOn, n1.EditedOn, n1.Body, n1.Deleted, n1.Dirty)
|
||||
MustExec(t, fmt.Sprintf("inserting n2 for test case %d", idx), db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", n2.UUID, n2.BookUUID, n2.USN, n2.AddedOn, n2.EditedOn, n2.Body, n2.Deleted, n2.Dirty)
|
||||
|
||||
// execute
|
||||
tx, err := db.Begin()
|
||||
|
|
@ -336,7 +334,6 @@ func TestNoteUpdateUUID(t *testing.T) {
|
|||
t.Run(fmt.Sprintf("testCase%d", idx), func(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
n1 := Note{
|
||||
UUID: "n1-uuid",
|
||||
|
|
@ -391,7 +388,6 @@ func TestNoteUpdateUUID(t *testing.T) {
|
|||
func TestNoteExpunge(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
n1 := Note{
|
||||
UUID: "n1-uuid",
|
||||
|
|
@ -414,8 +410,8 @@ func TestNoteExpunge(t *testing.T) {
|
|||
Dirty: false,
|
||||
}
|
||||
|
||||
MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", n1.UUID, n1.BookUUID, n1.USN, n1.AddedOn, n1.EditedOn, n1.Body, n1.Deleted, n1.Dirty)
|
||||
MustExec(t, "inserting n2", db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", n2.UUID, n2.BookUUID, n2.USN, n2.AddedOn, n2.EditedOn, n2.Body, n2.Deleted, n2.Dirty)
|
||||
MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", n1.UUID, n1.BookUUID, n1.USN, n1.AddedOn, n1.EditedOn, n1.Body, n1.Deleted, n1.Dirty)
|
||||
MustExec(t, "inserting n2", db, "INSERT INTO notes (uuid, book_uuid, usn, added_on, edited_on, body, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", n2.UUID, n2.BookUUID, n2.USN, n2.AddedOn, n2.EditedOn, n2.Body, n2.Deleted, n2.Dirty)
|
||||
|
||||
// execute
|
||||
tx, err := db.Begin()
|
||||
|
|
@ -514,7 +510,6 @@ func TestBookInsert(t *testing.T) {
|
|||
func() {
|
||||
// Setup
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
b := Book{
|
||||
UUID: tc.uuid,
|
||||
|
|
@ -595,7 +590,6 @@ func TestBookUpdate(t *testing.T) {
|
|||
func() {
|
||||
// Setup
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
b1 := Book{
|
||||
UUID: "b1-uuid",
|
||||
|
|
@ -674,7 +668,6 @@ func TestBookUpdateUUID(t *testing.T) {
|
|||
|
||||
// Setup
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
b1 := Book{
|
||||
UUID: "b1-uuid",
|
||||
|
|
@ -725,7 +718,6 @@ func TestBookUpdateUUID(t *testing.T) {
|
|||
func TestBookExpunge(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
b1 := Book{
|
||||
UUID: "b1-uuid",
|
||||
|
|
@ -780,7 +772,6 @@ func TestBookExpunge(t *testing.T) {
|
|||
func TestNoteFTS(t *testing.T) {
|
||||
// set up
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
// execute - insert
|
||||
n := Note{
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ func TestInsertSystem(t *testing.T) {
|
|||
t.Run(fmt.Sprintf("insert %s %s", tc.key, tc.val), func(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
// execute
|
||||
tx, err := db.Begin()
|
||||
|
|
@ -96,7 +95,6 @@ func TestUpsertSystem(t *testing.T) {
|
|||
t.Run(fmt.Sprintf("insert %s %s", tc.key, tc.val), func(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
MustExec(t, "inserting a system configuration", db, "INSERT INTO system (key, value) VALUES (?, ?)", "baz", "quz")
|
||||
|
||||
|
|
@ -135,7 +133,6 @@ func TestGetSystem(t *testing.T) {
|
|||
t.Run(fmt.Sprintf("get string value"), func(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
// execute
|
||||
MustExec(t, "inserting a system configuration", db, "INSERT INTO system (key, value) VALUES (?, ?)", "foo", "bar")
|
||||
|
|
@ -158,7 +155,6 @@ func TestGetSystem(t *testing.T) {
|
|||
t.Run(fmt.Sprintf("get int64 value"), func(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
// execute
|
||||
MustExec(t, "inserting a system configuration", db, "INSERT INTO system (key, value) VALUES (?, ?)", "foo", 1234)
|
||||
|
|
@ -199,7 +195,6 @@ func TestUpdateSystem(t *testing.T) {
|
|||
t.Run(fmt.Sprintf("update %s %s", tc.key, tc.val), func(t *testing.T) {
|
||||
// Setup
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
MustExec(t, "inserting a system configuration", db, "INSERT INTO system (key, value) VALUES (?, ?)", "foo", "fuz")
|
||||
MustExec(t, "inserting a system configuration", db, "INSERT INTO system (key, value) VALUES (?, ?)", "baz", "quz")
|
||||
|
|
@ -239,7 +234,6 @@ func TestGetActiveNote(t *testing.T) {
|
|||
t.Run("not deleted", func(t *testing.T) {
|
||||
// set up
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
n1UUID := "n1-uuid"
|
||||
MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, body, added_on, edited_on, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", n1UUID, "b1-uuid", "n1 content", 1542058875, 1542058876, 1, false, true)
|
||||
|
|
@ -268,7 +262,6 @@ func TestGetActiveNote(t *testing.T) {
|
|||
t.Run("deleted", func(t *testing.T) {
|
||||
// set up
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
n1UUID := "n1-uuid"
|
||||
MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, body, added_on, edited_on, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", n1UUID, "b1-uuid", "n1 content", 1542058875, 1542058876, 1, true, true)
|
||||
|
|
@ -292,7 +285,6 @@ func TestGetActiveNote(t *testing.T) {
|
|||
func TestUpdateNoteContent(t *testing.T) {
|
||||
// set up
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
uuid := "n1-uuid"
|
||||
MustExec(t, "inserting n1", db, "INSERT INTO notes (uuid, book_uuid, body, added_on, edited_on, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", uuid, "b1-uuid", "n1 content", 1542058875, 0, 1, false, false)
|
||||
|
|
@ -324,7 +316,6 @@ func TestUpdateNoteContent(t *testing.T) {
|
|||
func TestUpdateNoteBook(t *testing.T) {
|
||||
// set up
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
b1UUID := "b1-uuid"
|
||||
b2UUID := "b2-uuid"
|
||||
|
|
@ -361,7 +352,6 @@ func TestUpdateNoteBook(t *testing.T) {
|
|||
func TestUpdateBookName(t *testing.T) {
|
||||
// set up
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
b1UUID := "b1-uuid"
|
||||
MustExec(t, "inserting b1", db, "INSERT INTO books (uuid, label, usn, deleted, dirty) VALUES (?, ?, ?, ?, ?)", b1UUID, "b1-label", 8, false, false)
|
||||
|
|
|
|||
|
|
@ -34,3 +34,7 @@ CREATE TRIGGER notes_after_update AFTER UPDATE ON notes BEGIN
|
|||
INSERT INTO note_fts(note_fts, rowid, body) VALUES ('delete', old.rowid, old.body);
|
||||
INSERT INTO note_fts(rowid, body) VALUES (new.rowid, new.body);
|
||||
END;
|
||||
|
||||
-- Migration version data.
|
||||
INSERT INTO system (key, value) VALUES ('schema', 14);
|
||||
INSERT INTO system (key, value) VALUES ('remote_schema', 1);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/dnote/dnote/pkg/cli/config"
|
||||
"github.com/dnote/dnote/pkg/cli/consts"
|
||||
"github.com/dnote/dnote/pkg/cli/context"
|
||||
"github.com/dnote/dnote/pkg/cli/database"
|
||||
"github.com/dnote/dnote/pkg/cli/infra"
|
||||
|
|
@ -118,7 +119,12 @@ func generateSchema(tmpDir string) (string, error) {
|
|||
return "", fmt.Errorf("extracting schema: %w", err)
|
||||
}
|
||||
|
||||
return schema, nil
|
||||
// Add INSERT statements for migration versions.
|
||||
systemData := "\n-- Migration version data.\n"
|
||||
systemData += fmt.Sprintf("INSERT INTO system (key, value) VALUES ('%s', %d);\n", consts.SystemSchema, len(migrate.LocalSequence))
|
||||
systemData += fmt.Sprintf("INSERT INTO system (key, value) VALUES ('%s', %d);\n", consts.SystemRemoteSchema, len(migrate.RemoteSequence))
|
||||
|
||||
return schema + systemData, nil
|
||||
}
|
||||
|
||||
// extractSchema extracts the complete schema by querying sqlite_master
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/dnote/dnote/pkg/assert"
|
||||
"github.com/dnote/dnote/pkg/cli/consts"
|
||||
)
|
||||
|
||||
func TestRun(t *testing.T) {
|
||||
|
|
@ -73,4 +74,11 @@ func TestRun(t *testing.T) {
|
|||
|
||||
// Verify schema does not contain sqlite internal tables
|
||||
assert.Equal(t, strings.Contains(schema, "sqlite_sequence"), false, "schema should not contain sqlite_sequence")
|
||||
|
||||
// Verify system key-value pairs for schema versions are present
|
||||
expectedSchemaKey := fmt.Sprintf("INSERT INTO system (key, value) VALUES ('%s',", consts.SystemSchema)
|
||||
assert.Equal(t, strings.Contains(schema, expectedSchemaKey), true, "schema should contain schema version INSERT statement")
|
||||
|
||||
expectedRemoteSchemaKey := fmt.Sprintf("INSERT INTO system (key, value) VALUES ('%s',", consts.SystemRemoteSchema)
|
||||
assert.Equal(t, strings.Contains(schema, expectedRemoteSchemaKey), true, "schema should contain remote_schema version INSERT statement")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
package database
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSchemaEmbed(t *testing.T) {
|
||||
db := InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
// Try to insert a book to verify schema is loaded
|
||||
_, err := db.Exec("INSERT INTO books (uuid, label) VALUES (?, ?)", "test-uuid", "test-label")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to insert into books: %v", err)
|
||||
}
|
||||
|
||||
// Verify it was inserted
|
||||
var label string
|
||||
err = db.QueryRow("SELECT label FROM books WHERE uuid = ?", "test-uuid").Scan(&label)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to query books: %v", err)
|
||||
}
|
||||
if label != "test-label" {
|
||||
t.Fatalf("Expected label 'test-label', got '%s'", label)
|
||||
}
|
||||
t.Log("Schema embed test passed!")
|
||||
}
|
||||
|
|
@ -58,9 +58,7 @@ func MustExec(t *testing.T, message string, db *DB, query string, args ...interf
|
|||
|
||||
// InitTestMemoryDB initializes an in-memory test database with the default schema.
|
||||
func InitTestMemoryDB(t *testing.T) *DB {
|
||||
db := InitTestMemoryDBRaw(t, "")
|
||||
MarkMigrationComplete(t, db)
|
||||
return db
|
||||
return InitTestMemoryDBRaw(t, "")
|
||||
}
|
||||
|
||||
// InitTestFileDB initializes a file-based test database with the default schema.
|
||||
|
|
@ -81,8 +79,6 @@ func InitTestFileDBRaw(t *testing.T, dbPath string) *DB {
|
|||
t.Fatal(errors.Wrap(err, "running schema sql"))
|
||||
}
|
||||
|
||||
MarkMigrationComplete(t, db)
|
||||
|
||||
t.Cleanup(func() { db.Close() })
|
||||
return db
|
||||
}
|
||||
|
|
@ -125,16 +121,6 @@ func OpenTestDB(t *testing.T, dnoteDir string) *DB {
|
|||
return db
|
||||
}
|
||||
|
||||
// MarkMigrationComplete marks all migrations as complete in the database
|
||||
func MarkMigrationComplete(t *testing.T, db *DB) {
|
||||
if _, err := db.Exec("INSERT INTO system (key, value) VALUES (? , ?);", consts.SystemSchema, 14); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "inserting schema"))
|
||||
}
|
||||
if _, err := db.Exec("INSERT INTO system (key, value) VALUES (? , ?);", consts.SystemRemoteSchema, 1); err != nil {
|
||||
t.Fatal(errors.Wrap(err, "inserting remote schema"))
|
||||
}
|
||||
}
|
||||
|
||||
// mustGenerateTestUUID generates a UUID for test databases and fails the test on error
|
||||
func mustGenerateTestUUID(t *testing.T) string {
|
||||
uuid, err := utils.GenerateUUID()
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ import (
|
|||
"database/sql"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
|
|
@ -329,37 +328,6 @@ func getEditorCommand() string {
|
|||
return ret
|
||||
}
|
||||
|
||||
// initDir creates a directory if it doesn't exist
|
||||
func initDir(path string) error {
|
||||
ok, err := utils.FileExists(path)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "checking if dir exists at %s", path)
|
||||
}
|
||||
if ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(path, 0755); err != nil {
|
||||
return errors.Wrapf(err, "creating a directory at %s", path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initDnoteDir initializes missing directories that Dnote uses
|
||||
func initDnoteDir(ctx context.DnoteCtx) error {
|
||||
if err := initDir(filepath.Join(ctx.Paths.Config, consts.DnoteDirName)); err != nil {
|
||||
return errors.Wrap(err, "initializing config dir")
|
||||
}
|
||||
if err := initDir(filepath.Join(ctx.Paths.Data, consts.DnoteDirName)); err != nil {
|
||||
return errors.Wrap(err, "initializing data dir")
|
||||
}
|
||||
if err := initDir(filepath.Join(ctx.Paths.Cache, consts.DnoteDirName)); err != nil {
|
||||
return errors.Wrap(err, "initializing cache dir")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// initConfigFile populates a new config file if it does not exist yet
|
||||
func initConfigFile(ctx context.DnoteCtx, apiEndpoint string) error {
|
||||
|
|
@ -395,7 +363,7 @@ func initConfigFile(ctx context.DnoteCtx, apiEndpoint string) error {
|
|||
|
||||
// initFiles creates, if necessary, the dnote directory and files inside
|
||||
func initFiles(ctx context.DnoteCtx, apiEndpoint string) error {
|
||||
if err := initDnoteDir(ctx); err != nil {
|
||||
if err := context.InitDnoteDirs(ctx.Paths); err != nil {
|
||||
return errors.Wrap(err, "creating the dnote dir")
|
||||
}
|
||||
if err := initConfigFile(ctx, apiEndpoint); err != nil {
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ import (
|
|||
func TestInitSystemKV(t *testing.T) {
|
||||
// Setup
|
||||
db := database.InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
var originalCount int
|
||||
database.MustScan(t, "counting system configs", db.QueryRow("SELECT count(*) FROM system"), &originalCount)
|
||||
|
|
@ -65,7 +64,6 @@ func TestInitSystemKV(t *testing.T) {
|
|||
func TestInitSystemKV_existing(t *testing.T) {
|
||||
// Setup
|
||||
db := database.InitTestMemoryDB(t)
|
||||
defer db.Close()
|
||||
|
||||
database.MustExec(t, "inserting a system config", db, "INSERT INTO system (key, value) VALUES (?, ?)", "testKey", "testVal")
|
||||
|
||||
|
|
|
|||
|
|
@ -38,6 +38,14 @@ import (
|
|||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// initTestDBNoMigration initializes a test database with schema.sql but removes
|
||||
// migration version data so tests can control the migration state themselves.
|
||||
func initTestDBNoMigration(t *testing.T) *database.DB {
|
||||
db := database.InitTestMemoryDBRaw(t, "")
|
||||
// Remove migration versions from schema.sql so tests can set their own
|
||||
database.MustExec(t, "clearing schema versions", db, "DELETE FROM system WHERE key IN (?, ?)", consts.SystemSchema, consts.SystemRemoteSchema)
|
||||
return db
|
||||
}
|
||||
|
||||
func TestExecute_bump_schema(t *testing.T) {
|
||||
testCases := []struct {
|
||||
|
|
@ -54,7 +62,7 @@ func TestExecute_bump_schema(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
db := database.InitTestMemoryDBRaw(t, "")
|
||||
db := initTestDBNoMigration(t)
|
||||
ctx := context.InitTestCtxWithDB(t, db)
|
||||
|
||||
database.MustExec(t, "inserting a schema", db, "INSERT INTO system (key, value) VALUES (?, ?)", tc.schemaKey, 8)
|
||||
|
|
@ -108,7 +116,7 @@ func TestRun_nonfresh(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
db := database.InitTestMemoryDBRaw(t, "")
|
||||
db := initTestDBNoMigration(t)
|
||||
ctx := context.InitTestCtxWithDB(t, db)
|
||||
database.MustExec(t, "inserting a schema", db, "INSERT INTO system (key, value) VALUES (?, ?)", tc.schemaKey, 2)
|
||||
database.MustExec(t, "creating a temporary table for testing", db,
|
||||
|
|
@ -185,7 +193,7 @@ func TestRun_fresh(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
db := database.InitTestMemoryDBRaw(t, "")
|
||||
db := initTestDBNoMigration(t)
|
||||
ctx := context.InitTestCtxWithDB(t, db)
|
||||
|
||||
database.MustExec(t, "creating a temporary table for testing", db,
|
||||
|
|
@ -256,7 +264,7 @@ func TestRun_up_to_date(t *testing.T) {
|
|||
for _, tc := range testCases {
|
||||
func() {
|
||||
// set up
|
||||
db := database.InitTestMemoryDBRaw(t, "")
|
||||
db := initTestDBNoMigration(t)
|
||||
ctx := context.InitTestCtxWithDB(t, db)
|
||||
|
||||
database.MustExec(t, "creating a temporary table for testing", db,
|
||||
|
|
|
|||
|
|
@ -55,6 +55,24 @@ func FileExists(filepath string) (bool, error) {
|
|||
return false, errors.Wrap(err, "getting file info")
|
||||
}
|
||||
|
||||
// EnsureDir creates a directory if it doesn't exist.
|
||||
// Returns nil if the directory already exists or was successfully created.
|
||||
func EnsureDir(path string) error {
|
||||
ok, err := FileExists(path)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "checking if dir exists at %s", path)
|
||||
}
|
||||
if ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(path, 0755); err != nil {
|
||||
return errors.Wrapf(err, "creating directory at %s", path)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// CopyDir copies a directory from src to dest, recursively copying nested
|
||||
// directories
|
||||
func CopyDir(src, dest string) error {
|
||||
|
|
|
|||
45
pkg/cli/utils/files_test.go
Normal file
45
pkg/cli/utils/files_test.go
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/* Copyright (C) 2019, 2020, 2021, 2022, 2023, 2024, 2025 Dnote contributors
|
||||
*
|
||||
* This file is part of Dnote.
|
||||
*
|
||||
* Dnote is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Dnote is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Dnote. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/dnote/dnote/pkg/assert"
|
||||
)
|
||||
|
||||
func TestEnsureDir(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
testPath := filepath.Join(tmpDir, "test", "nested", "dir")
|
||||
|
||||
// Create directory
|
||||
err := EnsureDir(testPath)
|
||||
assert.Equal(t, err, nil, "EnsureDir should succeed")
|
||||
|
||||
// Verify it exists
|
||||
info, err := os.Stat(testPath)
|
||||
assert.Equal(t, err, nil, "directory should exist")
|
||||
assert.Equal(t, info.IsDir(), true, "should be a directory")
|
||||
|
||||
// Call again on existing directory - should not error
|
||||
err = EnsureDir(testPath)
|
||||
assert.Equal(t, err, nil, "EnsureDir should succeed on existing directory")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue