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

Commit

Permalink
config: Only marshal Slug, UUID, Deprecated of deprecated exercises
Browse files Browse the repository at this point in the history
We don't need any of the other fields, and it's deceptive to keep them
in the JSON file because a maintainer may mistakenly believe them to
mean something, whereas they mean nothing.

Two new tests were added: TestMarshalActive and TestMarshalDeprecated.
TestMarshalActive passes both before and after the associated code
change.
TestMarshalDeprecated fails before the associated code change, and
passes after.

Closes exercism/configlet#140
  • Loading branch information
petertseng committed Sep 17, 2019
1 parent b574418 commit 53d2d8a
Show file tree
Hide file tree
Showing 2 changed files with 111 additions and 0 deletions.
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

0 comments on commit 53d2d8a

Please sign in to comment.