...

Source file src/edge-infra.dev/pkg/sds/lib/systemd/systemdconfig/systemdconfig_test.go

Documentation: edge-infra.dev/pkg/sds/lib/systemd/systemdconfig

     1  package systemdconfig
     2  
     3  import (
     4  	"errors"
     5  	"testing"
     6  
     7  	"github.com/stretchr/testify/assert"
     8  )
     9  
    10  var (
    11  	defaultSectionLines = "#  This file is part of systemd.\n#\n#  systemd is free software; you can redistribute it and/or modify it\n#  under the terms of the GNU Lesser General Public License as published by\n#  the Free Software Foundation; either version 2.1 of the License, or\n#  (at your option) any later version.\n#\n# Entries in this file show the compile time defaults.\n# You can change settings by editing this file.\n# Defaults can be restored by simply deleting this file.\n#\n# See systemd.syntax(7) for details."
    12  	defaultSection      = &Section{
    13  		map[string]*Field{
    14  			"!0":  {"", "", "#  This file is part of systemd."},
    15  			"!1":  {"", "", "#"},
    16  			"!2":  {"", "", "#  systemd is free software; you can redistribute it and/or modify it"},
    17  			"!3":  {"", "", "#  under the terms of the GNU Lesser General Public License as published by"},
    18  			"!4":  {"", "", "#  the Free Software Foundation; either version 2.1 of the License, or"},
    19  			"!5":  {"", "", "#  (at your option) any later version."},
    20  			"!6":  {"", "", "#"},
    21  			"!7":  {"", "", "# Entries in this file show the compile time defaults."},
    22  			"!8":  {"", "", "# You can change settings by editing this file."},
    23  			"!9":  {"", "", "# Defaults can be restored by simply deleting this file."},
    24  			"!10": {"", "", "#"},
    25  			"!11": {"", "", "# See systemd.syntax(7) for details."},
    26  		},
    27  		[]string{"!0", "!1", "!2", "!3", "!4", "!5", "!6", "!7", "!8", "!9", "!10", "!11"},
    28  	}
    29  
    30  	testSectionAHeader = "[Section A]"
    31  	testSectionALines  = "KeyOne=value 1\nKeyTwo=value 2\nKeyThree=value 3\n#KeyFour=value 4 ; comment\n;KeyFive=value 5\n\nKeySix=value 6"
    32  	testSectionA       = &Section{
    33  		map[string]*Field{
    34  			"KeyOne":   {"KeyOne", "value 1", ""},
    35  			"KeyTwo":   {"KeyTwo", "value 2", ""},
    36  			"KeyThree": {"KeyThree", "value 3", ""},
    37  			"KeyFour":  {"#KeyFour", "value 4", "; comment"},
    38  			"KeyFive":  {";KeyFive", "value 5", ""},
    39  			"!5":       {"", "", ""},
    40  			"KeySix":   {"KeySix", "value 6", ""},
    41  		},
    42  		[]string{"KeyOne", "KeyTwo", "KeyThree", "KeyFour", "KeyFive", "!5", "KeySix"},
    43  	}
    44  	testSectionAUpdated = &Section{
    45  		map[string]*Field{
    46  			"KeyOne":   {"KeyOne", "value 1", ""},
    47  			"KeyTwo":   {"KeyTwo", "value updated", ""},
    48  			"KeyThree": {"KeyThree", "value 3", ""},
    49  			"KeyFour":  {"#KeyFour", "value 4", "; comment"},
    50  			"KeyFive":  {";KeyFive", "value 5", ""},
    51  			"!5":       {"", "", ""},
    52  			"KeySix":   {"KeySix", "value 6", ""},
    53  		},
    54  		[]string{"KeyOne", "KeyTwo", "KeyThree", "KeyFour", "KeyFive", "!5", "KeySix"},
    55  	}
    56  	testSectionAKeyRemoved = &Section{
    57  		map[string]*Field{
    58  			"KeyOne":  {"KeyOne", "value 1", ""},
    59  			"KeyTwo":  {"KeyTwo", "value 2", ""},
    60  			"KeyFour": {"#KeyFour", "value 4", "; comment"},
    61  			"KeyFive": {";KeyFive", "value 5", ""},
    62  			"!5":      {"", "", ""},
    63  			"KeySix":  {"KeySix", "value 6", ""},
    64  		},
    65  		[]string{"KeyOne", "KeyTwo", "KeyFour", "KeyFive", "!5", "KeySix"},
    66  	}
    67  	testSectionBHeader = "[Section B]"
    68  	testSectionBLines  = "#KeyOne=value 1\n\nKeyTwo=value 2 # comment\n;KeyThree=value 3\n#KeyFour=value 4"
    69  	testSectionB       = &Section{
    70  		map[string]*Field{
    71  			"KeyOne":   {"#KeyOne", "value 1", ""},
    72  			"!1":       {"", "", ""},
    73  			"KeyTwo":   {"KeyTwo", "value 2", "# comment"},
    74  			"KeyThree": {";KeyThree", "value 3", ""},
    75  			"KeyFour":  {"#KeyFour", "value 4", ""},
    76  		},
    77  		[]string{"KeyOne", "!1", "KeyTwo", "KeyThree", "KeyFour"},
    78  	}
    79  	testSectionBUpdated = &Section{
    80  		map[string]*Field{
    81  			"KeyOne":   {"#KeyOne", "value 1", ""},
    82  			"!1":       {"", "", ""},
    83  			"KeyTwo":   {"KeyTwo", "value 2", "# comment"},
    84  			"KeyThree": {";KeyThree", "value 3", ""},
    85  			"KeyFour":  {"KeyFour", "value updated", ""},
    86  		},
    87  		[]string{"KeyOne", "!1", "KeyTwo", "KeyThree", "KeyFour"},
    88  	}
    89  	testSectionCHeader = "[Section C]"
    90  	testSectionCLines  = "#KeyOne=value 1\n#KeyTwo=\n#KeyThree=value 3\n#KeyFour=value 4\n# comment\n;KeyFive=value 5"
    91  	testSectionC       = &Section{
    92  		map[string]*Field{
    93  			"KeyOne":   {"#KeyOne", "value 1", ""},
    94  			"KeyTwo":   {"#KeyTwo", "", ""},
    95  			"KeyThree": {"#KeyThree", "value 3", ""},
    96  			"KeyFour":  {"#KeyFour", "value 4", ""},
    97  			"!4":       {"", "", "# comment"},
    98  			"KeyFive":  {";KeyFive", "value 5", ""},
    99  		},
   100  		[]string{"KeyOne", "KeyTwo", "KeyThree", "KeyFour", "!4", "KeyFive"},
   101  	}
   102  	testSectionCKeyAdded = &Section{
   103  		map[string]*Field{
   104  			"KeyOne":   {"#KeyOne", "value 1", ""},
   105  			"KeyTwo":   {"#KeyTwo", "", ""},
   106  			"KeyThree": {"#KeyThree", "value 3", ""},
   107  			"KeyFour":  {"#KeyFour", "value 4", ""},
   108  			"!4":       {"", "", "# comment"},
   109  			"KeyFive":  {";KeyFive", "value 5", ""},
   110  			"NewKey":   {"NewKey", "value added", ""},
   111  		},
   112  		[]string{"KeyOne", "KeyTwo", "KeyThree", "KeyFour", "!4", "KeyFive", "NewKey"},
   113  	}
   114  	testSectionD = &Section{map[string]*Field{}, []string{}}
   115  
   116  	testSystemdConfig = &SystemdConfig{
   117  		sections:              map[string]*Section{defaultSectionHeader: defaultSection, testSectionAHeader: testSectionA, testSectionBHeader: testSectionB, testSectionCHeader: testSectionC},
   118  		orderedSectionHeaders: []string{defaultSectionHeader, testSectionAHeader, testSectionBHeader, testSectionCHeader},
   119  	}
   120  	testSystemdConfigKeyValueUpdated = &SystemdConfig{
   121  		sections:              map[string]*Section{defaultSectionHeader: defaultSection, testSectionAHeader: testSectionAUpdated, testSectionBHeader: testSectionB, testSectionCHeader: testSectionC},
   122  		orderedSectionHeaders: []string{defaultSectionHeader, testSectionAHeader, testSectionBHeader, testSectionCHeader},
   123  	}
   124  	testSystemdConfigCommentedKeyValueUpdated = &SystemdConfig{
   125  		sections:              map[string]*Section{defaultSectionHeader: defaultSection, testSectionAHeader: testSectionA, testSectionBHeader: testSectionBUpdated, testSectionCHeader: testSectionC},
   126  		orderedSectionHeaders: []string{defaultSectionHeader, testSectionAHeader, testSectionBHeader, testSectionCHeader},
   127  	}
   128  	testSystemdConfigKeyAdded = &SystemdConfig{
   129  		sections:              map[string]*Section{defaultSectionHeader: defaultSection, testSectionAHeader: testSectionA, testSectionBHeader: testSectionB, testSectionCHeader: testSectionCKeyAdded},
   130  		orderedSectionHeaders: []string{defaultSectionHeader, testSectionAHeader, testSectionBHeader, testSectionCHeader},
   131  	}
   132  	testSystemdConfigKeyRemoved = &SystemdConfig{
   133  		sections:              map[string]*Section{defaultSectionHeader: defaultSection, testSectionAHeader: testSectionAKeyRemoved, testSectionBHeader: testSectionB, testSectionCHeader: testSectionC},
   134  		orderedSectionHeaders: []string{defaultSectionHeader, testSectionAHeader, testSectionBHeader, testSectionCHeader},
   135  	}
   136  	testSystemdConfigSectionRemoved = &SystemdConfig{
   137  		sections:              map[string]*Section{defaultSectionHeader: defaultSection, testSectionAHeader: testSectionA, testSectionCHeader: testSectionC},
   138  		orderedSectionHeaders: []string{defaultSectionHeader, testSectionAHeader, testSectionCHeader},
   139  	}
   140  
   141  	testData                       = []byte(defaultSectionLines + "\n\n" + testSectionAHeader + "\n" + testSectionALines + "\n\n" + testSectionBHeader + "\n" + testSectionBLines + "\n\n" + testSectionCHeader + "\n" + testSectionCLines)
   142  	testInvalidKey                 = []byte(defaultSectionLines + "\n\n" + testSectionAHeader + "\n" + "KeyOne=value 1\nKey!!!=value 2\nKeyThree=value 3")
   143  	testEmptyKey                   = []byte(defaultSectionLines + "\n\n" + testSectionAHeader + "\n" + "KeyOne=value 1\n#=value 2\nKeyThree=value 3")
   144  	testValueWithoutKey            = []byte(defaultSectionLines + "\n\n" + testSectionAHeader + "\n" + "KeyOne=value 1\n=value 2\nKeyThree=value 3")
   145  	testMultiLineValueNotSupported = []byte(defaultSectionLines + "\n\n" + testSectionAHeader + "\n" + "KeyOne=value 1\nKeyTwo=value 2\nKeyThree=value 3\\\ncontinued")
   146  	testInvalidLine                = []byte(defaultSectionLines + "\n\n" + testSectionAHeader + "\n" + "KeyOne=value 1\ninvalid line\nKeyThree=value 3")
   147  )
   148  
   149  // Tests SyntaxError displays correct message
   150  func TestSyntaxError(t *testing.T) {
   151  	expectedErr := errors.New("context: error message")
   152  	err := &SyntaxError{"context", errors.New("error message")}
   153  	assert.Equal(t, expectedErr.Error(), err.Error())
   154  }
   155  
   156  // Tests UnsupportedError displays correct message
   157  func TestUnsupportedError(t *testing.T) {
   158  	expectedErr := errors.New("context: error message")
   159  	err := &UnsupportedError{"context", errors.New("error message")}
   160  	assert.Equal(t, expectedErr.Error(), err.Error())
   161  }
   162  
   163  // Tests SystemdConfig can be built from byte data as expected
   164  func TestLoadFromBytes(t *testing.T) {
   165  	tests := []struct {
   166  		inputBytes           []byte
   167  		expectedSystemConfig *SystemdConfig
   168  		expectedErr          error
   169  	}{
   170  		{testData, testSystemdConfig, nil},                    // create SystemdConfig as expected
   171  		{testInvalidKey, nil, &SyntaxError{}},                 // invalid characters in key
   172  		{testEmptyKey, nil, &SyntaxError{}},                   // empty commented key (#=...) should fail
   173  		{testValueWithoutKey, nil, &SyntaxError{}},            // value without key (=...) should fail
   174  		{testInvalidLine, nil, &SyntaxError{}},                // non-commented text (abc...) should fail
   175  		{testMultiLineValueNotSupported, nil, &SyntaxError{}}, // multi-line values are not supported and should fail
   176  	}
   177  	for i, test := range tests {
   178  		systemdConfig, err := LoadFromBytes(test.inputBytes)
   179  		assert.Equal(t, test.expectedSystemConfig, systemdConfig)
   180  		if test.expectedErr != nil {
   181  			assert.ErrorAs(t, err, &tests[i].expectedErr)
   182  		} else {
   183  			assert.NoError(t, err)
   184  		}
   185  	}
   186  }
   187  
   188  // Tests only syntactically correct section headers are validated
   189  func TestSectionHeaderIsValid(t *testing.T) {
   190  	tests := []struct {
   191  		inputLine      string
   192  		expectedResult bool
   193  	}{
   194  		{"[Time]", true},
   195  		{"[section]", true},
   196  		{"not-section", false},
   197  		{"not[section]", false},
   198  		{"[[not] section]", false},
   199  		{"[test section]", true},
   200  	}
   201  	for _, test := range tests {
   202  		result := sectionHeaderIsValid(test.inputLine)
   203  		assert.Equal(t, test.expectedResult, result)
   204  	}
   205  }
   206  
   207  // Tests byte output of the SystemdConfig is as expected
   208  func TestBytes(t *testing.T) {
   209  	bytes := testSystemdConfig.Bytes()
   210  	assert.Equal(t, testData, bytes)
   211  }
   212  
   213  // Test changes to deep copy do not affect original
   214  func TestDeepCopySystemdConfig(t *testing.T) {
   215  	systemdConfig := testSystemdConfig                                                 // original
   216  	systemdConfigCopied := systemdConfig.DeepCopy()                                    // (deep) copy
   217  	_ = systemdConfigCopied.Section("[Section A]").SetField("KeyOne", "value updated") // update copy
   218  	assert.NotEqual(t, systemdConfig, systemdConfigCopied)                             // assert copy was changed
   219  	assert.Equal(t, testSystemdConfig, systemdConfig)                                  // assert original has not been changed
   220  }
   221  
   222  // Test correct sections are returned for SystemdConfig
   223  func TestListSectionsFromSystemdConfig(t *testing.T) {
   224  	expectedSections := []string{testSectionAHeader, testSectionBHeader, testSectionCHeader}
   225  	sections := testSystemdConfig.ListSections()
   226  	assert.Equal(t, expectedSections, sections)
   227  }
   228  
   229  // Test section can be added to SystemdConfig
   230  func TestAddSectionToSystemdConfig(t *testing.T) {
   231  	// section is removed as expected
   232  	systemdConfig := testSystemdConfig.DeepCopy()
   233  	assert.NoError(t, systemdConfig.AddSection("[Section D]"))
   234  	assert.Equal(t, testSectionD, systemdConfig.Section("[Section D]"))
   235  
   236  	// invalid section header returns syntax error
   237  	systemdConfig = testSystemdConfig.DeepCopy()
   238  	expectedErr := &SyntaxError{}
   239  	err := systemdConfig.AddSection("Section D")
   240  	assert.ErrorAs(t, err, &expectedErr)
   241  }
   242  
   243  // Tests a section can be removed from the SystemdConfig as expected
   244  func TestRemoveSectionFromSystemdConfig(t *testing.T) {
   245  	// section is removed as expected
   246  	systemdConfig := testSystemdConfig.DeepCopy()
   247  	assert.NoError(t, systemdConfig.RemoveSection("[Section B]"))
   248  	assert.Equal(t, testSystemdConfigSectionRemoved, systemdConfig)
   249  
   250  	// invalid section header returns syntax error
   251  	systemdConfig = testSystemdConfig.DeepCopy()
   252  	expectedErr := &SyntaxError{}
   253  	err := systemdConfig.RemoveSection("Section A")
   254  	assert.ErrorAs(t, err, &expectedErr)
   255  
   256  	// non-existent section header returns nil and removes nothing
   257  	systemdConfig = testSystemdConfig.DeepCopy()
   258  	assert.NoError(t, systemdConfig.RemoveSection("[Section D]"))
   259  	assert.Equal(t, testSystemdConfig, systemdConfig)
   260  }
   261  
   262  // Test check for section in SystemdConfig returns result as expected
   263  func TestSystemdConfigHasSection(t *testing.T) {
   264  	assert.True(t, testSystemdConfig.HasSection("[Section A]"))
   265  	assert.False(t, testSystemdConfig.HasSection("[Section D]"))
   266  	assert.False(t, testSystemdConfig.HasSection("Section A"))
   267  	assert.False(t, testSystemdConfig.HasSection(""))
   268  }
   269  
   270  // Test keys in section are returned as expected
   271  func TestListFieldsForSection(t *testing.T) {
   272  	expectedKeys := []string{"KeyOne", "KeyTwo", "KeyThree", "KeyFour", "KeyFive", "KeySix"}
   273  	keys := testSystemdConfig.Section("[Section A]").ListFields()
   274  	assert.Equal(t, expectedKeys, keys)
   275  }
   276  
   277  // Tests key:value can be set for section in the SystemdConfig as expected
   278  func TestSetFieldInSection(t *testing.T) {
   279  	// update key value
   280  	systemdConfig := testSystemdConfig.DeepCopy()
   281  	assert.NoError(t, systemdConfig.Section("[Section A]").SetField("KeyTwo", "value updated"))
   282  	assert.Equal(t, testSystemdConfigKeyValueUpdated, systemdConfig)
   283  
   284  	// uncomment and update key value
   285  	systemdConfig = testSystemdConfig.DeepCopy()
   286  	assert.NoError(t, systemdConfig.Section("[Section B]").SetField("KeyFour", "value updated"))
   287  	assert.Equal(t, testSystemdConfigCommentedKeyValueUpdated, systemdConfig)
   288  
   289  	// add new key value to section
   290  	systemdConfig = testSystemdConfig.DeepCopy()
   291  	assert.NoError(t, systemdConfig.Section("[Section C]").SetField("NewKey", "value added"))
   292  	assert.Equal(t, testSystemdConfigKeyAdded, systemdConfig)
   293  
   294  	// invalid key returns error and doesn't set new key
   295  	systemdConfig = testSystemdConfig.DeepCopy()
   296  	expectedErr := &SyntaxError{}
   297  	err := systemdConfig.Section("[Section C]").SetField("NewKey!", "value added")
   298  	assert.ErrorAs(t, err, &expectedErr)
   299  	assert.False(t, systemdConfig.Section("[Section C]").HasField("NewKey!"))
   300  
   301  	// invalid value returns error and doesn't set new key
   302  	systemdConfig = testSystemdConfig.DeepCopy()
   303  	expectedErr = &SyntaxError{}
   304  	err = systemdConfig.Section("[Section C]").SetField("NewKey", "value #added")
   305  	assert.ErrorAs(t, err, &expectedErr)
   306  	assert.False(t, systemdConfig.Section("[Section C]").HasField("NewKey"))
   307  
   308  	// multi-line value returns error and doesn't set new key
   309  	systemdConfig = testSystemdConfig.DeepCopy()
   310  	expectedUnsupporedErr := &UnsupportedError{}
   311  	err = systemdConfig.Section("[Section C]").SetField("NewKey", "value added \\")
   312  	assert.ErrorAs(t, err, &expectedUnsupporedErr)
   313  	assert.False(t, systemdConfig.Section("[Section C]").HasField("NewKey"))
   314  }
   315  
   316  // Tests key can be removed from section in the SystemdConfig as expected
   317  func TestRemoveKeyFromSection(t *testing.T) {
   318  	// remove key from section
   319  	systemdConfig := testSystemdConfig.DeepCopy()
   320  	assert.NoError(t, systemdConfig.Section("[Section A]").RemoveField("KeyThree"))
   321  	assert.Equal(t, testSystemdConfigKeyRemoved.Section("[Section A]"), systemdConfig.Section("[Section A]"))
   322  
   323  	// // non-existent key in section returns nil and removes nothing
   324  	systemdConfig = testSystemdConfig.DeepCopy()
   325  	assert.NoError(t, systemdConfig.Section("[Section A]").RemoveField("KeyTen"))
   326  	assert.Equal(t, testSystemdConfig, systemdConfig)
   327  
   328  	// invalid key returns error
   329  	systemdConfig = testSystemdConfig.DeepCopy()
   330  	expectedErr := &SyntaxError{}
   331  	err := systemdConfig.Section("[Section C]").RemoveField("NewKey!")
   332  	assert.ErrorAs(t, err, &expectedErr)
   333  }
   334  
   335  // Test check for key in section returns result as expected
   336  func TestSectionHasKey(t *testing.T) {
   337  	assert.True(t, testSystemdConfig.Section("[Section A]").HasField("KeyOne"))  // existent key
   338  	assert.False(t, testSystemdConfig.Section("[Section A]").HasField("KeyTen")) // non-existent key
   339  	assert.False(t, testSystemdConfig.Section("[Section A]").HasField(""))       // empty key does not exist
   340  }
   341  
   342  // Test check for key literal returns result as expected
   343  func TestFieldHasKey(t *testing.T) {
   344  	assert.True(t, testSystemdConfig.Section("[Section A]").Field("KeyOne").HasKey())  // uncommented key has literal
   345  	assert.True(t, testSystemdConfig.Section("[Section A]").Field("KeyFive").HasKey()) // commented key has literal
   346  	assert.False(t, testSystemdConfig.Section("[Section C]").Field("!4").HasKey())     // comment line has no literal
   347  	assert.False(t, testSystemdConfig.Section("[Section A]").Field("!5").HasKey())     // empty line has no literal
   348  }
   349  
   350  // Test key literal can be commented
   351  func TestFieldKeyIsCommented(t *testing.T) {
   352  	// uncommented key is commented
   353  	expectedKey := "#KeyOne"
   354  	systemdConfig := testSystemdConfig.DeepCopy()
   355  	systemdConfig.Section("[Section A]").Field("KeyOne").CommentKey()
   356  	assert.Equal(t, expectedKey, systemdConfig.Section("[Section A]").Field("KeyOne").GetKey())
   357  
   358  	// commented key is left as is
   359  	expectedKey = ";KeyFive"
   360  	systemdConfig = testSystemdConfig.DeepCopy()
   361  	systemdConfig.Section("[Section A]").Field("KeyFive").CommentKey()
   362  	assert.Equal(t, expectedKey, systemdConfig.Section("[Section A]").Field("KeyFive").GetKey())
   363  }
   364  
   365  // Test key literal can be uncommented
   366  func TestFieldKeyIsUncommented(t *testing.T) {
   367  	// commented key is uncommented
   368  	expectedKey := "KeyFive"
   369  	systemdConfig := testSystemdConfig.DeepCopy()
   370  	systemdConfig.Section("[Section A]").Field("KeyFive").UncommentKey()
   371  	assert.Equal(t, expectedKey, systemdConfig.Section("[Section A]").Field("KeyFive").GetKey())
   372  
   373  	// uncommented key is left as is
   374  	expectedKey = "KeyOne"
   375  	systemdConfig = testSystemdConfig.DeepCopy()
   376  	systemdConfig.Section("[Section A]").Field("KeyOne").UncommentKey()
   377  	assert.Equal(t, expectedKey, systemdConfig.Section("[Section A]").Field("KeyOne").GetKey())
   378  }
   379  
   380  // Test value can be set for field
   381  func TestSetValueInField(t *testing.T) {
   382  	// value is set as expected
   383  	expectedValue := "new value"
   384  	systemdConfig := testSystemdConfig.DeepCopy()
   385  	err := systemdConfig.Section("[Section A]").Field("KeyOne").SetValue(expectedValue)
   386  	assert.NoError(t, err)
   387  	assert.Equal(t, expectedValue, systemdConfig.Section("[Section A]").Field("KeyOne").GetValue())
   388  
   389  	// empty value is set as expected
   390  	expectedValue = ""
   391  	systemdConfig = testSystemdConfig.DeepCopy()
   392  	err = systemdConfig.Section("[Section A]").Field("KeyOne").SetValue(expectedValue)
   393  	assert.NoError(t, err)
   394  	assert.Equal(t, expectedValue, systemdConfig.Section("[Section A]").Field("KeyOne").GetValue())
   395  
   396  	// invalid value returns error isn't set
   397  	invalidValue := "new #value"
   398  	expectedErr := &SyntaxError{}
   399  	systemdConfig = testSystemdConfig.DeepCopy()
   400  	err = systemdConfig.Section("[Section A]").Field("KeyOne").SetValue(invalidValue)
   401  	assert.ErrorAs(t, err, &expectedErr)
   402  	assert.Equal(t, testSystemdConfig.Section("[Section A]").Field("KeyOne").GetValue(), systemdConfig.Section("[Section A]").Field("KeyOne").GetValue())
   403  
   404  	// multi-line value returns error isn't set
   405  	multiLineValue := "new value \\"
   406  	expectedUnsupporedErr := &UnsupportedError{}
   407  	systemdConfig = testSystemdConfig.DeepCopy()
   408  	err = systemdConfig.Section("[Section A]").Field("KeyOne").SetValue(multiLineValue)
   409  	assert.ErrorAs(t, err, &expectedUnsupporedErr)
   410  	assert.Equal(t, testSystemdConfig.Section("[Section A]").Field("KeyOne").GetValue(), systemdConfig.Section("[Section A]").Field("KeyOne").GetValue())
   411  }
   412  
   413  // Test value can be set for field
   414  func TestRemoveValueFromField(t *testing.T) {
   415  	// value is removed
   416  	systemdConfig := testSystemdConfig.DeepCopy()
   417  	systemdConfig.Section("[Section A]").Field("KeyOne").RemoveValue()
   418  	assert.Equal(t, "", systemdConfig.Section("[Section A]").Field("KeyOne").GetValue())
   419  
   420  	// no-value is unchanged
   421  	systemdConfig = testSystemdConfig.DeepCopy()
   422  	systemdConfig.Section("[Section C]").Field("KeyTwo").RemoveValue()
   423  	assert.Equal(t, testSystemdConfig.Section("[Section C]").Field("KeyTwo").GetValue(), systemdConfig.Section("[Section C]").Field("KeyTwo").GetValue())
   424  }
   425  
   426  // Test check for value in field returns result as expected
   427  func TestFieldHasValue(t *testing.T) {
   428  	assert.True(t, testSystemdConfig.Section("[Section A]").Field("KeyOne").HasValue())
   429  	assert.False(t, testSystemdConfig.Section("[Section C]").Field("KeyTwo").HasValue())
   430  }
   431  
   432  // Test comment can be set for field
   433  func TestSetCommentInField(t *testing.T) {
   434  	expectedComment := "# new comment"
   435  	systemdConfig := testSystemdConfig.DeepCopy()
   436  	systemdConfig.Section("[Section A]").Field("KeyOne").SetComment("new comment")
   437  	assert.Equal(t, expectedComment, systemdConfig.Section("[Section A]").Field("KeyOne").GetComment())
   438  }
   439  
   440  // Test comment can be set for field
   441  func TestRemoveCommentFromField(t *testing.T) {
   442  	// in-line comment is removed
   443  	systemdConfig := testSystemdConfig.DeepCopy()
   444  	systemdConfig.Section("[Section A]").Field("KeyFour").RemoveComment()
   445  	assert.Equal(t, "", systemdConfig.Section("[Section A]").Field("KeyFour").GetComment())
   446  
   447  	// comment line becomes empty
   448  	systemdConfig = testSystemdConfig.DeepCopy()
   449  	systemdConfig.Section("[Section A]").Field("!5").RemoveComment()
   450  	assert.True(t, systemdConfig.Section("[Section A]").Field("!5").IsEmptyLine())
   451  
   452  	// no-comment is unchanged
   453  	systemdConfig = testSystemdConfig.DeepCopy()
   454  	systemdConfig.Section("[Section A]").Field("KeyOne").RemoveComment()
   455  	assert.Equal(t, testSystemdConfig.Section("[Section A]").Field("KeyOne").GetComment(), systemdConfig.Section("[Section A]").Field("KeyOne").GetComment())
   456  }
   457  
   458  // Test check for comment in field returns result as expected
   459  func TestFieldHasComment(t *testing.T) {
   460  	assert.False(t, testSystemdConfig.Section("[Section A]").Field("KeyOne").HasComment()) // no comment key:value
   461  	assert.False(t, testSystemdConfig.Section("[Section A]").Field("!5").HasComment())     // no comment empty line
   462  	assert.True(t, testSystemdConfig.Section("[Section A]").Field("KeyFour").HasComment()) // in-line comment
   463  	assert.True(t, testSystemdConfig.Section("[Section C]").Field("!4").HasComment())      // comment line
   464  }
   465  

View as plain text