From 1f71cb3bc3ccc04b229ae2eee5f4993b2c178a00 Mon Sep 17 00:00:00 2001 From: George Vilches Date: Fri, 25 Nov 2016 19:17:32 -0500 Subject: [PATCH 1/3] Added support for unparseable sections. --- ini.go | 3 +++ parser.go | 17 +++++++++++++++++ section.go | 9 ++++++++- section_test.go | 28 ++++++++++++++++++++++++++++ testdata/aicc.ini | 11 +++++++++++ 5 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 testdata/aicc.ini diff --git a/ini.go b/ini.go index cd065e7..36d8a0e 100644 --- a/ini.go +++ b/ini.go @@ -164,6 +164,9 @@ type LoadOptions struct { // AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing. // This type of keys are mostly used in my.cnf. AllowBooleanKeys bool + // Some INI formats allow group blocks that store a block of raw content that doesn't otherwise + // conform to key/value pairs. Specify the names of those blocks here. + UnparseableSections []string } func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) { diff --git a/parser.go b/parser.go index dc6df87..3b12d96 100644 --- a/parser.go +++ b/parser.go @@ -235,6 +235,7 @@ func (f *File) parse(reader io.Reader) (err error) { section, _ := f.NewSection(DEFAULT_SECTION) var line []byte + var inUnparseableSection bool for !p.isEOF { line, err = p.readUntil('\n') if err != nil { @@ -280,6 +281,22 @@ func (f *File) parse(reader io.Reader) (err error) { // Reset aotu-counter and comments p.comment.Reset() p.count = 1 + + inUnparseableSection = false + if len(f.options.UnparseableSections) > 0 { + for _, sectionName := range f.options.UnparseableSections { + if sectionName == name || + (f.options.Insensitive && strings.ToLower(sectionName) == strings.ToLower(name)) { + inUnparseableSection = true + continue + } + } + } + continue + } + + if inUnparseableSection { + section.rawBody += string(line) continue } diff --git a/section.go b/section.go index bbb73ca..e3b58d5 100644 --- a/section.go +++ b/section.go @@ -28,10 +28,11 @@ type Section struct { keys map[string]*Key keyList []string keysHash map[string]string + rawBody string } func newSection(f *File, name string) *Section { - return &Section{f, "", name, make(map[string]*Key), make([]string, 0, 10), make(map[string]string)} + return &Section{f, "", name, make(map[string]*Key), make([]string, 0, 10), make(map[string]string), ""} } // Name returns name of Section. @@ -39,6 +40,12 @@ func (s *Section) Name() string { return s.name } +// Body returns rawBody of Section if the section was marked as unparseable. +// It still follows the other rules of the INI format surrounding leading/trailing whitespace. +func (s *Section) Body() string { + return strings.TrimSpace(s.rawBody) +} + // NewKey creates a new key to given section. func (s *Section) NewKey(name, val string) (*Key, error) { if len(name) == 0 { diff --git a/section_test.go b/section_test.go index c6efb2c..80282c1 100644 --- a/section_test.go +++ b/section_test.go @@ -45,3 +45,31 @@ func Test_Section(t *testing.T) { }) }) } + +func Test_SectionRaw(t *testing.T) { + Convey("Test section raw string", t, func() { + cfg, err := LoadSources( + LoadOptions{ + Insensitive: true, + UnparseableSections: []string{"core_lesson", "comments"}, + }, + "testdata/aicc.ini") + So(err, ShouldBeNil) + So(cfg, ShouldNotBeNil) + + Convey("Get section strings", func() { + So(strings.Join(cfg.SectionStrings(), ","), ShouldEqual, "DEFAULT,core,core_lesson,comments") + }) + + Convey("Validate non-raw section", func() { + val, err := cfg.Section("core").GetKey("lesson_status") + So(err, ShouldBeNil) + So(val.String(), ShouldEqual, "C") + }) + + Convey("Validate raw section", func() { + So(cfg.Section("core_lesson").Body(), ShouldEqual, `my lesson state data – 1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000 – end my lesson state data`) + }) + }) +} \ No newline at end of file diff --git a/testdata/aicc.ini b/testdata/aicc.ini new file mode 100644 index 0000000..6b122ac --- /dev/null +++ b/testdata/aicc.ini @@ -0,0 +1,11 @@ +[Core] + Lesson_Location = 87 +Lesson_Status = C + Score = +Time = 00:02:30 + +[CORE_LESSON] +my lesson state data – 1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000 – end my lesson state data +[COMMENTS] +<1> This slide has the fuel listed in the wrong units \ No newline at end of file From f6fe8a58106788e36f1e831aa234b6d0c7a44d6f Mon Sep 17 00:00:00 2001 From: George Vilches Date: Fri, 25 Nov 2016 20:34:38 -0500 Subject: [PATCH 2/3] Add write support for unparseable sections. --- ini.go | 14 ++++++++++++++ ini_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/ini.go b/ini.go index 36d8a0e..5212730 100644 --- a/ini.go +++ b/ini.go @@ -236,6 +236,13 @@ func (f *File) NewSection(name string) (*Section, error) { return f.sections[name], nil } +// NewRawSection creates a new section as an unparseable body. +func (f *File) NewRawSection(name string, body string) (*Section, error) { + section, err := f.NewSection(name) + section.rawBody = body + return section, err +} + // NewSections creates a list of sections. func (f *File) NewSections(names ...string) (err error) { for _, name := range names { @@ -389,6 +396,13 @@ func (f *File) WriteToIndent(w io.Writer, indent string) (n int64, err error) { } } + if sec.rawBody != "" { + if _, err = buf.WriteString(sec.rawBody); err != nil { + return 0, err + } + continue + } + // Count and generate alignment length and buffer spaces using the // longest key. Keys may be modifed if they contain certain characters so // we need to take that into account in our calculation. diff --git a/ini_test.go b/ini_test.go index 66a5098..bc79df8 100644 --- a/ini_test.go +++ b/ini_test.go @@ -357,6 +357,31 @@ NotFound, State, 50000""" }) } +func Test_File_WriteTo_SectionRaw(t *testing.T) { + Convey("Write a INI with a raw section", t, func() { + var buf bytes.Buffer + cfg, err := LoadSources( + LoadOptions{ + UnparseableSections: []string{"CORE_LESSON", "COMMENTS"}, + }, + "testdata/aicc.ini") + So(err, ShouldBeNil) + So(cfg, ShouldNotBeNil) + cfg.WriteToIndent(&buf, "\t") + So(buf.String(), ShouldEqual, `[Core] + Lesson_Location = 87 + Lesson_Status = C + Score = + Time = 00:02:30 + +[CORE_LESSON] +my lesson state data – 1111111111111111111000000000000000001110000 +111111111111111111100000000000111000000000 – end my lesson state data +[COMMENTS] +<1> This slide has the fuel listed in the wrong units `) + }) +} + // Helpers for slice tests. func float64sEqual(values []float64, expected ...float64) { So(values, ShouldHaveLength, len(expected)) From 489bfc9578b41013b879efab9d1f613765d3316c Mon Sep 17 00:00:00 2001 From: George Vilches Date: Fri, 25 Nov 2016 21:12:11 -0500 Subject: [PATCH 3/3] Slightly changed test files to make test results clearer with tools/platforms that handle whitespace differently. --- ini_test.go | 5 +++-- testdata/aicc.ini | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ini_test.go b/ini_test.go index bc79df8..fef7035 100644 --- a/ini_test.go +++ b/ini_test.go @@ -371,14 +371,15 @@ func Test_File_WriteTo_SectionRaw(t *testing.T) { So(buf.String(), ShouldEqual, `[Core] Lesson_Location = 87 Lesson_Status = C - Score = + Score = 3 Time = 00:02:30 [CORE_LESSON] my lesson state data – 1111111111111111111000000000000000001110000 111111111111111111100000000000111000000000 – end my lesson state data [COMMENTS] -<1> This slide has the fuel listed in the wrong units `) +<1> This slide has the fuel listed in the wrong units +`) }) } diff --git a/testdata/aicc.ini b/testdata/aicc.ini index 6b122ac..59a6197 100644 --- a/testdata/aicc.ini +++ b/testdata/aicc.ini @@ -1,11 +1,11 @@ [Core] Lesson_Location = 87 Lesson_Status = C - Score = + Score = 3 Time = 00:02:30 [CORE_LESSON] my lesson state data – 1111111111111111111000000000000000001110000 111111111111111111100000000000111000000000 – end my lesson state data [COMMENTS] -<1> This slide has the fuel listed in the wrong units \ No newline at end of file +<1> This slide has the fuel listed in the wrong units