diff --git a/append_test.go b/append_test.go index ac1c9d5..acf020a 100644 --- a/append_test.go +++ b/append_test.go @@ -10,20 +10,20 @@ import ( ) func TestAppend(t *testing.T) { - rand := strconv.Itoa(rand.Int()) + randomValue := strconv.Itoa(rand.Int()) c := cheapcash.Default() - err := c.Write(rand, []byte("Hello")) + err := c.Write(randomValue, []byte("Hello")) if err != nil { t.Error("an error was thrown:", err) } - err = c.Append(rand, []byte("World")) + err = c.Append(randomValue, []byte("World")) if err != nil { t.Error("an error was thrown:", err) } - r, err := c.Read(rand) + r, err := c.Read(randomValue) if err != nil { t.Error("an error was thrown:", err) } @@ -34,10 +34,10 @@ func TestAppend(t *testing.T) { } func TestAppend_NotExists(t *testing.T) { - rand := strconv.Itoa(rand.Int()) + randomValue := strconv.Itoa(rand.Int()) c := cheapcash.Default() - err := c.Append(rand, []byte("Hello")) + err := c.Append(randomValue, []byte("Hello")) if err == nil { t.Error("expected an error, got nil") } diff --git a/cheapcash.go b/cheapcash.go index 891adc0..f7b36e6 100644 --- a/cheapcash.go +++ b/cheapcash.go @@ -15,6 +15,7 @@ type Cache struct { var ErrNotExists = errors.New("key does not exist") var ErrInvalidPath = errors.New("path supplied is invalid") var ErrDiskFull = errors.New("there was no space left on the device") +var ErrExists = errors.New("key already exists") func Default() *Cache { return &Cache{ diff --git a/check_test.go b/check_test.go index ec29611..fc3e4cd 100644 --- a/check_test.go +++ b/check_test.go @@ -3,15 +3,16 @@ package cheapcash_test import ( "math/rand" "strconv" + "sync" "testing" "github.com/aldy505/cheapcash" ) func TestExists(t *testing.T) { - rand := strconv.Itoa(rand.Int()) + randomValue := strconv.Itoa(rand.Int()) c := cheapcash.Default() - b, err := c.Exists(c.Path + "/" + rand) + b, err := c.Exists(c.Path + "/" + randomValue) if err != nil { t.Error("an error was thrown:", err) } @@ -20,12 +21,12 @@ func TestExists(t *testing.T) { t.Error("expected false, got true") } - err = c.Write(rand, []byte("value")) + err = c.Write(randomValue, []byte("value")) if err != nil { t.Error("an error was thrown:", err) } - b, err = c.Exists(c.Path + "/" + rand) + b, err = c.Exists(c.Path + "/" + randomValue) if err != nil { t.Error("an error was thrown:", err) } @@ -36,80 +37,28 @@ func TestExists(t *testing.T) { } func TestExists_Concurrency(t *testing.T) { - rand := strconv.Itoa(rand.Int()) + randomValue := strconv.Itoa(rand.Int()) c := cheapcash.Default() - res := make(chan bool, 5) + var wg sync.WaitGroup - go func() { - b, err := c.Exists(c.Path + "/" + rand) + existsFunc := func() { + b, err := c.Exists(c.Path + "/" + randomValue) if err != nil { t.Error("an error was thrown:", err) } if b == true { t.Error("expected false, got true") } - res <- true - }() + wg.Done() + } - go func() { - b, err := c.Exists(c.Path + "/" + rand) - if err != nil { - t.Error("an error was thrown:", err) - } - if b == true { - t.Error("expected false, got true") - } - res <- true - }() + wg.Add(5) + go existsFunc() + go existsFunc() + go existsFunc() + go existsFunc() + go existsFunc() - go func() { - b, err := c.Exists(c.Path + "/" + rand) - if err != nil { - t.Error("an error was thrown:", err) - } - if b == true { - t.Error("expected false, got true") - } - res <- true - }() - - go func() { - b, err := c.Exists(c.Path + "/" + rand) - if err != nil { - t.Error("an error was thrown:", err) - } - if b == true { - t.Error("expected false, got true") - } - res <- true - }() - - go func() { - b, err := c.Exists(c.Path + "/" + rand) - if err != nil { - t.Error("an error was thrown:", err) - } - if b == true { - t.Error("expected false, got true") - } - res <- true - }() - - go func() { - b, err := c.Exists(c.Path + "/" + rand) - if err != nil { - t.Error("an error was thrown:", err) - } - if b == true { - t.Error("expected false, got true") - } - res <- true - }() - - <-res - <-res - <-res - <-res - <-res + wg.Wait() } diff --git a/delete_test.go b/delete_test.go index 97d419b..873d5e8 100644 --- a/delete_test.go +++ b/delete_test.go @@ -11,23 +11,23 @@ import ( ) func TestDelete(t *testing.T) { - rand := strconv.Itoa(rand.Int()) + randomValue := strconv.Itoa(rand.Int()) c := cheapcash.Default() - err := c.Write(rand, []byte("value")) + err := c.Write(randomValue, []byte("value")) if err != nil { t.Error("an error was thrown:", err) } - err = c.Delete(rand) + err = c.Delete(randomValue) if err != nil { t.Error("an error was thrown:", err) } } func TestDelete_Concurrency(t *testing.T) { - rand := strconv.Itoa(rand.Int()) + randomValue := strconv.Itoa(rand.Int()) c := cheapcash.Default() - err := c.Write(rand, []byte("value")) + err := c.Write(randomValue, []byte("value")) if err != nil { t.Error("an error was thrown:", err) } @@ -35,7 +35,7 @@ func TestDelete_Concurrency(t *testing.T) { var wg sync.WaitGroup deleteFunc := func() { - err = c.Delete(rand) + err = c.Delete(randomValue) if err != nil && !errors.Is(err, cheapcash.ErrNotExists) { t.Error("an error was thrown:", err) } diff --git a/reader_test.go b/reader_test.go index 86d6527..1a0bcb8 100644 --- a/reader_test.go +++ b/reader_test.go @@ -11,14 +11,14 @@ import ( ) func TestRead(t *testing.T) { - rand := strconv.Itoa(rand.Int()) + randomValue := strconv.Itoa(rand.Int()) c := cheapcash.Default() - err := c.Write(rand, []byte("value")) + err := c.Write(randomValue, []byte("value")) if err != nil { t.Error("an error was thrown:", err) } - v, err := c.Read(rand) + v, err := c.Read(randomValue) if err != nil { t.Error("an error was thrown:", err) } @@ -28,10 +28,10 @@ func TestRead(t *testing.T) { } func TestRead_Concurrency(t *testing.T) { - rand := strconv.Itoa(rand.Int()) + randomValue := strconv.Itoa(rand.Int()) c := cheapcash.Default() - err := c.Write(rand, []byte("value")) + err := c.Write(randomValue, []byte("value")) if err != nil { t.Error("an error was thrown:", err) } @@ -39,7 +39,7 @@ func TestRead_Concurrency(t *testing.T) { var wg sync.WaitGroup readFunc := func() { - r, err := c.Read(rand) + r, err := c.Read(randomValue) if err != nil { t.Error("an error was thrown:", err) } @@ -60,10 +60,10 @@ func TestRead_Concurrency(t *testing.T) { } func TestRead_NotExists(t *testing.T) { - rand := strconv.Itoa(rand.Int()) + randomValue := strconv.Itoa(rand.Int()) c := cheapcash.Default() - _, err := c.Read(rand) + _, err := c.Read(randomValue) if err == nil { t.Error("expected an error, got nil") } diff --git a/rename.go b/rename.go new file mode 100644 index 0000000..31e3717 --- /dev/null +++ b/rename.go @@ -0,0 +1,35 @@ +package cheapcash + +import "os" + +func (c *Cache) Rename(old, new string) error { + err := checkDir(sanitizePath(c.Path)) + if err != nil { + return err + } + + checkOld, err := c.Exists(c.Path + old) + if err != nil { + return err + } + + checkNew, err := c.Exists(c.Path + new) + if err != nil { + return err + } + + if !checkOld { + return ErrNotExists + } + + if checkNew { + return ErrExists + } + + err = os.Rename(c.Path+old, c.Path+new) + if err != nil { + return err + } + + return nil +} diff --git a/rename_test.go b/rename_test.go new file mode 100644 index 0000000..3b992d9 --- /dev/null +++ b/rename_test.go @@ -0,0 +1,102 @@ +package cheapcash_test + +import ( + "errors" + "math/rand" + "strconv" + "sync" + "testing" + + "github.com/aldy505/cheapcash" +) + +func TestRename(t *testing.T) { + randomValue := strconv.Itoa(rand.Int()) + randomValue2 := strconv.Itoa(rand.Int()) + + c := cheapcash.Default() + + err := c.Write(randomValue, []byte("Another random value")) + if err != nil { + t.Error("an error was thrown:", err) + } + + err = c.Rename(randomValue, randomValue2) + if err != nil { + t.Error("an error was thrown:", err) + } + + v, err := c.Read(randomValue2) + if err != nil { + t.Error("an error was thrown:", err) + } + + if string(v) != "Another random value" { + t.Errorf("expected %s, got %v", "Another random value", string(v)) + } + + _, err = c.Read(randomValue) + if err != nil && !errors.Is(err, cheapcash.ErrNotExists) { + t.Error("expected ErrNotExists, got:", err.Error()) + } +} + +func TestRename_Concurrency(t *testing.T) { + randomValue := strconv.Itoa(rand.Int()) + randomValue2 := strconv.Itoa(rand.Int()) + + c := cheapcash.Default() + err := c.Write(randomValue, []byte("Another random value")) + if err != nil { + t.Error("an error was thrown:", err) + } + + var wg sync.WaitGroup + + renameFunc := func() { + err = c.Rename(randomValue, randomValue2) + if err != nil && !errors.Is(err, cheapcash.ErrNotExists) { + t.Error("an error was thrown", err) + } + wg.Done() + } + + wg.Add(5) + go renameFunc() + go renameFunc() + go renameFunc() + go renameFunc() + go renameFunc() + wg.Wait() +} + +func TestRename_OldNotExists(t *testing.T) { + randomValue := strconv.Itoa(rand.Int()) + + c := cheapcash.Default() + err := c.Rename(randomValue, "test") + if !errors.Is(err, cheapcash.ErrNotExists) { + t.Error("expected ErrNotExists, got:", err) + } +} + +func TestRename_NewExists(t *testing.T) { + randomValue := strconv.Itoa(rand.Int()) + randomValue2 := strconv.Itoa(rand.Int()) + + c := cheapcash.Default() + err := c.Write(randomValue, []byte("value")) + if err != nil { + t.Error("an error was thrown:", err) + } + + err = c.Write(randomValue2, []byte("value")) + if err != nil { + t.Error("an error was thrown:", err) + } + + err = c.Rename(randomValue, randomValue2) + if !errors.Is(err, cheapcash.ErrExists) { + t.Error("expected ErrExists, got:", err) + } +} diff --git a/writer_test.go b/writer_test.go index 97fc6c3..303e83c 100644 --- a/writer_test.go +++ b/writer_test.go @@ -41,15 +41,15 @@ func TestWrite_Concurrency(t *testing.T) { } func TestWrite_Exists(t *testing.T) { - rand := strconv.Itoa(rand.Int()) + randomValue := strconv.Itoa(rand.Int()) c := cheapcash.Default() - err := c.Write(rand, []byte("value")) + err := c.Write(randomValue, []byte("value")) if err != nil { t.Error("an error was thrown:", err) } - err = c.Write(rand, []byte("another value")) + err = c.Write(randomValue, []byte("another value")) if err != nil { t.Error("an error was thrown:", err) }