Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package basic_key_value_store

import (
"bufio"
"fmt"
"os"
"strings"
"sync"
)

Expand All @@ -27,29 +31,83 @@ func (e *StoreError) Error() string {

func NewKeyValueStore(filepath string) *KeyValueStore {
// TODO: initialize the store
return &KeyValueStore{}
return &KeyValueStore{
data: make(map[string]string),
filepath: filepath,
}
}

func (s *KeyValueStore) Load() error {
// TODO: load key/value pairs from file if present
return nil
s.mu.Lock()
defer s.mu.Unlock()

file, err := os.Open(s.filepath)
if err != nil {
if os.IsNotExist(err) {
return nil
}
return err
}
defer file.Close()

scanner := bufio.NewScanner(file)
for scanner.Scan() {
line := scanner.Text()
parts := strings.SplitN(line, "=", 2)
if len(parts) == 2 {
s.data[parts[0]] = parts[1]
}
}

return scanner.Err()
}

func (s *KeyValueStore) Save() error {
// TODO: write pairs to file
return nil
s.mu.Lock()
defer s.mu.Unlock()
file, err := os.Create(s.filepath)
if err != nil {
return err
}
defer file.Close()

writer := bufio.NewWriter(file)
for k, v := range s.data {
_, err := fmt.Fprintf(writer, "%s=%s\n", k, v)
if err != nil {
return err
}
}
return writer.Flush()
}

func (s *KeyValueStore) Set(key, value string) {
// TODO: set key to value
s.mu.Lock()
defer s.mu.Unlock()
s.data[key] = value
}

func (s *KeyValueStore) Get(key string) (string, *StoreError) {
// TODO: get value or return error when missing
return "", nil
s.mu.RLock()
defer s.mu.RUnlock()
val, ok := s.data[key]
if !ok {
return "", &StoreError{Message: "key not found"}
}
return val, nil
}

func (s *KeyValueStore) Delete(key string) *StoreError {
// TODO: delete key or return error when missing
s.mu.Lock()
defer s.mu.Unlock()
if _, ok := s.data[key]; !ok {
return &StoreError{Message: "key not found"}
}
delete(s.data, key)
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,94 +5,61 @@ import (
"testing"
)

func TestNewKeyValueStore(t *testing.T) {
filepath := "test_kv_store.txt"
s := NewKeyValueStore(filepath)
if s == nil {
t.Errorf("Expected a new KeyValueStore, got nil")
}
if s.filepath != filepath {
t.Errorf("Expected filepath %s, got %s", filepath, s.filepath)
}
if s.data == nil {
t.Errorf("Expected data map to be initialized, got nil")
}
// helper to clean up after tests
func cleanup(filename string) {
_ = os.Remove(filename)
}

func TestSetAndGet(t *testing.T) {
filepath := "test_set_get.txt"
defer os.Remove(filepath)

s := NewKeyValueStore(filepath)
s.Set("name", "Alice")
s.Set("age", "30")
func TestLoadAndSave(t *testing.T) {
filename := "test_store.db"
defer cleanup(filename)

val, err := s.Get("name")
if err != nil || val != "Alice" {
t.Errorf("Expected 'Alice', got %q, error: %v", val, err)
}
store := NewKeyValueStore(filename)

val, err = s.Get("age")
if err != nil || val != "30" {
t.Errorf("Expected '30', got %q, error: %v", val, err)
}
// Save data
store.Set("city", "New York")
store.Set("country", "USA")

_, err = s.Get("nonexistent")
if err == nil {
t.Errorf("Expected error for non-existent key, got nil")
// Persist to file
if err := store.Save(); err != nil {
t.Fatalf("failed to save: %v", err)
}
}

func TestDelete(t *testing.T) {
filepath := "test_delete.txt"
defer os.Remove(filepath)
// Create a new store instance to load from file
store2 := NewKeyValueStore(filename)

s := NewKeyValueStore(filepath)
s.Set("key1", "value1")

err := s.Delete("key1")
if err != nil {
t.Errorf("Expected no error, got %v", err)
// Reload data
if err := store2.Load(); err != nil {
t.Fatalf("failed to load: %v", err)
}

_, err = s.Get("key1")
if err == nil {
t.Errorf("Expected error for deleted key, got nil")
// Verify city
val, err := store2.Get("city")
if err != nil {
t.Errorf("unexpected error: %v", err)
}

err = s.Delete("nonexistent")
if err == nil {
t.Errorf("Expected error for deleting non-existent key, got nil")
if val != "New York" {
t.Errorf("Expected %q, got %q", "New York", val)
}
}

func TestLoadAndSave(t *testing.T) {
filepath := "test_load_save.txt"
defer os.Remove(filepath)

// Create a store and save it
s1 := NewKeyValueStore(filepath)
s1.Set("city", "New York")
s1.Set("country", "USA")
err := s1.Save()
// Verify country
val, err = store2.Get("country")
if err != nil {
t.Fatalf("Failed to save store: %v", err)
t.Errorf("unexpected error: %v", err)
}

// Load into a new store
s2 := NewKeyValueStore(filepath)
err = s2.Load()
if err != nil {
t.Fatalf("Failed to load store: %v", err)
if val != "USA" {
t.Errorf("Expected %q, got %q", "USA", val)
}
}

val, err := s2.Get("city")
if err != nil || val != "New York" {
t.Errorf("Expected 'New York', got %q, error: %v", val, err)
}
func TestMissingKey(t *testing.T) {
filename := "test_store_missing.db"
defer cleanup(filename)

store := NewKeyValueStore(filename)

val, err = s2.Get("country")
if err != nil || val != "USA" {
t.Errorf("Expected 'USA', got %q, error: %v", val, err)
_, err := store.Get("notthere")
if err == nil {
t.Errorf("expected error for missing key, got nil")
}
}