You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							338 lines
						
					
					
						
							9.1 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							338 lines
						
					
					
						
							9.1 KiB
						
					
					
				
								package base
							 | 
						|
								
							 | 
						|
								import (
							 | 
						|
									"reflect"
							 | 
						|
									"testing"
							 | 
						|
								)
							 | 
						|
								
							 | 
						|
								// Test structs that mirror the actual configuration structure
							 | 
						|
								type TestBaseConfig struct {
							 | 
						|
									Enabled             bool `json:"enabled"`
							 | 
						|
									ScanIntervalSeconds int  `json:"scan_interval_seconds"`
							 | 
						|
									MaxConcurrent       int  `json:"max_concurrent"`
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								type TestTaskConfig struct {
							 | 
						|
									TestBaseConfig
							 | 
						|
									TaskSpecificField    float64 `json:"task_specific_field"`
							 | 
						|
									AnotherSpecificField string  `json:"another_specific_field"`
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								type TestNestedConfig struct {
							 | 
						|
									TestBaseConfig
							 | 
						|
									NestedStruct struct {
							 | 
						|
										NestedField string `json:"nested_field"`
							 | 
						|
									} `json:"nested_struct"`
							 | 
						|
									TaskField int `json:"task_field"`
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestStructToMap_WithEmbeddedStruct(t *testing.T) {
							 | 
						|
									// Test case 1: Basic embedded struct
							 | 
						|
									config := &TestTaskConfig{
							 | 
						|
										TestBaseConfig: TestBaseConfig{
							 | 
						|
											Enabled:             true,
							 | 
						|
											ScanIntervalSeconds: 1800,
							 | 
						|
											MaxConcurrent:       3,
							 | 
						|
										},
							 | 
						|
										TaskSpecificField:    0.25,
							 | 
						|
										AnotherSpecificField: "test_value",
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									result := StructToMap(config)
							 | 
						|
								
							 | 
						|
									// Verify all fields are present
							 | 
						|
									expectedFields := map[string]interface{}{
							 | 
						|
										"enabled":                true,
							 | 
						|
										"scan_interval_seconds":  1800,
							 | 
						|
										"max_concurrent":         3,
							 | 
						|
										"task_specific_field":    0.25,
							 | 
						|
										"another_specific_field": "test_value",
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if len(result) != len(expectedFields) {
							 | 
						|
										t.Errorf("Expected %d fields, got %d. Result: %+v", len(expectedFields), len(result), result)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									for key, expectedValue := range expectedFields {
							 | 
						|
										if actualValue, exists := result[key]; !exists {
							 | 
						|
											t.Errorf("Missing field: %s", key)
							 | 
						|
										} else if !reflect.DeepEqual(actualValue, expectedValue) {
							 | 
						|
											t.Errorf("Field %s: expected %v (%T), got %v (%T)", key, expectedValue, expectedValue, actualValue, actualValue)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestStructToMap_WithNestedStruct(t *testing.T) {
							 | 
						|
									config := &TestNestedConfig{
							 | 
						|
										TestBaseConfig: TestBaseConfig{
							 | 
						|
											Enabled:             false,
							 | 
						|
											ScanIntervalSeconds: 3600,
							 | 
						|
											MaxConcurrent:       1,
							 | 
						|
										},
							 | 
						|
										NestedStruct: struct {
							 | 
						|
											NestedField string `json:"nested_field"`
							 | 
						|
										}{
							 | 
						|
											NestedField: "nested_value",
							 | 
						|
										},
							 | 
						|
										TaskField: 42,
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									result := StructToMap(config)
							 | 
						|
								
							 | 
						|
									// Verify embedded struct fields are included
							 | 
						|
									if enabled, exists := result["enabled"]; !exists || enabled != false {
							 | 
						|
										t.Errorf("Expected enabled=false from embedded struct, got %v", enabled)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if scanInterval, exists := result["scan_interval_seconds"]; !exists || scanInterval != 3600 {
							 | 
						|
										t.Errorf("Expected scan_interval_seconds=3600 from embedded struct, got %v", scanInterval)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if maxConcurrent, exists := result["max_concurrent"]; !exists || maxConcurrent != 1 {
							 | 
						|
										t.Errorf("Expected max_concurrent=1 from embedded struct, got %v", maxConcurrent)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify regular fields are included
							 | 
						|
									if taskField, exists := result["task_field"]; !exists || taskField != 42 {
							 | 
						|
										t.Errorf("Expected task_field=42, got %v", taskField)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify nested struct is included as a whole
							 | 
						|
									if nestedStruct, exists := result["nested_struct"]; !exists {
							 | 
						|
										t.Errorf("Missing nested_struct field")
							 | 
						|
									} else {
							 | 
						|
										// The nested struct should be included as-is, not flattened
							 | 
						|
										if nested, ok := nestedStruct.(struct {
							 | 
						|
											NestedField string `json:"nested_field"`
							 | 
						|
										}); !ok || nested.NestedField != "nested_value" {
							 | 
						|
											t.Errorf("Expected nested_struct with NestedField='nested_value', got %v", nestedStruct)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestMapToStruct_WithEmbeddedStruct(t *testing.T) {
							 | 
						|
									// Test data with all fields including embedded struct fields
							 | 
						|
									data := map[string]interface{}{
							 | 
						|
										"enabled":                true,
							 | 
						|
										"scan_interval_seconds":  2400,
							 | 
						|
										"max_concurrent":         5,
							 | 
						|
										"task_specific_field":    0.15,
							 | 
						|
										"another_specific_field": "updated_value",
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									config := &TestTaskConfig{}
							 | 
						|
									err := MapToStruct(data, config)
							 | 
						|
								
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("MapToStruct failed: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify embedded struct fields were set
							 | 
						|
									if config.Enabled != true {
							 | 
						|
										t.Errorf("Expected Enabled=true, got %v", config.Enabled)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if config.ScanIntervalSeconds != 2400 {
							 | 
						|
										t.Errorf("Expected ScanIntervalSeconds=2400, got %v", config.ScanIntervalSeconds)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if config.MaxConcurrent != 5 {
							 | 
						|
										t.Errorf("Expected MaxConcurrent=5, got %v", config.MaxConcurrent)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify regular fields were set
							 | 
						|
									if config.TaskSpecificField != 0.15 {
							 | 
						|
										t.Errorf("Expected TaskSpecificField=0.15, got %v", config.TaskSpecificField)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if config.AnotherSpecificField != "updated_value" {
							 | 
						|
										t.Errorf("Expected AnotherSpecificField='updated_value', got %v", config.AnotherSpecificField)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestMapToStruct_PartialData(t *testing.T) {
							 | 
						|
									// Test with only some fields present (simulating form data)
							 | 
						|
									data := map[string]interface{}{
							 | 
						|
										"enabled":             false,
							 | 
						|
										"max_concurrent":      2,
							 | 
						|
										"task_specific_field": 0.30,
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Start with some initial values
							 | 
						|
									config := &TestTaskConfig{
							 | 
						|
										TestBaseConfig: TestBaseConfig{
							 | 
						|
											Enabled:             true,
							 | 
						|
											ScanIntervalSeconds: 1800,
							 | 
						|
											MaxConcurrent:       1,
							 | 
						|
										},
							 | 
						|
										TaskSpecificField:    0.20,
							 | 
						|
										AnotherSpecificField: "initial_value",
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									err := MapToStruct(data, config)
							 | 
						|
								
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("MapToStruct failed: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify updated fields
							 | 
						|
									if config.Enabled != false {
							 | 
						|
										t.Errorf("Expected Enabled=false (updated), got %v", config.Enabled)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if config.MaxConcurrent != 2 {
							 | 
						|
										t.Errorf("Expected MaxConcurrent=2 (updated), got %v", config.MaxConcurrent)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if config.TaskSpecificField != 0.30 {
							 | 
						|
										t.Errorf("Expected TaskSpecificField=0.30 (updated), got %v", config.TaskSpecificField)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify unchanged fields remain the same
							 | 
						|
									if config.ScanIntervalSeconds != 1800 {
							 | 
						|
										t.Errorf("Expected ScanIntervalSeconds=1800 (unchanged), got %v", config.ScanIntervalSeconds)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if config.AnotherSpecificField != "initial_value" {
							 | 
						|
										t.Errorf("Expected AnotherSpecificField='initial_value' (unchanged), got %v", config.AnotherSpecificField)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestRoundTripSerialization(t *testing.T) {
							 | 
						|
									// Test complete round-trip: struct -> map -> struct
							 | 
						|
									original := &TestTaskConfig{
							 | 
						|
										TestBaseConfig: TestBaseConfig{
							 | 
						|
											Enabled:             true,
							 | 
						|
											ScanIntervalSeconds: 3600,
							 | 
						|
											MaxConcurrent:       4,
							 | 
						|
										},
							 | 
						|
										TaskSpecificField:    0.18,
							 | 
						|
										AnotherSpecificField: "round_trip_test",
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Convert to map
							 | 
						|
									dataMap := StructToMap(original)
							 | 
						|
								
							 | 
						|
									// Convert back to struct
							 | 
						|
									roundTrip := &TestTaskConfig{}
							 | 
						|
									err := MapToStruct(dataMap, roundTrip)
							 | 
						|
								
							 | 
						|
									if err != nil {
							 | 
						|
										t.Fatalf("Round-trip MapToStruct failed: %v", err)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									// Verify all fields match
							 | 
						|
									if !reflect.DeepEqual(original.TestBaseConfig, roundTrip.TestBaseConfig) {
							 | 
						|
										t.Errorf("BaseConfig mismatch:\nOriginal: %+v\nRound-trip: %+v", original.TestBaseConfig, roundTrip.TestBaseConfig)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if original.TaskSpecificField != roundTrip.TaskSpecificField {
							 | 
						|
										t.Errorf("TaskSpecificField mismatch: %v != %v", original.TaskSpecificField, roundTrip.TaskSpecificField)
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									if original.AnotherSpecificField != roundTrip.AnotherSpecificField {
							 | 
						|
										t.Errorf("AnotherSpecificField mismatch: %v != %v", original.AnotherSpecificField, roundTrip.AnotherSpecificField)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestStructToMap_EmptyStruct(t *testing.T) {
							 | 
						|
									config := &TestTaskConfig{}
							 | 
						|
									result := StructToMap(config)
							 | 
						|
								
							 | 
						|
									// Should still include all fields, even with zero values
							 | 
						|
									expectedFields := []string{"enabled", "scan_interval_seconds", "max_concurrent", "task_specific_field", "another_specific_field"}
							 | 
						|
								
							 | 
						|
									for _, field := range expectedFields {
							 | 
						|
										if _, exists := result[field]; !exists {
							 | 
						|
											t.Errorf("Missing field: %s", field)
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestStructToMap_NilPointer(t *testing.T) {
							 | 
						|
									var config *TestTaskConfig = nil
							 | 
						|
									result := StructToMap(config)
							 | 
						|
								
							 | 
						|
									if len(result) != 0 {
							 | 
						|
										t.Errorf("Expected empty map for nil pointer, got %+v", result)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestMapToStruct_InvalidInput(t *testing.T) {
							 | 
						|
									data := map[string]interface{}{
							 | 
						|
										"enabled": "not_a_bool", // Wrong type
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									config := &TestTaskConfig{}
							 | 
						|
									err := MapToStruct(data, config)
							 | 
						|
								
							 | 
						|
									if err == nil {
							 | 
						|
										t.Errorf("Expected error for invalid input type, but got none")
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func TestMapToStruct_NonPointer(t *testing.T) {
							 | 
						|
									data := map[string]interface{}{
							 | 
						|
										"enabled": true,
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									config := TestTaskConfig{} // Not a pointer
							 | 
						|
									err := MapToStruct(data, config)
							 | 
						|
								
							 | 
						|
									if err == nil {
							 | 
						|
										t.Errorf("Expected error for non-pointer input, but got none")
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								// Benchmark tests to ensure performance is reasonable
							 | 
						|
								func BenchmarkStructToMap(b *testing.B) {
							 | 
						|
									config := &TestTaskConfig{
							 | 
						|
										TestBaseConfig: TestBaseConfig{
							 | 
						|
											Enabled:             true,
							 | 
						|
											ScanIntervalSeconds: 1800,
							 | 
						|
											MaxConcurrent:       3,
							 | 
						|
										},
							 | 
						|
										TaskSpecificField:    0.25,
							 | 
						|
										AnotherSpecificField: "benchmark_test",
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									b.ResetTimer()
							 | 
						|
									for i := 0; i < b.N; i++ {
							 | 
						|
										_ = StructToMap(config)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func BenchmarkMapToStruct(b *testing.B) {
							 | 
						|
									data := map[string]interface{}{
							 | 
						|
										"enabled":                true,
							 | 
						|
										"scan_interval_seconds":  1800,
							 | 
						|
										"max_concurrent":         3,
							 | 
						|
										"task_specific_field":    0.25,
							 | 
						|
										"another_specific_field": "benchmark_test",
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									b.ResetTimer()
							 | 
						|
									for i := 0; i < b.N; i++ {
							 | 
						|
										config := &TestTaskConfig{}
							 | 
						|
										_ = MapToStruct(data, config)
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								func BenchmarkRoundTrip(b *testing.B) {
							 | 
						|
									original := &TestTaskConfig{
							 | 
						|
										TestBaseConfig: TestBaseConfig{
							 | 
						|
											Enabled:             true,
							 | 
						|
											ScanIntervalSeconds: 1800,
							 | 
						|
											MaxConcurrent:       3,
							 | 
						|
										},
							 | 
						|
										TaskSpecificField:    0.25,
							 | 
						|
										AnotherSpecificField: "benchmark_test",
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									b.ResetTimer()
							 | 
						|
									for i := 0; i < b.N; i++ {
							 | 
						|
										dataMap := StructToMap(original)
							 | 
						|
										roundTrip := &TestTaskConfig{}
							 | 
						|
										_ = MapToStruct(dataMap, roundTrip)
							 | 
						|
									}
							 | 
						|
								}
							 |