package main import ( "encoding/json" "os" "path/filepath" "reflect" "testing" ) func TestRecordRoundTrip(t *testing.T) { want := StudyRecord{Title: "学习 Go", Minutes: 30, Finished: true, Tags: []string{"Go", "JSON"}, Note: "复习"} data, err := encodeRecord(want) if err != nil { t.Fatalf("编码失败:%v", err) } // 测试使用隔离目录,结束后由测试框架清理。 path := filepath.Join(t.TempDir(), "record.json") if err := os.WriteFile(path, data, 0600); err != nil { t.Fatalf("写文件失败:%v", err) } saved, err := os.ReadFile(path) if err != nil { t.Fatalf("读文件失败:%v", err) } got, err := decodeRecord(saved) if err != nil { t.Fatalf("解码失败:%v", err) } // 结构体含切片,不能直接用 == 比较;这里用 DeepEqual 检查内容。 if !reflect.DeepEqual(got, want) { t.Errorf("往返结果=%+v,期望=%+v", got, want) } } func TestOmitEmptyNote(t *testing.T) { data, err := encodeRecord(StudyRecord{Title: "练习"}) if err != nil { t.Fatal(err) } var fields map[string]json.RawMessage if err := json.Unmarshal(data, &fields); err != nil { t.Fatal(err) } if _, ok := fields["note"]; ok { t.Error("空 note 应当在编码时被省略") } if _, ok := fields["title"]; !ok { t.Error("应包含 title 字段") } } func TestDecodeInvalid(t *testing.T) { tests := []struct { name string data string }{ {name: "malformed", data: `{"title":`}, {name: "wrong_type", data: `{"minutes":"三十"}`}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if _, err := decodeRecord([]byte(tt.data)); err == nil { t.Error("非法输入应返回错误") } }) } }