From a53f53e54a833f5b044e4aa5971af056bb7761dc Mon Sep 17 00:00:00 2001 From: Nicko Lee Date: Fri, 7 Jun 2019 10:35:36 +1000 Subject: [PATCH 1/3] Add lab 3 solution with some tests Implement letters() and sortLetters() and some tests for them. Stil need to fix test cases and understand table driven testing --- 03_letters/nickolee/letter_frequency.go | 47 +++++++ 03_letters/nickolee/letter_frequency_test.go | 123 +++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 03_letters/nickolee/letter_frequency.go create mode 100644 03_letters/nickolee/letter_frequency_test.go diff --git a/03_letters/nickolee/letter_frequency.go b/03_letters/nickolee/letter_frequency.go new file mode 100644 index 000000000..b6623ba83 --- /dev/null +++ b/03_letters/nickolee/letter_frequency.go @@ -0,0 +1,47 @@ +package main + +import ( + "fmt" + "io" + "os" + "sort" + "strings" +) + +var out io.Writer = os.Stdout + +func letters(s string) map[rune]int { + count := map[rune]int{} + + for _, char := range s { + count[char] = count[char] + 1 + } + + return count +} + +func sortLetters(m map[rune]int) []string { + result := make([]string, len(m)) + keys := []int{} + + // loop to get keys out of m. Ranging through m to extract keys to fill up keys slice + for char := range m { + keys = append(keys, int(char)) + } + + sort.Ints(keys) + + // building the result []string + for i, key := range keys { + result[i] = fmt.Sprintf("%c:%d", key, m[rune(key)]) // note that Sprintf returns u a formatted string it doesn't print anything + + } + + return result +} + +func main() { + // the strings.Join is to concatenate the new space to every char in s + fmt.Fprintln(out, strings.Join(sortLetters(letters("aba")), "\n")) + +} diff --git a/03_letters/nickolee/letter_frequency_test.go b/03_letters/nickolee/letter_frequency_test.go new file mode 100644 index 000000000..ecbc90c89 --- /dev/null +++ b/03_letters/nickolee/letter_frequency_test.go @@ -0,0 +1,123 @@ +package main + +import ( + "bytes" + "fmt" + "reflect" + "strconv" + "testing" +) + +func TestMainOutput(t *testing.T) { + var buf bytes.Buffer + out = &buf + + main() + + expected := strconv.Quote(`a:2 +b:1 +`) + actual := strconv.Quote(buf.String()) + + if expected != actual { + t.Errorf("Unexpected output in main()\nexpected: %q\nactual: %q", expected, actual) + } +} + +func TestLettersFunc(t *testing.T) { + tests := map[string]struct { + // input and expected are based on the function signature + input string + expected map[rune]int + }{ + "Empty string": { + input: "", + expected: map[rune]int{}}, // expect empty map + "ASCII string": { + // every possible ASCII character + input: " ]:!dx{,4E_ H@`)z?}pP?;qV>;#BhTxuro7o0,7x^B0'Bk{rfRu+#z_)?z1y'_>:o,2zEPKKcJ |p,s_*{=,h-BZpd-DzB<5y~ip/4SVL&;BWFK5vDAIVte\"t0E[e!5Mdag$kuV4NfpH*7t~Fs8^|I1V>Z;! ", + expected: map[rune]int{ + '@': 2, 'C': 2, 'H': 1, 'I': 1, 'K': 1, 'L': 1, 'O': 1, 'P': 1, 'R': 1, 'X': 2, 'Y': 1, '[': 1, + ' ': 6, '(': 1, ')': 2, ',': 1, '-': 2, '.': 1, '0': 3, '2': 2, '6': 1, '8': 3, '9': 3, '<': 3, + 'p': 1, 'q': 1, 't': 1, 'u': 2, 'x': 1, 'y': 1, 'z': 2, '{': 1, '}': 1, '~': 1, 'o': 1, + ']': 1, '`': 2, 'b': 1, 'd': 1, 'e': 2, 'f': 2, 'g': 1, 'h': 1, 'j': 1, 'm': 1, 'n': 3, + }}, + "Rune string": { + input: "踎걀핢॓슗ୱ戅ȏ捩뛃祿劉飋눣怅ቔⳟ螱∴औﺟ䚍ℝ૭😄耀膸݃โ✕뱔⯡㪦谏斦⫣ᄊ뵩䃽䇋㳀僝ꊏЭ쌮夋ㅀ걖৞⨹㓃吉☳〹ᦨ龮ﭯ⸋됅", + expected: map[rune]int{ + '㰗': 1, '㼪': 1, '哫': 1, '菎': 1, '뾬': 1, '쉱': 1, '췡': 1, '🀆': 1, '🀶': 1, '🁒': 1, + 'Ω': 1, 'ℬ': 1, '∲': 1, '≷': 1, '⊇': 1, '☞': 1, '✌': 1, '✤': 1, '❡': 1, 'Ɑ': 1, + '$': 1, 'ν': 1, '৲': 1, 'Ḹ': 1, 'Ṅ': 1, '€': 1, '₯': 1, '₲': 1, '₷': 1, '℠': 1, + '🂁': 1, '🃊': 1, '🐧': 1, '👀': 1, '😄': 1, '🤒': 1, + }}, + "String with esc chars": { + input: "\"Kia ora\"", + expected: map[rune]int{ + 'i': 1, 'o': 1, 'r': 1, ' ': 1, '"': 2, 'K': 1, 'a': 2, + }}, + } + + for name, test := range tests { + testData := test + t.Run(name, func(t *testing.T) { + actual := letters(testData.input) + if !reflect.DeepEqual(testData.expected, actual) { + fmt.Println(actual) + t.Errorf("Unexpected output in main()\nexpected: %q\nactual: %v", testData.expected, actual) + } + }) + } +} + +func TestSortLettersFunc(t *testing.T) { + tests := map[string]struct { + input map[rune]int + expected []string + }{ + "Empty map": { + input: map[rune]int{}, + expected: []string{}}, + "ASCII map": { + input: map[rune]int{ + '@': 2, 'C': 2, 'H': 1, 'I': 1, 'K': 1, 'L': 1, 'O': 1, 'P': 1, 'R': 1, 'X': 2, 'Y': 1, '[': 1, + ' ': 6, '(': 1, ')': 2, ',': 1, '-': 2, '.': 1, '0': 3, '2': 2, '6': 1, '8': 3, '9': 3, '<': 3, + 'p': 1, 'q': 1, 't': 1, 'u': 2, 'x': 1, 'y': 1, 'z': 2, '{': 1, '}': 1, '~': 1, 'o': 1, + ']': 1, '`': 2, 'b': 1, 'd': 1, 'e': 2, 'f': 2, 'g': 1, 'h': 1, 'j': 1, 'm': 1, 'n': 3, + }, + expected: []string{ + " :6", "(:1", "):2", ",:1", "-:2", ".:1", "0:3", "2:2", "6:1", "8:3", "9:3", "<:3", "@:2", "C:2", + "H:1", "I:1", "K:1", "L:1", "O:1", "P:1", "R:1", "X:2", "Y:1", "[:1", "]:1", "`:2", "b:1", "d:1", + "e:2", "f:2", "g:1", "h:1", "j:1", "m:1", "n:3", "o:1", "p:1", "q:1", "t:1", "u:2", "x:1", "y:1", + "z:2", "{:1", "}:1", "~:1", + }}, + "Rune map": { + input: map[rune]int{ + '㰗': 1, '㼪': 1, '哫': 1, '菎': 1, '뾬': 1, '쉱': 1, '췡': 1, '🀆': 1, '🀶': 1, '🁒': 1, + 'Ω': 1, 'ℬ': 1, '∲': 1, '≷': 1, '⊇': 1, '☞': 1, '✌': 1, '✤': 1, '❡': 1, 'Ɑ': 1, + '$': 1, '🃊': 1, '🐧': 1, '👀': 1, '😄': 1, '🤒': 1, '₯': 1, '₲': 1, '₷': 1, '℠': 1, + '🂁': 1, 'ν': 1, '৲': 1, 'Ḹ': 1, 'Ṅ': 1, '€': 1, + }, + expected: []string{ + "$:1", "ν:1", "৲:1", "Ḹ:1", "Ṅ:1", "€:1", "₯:1", "₲:1", "₷:1", "℠:1", "Ω:1", "ℬ:1", + "∲:1", "≷:1", "⊇:1", "☞:1", "✌:1", "✤:1", "❡:1", "Ɑ:1", "㰗:1", "㼪:1", "哫:1", "菎:1", "뾬:1", "쉱:1", + "췡:1", "🀆:1", "🀶:1", "🁒:1", "🂁:1", "🃊:1", "🐧:1", "👀:1", "😄:1", "🤒:1", + }}, + "Map with esc chars": { + input: map[rune]int{ + 'i': 1, 'o': 1, 'r': 1, ' ': 1, '"': 2, 'K': 1, 'a': 2, + }, + expected: []string{ + " :1", "\":2", "K:1", "a:2", "i:1", "o:1", "r:1", + }}, + } + + for name, test := range tests { + testData := test + t.Run(name, func(t *testing.T) { + actual := sortLetters(testData.input) + if !reflect.DeepEqual(testData.expected, actual) { + t.Errorf("Unexpected output in main()\nexpected: %s\nactual: %s", testData.expected, actual) + } + }) + } +} From 397834b0c9f6b2852a5422ccde11d16d7946e4e5 Mon Sep 17 00:00:00 2001 From: Nicko Lee Date: Mon, 24 Jun 2019 14:53:23 +1000 Subject: [PATCH 2/3] Write test cases and run golangci-lint run Get familiar with table driven testing based on the following article https://dave.cheney.net/2019/05/07/prefer-table-driven-tests --- 03_letters/nickolee/letter_frequency.go | 5 +- 03_letters/nickolee/letter_frequency_test.go | 129 ++++++++----------- 2 files changed, 56 insertions(+), 78 deletions(-) diff --git a/03_letters/nickolee/letter_frequency.go b/03_letters/nickolee/letter_frequency.go index b6623ba83..b5f09d8a4 100644 --- a/03_letters/nickolee/letter_frequency.go +++ b/03_letters/nickolee/letter_frequency.go @@ -14,7 +14,7 @@ func letters(s string) map[rune]int { count := map[rune]int{} for _, char := range s { - count[char] = count[char] + 1 + count[char]++ } return count @@ -33,7 +33,8 @@ func sortLetters(m map[rune]int) []string { // building the result []string for i, key := range keys { - result[i] = fmt.Sprintf("%c:%d", key, m[rune(key)]) // note that Sprintf returns u a formatted string it doesn't print anything + result[i] = fmt.Sprintf("%c:%d", key, m[rune(key)]) + // note that Sprintf returns u a formatted string it doesn't print anything } diff --git a/03_letters/nickolee/letter_frequency_test.go b/03_letters/nickolee/letter_frequency_test.go index ecbc90c89..954a50307 100644 --- a/03_letters/nickolee/letter_frequency_test.go +++ b/03_letters/nickolee/letter_frequency_test.go @@ -25,99 +25,76 @@ b:1 } func TestLettersFunc(t *testing.T) { - tests := map[string]struct { - // input and expected are based on the function signature + type test struct { + name string input string expected map[rune]int - }{ - "Empty string": { - input: "", - expected: map[rune]int{}}, // expect empty map - "ASCII string": { - // every possible ASCII character - input: " ]:!dx{,4E_ H@`)z?}pP?;qV>;#BhTxuro7o0,7x^B0'Bk{rfRu+#z_)?z1y'_>:o,2zEPKKcJ |p,s_*{=,h-BZpd-DzB<5y~ip/4SVL&;BWFK5vDAIVte\"t0E[e!5Mdag$kuV4NfpH*7t~Fs8^|I1V>Z;! ", + } + + tests := []test{ + {name: "empty string", input: "", expected: map[rune]int{}}, // expect empty map + {name: "ASCII string", input: " ``~8I,dzye[uY6 Date: Thu, 27 Jun 2019 21:27:33 +1000 Subject: [PATCH 3/3] Fix changes requested in PR Mainly around unnecessary whitespace --- 03_letters/nickolee/letter_frequency.go | 7 ------- 03_letters/nickolee/letter_frequency_test.go | 5 ----- 2 files changed, 12 deletions(-) diff --git a/03_letters/nickolee/letter_frequency.go b/03_letters/nickolee/letter_frequency.go index b5f09d8a4..c0e385bcf 100644 --- a/03_letters/nickolee/letter_frequency.go +++ b/03_letters/nickolee/letter_frequency.go @@ -12,11 +12,9 @@ var out io.Writer = os.Stdout func letters(s string) map[rune]int { count := map[rune]int{} - for _, char := range s { count[char]++ } - return count } @@ -28,21 +26,16 @@ func sortLetters(m map[rune]int) []string { for char := range m { keys = append(keys, int(char)) } - sort.Ints(keys) - // building the result []string for i, key := range keys { result[i] = fmt.Sprintf("%c:%d", key, m[rune(key)]) // note that Sprintf returns u a formatted string it doesn't print anything - } - return result } func main() { // the strings.Join is to concatenate the new space to every char in s fmt.Fprintln(out, strings.Join(sortLetters(letters("aba")), "\n")) - } diff --git a/03_letters/nickolee/letter_frequency_test.go b/03_letters/nickolee/letter_frequency_test.go index 954a50307..b18a6a02e 100644 --- a/03_letters/nickolee/letter_frequency_test.go +++ b/03_letters/nickolee/letter_frequency_test.go @@ -11,14 +11,11 @@ import ( func TestMainOutput(t *testing.T) { var buf bytes.Buffer out = &buf - main() - expected := strconv.Quote(`a:2 b:1 `) actual := strconv.Quote(buf.String()) - if expected != actual { t.Errorf("Unexpected output in main()\nexpected: %q\nactual: %q", expected, actual) } @@ -53,7 +50,6 @@ func TestLettersFunc(t *testing.T) { t.Fatalf("test case: %s failed. expected: %v, got: %v", testCase.name, testCase.expected, actual) } } - } func TestSortLettersFunction(t *testing.T) { @@ -96,5 +92,4 @@ func TestSortLettersFunction(t *testing.T) { t.Fatalf("test case: %s failed. expected: %v, got: %v", testCase.name, testCase.expected, actual) } } - }