From e2b54c384c6e2b7b7a5ab965d63d44ff5cfc1858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bertalan=20Kov=C3=A1cs?= Date: Tue, 16 Dec 2025 00:03:57 +0100 Subject: [PATCH 1/3] feat: init structure --- 25-testing/01-testify/.README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 25-testing/01-testify/.README.md diff --git a/25-testing/01-testify/.README.md b/25-testing/01-testify/.README.md new file mode 100644 index 0000000..e69de29 From c0ca3a6dab0ac67829af96e8dd6213e4cdee6518 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bertalan=20Kov=C3=A1cs?= Date: Tue, 16 Dec 2025 00:08:06 +0100 Subject: [PATCH 2/3] feat: created exercise --- 25-testing/01-testify/.exercise.go | 82 +++++++++++++++++++++++++ 25-testing/01-testify/.exercise_test.go | 80 ++++++++++++++++++++++++ 25-testing/01-testify/exercise.yaml | 5 ++ 3 files changed, 167 insertions(+) create mode 100644 25-testing/01-testify/.exercise.go create mode 100644 25-testing/01-testify/.exercise_test.go create mode 100644 25-testing/01-testify/exercise.yaml diff --git a/25-testing/01-testify/.exercise.go b/25-testing/01-testify/.exercise.go new file mode 100644 index 0000000..6938dfe --- /dev/null +++ b/25-testing/01-testify/.exercise.go @@ -0,0 +1,82 @@ +package testimony + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +// DO NOT REMOVE THIS COMMENT +//go:generate go run ../../exercises-cli.go -student-id=$STUDENT_ID generate +{{if eq (index . "name") "strstr"}} +func strstr(str string, substr string) int { + if substr == "" { + return 0 + } + + for i := 0; i <= len(str)-len(substr); i++ { + if str[i:i+len(substr)] == substr { + return i + } + } + + return -1 +} +{{end}} +{{if eq (index . "name") "strncat"}} +func strncat(dest *string, src string, n int) { + if n > len(src) { + n = len(src) + } + *dest += src[:n] +} +{{end}} +{{if eq (index . "name") "strncpy"}} +func strncpy(dest *string, src string, n int) { + if n > len(src) { + n = len(src) + } + *dest = src[:n] +} +{{end}} + +// INSERT YOUR CODE HERE +{{if eq (index . "name") "strstr"}} +func StrStrMatch(t *testing.T) { + +} + +func StrStrNoMatch(t *testing.T) { + +} + +func StrStrEmptySubString(t *testing.T) { + +} +{{end}} +{{if eq (index . "name") "strncat"}} +func StrNCatInbounds(t *testing.T) { + +} + +func StrNCatOutOfBounds(t *testing.T) { + +} + +func StrNCatEmptySource(t *testing.T) { + +} +{{end}} +{{if eq (index . "name") "strncpy"}} +func StrNCpyINbounds(t *testing.T) { + +} + +func StrNCpyEmptyDestination(t *testing.T) { + +} + +func StrNCpyEmptySource(t *testing.T) { + +} +{{end}} \ No newline at end of file diff --git a/25-testing/01-testify/.exercise_test.go b/25-testing/01-testify/.exercise_test.go new file mode 100644 index 0000000..8300b8b --- /dev/null +++ b/25-testing/01-testify/.exercise_test.go @@ -0,0 +1,80 @@ +package testimony + +import ( + "os" + "regexp" + "testing" +) + +const requiredAsserts = 3 + +func TestStudentUsesAssertions(t *testing.T) { + src, err := os.ReadFile("exercise.go") + if err != nil { + t.Fatalf("cannot read exercise.go: %v", err) + } + + source := string(src) + + re := regexp.MustCompile(`assert\.\w+\s*\(`) + if !re.MatchString(source) { + t.Fatalf("no assert.* call found in exercise.go") + } +} + +func TestStudentHasEnoughAsserts(t *testing.T) { + src, err := os.ReadFile("exercise.go") + if err != nil { + t.Fatalf("cannot read exercise.go: %v", err) + } + + source := string(src) + + re := regexp.MustCompile(`assert\.\w+\s*\(`) + matches := re.FindAllString(source, -1) + + if len(matches) < requiredAsserts { + t.Fatalf("not enough assert calls: found %d, required %d", len(matches), requiredAsserts) + } +} + +func TestNoTrivialAssertions(t *testing.T) { + src, err := os.ReadFile("exercise.go") + if err != nil { + t.Fatalf("cannot read exercise.go: %v", err) + } + + source := string(src) + + patterns := []string{ + `assert\.False\s*\(\s*t\s*,\s*false\s*[,)]`, + `assert\.True\s*\(\s*t\s*,\s*true\s*[,)]`, + `assert\.Equal\s*\(\s*t\s*,\s*true\s*,\s*true\s*[,)]`, + `assert\.Equal\s*\(\s*t\s*,\s*false\s*,\s*false\s*[,)]`, + } + + for _, p := range patterns { + re := regexp.MustCompile(p) + if re.MatchString(source) { + t.Fatalf("trivial assertion detected") + } + } +} + +func TestRunStudentTests(t *testing.T) { +{{if eq (index . "name") "strstr"}} + t.Run("StrStrMatch", StrStrMatch) + t.Run("StrStrNoMatch", StrStrNoMatch) + t.Run("StrStrEmptySubString", StrStrEmptySubString) +{{end}} +{{if eq (index . "name") "strncat"}} + t.Run("StrNCatInbounds", StrNCatInbounds) + t.Run("StrNCatOutOfBounds", StrNCatOutOfBounds) + t.Run("StrNCatEmptySource", StrNCatEmptySource) +{{end}} +{{if eq (index . "name") "strncpy"}} + t.Run("StrNCpyINbounds", StrNCpyINbounds) + t.Run("StrNCpyEmptyDestination", StrNCpyEmptyDestination) + t.Run("StrNCpyEmptySource", StrNCpyEmptySource) +{{end}} +} diff --git a/25-testing/01-testify/exercise.yaml b/25-testing/01-testify/exercise.yaml new file mode 100644 index 0000000..39bf2b0 --- /dev/null +++ b/25-testing/01-testify/exercise.yaml @@ -0,0 +1,5 @@ +name: testimony +input: +- name: strstr +- name: strncat +- name: strncpy \ No newline at end of file From 61141181d1e5d29aafd9b73eab3384ac78904eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bertalan=20Kov=C3=A1cs?= Date: Tue, 16 Dec 2025 00:29:40 +0100 Subject: [PATCH 3/3] feat: .README.md --- 25-testing/01-testify/.README.md | 85 ++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/25-testing/01-testify/.README.md b/25-testing/01-testify/.README.md index e69de29..6aaa6b6 100644 --- a/25-testing/01-testify/.README.md +++ b/25-testing/01-testify/.README.md @@ -0,0 +1,85 @@ +# Testing + +In this task, you need to test the function `{{ index . "name" }}` in Go using **`testify/assert`**. + +## Function Description + +{{- if eq (index . "name") "strstr" -}} +### `strstr(str string, substr string) int` + +- Returns the **index of the first occurrence** of `substr` in `str`. +- Returns `0` if `substr` is empty. +- Returns `-1` if `substr` is not found. + +**Example:** + +```go +strstr("hello world", "lo") // 3 + +strstr("hello", "Go") // -1 + +strstr("abc", "") // 0 +``` +{{- end -}} +{{- if eq (index . "name") "strncat" -}} +### `strncat(dest *string, src string, n int)` + +- Appends at most `n` characters from `src` to `dest`. +- Modifies `dest` in place + +**Example:** + +```go +dest := "Hello" +strncat(&dest, "World", 3) // dest == "HelloWor" + +dest := "Hi" +strncat(&dest, "All", 10) // dest == "HiAll" + +dest := "" +strncat(&dest, "Go", 1) // dest == "G" +``` +{{- end -}} +{{- if eq (index . "name") "strncpy" -}} +### `strncpy(dest *string, src string, n int)` + +- Copies at most `n` characters from `src` to `dest`. +- Modifies `dest` in place + +**Example:** + +```go +dest := "Hello" +strncpy(&dest, "Go", 2) // dest == "Go" + +dest := "" +strncpy(&dest, "World", 3) // dest == "Wor" + +dest := "Hi" +strncpy(&dest, "", 1) // dest == "" +``` +{{- end -}} + +## Requirements +1. Use only assert statements from the [testify/assert](https://pkg.go.dev/github.com/stretchr/testify/assert) package. +2. Do not modify the provided function signature. +3. Write exactly three test functions for the function `{{ index . "name" }}`. + +## Needed test functions: +{{- if eq (index . "name") "strstr" -}} +- `StrStrMatch` — test when the substring exists +- `StrStrNoMatch` — test when the substring does not exist +- `StrStrEmptySubString` — test when the substring is empty +{{end}} +{{- if eq (index . "name") "strncat" -}} +- `StrNCatInbounds` — append a part of the source within index bounds +- `StrNCatOutOfBounds` — append more than the source length +- `StrNCatEmptySource` — append from an empty source +{{end}} +{{- if eq (index . "name") "strncpy" -}} +- `StrNCpyINbounds` — copy part of the source within index bounds +- `StrNCpyEmptyDestination` — copy into an empty destination +- `StrNCpyEmptySource` — copy from an empty source +{{end}} + +Insert the code into the file `exercise.go` at the placeholder `// INSERT YOUR CODE HERE`. \ No newline at end of file