Skip to content
This repository has been archived by the owner on Mar 22, 2022. It is now read-only.

config: Only marshal Slug, UUID, Deprecated of deprecated exercises #169

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions track/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,36 @@ func (cfg *Config) ToJSON() ([]byte, error) {
return json.MarshalIndent(&cfg, "", " ")
}

// MarshalJSON marshals a exercise metadata to JSON,
// only marshalling certain fields if the exercise is deprecated.
func (e *ExerciseMetadata) MarshalJSON() ([]byte, error) {
if e.IsDeprecated {
// Only marshal Slug, UUID, Deprecated.
return json.Marshal(&struct {
Slug string `json:"slug"`
UUID string `json:"uuid"`
IsDeprecated bool `json:"deprecated"`
}{
Slug: e.Slug,
UUID: e.UUID,
IsDeprecated: true,
})
} else {
// Use the default marshalling.
// We can't embed ExerciseMetadata into an anonymous struct,
// since that will cause infinite recursion on this MarshalJSON,
// But we can embed a new typedef of it,
// since the typedef does not have this MarshalJSON function.
// Technique discovered from http://choly.ca/post/go-json-marshalling/
type ExerciseMetadataJ ExerciseMetadata
return json.Marshal(&struct {
*ExerciseMetadataJ
}{
ExerciseMetadataJ: (*ExerciseMetadataJ)(e),
})
}
}

func normalizeTopic(t string) string {
s := strings.ToLower(t)
s = rgxFunkyChars.ReplaceAllString(s, "")
Expand Down
81 changes: 81 additions & 0 deletions track/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,87 @@ func TestMarshalingNormalizesTopics(t *testing.T) {
assert.Equal(t, []string{"apple", "fig", "honeydew_melon"}, dstCfg.Exercises[0].Topics)
}

var allExercisesKeys = []string{
"slug",
"uuid",
}

var activeExercisesKeys = []string{
"core",
// not auto_approve, since it is omitempty
"unlocked_by",
"difficulty",
"topics",
}

func TestMarshalActive(t *testing.T) {
srcCfg := Config{
Exercises: []ExerciseMetadata{
ExerciseMetadata{
Slug: "active",
Topics: []string{"topic_one", "topic_two"},
IsDeprecated: false,
},
},
}

dst, err := srcCfg.ToJSON()
if err != nil {
t.Fatal(err)
}

// contains all the keys we expect it to contain:
for _, key := range append(allExercisesKeys, activeExercisesKeys...) {
assert.True(t, strings.Contains(string(dst), key), "expected JSON representation to contain %q, but it didn't: %s", key, string(dst))
}

var dstCfg Config
if err := json.NewDecoder(bytes.NewReader(dst)).Decode(&dstCfg); err != nil {
t.Fatal(err)
}

// survived an encode -> decode:
assert.Equal(t, "active", dstCfg.Exercises[0].Slug)
assert.False(t, dstCfg.Exercises[0].IsDeprecated)
assert.Equal(t, []string{"topic_one", "topic_two"}, dstCfg.Exercises[0].Topics)
}

func TestMarshalDeprecated(t *testing.T) {
srcCfg := Config{
Exercises: []ExerciseMetadata{
ExerciseMetadata{
Slug: "deprecated",
Topics: []string{"topic_one", "topic_two"},
IsDeprecated: true,
},
},
}

dst, err := srcCfg.ToJSON()
if err != nil {
t.Fatal(err)
}

// contains the keys we want, and not the ones we don't:
for _, key := range append(allExercisesKeys, "deprecated") {
assert.True(t, strings.Contains(string(dst), key), "expected JSON representation to contain %q, but it didn't: %s", key, string(dst))
}
for _, key := range activeExercisesKeys {
assert.False(t, strings.Contains(string(dst), key), "expected JSON representation NOT to contain %q, but it did: %s", key, string(dst))
}

var dstCfg Config
if err := json.NewDecoder(bytes.NewReader(dst)).Decode(&dstCfg); err != nil {
t.Fatal(err)
}

// survived an encode -> decode:
assert.Equal(t, "deprecated", dstCfg.Exercises[0].Slug)
assert.True(t, dstCfg.Exercises[0].IsDeprecated)
// Note that since topics was never marshalled, it should be nil.
assert.Nil(t, dstCfg.Exercises[0].Topics)
}

func TestSemanticsOfMissingTopics(t *testing.T) {
src := `
{
Expand Down