...
This commit is contained in:
		
							
								
								
									
										137
									
								
								_pkg2_dont_use/heroscript/paramsparser/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								_pkg2_dont_use/heroscript/paramsparser/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,137 @@ | ||||
| # ParamsParser | ||||
|  | ||||
| A Go package for parsing and manipulating parameters from text in a key-value format with support for multiline strings. | ||||
|  | ||||
| ## Features | ||||
|  | ||||
| - Parse parameters in a natural format: `key: 'value' anotherKey: 'another value'` | ||||
| - Support for multiline string values | ||||
| - Support for numeric values without quotes: `port: 25` | ||||
| - Support for boolean-like values: `secure: 1` | ||||
| - Type conversion helpers (string, int, float, boolean) | ||||
| - Default value support | ||||
| - Required parameter validation with panic-on-missing options | ||||
| - Simple and intuitive API | ||||
|  | ||||
| ## Usage | ||||
|  | ||||
| ### Basic Usage | ||||
|  | ||||
| ```go | ||||
| import ( | ||||
|     "git.ourworld.tf/herocode/heroagent/pkg/paramsparser" | ||||
| ) | ||||
|  | ||||
| // Create a new parser | ||||
| parser := paramsparser.New() | ||||
|  | ||||
| // Parse a string with parameters | ||||
| inputStr := ` | ||||
|     name: 'myapp'  | ||||
|     host: 'localhost' | ||||
|     port: 25 | ||||
|     secure: 1 | ||||
|     reset: 1  | ||||
|     description: ' | ||||
|         A multiline description | ||||
|         for my application. | ||||
|     ' | ||||
| ` | ||||
|  | ||||
| err := parser.Parse(inputStr) | ||||
| if err != nil { | ||||
|     // Handle error | ||||
| } | ||||
|  | ||||
| // Or parse a simpler one-line string | ||||
| parser.ParseString("name: 'myapp' version: '1.0' active: 1") | ||||
|  | ||||
| // Set default values | ||||
| parser.SetDefault("host", "localhost") | ||||
| parser.SetDefault("port", "8080") | ||||
|  | ||||
| // Or set multiple defaults at once | ||||
| parser.SetDefaults(map[string]string{ | ||||
|     "debug": "false", | ||||
|     "timeout": "30", | ||||
| }) | ||||
|  | ||||
| // Get values with type conversion | ||||
| name := parser.Get("name") | ||||
| port := parser.GetIntDefault("port", 8080) | ||||
| secure := parser.GetBool("secure") | ||||
| ``` | ||||
|  | ||||
| ### Type Conversion | ||||
|  | ||||
| ```go | ||||
| // String value (with default if not found) | ||||
| value := parser.Get("key") | ||||
|  | ||||
| // Integer value | ||||
| intValue, err := parser.GetInt("key") | ||||
| // Or with default | ||||
| intValue := parser.GetIntDefault("key", 42) | ||||
|  | ||||
| // Float value | ||||
| floatValue, err := parser.GetFloat("key") | ||||
| // Or with default | ||||
| floatValue := parser.GetFloatDefault("key", 3.14) | ||||
|  | ||||
| // Boolean value (true, yes, 1, on are considered true) | ||||
| boolValue := parser.GetBool("key") | ||||
| // Or with default | ||||
| boolValue := parser.GetBoolDefault("key", false) | ||||
| ``` | ||||
|  | ||||
| ### Required Parameters | ||||
|  | ||||
| ```go | ||||
| // These will panic if the parameter is missing or invalid | ||||
| value := parser.MustGet("required_param") | ||||
| intValue := parser.MustGetInt("required_int_param") | ||||
| floatValue := parser.MustGetFloat("required_float_param") | ||||
| ``` | ||||
|  | ||||
| ### Getting All Parameters | ||||
|  | ||||
| ```go | ||||
| // Get all parameters (including defaults) | ||||
| allParams := parser.GetAll() | ||||
| for key, value := range allParams { | ||||
|     fmt.Printf("%s = %s\n", key, value) | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ## Example Input Format | ||||
|  | ||||
| The parser supports the following format: | ||||
|  | ||||
| ``` | ||||
| name: 'myname' host: 'localhost' | ||||
| port: 25 | ||||
| secure: 1 | ||||
| reset: 1  | ||||
| description: ' | ||||
|     a description can be multiline | ||||
|  | ||||
|     like this | ||||
| ' | ||||
| ``` | ||||
|  | ||||
| Key features of the format: | ||||
| - Keys are alphanumeric (plus underscore) | ||||
| - String values are enclosed in single quotes | ||||
| - Numeric values don't need quotes | ||||
| - Boolean values can be specified as 1/0 | ||||
| - Multiline strings start with a single quote and continue until a closing quote is found | ||||
|  | ||||
| ## Example | ||||
|  | ||||
| See the [example](./example/main.go) for a complete demonstration of how to use this package. | ||||
|  | ||||
| ## Running Tests | ||||
|  | ||||
| ```bash | ||||
| go test -v ./pkg/paramsparser | ||||
| ``` | ||||
							
								
								
									
										84
									
								
								_pkg2_dont_use/heroscript/paramsparser/example/main.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								_pkg2_dont_use/heroscript/paramsparser/example/main.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| // Example usage of the paramsparser package | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/heroscript/paramsparser" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	// Create a new parser | ||||
| 	parser := paramsparser.New() | ||||
|  | ||||
| 	// Set some default values | ||||
| 	parser.SetDefaults(map[string]string{ | ||||
| 		"host":     "localhost", | ||||
| 		"port":     "8080", | ||||
| 		"debug":    "false", | ||||
| 		"timeout":  "30", | ||||
| 		"greeting": "Hello, World!", | ||||
| 	}) | ||||
|  | ||||
| 	// Parse a string in the specified format | ||||
| 	inputStr := ` | ||||
| 		name: 'myapp'  | ||||
| 		host: 'example.com' | ||||
| 		port: 25 | ||||
| 		secure: 1 | ||||
| 		reset: 1  | ||||
| 		description: ' | ||||
| 			This is a multiline description | ||||
| 			for my application. | ||||
|  | ||||
| 			It can span multiple lines. | ||||
| 		' | ||||
| 	` | ||||
|  | ||||
| 	err := parser.Parse(inputStr) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error parsing input: %v\n", err) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Access parameters with type conversion | ||||
| 	name := parser.Get("name") | ||||
| 	host := parser.Get("host") | ||||
| 	port := parser.GetIntDefault("port", 8080) | ||||
| 	secure := parser.GetBool("secure") | ||||
| 	reset := parser.GetBool("reset") | ||||
| 	description := parser.Get("description") | ||||
|  | ||||
| 	fmt.Println("Configuration:") | ||||
| 	fmt.Printf("  Name:        %s\n", name) | ||||
| 	fmt.Printf("  Host:        %s\n", host) | ||||
| 	fmt.Printf("  Port:        %d\n", port) | ||||
| 	fmt.Printf("  Secure:      %t\n", secure) | ||||
| 	fmt.Printf("  Reset:       %t\n", reset) | ||||
| 	fmt.Printf("  Description: %s\n", description) | ||||
|  | ||||
| 	// Get all parameters | ||||
| 	fmt.Println("\nAll parameters:") | ||||
| 	for key, value := range parser.GetAll() { | ||||
| 		if key == "description" { | ||||
| 			// Truncate long values for display | ||||
| 			if len(value) > 30 { | ||||
| 				value = value[:30] + "..." | ||||
| 			} | ||||
| 		} | ||||
| 		fmt.Printf("  %s = %s\n", key, value) | ||||
| 	} | ||||
|  | ||||
| 	// Example of using MustGet for required parameters | ||||
| 	if parser.Has("name") { | ||||
| 		fmt.Printf("\nRequired parameter: %s\n", parser.MustGet("name")) | ||||
| 	} | ||||
|  | ||||
| 	// Example of a simpler one-line parse | ||||
| 	simpleParser := paramsparser.New() | ||||
| 	simpleParser.ParseString("name: 'simple' version: '1.0' active: 1") | ||||
| 	fmt.Println("\nSimple parser results:") | ||||
| 	fmt.Printf("  Name:    %s\n", simpleParser.Get("name")) | ||||
| 	fmt.Printf("  Version: %s\n", simpleParser.Get("version")) | ||||
| 	fmt.Printf("  Active:  %t\n", simpleParser.GetBool("active")) | ||||
| } | ||||
							
								
								
									
										447
									
								
								_pkg2_dont_use/heroscript/paramsparser/paramsparser.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										447
									
								
								_pkg2_dont_use/heroscript/paramsparser/paramsparser.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,447 @@ | ||||
| // Package paramsparser provides functionality for parsing and manipulating parameters | ||||
| // from text in a key-value format with support for multiline strings. | ||||
| package paramsparser | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/tools" | ||||
| ) | ||||
|  | ||||
| // ParamsParser represents a parameter parser that can handle various parameter sources | ||||
| type ParamsParser struct { | ||||
| 	params        map[string]string | ||||
| 	defaultParams map[string]string | ||||
| } | ||||
|  | ||||
| // New creates a new ParamsParser instance | ||||
| func New() *ParamsParser { | ||||
| 	return &ParamsParser{ | ||||
| 		params:        make(map[string]string), | ||||
| 		defaultParams: make(map[string]string), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Parse parses a string containing key-value pairs in the format: | ||||
| // key:value or key:'value' | ||||
| // It supports multiline string values. | ||||
| func (p *ParamsParser) Parse(input string) error { | ||||
| 	// Normalize line endings | ||||
| 	input = strings.ReplaceAll(input, "\r\n", "\n") | ||||
|  | ||||
| 	// Track the current state | ||||
| 	var currentKey string | ||||
| 	var currentValue strings.Builder | ||||
| 	var inMultilineString bool | ||||
|  | ||||
| 	// Process each line | ||||
| 	lines := strings.Split(input, "\n") | ||||
| 	for i := 0; i < len(lines); i++ { | ||||
| 		// Only trim space for non-multiline string processing | ||||
| 		var line string | ||||
| 		if !inMultilineString { | ||||
| 			line = strings.TrimSpace(lines[i]) | ||||
| 		} else { | ||||
| 			line = lines[i] | ||||
| 		} | ||||
|  | ||||
| 		// Skip empty lines unless we're in a multiline string | ||||
| 		if line == "" && !inMultilineString { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// If we're in a multiline string | ||||
| 		if inMultilineString { | ||||
| 			// Check if this line ends the multiline string | ||||
| 			if strings.HasSuffix(line, "'") && !strings.HasSuffix(line, "\\'") { | ||||
| 				// Add the line without the closing quote | ||||
| 				currentValue.WriteString(line[:len(line)-1]) | ||||
| 				p.params[currentKey] = currentValue.String() | ||||
| 				inMultilineString = false | ||||
| 				currentKey = "" | ||||
| 				currentValue.Reset() | ||||
| 			} else { | ||||
| 				// Continue the multiline string | ||||
| 				currentValue.WriteString(line) | ||||
| 				currentValue.WriteString("\n") | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// Process the line to extract key-value pairs | ||||
| 		var processedPos int | ||||
| 		for processedPos < len(line) { | ||||
| 			// Skip leading whitespace | ||||
| 			for processedPos < len(line) && (line[processedPos] == ' ' || line[processedPos] == '\t') { | ||||
| 				processedPos++ | ||||
| 			} | ||||
|  | ||||
| 			if processedPos >= len(line) { | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 			// Find the next key by looking for a colon | ||||
| 			keyStart := processedPos | ||||
| 			colonPos := -1 | ||||
|  | ||||
| 			for j := processedPos; j < len(line); j++ { | ||||
| 				if line[j] == ':' { | ||||
| 					colonPos = j | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if colonPos == -1 { | ||||
| 				// No colon found, skip this part | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 			// Extract key and use NameFix to standardize it | ||||
| 			rawKey := strings.TrimSpace(line[keyStart:colonPos]) | ||||
| 			key := tools.NameFix(rawKey) | ||||
|  | ||||
| 			if key == "" { | ||||
| 				// Invalid key, move past the colon and continue | ||||
| 				processedPos = colonPos + 1 | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			// Move position past the colon | ||||
| 			processedPos = colonPos + 1 | ||||
|  | ||||
| 			if processedPos >= len(line) { | ||||
| 				// End of line reached, store empty value | ||||
| 				p.params[key] = "" | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 			// Skip whitespace after the colon | ||||
| 			for processedPos < len(line) && (line[processedPos] == ' ' || line[processedPos] == '\t') { | ||||
| 				processedPos++ | ||||
| 			} | ||||
|  | ||||
| 			if processedPos >= len(line) { | ||||
| 				// End of line reached after whitespace, store empty value | ||||
| 				p.params[key] = "" | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 			// Check if the value is quoted | ||||
| 			if line[processedPos] == '\'' { | ||||
| 				// This is a quoted string | ||||
| 				processedPos++ // Skip the opening quote | ||||
|  | ||||
| 				// Look for the closing quote | ||||
| 				quoteEnd := -1 | ||||
| 				for j := processedPos; j < len(line); j++ { | ||||
| 					// Check for escaped quote | ||||
| 					if line[j] == '\'' && (j == 0 || line[j-1] != '\\') { | ||||
| 						quoteEnd = j | ||||
| 						break | ||||
| 					} | ||||
| 				} | ||||
|  | ||||
| 				if quoteEnd != -1 { | ||||
| 					// Single-line quoted string | ||||
| 					value := line[processedPos:quoteEnd] | ||||
| 					// For quoted values, we preserve the original formatting | ||||
| 					// But for single-line values, we can apply NameFix if needed | ||||
| 					if key != "description" { | ||||
| 						value = tools.NameFix(value) | ||||
| 					} | ||||
| 					p.params[key] = value | ||||
| 					processedPos = quoteEnd + 1 // Move past the closing quote | ||||
| 				} else { | ||||
| 					// Start of multiline string | ||||
| 					currentKey = key | ||||
| 					currentValue.WriteString(line[processedPos:]) | ||||
| 					currentValue.WriteString("\n") | ||||
| 					inMultilineString = true | ||||
| 					break | ||||
| 				} | ||||
| 			} else { | ||||
| 				// This is an unquoted value | ||||
| 				valueStart := processedPos | ||||
| 				valueEnd := valueStart | ||||
|  | ||||
| 				// Find the end of the value (space or end of line) | ||||
| 				for valueEnd < len(line) && line[valueEnd] != ' ' && line[valueEnd] != '\t' { | ||||
| 					valueEnd++ | ||||
| 				} | ||||
|  | ||||
| 				value := line[valueStart:valueEnd] | ||||
| 				// For unquoted values, use NameFix to standardize them | ||||
| 				// This handles the 'without' keyword and other special cases | ||||
| 				p.params[key] = tools.NameFix(value) | ||||
| 				processedPos = valueEnd | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// If we're still in a multiline string at the end, that's an error | ||||
| 	if inMultilineString { | ||||
| 		return errors.New("unterminated multiline string") | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // ParseString is a simpler version that parses a string with the format: | ||||
| // key:value or key:'value' | ||||
| // This version doesn't support multiline strings and is optimized for one-line inputs | ||||
| func (p *ParamsParser) ParseString(input string) error { | ||||
| 	// Trim the input | ||||
| 	input = strings.TrimSpace(input) | ||||
|  | ||||
| 	// Process the input to extract key-value pairs | ||||
| 	var processedPos int | ||||
| 	for processedPos < len(input) { | ||||
| 		// Skip leading whitespace | ||||
| 		for processedPos < len(input) && (input[processedPos] == ' ' || input[processedPos] == '\t') { | ||||
| 			processedPos++ | ||||
| 		} | ||||
|  | ||||
| 		if processedPos >= len(input) { | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		// Find the next key by looking for a colon | ||||
| 		keyStart := processedPos | ||||
| 		colonPos := -1 | ||||
|  | ||||
| 		for j := processedPos; j < len(input); j++ { | ||||
| 			if input[j] == ':' { | ||||
| 				colonPos = j | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if colonPos == -1 { | ||||
| 			// No colon found, skip this part | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		// Extract key and use NameFix to standardize it | ||||
| 		rawKey := strings.TrimSpace(input[keyStart:colonPos]) | ||||
| 		key := tools.NameFix(rawKey) | ||||
|  | ||||
| 		if key == "" { | ||||
| 			// Invalid key, move past the colon and continue | ||||
| 			processedPos = colonPos + 1 | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// Move position past the colon | ||||
| 		processedPos = colonPos + 1 | ||||
|  | ||||
| 		if processedPos >= len(input) { | ||||
| 			// End of input reached, store empty value | ||||
| 			p.params[key] = "" | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		// Skip whitespace after the colon | ||||
| 		for processedPos < len(input) && (input[processedPos] == ' ' || input[processedPos] == '\t') { | ||||
| 			processedPos++ | ||||
| 		} | ||||
|  | ||||
| 		if processedPos >= len(input) { | ||||
| 			// End of input reached after whitespace, store empty value | ||||
| 			p.params[key] = "" | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		// Check if the value is quoted | ||||
| 		if input[processedPos] == '\'' { | ||||
| 			// This is a quoted string | ||||
| 			processedPos++ // Skip the opening quote | ||||
|  | ||||
| 			// Look for the closing quote | ||||
| 			quoteEnd := -1 | ||||
| 			for j := processedPos; j < len(input); j++ { | ||||
| 				// Check for escaped quote | ||||
| 				if input[j] == '\'' && (j == 0 || input[j-1] != '\\') { | ||||
| 					quoteEnd = j | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
|  | ||||
| 			if quoteEnd == -1 { | ||||
| 				return errors.New("unterminated quoted string") | ||||
| 			} | ||||
|  | ||||
| 			value := input[processedPos:quoteEnd] | ||||
| 			// For quoted values in ParseString, we can apply NameFix | ||||
| 			// since this method doesn't handle multiline strings | ||||
| 			if key != "description" { | ||||
| 				value = tools.NameFix(value) | ||||
| 			} | ||||
| 			p.params[key] = value | ||||
| 			processedPos = quoteEnd + 1 // Move past the closing quote | ||||
| 		} else { | ||||
| 			// This is an unquoted value | ||||
| 			valueStart := processedPos | ||||
| 			valueEnd := valueStart | ||||
|  | ||||
| 			// Find the end of the value (space or end of input) | ||||
| 			for valueEnd < len(input) && input[valueEnd] != ' ' && input[valueEnd] != '\t' { | ||||
| 				valueEnd++ | ||||
| 			} | ||||
|  | ||||
| 			value := input[valueStart:valueEnd] | ||||
| 			// For unquoted values, use NameFix to standardize them | ||||
| 			// This handles the 'without' keyword and other special cases | ||||
| 			p.params[key] = tools.NameFix(value) | ||||
| 			processedPos = valueEnd | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // ParseFile parses a file containing key-value pairs | ||||
| func (p *ParamsParser) ParseFile(filename string) error { | ||||
| 	data, err := os.ReadFile(filename) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return p.Parse(string(data)) | ||||
| } | ||||
|  | ||||
| // SetDefault sets a default value for a parameter | ||||
| func (p *ParamsParser) SetDefault(key, value string) { | ||||
| 	p.defaultParams[key] = value | ||||
| } | ||||
|  | ||||
| // SetDefaults sets multiple default values at once | ||||
| func (p *ParamsParser) SetDefaults(defaults map[string]string) { | ||||
| 	for k, v := range defaults { | ||||
| 		p.defaultParams[k] = v | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // Set explicitly sets a parameter value | ||||
| func (p *ParamsParser) Set(key, value string) { | ||||
| 	p.params[key] = value | ||||
| } | ||||
|  | ||||
| // Get retrieves a parameter value, returning the default if not found | ||||
| func (p *ParamsParser) Get(key string) string { | ||||
| 	if value, exists := p.params[key]; exists { | ||||
| 		return value | ||||
| 	} | ||||
| 	if defaultValue, exists := p.defaultParams[key]; exists { | ||||
| 		return defaultValue | ||||
| 	} | ||||
| 	return "" | ||||
| } | ||||
|  | ||||
| // GetInt retrieves a parameter as an integer | ||||
| func (p *ParamsParser) GetInt(key string) (int, error) { | ||||
| 	value := p.Get(key) | ||||
| 	if value == "" { | ||||
| 		return 0, errors.New("parameter not found") | ||||
| 	} | ||||
| 	return strconv.Atoi(value) | ||||
| } | ||||
|  | ||||
| // GetIntDefault retrieves a parameter as an integer with a default value | ||||
| func (p *ParamsParser) GetIntDefault(key string, defaultValue int) int { | ||||
| 	value, err := p.GetInt(key) | ||||
| 	if err != nil { | ||||
| 		return defaultValue | ||||
| 	} | ||||
| 	return value | ||||
| } | ||||
|  | ||||
| // GetBool retrieves a parameter as a boolean | ||||
| func (p *ParamsParser) GetBool(key string) bool { | ||||
| 	value := p.Get(key) | ||||
| 	if value == "" { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	// Check for common boolean string representations | ||||
| 	value = strings.ToLower(value) | ||||
| 	return value == "true" || value == "yes" || value == "1" || value == "on" | ||||
| } | ||||
|  | ||||
| // GetBoolDefault retrieves a parameter as a boolean with a default value | ||||
| func (p *ParamsParser) GetBoolDefault(key string, defaultValue bool) bool { | ||||
| 	if !p.Has(key) { | ||||
| 		return defaultValue | ||||
| 	} | ||||
| 	return p.GetBool(key) | ||||
| } | ||||
|  | ||||
| // GetFloat retrieves a parameter as a float64 | ||||
| func (p *ParamsParser) GetFloat(key string) (float64, error) { | ||||
| 	value := p.Get(key) | ||||
| 	if value == "" { | ||||
| 		return 0, errors.New("parameter not found") | ||||
| 	} | ||||
| 	return strconv.ParseFloat(value, 64) | ||||
| } | ||||
|  | ||||
| // GetFloatDefault retrieves a parameter as a float64 with a default value | ||||
| func (p *ParamsParser) GetFloatDefault(key string, defaultValue float64) float64 { | ||||
| 	value, err := p.GetFloat(key) | ||||
| 	if err != nil { | ||||
| 		return defaultValue | ||||
| 	} | ||||
| 	return value | ||||
| } | ||||
|  | ||||
| // Has checks if a parameter exists | ||||
| func (p *ParamsParser) Has(key string) bool { | ||||
| 	_, exists := p.params[key] | ||||
| 	return exists | ||||
| } | ||||
|  | ||||
| // GetAll returns all parameters as a map | ||||
| func (p *ParamsParser) GetAll() map[string]string { | ||||
| 	result := make(map[string]string) | ||||
|  | ||||
| 	// First add defaults | ||||
| 	for k, v := range p.defaultParams { | ||||
| 		result[k] = v | ||||
| 	} | ||||
|  | ||||
| 	// Then override with actual params | ||||
| 	for k, v := range p.params { | ||||
| 		result[k] = v | ||||
| 	} | ||||
|  | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // MustGet retrieves a parameter value, panicking if not found | ||||
| func (p *ParamsParser) MustGet(key string) string { | ||||
| 	value := p.Get(key) | ||||
| 	if value == "" { | ||||
| 		panic(fmt.Sprintf("required parameter '%s' not found", key)) | ||||
| 	} | ||||
| 	return value | ||||
| } | ||||
|  | ||||
| // MustGetInt retrieves a parameter as an integer, panicking if not found or invalid | ||||
| func (p *ParamsParser) MustGetInt(key string) int { | ||||
| 	value, err := p.GetInt(key) | ||||
| 	if err != nil { | ||||
| 		panic(fmt.Sprintf("required integer parameter '%s' not found or invalid", key)) | ||||
| 	} | ||||
| 	return value | ||||
| } | ||||
|  | ||||
| // MustGetFloat retrieves a parameter as a float64, panicking if not found or invalid | ||||
| func (p *ParamsParser) MustGetFloat(key string) float64 { | ||||
| 	value, err := p.GetFloat(key) | ||||
| 	if err != nil { | ||||
| 		panic(fmt.Sprintf("required float parameter '%s' not found or invalid", key)) | ||||
| 	} | ||||
| 	return value | ||||
| } | ||||
							
								
								
									
										226
									
								
								_pkg2_dont_use/heroscript/paramsparser/paramsparser_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										226
									
								
								_pkg2_dont_use/heroscript/paramsparser/paramsparser_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,226 @@ | ||||
| package paramsparser | ||||
|  | ||||
| import ( | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestParamsParserBasic(t *testing.T) { | ||||
| 	input := "name:'myname' host:'localhost' port:25 secure:1 reset:1" | ||||
| 	parser := New() | ||||
| 	err := parser.ParseString(input) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Failed to parse input: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	tests := []struct { | ||||
| 		name     string | ||||
| 		key      string | ||||
| 		expected string | ||||
| 	}{ | ||||
| 		{"string value", "name", "myname"}, | ||||
| 		{"another string value", "host", "localhost"}, | ||||
| 		{"numeric value", "port", "25"}, | ||||
| 		{"boolean-like value", "secure", "1"}, | ||||
| 		{"another boolean-like value", "reset", "1"}, | ||||
| 		{"non-existent key", "nonexistent", ""}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 			if got := parser.Get(tt.key); got != tt.expected { | ||||
| 				t.Errorf("ParamsParser.Get(%q) = %q, want %q", tt.key, got, tt.expected) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestParamsParserMultiline(t *testing.T) { | ||||
| 	input := "name:'myname' description:'\n\t\ta description can be multiline\n\n\t\tlike this\n'" | ||||
| 	parser := New() | ||||
| 	err := parser.Parse(input) | ||||
| 	if err != nil { | ||||
| 		t.Fatalf("Failed to parse input: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	// Check the name parameter | ||||
| 	if got := parser.Get("name"); got != "myname" { | ||||
| 		t.Errorf("ParamsParser.Get(\"name\") = %q, want %q", got, "myname") | ||||
| 	} | ||||
|  | ||||
| 	// Check the multiline description | ||||
| 	expectedDesc := "\n\t\ta description can be multiline\n\n\t\tlike this\n" | ||||
| 	if got := parser.Get("description"); got != expectedDesc { | ||||
| 		t.Errorf("ParamsParser.Get(\"description\") = %q, want %q", got, expectedDesc) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestParamsParserDefaults(t *testing.T) { | ||||
| 	parser := New() | ||||
| 	parser.SetDefault("key1", "default1") | ||||
| 	parser.SetDefaults(map[string]string{ | ||||
| 		"key2": "default2", | ||||
| 		"key3": "default3", | ||||
| 	}) | ||||
|  | ||||
| 	// Override one default | ||||
| 	parser.Set("key2", "override") | ||||
|  | ||||
| 	tests := []struct { | ||||
| 		name     string | ||||
| 		key      string | ||||
| 		expected string | ||||
| 	}{ | ||||
| 		{"default value", "key1", "default1"}, | ||||
| 		{"overridden value", "key2", "override"}, | ||||
| 		{"another default", "key3", "default3"}, | ||||
| 		{"non-existent key", "key4", ""}, | ||||
| 	} | ||||
|  | ||||
| 	for _, tt := range tests { | ||||
| 		t.Run(tt.name, func(t *testing.T) { | ||||
| 			if got := parser.Get(tt.key); got != tt.expected { | ||||
| 				t.Errorf("ParamsParser.Get(%q) = %q, want %q", tt.key, got, tt.expected) | ||||
| 			} | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestParamsParserTypes(t *testing.T) { | ||||
| 	parser := New() | ||||
| 	parser.Set("int", "123") | ||||
| 	parser.Set("float", "3.14") | ||||
| 	parser.Set("bool_true", "true") | ||||
| 	parser.Set("bool_yes", "yes") | ||||
| 	parser.Set("bool_1", "1") | ||||
| 	parser.Set("bool_false", "false") | ||||
| 	parser.Set("invalid_int", "not_an_int") | ||||
| 	parser.Set("invalid_float", "not_a_float") | ||||
|  | ||||
| 	t.Run("GetInt", func(t *testing.T) { | ||||
| 		if val, err := parser.GetInt("int"); err != nil || val != 123 { | ||||
| 			t.Errorf("GetInt(\"int\") = %d, %v, want 123, nil", val, err) | ||||
| 		} | ||||
| 		if val, err := parser.GetInt("invalid_int"); err == nil { | ||||
| 			t.Errorf("GetInt(\"invalid_int\") = %d, %v, want error", val, err) | ||||
| 		} | ||||
| 		if val, err := parser.GetInt("nonexistent"); err == nil { | ||||
| 			t.Errorf("GetInt(\"nonexistent\") = %d, %v, want error", val, err) | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("GetIntDefault", func(t *testing.T) { | ||||
| 		if val := parser.GetIntDefault("int", 0); val != 123 { | ||||
| 			t.Errorf("GetIntDefault(\"int\", 0) = %d, want 123", val) | ||||
| 		} | ||||
| 		if val := parser.GetIntDefault("invalid_int", 42); val != 42 { | ||||
| 			t.Errorf("GetIntDefault(\"invalid_int\", 42) = %d, want 42", val) | ||||
| 		} | ||||
| 		if val := parser.GetIntDefault("nonexistent", 42); val != 42 { | ||||
| 			t.Errorf("GetIntDefault(\"nonexistent\", 42) = %d, want 42", val) | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("GetFloat", func(t *testing.T) { | ||||
| 		if val, err := parser.GetFloat("float"); err != nil || val != 3.14 { | ||||
| 			t.Errorf("GetFloat(\"float\") = %f, %v, want 3.14, nil", val, err) | ||||
| 		} | ||||
| 		if val, err := parser.GetFloat("invalid_float"); err == nil { | ||||
| 			t.Errorf("GetFloat(\"invalid_float\") = %f, %v, want error", val, err) | ||||
| 		} | ||||
| 		if val, err := parser.GetFloat("nonexistent"); err == nil { | ||||
| 			t.Errorf("GetFloat(\"nonexistent\") = %f, %v, want error", val, err) | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("GetFloatDefault", func(t *testing.T) { | ||||
| 		if val := parser.GetFloatDefault("float", 0.0); val != 3.14 { | ||||
| 			t.Errorf("GetFloatDefault(\"float\", 0.0) = %f, want 3.14", val) | ||||
| 		} | ||||
| 		if val := parser.GetFloatDefault("invalid_float", 2.71); val != 2.71 { | ||||
| 			t.Errorf("GetFloatDefault(\"invalid_float\", 2.71) = %f, want 2.71", val) | ||||
| 		} | ||||
| 		if val := parser.GetFloatDefault("nonexistent", 2.71); val != 2.71 { | ||||
| 			t.Errorf("GetFloatDefault(\"nonexistent\", 2.71) = %f, want 2.71", val) | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("GetBool", func(t *testing.T) { | ||||
| 		if val := parser.GetBool("bool_true"); !val { | ||||
| 			t.Errorf("GetBool(\"bool_true\") = %v, want true", val) | ||||
| 		} | ||||
| 		if val := parser.GetBool("bool_yes"); !val { | ||||
| 			t.Errorf("GetBool(\"bool_yes\") = %v, want true", val) | ||||
| 		} | ||||
| 		if val := parser.GetBool("bool_1"); !val { | ||||
| 			t.Errorf("GetBool(\"bool_1\") = %v, want true", val) | ||||
| 		} | ||||
| 		if val := parser.GetBool("bool_false"); val { | ||||
| 			t.Errorf("GetBool(\"bool_false\") = %v, want false", val) | ||||
| 		} | ||||
| 		if val := parser.GetBool("nonexistent"); val { | ||||
| 			t.Errorf("GetBool(\"nonexistent\") = %v, want false", val) | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	t.Run("GetBoolDefault", func(t *testing.T) { | ||||
| 		if val := parser.GetBoolDefault("bool_true", false); !val { | ||||
| 			t.Errorf("GetBoolDefault(\"bool_true\", false) = %v, want true", val) | ||||
| 		} | ||||
| 		if val := parser.GetBoolDefault("nonexistent", true); !val { | ||||
| 			t.Errorf("GetBoolDefault(\"nonexistent\", true) = %v, want true", val) | ||||
| 		} | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func TestParamsParserGetAll(t *testing.T) { | ||||
| 	parser := New() | ||||
| 	parser.SetDefault("key1", "default1") | ||||
| 	parser.SetDefault("key2", "default2") | ||||
| 	parser.Set("key2", "override") | ||||
| 	parser.Set("key3", "value3") | ||||
|  | ||||
| 	all := parser.GetAll() | ||||
| 	 | ||||
| 	expected := map[string]string{ | ||||
| 		"key1": "default1", | ||||
| 		"key2": "override", | ||||
| 		"key3": "value3", | ||||
| 	} | ||||
|  | ||||
| 	if len(all) != len(expected) { | ||||
| 		t.Errorf("GetAll() returned map with %d entries, want %d", len(all), len(expected)) | ||||
| 	} | ||||
|  | ||||
| 	for k, v := range expected { | ||||
| 		if all[k] != v { | ||||
| 			t.Errorf("GetAll()[%q] = %q, want %q", k, all[k], v) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func TestParamsParserMustGet(t *testing.T) { | ||||
| 	parser := New() | ||||
| 	parser.Set("key", "value") | ||||
| 	parser.Set("int", "123") | ||||
| 	parser.Set("float", "3.14") | ||||
|  | ||||
| 	defer func() { | ||||
| 		if r := recover(); r == nil { | ||||
| 			t.Errorf("MustGet on non-existent key did not panic") | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	// These should not panic | ||||
| 	if val := parser.MustGet("key"); val != "value" { | ||||
| 		t.Errorf("MustGet(\"key\") = %q, want \"value\"", val) | ||||
| 	} | ||||
| 	if val := parser.MustGetInt("int"); val != 123 { | ||||
| 		t.Errorf("MustGetInt(\"int\") = %d, want 123", val) | ||||
| 	} | ||||
| 	if val := parser.MustGetFloat("float"); val != 3.14 { | ||||
| 		t.Errorf("MustGetFloat(\"float\") = %f, want 3.14", val) | ||||
| 	} | ||||
|  | ||||
| 	// This should panic | ||||
| 	parser.MustGet("nonexistent") | ||||
| } | ||||
		Reference in New Issue
	
	Block a user