diff options
| author | Shulhan <ms@kilabit.info> | 2019-05-26 03:28:53 +0700 |
|---|---|---|
| committer | Shulhan <ms@kilabit.info> | 2019-05-26 03:35:02 +0700 |
| commit | 671de3811ee64e7224fe8056290f5d3da2a1556d (patch) | |
| tree | d33c7bac71d125393e20af3aa2538dbe2bb3fa29 | |
| parent | 9e0f6248bce30a6517c8d8cf3a08e3e7fa748c2a (diff) | |
| download | pakakeh.go-671de3811ee64e7224fe8056290f5d3da2a1556d.tar.xz | |
ini: refactoring section methods
This is the fifth part of refactoring ini package.
Some of the changes,
* add() now will append the new variable if the same already exist but
the value is different.
* remove unused getFirstIndex() method
* add method getVariable() that return the last variable in the section
by key
* set() method will not add or append new variable if key is not exist,
instead it will return false.
* unset() method will remove the last variable on section, even if key
is duplicate.
| -rw-r--r-- | lib/ini/ini_test.go | 11 | ||||
| -rw-r--r-- | lib/ini/section.go | 135 | ||||
| -rw-r--r-- | lib/ini/section_test.go | 414 |
3 files changed, 306 insertions, 254 deletions
diff --git a/lib/ini/ini_test.go b/lib/ini/ini_test.go index 803f67c7..859b63cc 100644 --- a/lib/ini/ini_test.go +++ b/lib/ini/ini_test.go @@ -5,7 +5,6 @@ package ini import ( - "os" "testing" "github.com/shuLhan/share/lib/debug" @@ -20,16 +19,6 @@ const ( testdataVarWithoutSection = "testdata/var_without_section.ini" ) -var ( - sec *section //nolint: gochecknoglobals - lastSec *section //nolint: gochecknoglobals -) - -func TestMain(m *testing.M) { - sec = newSection("test", "") - os.Exit(m.Run()) -} - func TestOpen(t *testing.T) { cases := []struct { desc string diff --git a/lib/ini/section.go b/lib/ini/section.go index db0589c8..898393c9 100644 --- a/lib/ini/section.go +++ b/lib/ini/section.go @@ -91,21 +91,46 @@ func (sec *section) String() string { // // add append variable with `key` and `value` to current section. // -// If section already contains the same key, the value will not be replaced. -// Use set() or ReplaceAll() to set existing value without duplication. // If key is empty, no variable will be appended. // If value is empty, it will be set to true. +// If key and value already exist, no variable will be appended. +// Use set() or replaceAll() to set existing value without duplication. // -func (sec *section) add(key, value string) { +// It will return true if new variable is appended, otherwise it will return +// false. +// +func (sec *section) add(key, value string) bool { if len(key) == 0 { - return + return false + } + if len(value) == 0 { + value = varValueTrue + } + + keyLower := strings.ToLower(key) + + for x := 0; x < len(sec.vars); x++ { + if !isLineModeVar(sec.vars[x].mode) { + continue + } + if sec.vars[x].keyLower != keyLower { + continue + } + if sec.vars[x].value == value { + return false + } } + v := &variable{ - mode: lineModeValue, - key: key, - value: value, + mode: lineModeValue, + key: key, + keyLower: keyLower, + value: value, } - sec.addVariable(v) + + sec.vars = append(sec.vars, v) + + return true } // @@ -153,31 +178,6 @@ func (sec *section) addVariable(v *variable) { } // -// getFirstIndex will return the first index of variable `key`. If current -// section have duplicate `key` it will return true. -// If no variable with key found it will return -1 and false. -// -func (sec *section) getFirstIndex(key string) (idx int, dup bool) { - idx = -1 - n := 0 - for x := 0; x < len(sec.vars); x++ { - if sec.vars[x].keyLower != key { - continue - } - if idx < 0 { - idx = x - } - n++ - if n > 1 { - dup = true - return - } - } - - return -} - -// // get will return the last variable value based on key. // If no key found it will return default value and false. // @@ -204,6 +204,25 @@ func (sec *section) get(key, def string) (val string, ok bool) { } // +// getVariable return the last variable that have the same key. +// The key MUST have been converted to lowercase. +// +func (sec *section) getVariable(key string) (idx int, v *variable) { + idx = len(sec.vars) - 1 + for ; idx >= 0; idx-- { + if !isLineModeVar(sec.vars[idx].mode) { + continue + } + if sec.vars[idx].keyLower == key { + v = sec.vars[idx] + return + } + } + + return 0, nil +} + +// // gets all variable values that have the same key under section from top to // bottom. // If no key found it will return default values and false. @@ -241,68 +260,46 @@ func (sec *section) replaceAll(key, value string) { // // set will replace variable with matching key with value. -// If key is empty, no variable will be changed or added, and it will -// return false. -// If section contains two or more variable with the same `key`, it will -// return false. -// If no variable key matched, the new variable will be added to list. +// The key MUST be not empty and has been converted to lowercase. // If value is empty, it will be set to true. // func (sec *section) set(key, value string) bool { - if len(key) == 0 { + if len(sec.vars) == 0 || len(key) == 0 { return false } - keyLower := strings.ToLower(key) + key = strings.ToLower(key) - idx, dup := sec.getFirstIndex(keyLower) - if dup { + _, v := sec.getVariable(key) + if v == nil { return false } - - if idx < 0 { - sec.addVariable(&variable{ - mode: lineModeValue, - key: key, - value: value, - }) - return true - } - if len(value) == 0 { - sec.vars[idx].value = varValueTrue - } else { - sec.vars[idx].value = value + value = varValueTrue } + v.value = value + return true } // -// unset remove the variable with name `key` on current section. -// -// If key is empty, no variable will be removed, and it will return true. -// -// If current section contains two or more variables with the same key, -// no variables will be removed and it will return false. +// unset remove the last variable with name `key` on current section. // -// On success, where no variable removed or one variable is removed, it will -// return true. +// On success, where a variable removed or one variable is removed, it will +// return true, otherwise it will be removed. // func (sec *section) unset(key string) bool { if len(key) == 0 { - return true + return false } key = strings.ToLower(key) - idx, dup := sec.getFirstIndex(key) - if dup { + idx, v := sec.getVariable(key) + if v == nil { return false } - if idx < 0 { - return true - } copy(sec.vars[idx:], sec.vars[idx+1:]) sec.vars[len(sec.vars)-1] = nil diff --git a/lib/ini/section_test.go b/lib/ini/section_test.go index d0bf3d37..3e7df78e 100644 --- a/lib/ini/section_test.go +++ b/lib/ini/section_test.go @@ -51,6 +51,23 @@ func TestNewSection(t *testing.T) { } func TestSectionSet(t *testing.T) { + sec := §ion{ + mode: lineModeSection, + name: "section", + nameLower: "section", + vars: []*variable{{ + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v1", + }, { + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v2", + }}, + } + cases := []struct { desc string k string @@ -58,15 +75,8 @@ func TestSectionSet(t *testing.T) { expOK bool expSec *section }{{ - desc: "With empty key", - expSec: §ion{ - mode: sec.mode, - name: sec.name, - nameLower: sec.nameLower, - }, - }, { - desc: "With empty value (Key-1) (will be added)", - k: "Key-1", + desc: "With empty value", + k: "k", expOK: true, expSec: §ion{ mode: sec.mode, @@ -74,14 +84,19 @@ func TestSectionSet(t *testing.T) { nameLower: sec.nameLower, vars: []*variable{{ mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", + key: "k", + keyLower: "k", + value: "v1", + }, { + mode: lineModeValue, + key: "k", + keyLower: "k", value: "true", }}, }, }, { - desc: "With new value (Key-1)", - k: "Key-1", + desc: "With value", + k: "k", v: "false", expOK: true, expSec: §ion{ @@ -90,50 +105,14 @@ func TestSectionSet(t *testing.T) { nameLower: sec.nameLower, vars: []*variable{{ mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", - value: "false", - }}, - }, - }, { - desc: "With key not found (Key-2) (added)", - k: "Key-2", - v: "2", - expOK: true, - expSec: §ion{ - mode: sec.mode, - name: sec.name, - nameLower: sec.nameLower, - vars: []*variable{{ - mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", - value: "false", + key: "k", + keyLower: "k", + value: "v1", }, { mode: lineModeValue, - key: "Key-2", - keyLower: "key-2", - value: "2", - }}, - }, - }, { - desc: "With empty value on Key-2 (true)", - k: "Key-2", - expOK: true, - expSec: §ion{ - mode: sec.mode, - name: sec.name, - nameLower: sec.nameLower, - vars: []*variable{{ - mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", + key: "k", + keyLower: "k", value: "false", - }, { - mode: lineModeValue, - key: "Key-2", - keyLower: "key-2", - value: "true", }}, }, }} @@ -145,72 +124,97 @@ func TestSectionSet(t *testing.T) { test.Assert(t, "ok", c.expOK, ok, true) test.Assert(t, "section", c.expSec, sec, true) - - lastSec = c.expSec } } func TestSectionAdd(t *testing.T) { + sec := §ion{ + mode: lineModeSection, + name: "section", + nameLower: "section", + vars: []*variable{{ + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v1", + }, { + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v2", + }}, + } + cases := []struct { desc string k string v string expSec *section }{{ - desc: "Empty key (no change)", - expSec: lastSec, + desc: "With empty key", + expSec: §ion{ + mode: sec.mode, + name: sec.name, + nameLower: sec.nameLower, + vars: []*variable{{ + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v1", + }, { + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v2", + }}, + }, }, { - desc: "Duplicate key-1 (no value)", - k: "Key-1", + desc: "With no value", + k: "k", expSec: §ion{ mode: sec.mode, name: sec.name, nameLower: sec.nameLower, vars: []*variable{{ mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", - value: "false", + key: "k", + keyLower: "k", + value: "v1", }, { mode: lineModeValue, - key: "Key-2", - keyLower: "key-2", - value: "true", + key: "k", + keyLower: "k", + value: "v2", }, { mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", + key: "k", + keyLower: "k", value: "true", }}, }, }, { - desc: "Duplicate key-1 (1)", - k: "Key-1", - v: "1", + desc: "Duplicate key and value", + k: "k", + v: "v1", expSec: §ion{ mode: sec.mode, name: sec.name, nameLower: sec.nameLower, vars: []*variable{{ mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", - value: "false", + key: "k", + keyLower: "k", + value: "v1", }, { mode: lineModeValue, - key: "Key-2", - keyLower: "key-2", - value: "true", + key: "k", + keyLower: "k", + value: "v2", }, { mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", + key: "k", + keyLower: "k", value: "true", - }, { - mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", - value: "1", }}, }, }} @@ -221,84 +225,54 @@ func TestSectionAdd(t *testing.T) { sec.add(c.k, c.v) test.Assert(t, "section", c.expSec, sec, true) - - lastSec = c.expSec } } -func TestSectionSet2(t *testing.T) { - cases := []struct { - desc string - k string - v string - expOK bool - expSec *section - }{{ - desc: "Set duplicate Key-1", - k: "Key-1", - v: "new value", - expSec: lastSec, - }, { - desc: "Set duplicate key-1", - k: "key-1", - v: "new value", - expSec: lastSec, - }} - - for _, c := range cases { - t.Log(c.desc) - - ok := sec.set(c.k, c.v) - - test.Assert(t, "ok", c.expOK, ok, true) - test.Assert(t, "section", c.expSec, sec, true) - - lastSec = c.expSec +func TestSectionUnset(t *testing.T) { + sec := §ion{ + mode: lineModeSection, + name: "section", + nameLower: "section", + vars: []*variable{{ + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v1", + }, { + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v2", + }}, } -} -func TestSectionUnset(t *testing.T) { cases := []struct { desc string k string expOK bool expSec *section }{{ - desc: "With empty key", - expOK: true, - expSec: lastSec, - }, { - desc: "With duplicate key-1", - k: "key-1", - expSec: lastSec, - }, { - desc: "With valid key-2", - k: "key-2", - expOK: true, + desc: "With empty key", + expOK: false, expSec: §ion{ mode: sec.mode, name: sec.name, nameLower: sec.nameLower, vars: []*variable{{ mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", - value: "false", - }, { - mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", - value: "true", + key: "k", + keyLower: "k", + value: "v1", }, { mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", - value: "1", + key: "k", + keyLower: "k", + value: "v2", }}, }, }, { - desc: "With valid key-2 (again)", - k: "key-2", + desc: "With duplicate key", + k: "k", expOK: true, expSec: §ion{ mode: sec.mode, @@ -306,21 +280,35 @@ func TestSectionUnset(t *testing.T) { nameLower: sec.nameLower, vars: []*variable{{ mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", - value: "false", - }, { - mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", - value: "true", - }, { + key: "k", + keyLower: "k", + value: "v1", + }}, + }, + }, { + desc: "With invalid key", + k: "key-2", + expSec: §ion{ + mode: sec.mode, + name: sec.name, + nameLower: sec.nameLower, + vars: []*variable{{ mode: lineModeValue, - key: "Key-1", - keyLower: "key-1", - value: "1", + key: "k", + keyLower: "k", + value: "v1", }}, }, + }, { + desc: "With valid key (again)", + k: "k", + expOK: true, + expSec: §ion{ + mode: sec.mode, + name: sec.name, + nameLower: sec.nameLower, + vars: []*variable{}, + }, }} for _, c := range cases { @@ -330,34 +318,79 @@ func TestSectionUnset(t *testing.T) { test.Assert(t, "ok", c.expOK, ok, true) test.Assert(t, "section", c.expSec, sec, true) - - lastSec = c.expSec } } func TestSectionUnsetAll(t *testing.T) { + sec := §ion{ + mode: lineModeSection, + name: "section", + nameLower: "section", + vars: []*variable{{ + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v1", + }, { + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v2", + }}, + } + cases := []struct { desc string k string expSec *section }{{ - desc: "With empty key", - expSec: lastSec, + desc: "With empty key", + expSec: §ion{ + mode: sec.mode, + name: sec.name, + nameLower: sec.nameLower, + vars: []*variable{{ + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v1", + }, { + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v2", + }}, + }, }, { - desc: "With invalid key-3", - k: "key-3", - expSec: lastSec, + desc: "With unmatch key", + k: "unmatch", + expSec: §ion{ + mode: sec.mode, + name: sec.name, + nameLower: sec.nameLower, + vars: []*variable{{ + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v1", + }, { + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v2", + }}, + }, }, { - desc: "With valid key-1", - k: "KEY-1", + desc: "With valid k", + k: "K", expSec: §ion{ mode: sec.mode, name: sec.name, nameLower: sec.nameLower, }, }, { - desc: "With valid key-1 (again)", - k: "KEY-1", + desc: "With valid key (again)", + k: "K", expSec: §ion{ mode: sec.mode, name: sec.name, @@ -371,13 +404,15 @@ func TestSectionUnsetAll(t *testing.T) { sec.unsetAll(c.k) test.Assert(t, "section", c.expSec, sec, true) - - lastSec = c.expSec } } func TestSectionReplaceAll(t *testing.T) { - sec.addVariable(nil) + sec := §ion{ + mode: lineModeSection, + name: "section", + nameLower: "section", + } sec.add("key-3", "3") sec.add("key-3", "33") @@ -418,7 +453,7 @@ func TestSectionReplaceAll(t *testing.T) { }}, }, }, { - desc: "With invalid key-4 (will be added)", + desc: "With invalid key", k: "KEY-4", v: "4", expSec: §ion{ @@ -453,7 +488,7 @@ func TestSectionReplaceAll(t *testing.T) { }}, }, }, { - desc: "With valid key-3", + desc: "With valid key", k: "KEY-3", v: "replaced", expSec: §ion{ @@ -484,6 +519,23 @@ func TestSectionReplaceAll(t *testing.T) { } func TestSectionGet(t *testing.T) { + sec := §ion{ + mode: lineModeSection, + name: "section", + nameLower: "section", + vars: []*variable{{ + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v1", + }, { + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v2", + }}, + } + cases := []struct { desc string k string @@ -491,19 +543,16 @@ func TestSectionGet(t *testing.T) { expOK bool expVal string }{{ - desc: "On empty vars", - k: "key-1", - }, { - desc: "On empty vars with default", + desc: "With invalid key and default", k: "key-1", def: "default value", expVal: "default value", }, { desc: "Valid key", - k: "key-3", + k: "k", def: "default value", expOK: true, - expVal: "replaced", + expVal: "v2", }} for _, c := range cases { @@ -517,6 +566,23 @@ func TestSectionGet(t *testing.T) { } func TestSectionGets(t *testing.T) { + sec := §ion{ + mode: lineModeSection, + name: "section", + nameLower: "section", + vars: []*variable{{ + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v1", + }, { + mode: lineModeValue, + key: "k", + keyLower: "k", + value: "v2", + }}, + } + sec.add("dup", "value 1") sec.add("dup", "value 2") |
