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  }