decred.org/dcrdex@v1.0.5/dex/config/config_test.go (about) 1 package config 2 3 import ( 4 "fmt" 5 "path/filepath" 6 "testing" 7 8 "gopkg.in/ini.v1" 9 ) 10 11 type config struct { 12 Key1 string `ini:"key1"` 13 Key2 bool `ini:"key2"` 14 Key3 int `ini:"key3"` 15 KEY4 float64 // defaults to field name i.e. `ini:"KEY4"` 16 Key5 string `ini:"-"` // ignored because of '-' ini tag 17 } 18 19 // defaultConfig returns config with default values. 20 func defaultConfig() config { 21 return config{ 22 Key1: "default value", 23 Key2: true, 24 Key3: 0, 25 KEY4: 3.142, 26 Key5: "ignored", 27 } 28 } 29 30 // makeConfig returns a pointer to a config with default values. 31 func makeConfigPtr() *config { 32 c := defaultConfig() 33 return &c 34 } 35 36 // TestConfigParsing tests the Parse() and ParseInto() functions. 37 func TestConfigParsing(t *testing.T) { 38 var testConfig = defaultConfig() 39 40 tempDir := t.TempDir() 41 cfgFilePath := filepath.Join(tempDir, "test.conf") 42 cfgFile := ini.Empty() 43 err := cfgFile.ReflectFrom(&testConfig) 44 if err != nil { 45 t.Fatalf("error creating temporary config file: %v", err) 46 } 47 err = cfgFile.SaveTo(cfgFilePath) 48 if err != nil { 49 t.Fatalf("error creating temporary config file: %v", err) 50 } 51 52 type expectations struct { 53 parseError bool 54 optionsCount int 55 parseIntoError bool 56 parsedCfg config 57 } 58 59 type test struct { 60 name string 61 cfgData any 62 parsedCfg any 63 expect expectations 64 } 65 66 testCount := 0 67 makeOkTest := func(name, sectionHeader, secondSectionHeader string) test { 68 testCount++ 69 value1 := fmt.Sprintf("value %d", testCount) 70 value4 := 1.1 * float64(testCount) 71 cfgDataString := fmt.Sprintf(` 72 %v 73 key1=%v 74 key2=false 75 %v 76 key3=%v 77 KEY4=%v 78 key5=parsed as option, but not populated into struct 79 `, sectionHeader, value1, secondSectionHeader, testCount, value4) 80 81 return test{ 82 name: name, 83 cfgData: []byte(cfgDataString), 84 parsedCfg: makeConfigPtr(), 85 expect: expectations{ 86 parseError: false, 87 optionsCount: 5, 88 parseIntoError: false, 89 parsedCfg: config{ 90 Key1: value1, 91 Key2: false, 92 Key3: testCount, 93 KEY4: value4, 94 Key5: testConfig.Key5, // should be unchanged 95 }, 96 }, 97 } 98 } 99 100 // Prepare test data. 101 tests := []test{ 102 makeOkTest("ok, with default application options header", "[Application Options]", ""), 103 makeOkTest("ok, with random section header", "[Random Header]", ""), 104 makeOkTest("ok, with multiple section headers", "[Application Options]", "[Random Options]"), 105 makeOkTest("ok, with no section header", "", ""), 106 { 107 name: "ok, with file path", 108 cfgData: cfgFilePath, 109 parsedCfg: makeConfigPtr(), 110 expect: expectations{ 111 parseError: false, 112 optionsCount: 4, // file was created from struct with only 4 valid ini fields 113 parseIntoError: false, 114 parsedCfg: defaultConfig(), 115 }, 116 }, 117 { 118 name: "parse error, file path, parsedCfg obj not pointer", 119 cfgData: cfgFilePath, 120 parsedCfg: defaultConfig(), // not a pointer 121 expect: expectations{ 122 parseError: false, 123 optionsCount: 4, // file was created from cfg struct with only 4 valid ini fields 124 parseIntoError: true, 125 }, 126 }, 127 { 128 name: "parse error, []byte data, parsedCfg obj not pointer", 129 cfgData: []byte(` 130 key1=value 1 131 key2=false 132 key3=10 133 `), 134 parsedCfg: defaultConfig(), // not a pointer 135 expect: expectations{ 136 parseError: false, 137 optionsCount: 3, 138 parseIntoError: true, 139 }, 140 }, 141 { 142 name: "error, malformed section header", 143 cfgData: []byte(` 144 [Random Options 145 key1=value 1 146 key2=false 147 key3=10 148 `), 149 parsedCfg: makeConfigPtr(), 150 expect: expectations{ 151 parseError: true, 152 parseIntoError: true, 153 }, 154 }, 155 { 156 name: "error, malformed option", 157 cfgData: []byte(` 158 =value 1 159 key2=false 160 key3=10 161 `), 162 parsedCfg: makeConfigPtr(), 163 expect: expectations{ 164 parseError: true, 165 parseIntoError: true, 166 }, 167 }, 168 } 169 // Test Parse() and ParseInto() functions. 170 for _, tt := range tests { 171 parsedOptions, err := Parse(tt.cfgData) 172 if tt.expect.parseError && err == nil { 173 t.Fatalf("%s: expected Parse() to error but got no error", tt.name) 174 } else if !tt.expect.parseError && err != nil { 175 t.Fatalf("%s: got unexpected Parse() error: %v", tt.name, err) 176 } 177 if len(parsedOptions) != tt.expect.optionsCount { 178 t.Fatalf("%s: expected %d options, got %d", tt.name, tt.expect.optionsCount, len(parsedOptions)) 179 } 180 181 err = ParseInto(tt.cfgData, tt.parsedCfg) 182 if tt.expect.parseIntoError && err != nil { 183 return 184 } 185 if tt.expect.parseIntoError && err == nil { 186 t.Fatalf("%s: expected ParseInto() to error but got no error", tt.name) 187 } else if !tt.expect.parseIntoError && err != nil { 188 t.Fatalf("%s: got unexpected ParseInto() error: %v", tt.name, err) 189 } 190 191 parsedCfg, ok := tt.parsedCfg.(*config) 192 if !ok { 193 t.Fatalf("%s: unexpected type for parsed config", tt.name) 194 } 195 if parsedCfg.Key1 != tt.expect.parsedCfg.Key1 { 196 t.Fatalf("%s: expected parsed cfg key1 to have '%v', got '%v'", tt.name, tt.expect.parsedCfg.Key1, 197 parsedCfg.Key1) 198 } 199 if parsedCfg.Key2 != tt.expect.parsedCfg.Key2 { 200 t.Fatalf("%s: expected parsed cfg key2 to have '%v', got '%v'", tt.name, tt.expect.parsedCfg.Key2, 201 parsedCfg.Key2) 202 } 203 if parsedCfg.Key3 != tt.expect.parsedCfg.Key3 { 204 t.Fatalf("%s: expected parsed cfg key3 to have '%v', got '%v'", tt.name, tt.expect.parsedCfg.Key3, 205 parsedCfg.Key3) 206 } 207 if parsedCfg.KEY4 != tt.expect.parsedCfg.KEY4 { 208 t.Fatalf("%s: expected parsed cfg key4 to have '%v', got '%v'", tt.name, tt.expect.parsedCfg.KEY4, 209 parsedCfg.KEY4) 210 } 211 if parsedCfg.Key5 != tt.expect.parsedCfg.Key5 { 212 t.Fatalf("%s: expected parsed cfg key5 to have '%v', got '%v'", tt.name, tt.expect.parsedCfg.Key5, 213 parsedCfg.Key3) 214 } 215 216 mapifiedCfg, err := Mapify(tt.parsedCfg) 217 if err != nil { 218 t.Fatalf("%s: unexpected error from Mapify: %v", tt.name, err) 219 } 220 221 if len(mapifiedCfg) != 4 { 222 t.Fatalf("%s: expected all keys except ignored to be in map, but got %v", tt.name, len(mapifiedCfg)) 223 } 224 } 225 } 226 227 // Test Data() function to convert map to config data (in []byte). 228 func DataConversion(t *testing.T) { 229 m := map[string]string{ 230 "key1": "value1", 231 "key2": "false", 232 "key3": "3", 233 "KEY4": "4.4", 234 "key5": "parsed, but not populated into struct", 235 } 236 cfgData := Data(m) 237 238 opts, err := Parse(cfgData) 239 if err != nil { 240 t.Fatalf("unexpected error when parsing cfg data generated from map: %v", err) 241 } 242 if len(opts) != len(m) { 243 t.Fatalf("map-cfg-map: expected %d options, got %d", len(m), len(opts)) 244 } 245 for k, vOriginal := range m { 246 if vParsed, ok := opts[k]; !ok { 247 t.Fatalf("map-cfg-map: key '%s' not found in parsed options", k) 248 } else if vParsed != vOriginal { 249 t.Fatalf("map-cfg-map: unexpected value for key '%s', expected '%s', got '%s'", k, vOriginal, vParsed) 250 } 251 } 252 253 var cfg = makeConfigPtr() 254 err = ParseInto(cfgData, cfg) 255 if err != nil { 256 t.Fatalf("unexpected error when parsing cfg data generated from map into obj: %v", err) 257 } 258 if cfg.Key1 != m["key1"] { 259 t.Fatalf("map-cfg-obh: unexpected value for key 'key1', expected '%s', got '%s'", m["key1"], cfg.Key1) 260 } 261 if cfg.Key5 != defaultConfig().Key5 { 262 t.Fatalf("map-cfg-obh: expected value for key 'key5' not to change, changed to '%s'", cfg.Key5) 263 } 264 }