From 44827e16d41a392ffbf528b755648ebda3d09a83 Mon Sep 17 00:00:00 2001 From: Sky Johnson Date: Mon, 3 Mar 2025 21:13:39 -0600 Subject: [PATCH] update bench --- bench/bench_test.go | 648 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 648 insertions(+) diff --git a/bench/bench_test.go b/bench/bench_test.go index 4d5e542..08100cf 100644 --- a/bench/bench_test.go +++ b/bench/bench_test.go @@ -615,3 +615,651 @@ permissions = ["read", "write"] } } } + +// Value Retrieval Benchmarks for Custom Config Format +func BenchmarkRetrieveSimpleValues(b *testing.B) { + configData := ` + host = "localhost" + port = 8080 + debug = true + timeout = 30 + ` + + // Parse once before benchmarking retrieval + reader := strings.NewReader(configData) + cfg, err := config.Load(reader) + if err != nil { + b.Fatalf("Failed to parse config: %v", err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // String retrieval + host, err := cfg.GetString("host") + if err != nil || host != "localhost" { + b.Fatalf("Failed to retrieve host: %v", err) + } + + // Int retrieval + port, err := cfg.GetInt("port") + if err != nil || port != 8080 { + b.Fatalf("Failed to retrieve port: %v", err) + } + + // Bool retrieval + debug, err := cfg.GetBool("debug") + if err != nil || !debug { + b.Fatalf("Failed to retrieve debug: %v", err) + } + + // Generic retrieval + timeout, err := cfg.Get("timeout") + if err != nil || timeout.(int64) != 30 { + b.Fatalf("Failed to retrieve timeout: %v", err) + } + } +} + +func BenchmarkRetrieveNestedValues(b *testing.B) { + configData := ` + app { + name = "TestApp" + version = "1.0.0" + settings { + enableLogging = true + maxConnections = 100 + } + } + database { + host = "db.example.com" + port = 5432 + credentials { + username = "admin" + password = "secure123" + } + } + ` + + // Parse once before benchmarking retrieval + reader := strings.NewReader(configData) + cfg, err := config.Load(reader) + if err != nil { + b.Fatalf("Failed to parse config: %v", err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // First level nesting + appName, err := cfg.GetString("app.name") + if err != nil || appName != "TestApp" { + b.Fatalf("Failed to retrieve app.name: %v", err) + } + + dbPort, err := cfg.GetInt("database.port") + if err != nil || dbPort != 5432 { + b.Fatalf("Failed to retrieve database.port: %v", err) + } + + // Second level nesting + logging, err := cfg.GetBool("app.settings.enableLogging") + if err != nil || !logging { + b.Fatalf("Failed to retrieve app.settings.enableLogging: %v", err) + } + + username, err := cfg.GetString("database.credentials.username") + if err != nil || username != "admin" { + b.Fatalf("Failed to retrieve database.credentials.username: %v", err) + } + } +} + +func BenchmarkRetrieveArrayValues(b *testing.B) { + configData := ` + features = { + "authentication" + "authorization" + "reporting" + "analytics" + } + numbers = { + 1 + 2 + 3 + 4 + 5 + } + ` + + // Parse once before benchmarking retrieval + reader := strings.NewReader(configData) + cfg, err := config.Load(reader) + if err != nil { + b.Fatalf("Failed to parse config: %v", err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // Get entire array + features, err := cfg.GetArray("features") + if err != nil || len(features) != 4 { + b.Fatalf("Failed to retrieve features array: %v", err) + } + + // Check specific array element + if feature0, ok := features[0].(string); !ok || feature0 != "authentication" { + b.Fatalf("Failed to access array element: %v", features[0]) + } + + // Get with dot notation for array access + auth, err := cfg.GetString("features.0") + if err != nil || auth != "authentication" { + b.Fatalf("Failed to retrieve features.0: %v", err) + } + + // Numeric array + numbers, err := cfg.GetArray("numbers") + if err != nil || len(numbers) != 5 { + b.Fatalf("Failed to retrieve numbers array: %v", err) + } + } +} + +func BenchmarkRetrieveMixedValues(b *testing.B) { + configData := ` + app { + name = "TestApp" + version = "1.0.0" + environments = { + "development" + "testing" + "production" + } + limits { + requests = 1000 + connections = 100 + timeouts { + read = 5 + write = 10 + } + } + } + ` + + // Parse once before benchmarking retrieval + reader := strings.NewReader(configData) + cfg, err := config.Load(reader) + if err != nil { + b.Fatalf("Failed to parse config: %v", err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // Simple retrieval + appName, err := cfg.GetString("app.name") + if err != nil || appName != "TestApp" { + b.Fatalf("Failed to retrieve app.name: %v", err) + } + + // Array retrieval + environments, err := cfg.GetArray("app.environments") + if err != nil || len(environments) != 3 { + b.Fatalf("Failed to retrieve app.environments: %v", err) + } + + // Deeply nested value + readTimeout, err := cfg.GetInt("app.limits.timeouts.read") + if err != nil || readTimeout != 5 { + b.Fatalf("Failed to retrieve app.limits.timeouts.read: %v", err) + } + + // Array item with dot notation + prod, err := cfg.GetString("app.environments.2") + if err != nil || prod != "production" { + b.Fatalf("Failed to retrieve app.environments.2: %v", err) + } + } +} + +// Value Retrieval Benchmarks for JSON +func BenchmarkRetrieveSimpleValuesJSON(b *testing.B) { + configData := `{ + "host": "localhost", + "port": 8080, + "debug": true, + "timeout": 30 + }` + + // Parse once before benchmarking retrieval + var result map[string]interface{} + err := json.Unmarshal([]byte(configData), &result) + if err != nil { + b.Fatalf("Failed to parse JSON: %v", err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // String retrieval + host, ok := result["host"].(string) + if !ok || host != "localhost" { + b.Fatalf("Failed to retrieve host") + } + + // Number retrieval + port, ok := result["port"].(float64) + if !ok || port != 8080 { + b.Fatalf("Failed to retrieve port") + } + + // Boolean retrieval + debug, ok := result["debug"].(bool) + if !ok || !debug { + b.Fatalf("Failed to retrieve debug") + } + + // Generic retrieval + timeout := result["timeout"] + if timeout.(float64) != 30 { + b.Fatalf("Failed to retrieve timeout") + } + } +} + +func BenchmarkRetrieveNestedValuesJSON(b *testing.B) { + configData := `{ + "app": { + "name": "TestApp", + "version": "1.0.0", + "settings": { + "enableLogging": true, + "maxConnections": 100 + } + }, + "database": { + "host": "db.example.com", + "port": 5432, + "credentials": { + "username": "admin", + "password": "secure123" + } + } + }` + + // Parse once before benchmarking retrieval + var result map[string]interface{} + err := json.Unmarshal([]byte(configData), &result) + if err != nil { + b.Fatalf("Failed to parse JSON: %v", err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // First level nesting + app, ok := result["app"].(map[string]interface{}) + if !ok { + b.Fatalf("Failed to retrieve app") + } + appName, ok := app["name"].(string) + if !ok || appName != "TestApp" { + b.Fatalf("Failed to retrieve app.name") + } + + database, ok := result["database"].(map[string]interface{}) + if !ok { + b.Fatalf("Failed to retrieve database") + } + dbPort, ok := database["port"].(float64) + if !ok || dbPort != 5432 { + b.Fatalf("Failed to retrieve database.port") + } + + // Second level nesting + settings, ok := app["settings"].(map[string]interface{}) + if !ok { + b.Fatalf("Failed to retrieve app.settings") + } + logging, ok := settings["enableLogging"].(bool) + if !ok || !logging { + b.Fatalf("Failed to retrieve app.settings.enableLogging") + } + + credentials, ok := database["credentials"].(map[string]interface{}) + if !ok { + b.Fatalf("Failed to retrieve database.credentials") + } + username, ok := credentials["username"].(string) + if !ok || username != "admin" { + b.Fatalf("Failed to retrieve database.credentials.username") + } + } +} + +func BenchmarkRetrieveArrayValuesJSON(b *testing.B) { + configData := `{ + "features": [ + "authentication", + "authorization", + "reporting", + "analytics" + ], + "numbers": [1, 2, 3, 4, 5] + }` + + // Parse once before benchmarking retrieval + var result map[string]interface{} + err := json.Unmarshal([]byte(configData), &result) + if err != nil { + b.Fatalf("Failed to parse JSON: %v", err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // Get entire array + features, ok := result["features"].([]interface{}) + if !ok || len(features) != 4 { + b.Fatalf("Failed to retrieve features array") + } + + // Check specific array element + if feature0, ok := features[0].(string); !ok || feature0 != "authentication" { + b.Fatalf("Failed to access array element") + } + + // Numeric array + numbers, ok := result["numbers"].([]interface{}) + if !ok || len(numbers) != 5 { + b.Fatalf("Failed to retrieve numbers array") + } + } +} + +// Value Retrieval Benchmarks for YAML +func BenchmarkRetrieveSimpleValuesYAML(b *testing.B) { + configData := ` +host: localhost +port: 8080 +debug: true +timeout: 30 +` + + // Parse once before benchmarking retrieval + var result map[string]interface{} + err := yaml.Unmarshal([]byte(configData), &result) + if err != nil { + b.Fatalf("Failed to parse YAML: %v", err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // String retrieval + host, ok := result["host"].(string) + if !ok || host != "localhost" { + b.Fatalf("Failed to retrieve host") + } + + // Number retrieval + port, ok := result["port"].(int) + if !ok || port != 8080 { + b.Fatalf("Failed to retrieve port") + } + + // Boolean retrieval + debug, ok := result["debug"].(bool) + if !ok || !debug { + b.Fatalf("Failed to retrieve debug") + } + + // Generic retrieval + timeout := result["timeout"] + if timeout.(int) != 30 { + b.Fatalf("Failed to retrieve timeout") + } + } +} + +// Value Retrieval Benchmarks for TOML +func BenchmarkRetrieveSimpleValuesTOML(b *testing.B) { + configData := ` +host = "localhost" +port = 8080 +debug = true +timeout = 30 +` + + // Parse once before benchmarking retrieval + var result map[string]interface{} + err := toml.Unmarshal([]byte(configData), &result) + if err != nil { + b.Fatalf("Failed to parse TOML: %v", err) + } + + b.ResetTimer() + for i := 0; i < b.N; i++ { + // String retrieval + host, ok := result["host"].(string) + if !ok || host != "localhost" { + b.Fatalf("Failed to retrieve host") + } + + // Number retrieval + port, ok := result["port"].(int64) + if !ok || port != 8080 { + b.Fatalf("Failed to retrieve port") + } + + // Boolean retrieval + debug, ok := result["debug"].(bool) + if !ok || !debug { + b.Fatalf("Failed to retrieve debug") + } + + // Generic retrieval + timeout := result["timeout"] + if timeout.(int64) != 30 { + b.Fatalf("Failed to retrieve timeout") + } + } +} + +// Comprehensive value retrieval comparison benchmark +func BenchmarkComplexValueRetrieval(b *testing.B) { + // Setup complex config with deep nesting and arrays for all formats + customConfig := ` + app { + name = "TestApp" + version = "1.0.0" + settings { + enableLogging = true + maxConnections = 100 + timeouts { + read = 5 + write = 10 + } + } + environments = { + "development" + "testing" + "production" + } + } + ` + + jsonConfig := `{ + "app": { + "name": "TestApp", + "version": "1.0.0", + "settings": { + "enableLogging": true, + "maxConnections": 100, + "timeouts": { + "read": 5, + "write": 10 + } + }, + "environments": [ + "development", + "testing", + "production" + ] + } + }` + + yamlConfig := ` +app: + name: TestApp + version: 1.0.0 + settings: + enableLogging: true + maxConnections: 100 + timeouts: + read: 5 + write: 10 + environments: + - development + - testing + - production +` + + tomlConfig := ` +[app] +name = "TestApp" +version = "1.0.0" +environments = ["development", "testing", "production"] + +[app.settings] +enableLogging = true +maxConnections = 100 + +[app.settings.timeouts] +read = 5 +write = 10 +` + + // Parse configs once before benchmarking + + // Custom config + customReader := strings.NewReader(customConfig) + customCfg, err := config.Load(customReader) + if err != nil { + b.Fatalf("Failed to parse custom config: %v", err) + } + + // JSON config + var jsonResult map[string]interface{} + err = json.Unmarshal([]byte(jsonConfig), &jsonResult) + if err != nil { + b.Fatalf("Failed to parse JSON: %v", err) + } + + // YAML config + var yamlResult map[string]interface{} + err = yaml.Unmarshal([]byte(yamlConfig), &yamlResult) + if err != nil { + b.Fatalf("Failed to parse YAML: %v", err) + } + + // TOML config + var tomlResult map[string]interface{} + err = toml.Unmarshal([]byte(tomlConfig), &tomlResult) + if err != nil { + b.Fatalf("Failed to parse TOML: %v", err) + } + + b.Run("Custom-SimpleGet", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _, err := customCfg.GetString("app.name") + if err != nil { + b.Fatalf("Failed to retrieve app.name: %v", err) + } + } + }) + + b.Run("Custom-DeepGet", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _, err := customCfg.GetInt("app.settings.timeouts.read") + if err != nil { + b.Fatalf("Failed to retrieve app.settings.timeouts.read: %v", err) + } + } + }) + + b.Run("Custom-ArrayGet", func(b *testing.B) { + for i := 0; i < b.N; i++ { + _, err := customCfg.GetString("app.environments.1") + if err != nil { + b.Fatalf("Failed to retrieve app.environments.1: %v", err) + } + } + }) + + b.Run("JSON-SimpleGet", func(b *testing.B) { + for i := 0; i < b.N; i++ { + app := jsonResult["app"].(map[string]interface{}) + _ = app["name"].(string) + } + }) + + b.Run("JSON-DeepGet", func(b *testing.B) { + for i := 0; i < b.N; i++ { + app := jsonResult["app"].(map[string]interface{}) + settings := app["settings"].(map[string]interface{}) + timeouts := settings["timeouts"].(map[string]interface{}) + _ = timeouts["read"].(float64) + } + }) + + b.Run("JSON-ArrayGet", func(b *testing.B) { + for i := 0; i < b.N; i++ { + app := jsonResult["app"].(map[string]interface{}) + environments := app["environments"].([]interface{}) + _ = environments[1].(string) + } + }) + + b.Run("YAML-SimpleGet", func(b *testing.B) { + for i := 0; i < b.N; i++ { + app := yamlResult["app"].(map[string]interface{}) + _ = app["name"].(string) + } + }) + + b.Run("YAML-DeepGet", func(b *testing.B) { + for i := 0; i < b.N; i++ { + app := yamlResult["app"].(map[string]interface{}) + settings := app["settings"].(map[string]interface{}) + timeouts := settings["timeouts"].(map[string]interface{}) + _ = timeouts["read"].(int) + } + }) + + b.Run("YAML-ArrayGet", func(b *testing.B) { + for i := 0; i < b.N; i++ { + app := yamlResult["app"].(map[string]interface{}) + environments := app["environments"].([]interface{}) + _ = environments[1].(string) + } + }) + + b.Run("TOML-SimpleGet", func(b *testing.B) { + for i := 0; i < b.N; i++ { + app := tomlResult["app"].(map[string]interface{}) + _ = app["name"].(string) + } + }) + + b.Run("TOML-DeepGet", func(b *testing.B) { + for i := 0; i < b.N; i++ { + app := tomlResult["app"].(map[string]interface{}) + settings := app["settings"].(map[string]interface{}) + timeouts := settings["timeouts"].(map[string]interface{}) + _ = timeouts["read"].(int64) + } + }) + + b.Run("TOML-ArrayGet", func(b *testing.B) { + for i := 0; i < b.N; i++ { + app := tomlResult["app"].(map[string]interface{}) + environments := app["environments"].([]interface{}) + _ = environments[1].(string) + } + }) +}