package processor import ( "strings" "testing" "cook/utils" ) // TestRealWorldGameXML tests with game-like XML structure func TestRealWorldGameXML(t *testing.T) { original := ` ` // Parse origElem, err := parseXMLWithPositions(original) if err != nil { t.Fatalf("Failed to parse: %v", err) } // Modify: Double all MaxStack values and change Wood weight modElem := deepCopyXMLElement(origElem) // Fiber MaxStack: 1000 → 2000 fiberItem := modElem.Children[0] fiberMaxStack := fiberItem.Children[2] valueAttr := fiberMaxStack.Attributes["value"] valueAttr.Value = "2000" fiberMaxStack.Attributes["value"] = valueAttr // Wood MaxStack: 500 → 1000 woodItem := modElem.Children[1] woodMaxStack := woodItem.Children[2] valueAttr2 := woodMaxStack.Attributes["value"] valueAttr2.Value = "1000" woodMaxStack.Attributes["value"] = valueAttr2 // Wood Weight: 0.05 → 0.10 woodWeight := woodItem.Children[1] weightAttr := woodWeight.Attributes["value"] weightAttr.Value = "0.10" woodWeight.Attributes["value"] = weightAttr // Generate changes changes := findXMLChanges(origElem, modElem, "") if len(changes) != 3 { t.Fatalf("Expected 3 changes, got %d", len(changes)) } // Apply commands := applyXMLChanges(changes) result, _ := utils.ExecuteModifications(commands, original) // Verify changes if !strings.Contains(result, ``) { t.Errorf("XML declaration not preserved") } if !strings.Contains(result, "\n ` // Parse origElem, err := parseXMLWithPositions(original) if err != nil { t.Fatalf("Failed to parse: %v", err) } // Remove middle two items, add a new one modElem := deepCopyXMLElement(origElem) // Remove shield and potion (indices 1 and 2) modElem.Children = []*XMLElement{ modElem.Children[0], // sword modElem.Children[3], // scroll } // Add a new item newItem := &XMLElement{ Tag: "item", Attributes: map[string]XMLAttribute{ "name": {Value: "helmet"}, }, Children: []*XMLElement{}, } modElem.Children = append(modElem.Children, newItem) // Generate changes changes := findXMLChanges(origElem, modElem, "") // The algorithm compares by matching indices: // orig[0]=sword vs mod[0]=sword (no change) // orig[1]=shield vs mod[1]=scroll (treated as replace - shows as attribute changes) // orig[2]=potion vs mod[2]=helmet (treated as replace) // orig[3]=scroll (removed) // This is fine - the actual edits will be correct if len(changes) == 0 { t.Fatalf("Expected changes, got none") } // Apply commands := applyXMLChanges(changes) result, _ := utils.ExecuteModifications(commands, original) // Verify if strings.Contains(result, `name="shield"`) { t.Errorf("Shield not removed") } if strings.Contains(result, `name="potion"`) { t.Errorf("Potion not removed") } if !strings.Contains(result, `name="sword"`) { t.Errorf("Sword incorrectly removed") } if !strings.Contains(result, `name="scroll"`) { t.Errorf("Scroll incorrectly removed") } if !strings.Contains(result, `name="helmet"`) { t.Errorf("Helmet not added") } } // TestModifyAttributesAndText tests changing both attributes and text content func TestModifyAttributesAndText(t *testing.T) { original := ` Iron Sword Battle Axe ` // Parse origElem, err := parseXMLWithPositions(original) if err != nil { t.Fatalf("Failed to parse: %v", err) } // Modify both items modElem := deepCopyXMLElement(origElem) // First item: change damage and text item1 := modElem.Children[0] dmgAttr := item1.Attributes["damage"] dmgAttr.Value = "20" item1.Attributes["damage"] = dmgAttr item1.Text = "Steel Sword" // Second item: change damage and type item2 := modElem.Children[1] dmgAttr2 := item2.Attributes["damage"] dmgAttr2.Value = "30" item2.Attributes["damage"] = dmgAttr2 typeAttr := item2.Attributes["type"] typeAttr.Value = "greataxe" item2.Attributes["type"] = typeAttr // Generate and apply changes changes := findXMLChanges(origElem, modElem, "") commands := applyXMLChanges(changes) result, _ := utils.ExecuteModifications(commands, original) // Verify if !strings.Contains(result, `damage="20"`) { t.Errorf("First item damage not updated") } if !strings.Contains(result, "Steel Sword") { t.Errorf("First item text not updated") } if !strings.Contains(result, `damage="30"`) { t.Errorf("Second item damage not updated") } if !strings.Contains(result, `type="greataxe"`) { t.Errorf("Second item type not updated") } if strings.Contains(result, "Iron Sword") { t.Errorf("Old text still present") } } // TestSelfClosingTagPreservation tests that self-closing tags work correctly func TestSelfClosingTagPreservation(t *testing.T) { original := ` ` // Parse origElem, err := parseXMLWithPositions(original) if err != nil { t.Fatalf("Failed to parse: %v", err) } // Modify first item's attribute modElem := deepCopyXMLElement(origElem) item := modElem.Children[0] nameAttr := item.Attributes["name"] nameAttr.Value = "modified" item.Attributes["name"] = nameAttr // Generate and apply changes changes := findXMLChanges(origElem, modElem, "") commands := applyXMLChanges(changes) result, _ := utils.ExecuteModifications(commands, original) // Verify the change was made if !strings.Contains(result, `name="modified"`) { t.Errorf("Attribute not updated: %s", result) } } // TestNumericAttributeModification tests numeric attribute changes func TestNumericAttributeModification(t *testing.T) { original := `` // Parse origElem, err := parseXMLWithPositions(original) if err != nil { t.Fatalf("Failed to parse: %v", err) } // Double all numeric values modElem := deepCopyXMLElement(origElem) // Helper to modify numeric attributes modifyNumericAttr := func(attrName string, multiplier float64) { if attr, exists := modElem.Attributes[attrName]; exists { if val, ok := parseNumeric(attr.Value); ok { attr.Value = formatNumeric(val * multiplier) modElem.Attributes[attrName] = attr } } } modifyNumericAttr("health", 2.0) modifyNumericAttr("mana", 2.0) modifyNumericAttr("stamina", 2.0) // Generate and apply changes changes := findXMLChanges(origElem, modElem, "") if len(changes) != 3 { t.Fatalf("Expected 3 changes, got %d", len(changes)) } commands := applyXMLChanges(changes) result, _ := utils.ExecuteModifications(commands, original) // Verify numeric changes if !strings.Contains(result, `health="200"`) { t.Errorf("Health not doubled: %s", result) } if !strings.Contains(result, `mana="100"`) { t.Errorf("Mana not doubled: %s", result) } if !strings.Contains(result, `stamina="151"`) { t.Errorf("Stamina not doubled: %s", result) } } // TestMinimalGitDiff verifies that only changed parts are modified func TestMinimalGitDiff(t *testing.T) { original := ` ` // Parse origElem, err := parseXMLWithPositions(original) if err != nil { t.Fatalf("Failed to parse: %v", err) } // Change only brightness modElem := deepCopyXMLElement(origElem) brightnessItem := modElem.Children[1] valueAttr := brightnessItem.Attributes["value"] valueAttr.Value = "90" brightnessItem.Attributes["value"] = valueAttr // Generate changes changes := findXMLChanges(origElem, modElem, "") // Should be exactly 1 change if len(changes) != 1 { t.Fatalf("Expected exactly 1 change for minimal diff, got %d", len(changes)) } if changes[0].OldValue != "75" || changes[0].NewValue != "90" { t.Errorf("Wrong change detected: %v", changes[0]) } // Apply commands := applyXMLChanges(changes) result, _ := utils.ExecuteModifications(commands, original) // Calculate diff size (rough approximation) diffChars := len(changes[0].OldValue) + len(changes[0].NewValue) if diffChars > 10 { t.Errorf("Diff too large: %d characters changed (expected < 10)", diffChars) } // Verify only brightness changed if !strings.Contains(result, `value="50"`) { t.Errorf("Volume incorrectly modified") } if !strings.Contains(result, `value="90"`) { t.Errorf("Brightness not modified") } if !strings.Contains(result, `value="100"`) { t.Errorf("Contrast incorrectly modified") } }