From 7923305e1a538396eec42d7468eec953c0c5eeff Mon Sep 17 00:00:00 2001 From: Fabio Scotto di Santolo Date: Fri, 6 Oct 2017 21:33:29 +0200 Subject: [PATCH] init commit --- .gitignore | 16 +++- ini_test.properties | 3 + parser.go | 51 ++++++++++++ properties.go | 109 ++++++++++++++++++++++++++ properties_test.go | 186 ++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 364 insertions(+), 1 deletion(-) create mode 100644 ini_test.properties create mode 100644 parser.go create mode 100644 properties.go create mode 100644 properties_test.go diff --git a/.gitignore b/.gitignore index 541f92c..ef15dee 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,15 @@ -# Add any directories, files, or patterns you don't want to be tracked by version control \ No newline at end of file +# Add any directories, files, or patterns you don't want to be tracked by version control +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ \ No newline at end of file diff --git a/ini_test.properties b/ini_test.properties new file mode 100644 index 0000000..9e42047 --- /dev/null +++ b/ini_test.properties @@ -0,0 +1,3 @@ +TEST="RIUSCITO" +TEST2="PROVIAMO DDDDD" +URL="http://www.google.com" diff --git a/parser.go b/parser.go new file mode 100644 index 0000000..92fe5f2 --- /dev/null +++ b/parser.go @@ -0,0 +1,51 @@ +package properties + +import ( + "bufio" + "io" + "os" + "path/filepath" + "strings" +) + +// ParseFunction -- type +type ParseFunction func(string, string) (map[string]string, error) + +// Default parse method for parsing key - value file +func defaultParse(path, fileName string) (m map[string]string, err error) { + absolutePathFile, err := filepath.Abs(filepath.Join(path, fileName)) + if err != nil { + return nil, err + } + file, err := os.Open(absolutePathFile) + if err != nil { + return nil, err + } + + defer file.Close() + m = make(map[string]string) + reader := bufio.NewReader(file) + for { + line, err := reader.ReadString('\n') + + // check if the line has = sign + // and process the line. Ignore the rest. + if equal := strings.Index(line, "="); equal >= 0 { + if key := strings.TrimSpace(line[:equal]); len(key) > 0 { + value := "" + if len(line) > equal { + value = strings.TrimSpace(strings.Replace(line[equal+1:], "\"", "", -1)) + } + // assign the values map + m[key] = value + } + } + if err == io.EOF { + break + } + if err != nil { + return nil, err + } + } + return m, nil +} diff --git a/properties.go b/properties.go new file mode 100644 index 0000000..ae4c423 --- /dev/null +++ b/properties.go @@ -0,0 +1,109 @@ +package properties + +import ( + e "errors" + "path/filepath" + "strings" +) + +// Properties -- type +type Properties struct { + fileName string + path string + values map[string]string + length int +} + +// New -- Make new Properties object +func New(path, fileName string) Properties { + return Properties{ + fileName: fileName, + path: filepath.Clean(path), + values: make(map[string]string), + length: 0, + } +} + +// FileName -- Getter for filename's property file +func (p Properties) FileName() string { + return p.fileName +} + +// SetFileName -- Setter filename's property file +func (p *Properties) SetFileName(fileName string) { + p.fileName = fileName +} + +// Path -- Getter for path of property file +func (p Properties) Path() string { + return p.path +} + +// SetPath -- Setter for path of property file +func (p *Properties) SetPath(path string) { + p.path = path +} + +// Length -- Getter length of property file +func (p Properties) Length() int { + return p.length +} + +// Values -- Getter values of property file +func (p Properties) Values() map[string]string { + return p.values +} + +// Put -- Put key - value in the Properties object +func (p *Properties) Put(key, value string) error { + if key == "" || len(strings.TrimSpace(key)) == 0 { + return e.New("Key value is nil") + } + if p.values != nil { + p.values[key] = value + p.length++ + } else { + return e.New("Property values is nil") + } + return nil +} + +// Get -- Get value associated with key +func (p Properties) Get(key string) (string, error) { + if key == "" || len(strings.TrimSpace(key)) == 0 { + return "", e.New("Key value is nil") + } + if _, ok := p.values[key]; !ok { + return "", e.New("Key not found") + } + return p.values[key], nil +} + +// GetProperties -- Get all key value in Properties object +func (p Properties) GetProperties() (keys []string) { + for key := range p.values { + keys = append(keys, key) + } + return keys +} + +// DefaultLoad -- Load file in Properties object using default parse function +func (p *Properties) DefaultLoad() (int, error) { + return p.Load(defaultParse) +} + +// Load -- Load file in Properties object with specific parse function +func (p *Properties) Load(pf ParseFunction) (int, error) { + m, err := pf(p.path, p.fileName) + if err != nil { + return 0, err + } + p.values = m + p.length = len(m) + return len(m), nil +} + +// Store -- Create or modify property file with +func (p Properties) Store() { + // TODO method not implemeted +} diff --git a/properties_test.go b/properties_test.go new file mode 100644 index 0000000..9799f19 --- /dev/null +++ b/properties_test.go @@ -0,0 +1,186 @@ +package properties_test + +import ( + "os" + "path/filepath" + "testing" + + prop "bitbucket.org/fabio_scotto_di_santolo/properties" +) + +const FILENAME = "ini_test.properties" + +func TestNew(t *testing.T) { + path, _ := filepath.Abs(FILENAME) + p := prop.New(path, FILENAME) + if p.FileName() != FILENAME { + t.Failed() + } + if p.Path() != path { + t.Failed() + } + if p.Length() != 0 { + t.Failed() + } +} + +func TestFileName(t *testing.T) { + path, _ := filepath.Abs(FILENAME) + p := prop.New(path, FILENAME) + if p.FileName() != FILENAME { + t.Failed() + } +} + +func TestSetFileName(t *testing.T) { + path, _ := filepath.Abs(FILENAME) + p := prop.New(path, FILENAME) + if p.FileName() != FILENAME { + t.Failed() + } + if p.SetFileName("TEST"); p.FileName() == FILENAME { + t.Failed() + } + + if p.FileName() != "TEST" { + t.Failed() + } +} + +func TestPath(t *testing.T) { + path, _ := filepath.Abs(FILENAME) + p := prop.New(path, FILENAME) + if p.Path() != path { + t.Failed() + } +} + +func TestSetPath(t *testing.T) { + path, _ := filepath.Abs(FILENAME) + p := prop.New(path, FILENAME) + if p.Path() != path { + t.Failed() + } + if p.SetPath("TEST"); p.Path() == path { + t.Failed() + } + + if p.Path() != "TEST" { + t.Failed() + } +} + +func TestPutErrorKeyNoValue(t *testing.T) { + path, _ := filepath.Abs(FILENAME) + p := prop.New(path, FILENAME) + if err := p.Put("", "TEST"); err == nil { + t.Failed() + } else { + t.Logf("\n[DEBUG] %s\n", err.Error()) + } +} + +func TestPutErrorKeyValueWithSpaces(t *testing.T) { + path, _ := filepath.Abs(FILENAME) + p := prop.New(path, FILENAME) + if err := p.Put(" ", "TEST"); err == nil { + t.Failed() + } else { + t.Logf("\n[DEBUG] %s\n", err.Error()) + } +} + +func TestPutErrorPropertyNil(t *testing.T) { + var p prop.Properties + if err := p.Put("KEY", "VALUE"); err == nil { + t.Failed() + } else { + t.Logf("\n[DEBUG] %s\n", err.Error()) + } +} + +func TestPut(t *testing.T) { + path, _ := filepath.Abs(FILENAME) + p := prop.New(path, FILENAME) + if err := p.Put("KEY", "VALUE"); err != nil { + t.Failed() + } else { + t.Logf("\n[DEBUG] Length of property: %d\n", p.Length()) + } +} + +func TestGetErrorKeyNoValue(t *testing.T) { + path, _ := filepath.Abs(FILENAME) + p := prop.New(path, FILENAME) + if _, err := p.Get(""); err == nil { + t.Failed() + } else { + t.Logf("\n[DEBUG] %s\n", err.Error()) + } +} + +func TestGetErrorKeyValueWithSpaces(t *testing.T) { + path, _ := filepath.Abs(FILENAME) + p := prop.New(path, FILENAME) + if _, err := p.Get(" "); err == nil { + t.Failed() + } else { + t.Logf("\n[DEBUG] %s\n", err.Error()) + } +} + +func TestGetErrorKeyNotFound(t *testing.T) { + path, _ := filepath.Abs(FILENAME) + p := prop.New(path, FILENAME) + if _, err := p.Get("TEST"); err == nil { + t.Failed() + } else { + t.Logf("\n[DEBUG] %s\n", err.Error()) + } +} + +func TestGet(t *testing.T) { + path, _ := filepath.Abs(FILENAME) + p := prop.New(path, FILENAME) + p.Put("key1", "value1") + p.Put("key2", "value2") + p.Put("key3", "value3") + p.Put("key4", "value4") + p.Put("key5", "value5") + if value, err := p.Get("key4"); err != nil { + t.Failed() + } else if value != "value4" { + t.Failed() + } +} + +func TestGetProperties(t *testing.T) { + path, _ := filepath.Abs(FILENAME) + p := prop.New(path, FILENAME) + p.Put("key1", "value1") + p.Put("key2", "value2") + p.Put("key3", "value3") + p.Put("key4", "value4") + p.Put("key5", "value5") + keys := p.GetProperties() + length := len(keys) + if length != p.Length() { + t.Failed() + } +} + +func TestDefaultLoad(t *testing.T) { + path, _ := os.Getwd() + p := prop.New(path, FILENAME) + if rowNumber, err := p.DefaultLoad(); rowNumber == 3 { + if p.Length() != rowNumber { + t.Failed() + } + for key, value := range p.Values() { + t.Logf("%s = %s\n", key, value) + } + } else if err != nil { + t.Logf("\n[!!] Failed error %s\n", err.Error()) + t.Failed() + } +}