package sdkserver import ( "bytes" "encoding/json" "net/http" "net/http/httptest" "os" "strings" "testing" ) func TestAvatarCommandPatchesOnlyRequestedAvatarFields(t *testing.T) { chdirRepoRootSDK(t) raw, err := os.ReadFile("freesr-data.json") if err != nil { t.Fatal(err) } var root map[string]json.RawMessage if err = json.Unmarshal(raw, &root); err != nil { t.Fatal(err) } var avatars map[string]json.RawMessage if err = json.Unmarshal(root["avatars"], &avatars); err != nil { t.Fatal(err) } var avatar map[string]json.RawMessage if err = json.Unmarshal(avatars["1204"], &avatar); err != nil { t.Fatal(err) } avatar["future_field"] = json.RawMessage(`{"value":1234567890123456789}`) avatars["1204"], _ = json.Marshal(avatar) root["avatars"], _ = json.Marshal(avatars) root["future_root"] = json.RawMessage(`{"keep":true}`) compact := func(value json.RawMessage) string { if len(value) == 0 { return "" } var b bytes.Buffer if err := json.Compact(&b, value); err != nil { t.Fatal(err) } return b.String() } beforeMaterials := compact(root["materials"]) beforeOtherAvatar := compact(avatars["1213"]) initial, _ := json.Marshal(root) if err := os.WriteFile("freesr-data.json", initial, 0600); err != nil { t.Fatal(err) } run := func(command string) bool { body, _ := json.Marshal(map[string]string{"command": command}) w := httptest.NewRecorder() apiCommand(w, httptest.NewRequest(http.MethodPost, "/api/command", strings.NewReader(string(body)))) var result struct { Success bool `json:"success"` } if err := json.Unmarshal(w.Body.Bytes(), &result); err != nil { t.Fatal(err) } return result.Success } if !run("/avatar 1204 42 3") { t.Fatal("valid avatar update failed") } updated, _ := os.ReadFile("freesr-data.json") if err := json.Unmarshal(updated, &root); err != nil { t.Fatal(err) } if err := json.Unmarshal(root["avatars"], &avatars); err != nil { t.Fatal(err) } if err := json.Unmarshal(avatars["1204"], &avatar); err != nil { t.Fatal(err) } var data struct { Rank uint32 `json:"rank"` } if err := json.Unmarshal(avatar["data"], &data); err != nil { t.Fatal(err) } var level uint32 if err := json.Unmarshal(avatar["level"], &level); err != nil { t.Fatal(err) } if level != 42 || data.Rank != 3 || compact(avatar["future_field"]) != `{"value":1234567890123456789}` || compact(root["future_root"]) != `{"keep":true}` || compact(root["materials"]) != beforeMaterials || compact(avatars["1213"]) != beforeOtherAvatar { t.Fatal("avatar update lost or modified unrelated data") } for _, invalid := range []string{"/avatar 1204 81", "/avatar 1204 2 7", "/avatar nope 5", "/avatar 999999 5"} { if run(invalid) { t.Fatalf("accepted %s", invalid) } after, _ := os.ReadFile("freesr-data.json") if string(after) != string(updated) { t.Fatalf("invalid command rewrote save: %s", invalid) } } }