From 9dd89c4450d2599b6b760963ec09821239fd1a44 Mon Sep 17 00:00:00 2001 From: Saswata Mukherjee Date: Thu, 1 Dec 2022 13:55:09 +0530 Subject: [PATCH 1/2] Port Contains method Signed-off-by: Saswata Mukherjee --- testutil/testutil.go | 46 +++++++++++++++++++++++++ testutil/testutil_test.go | 70 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 testutil/testutil_test.go diff --git a/testutil/testutil.go b/testutil/testutil.go index 46b6fef..75ce4ef 100644 --- a/testutil/testutil.go +++ b/testutil/testutil.go @@ -92,6 +92,52 @@ func FaultOrPanicToErr(f func()) (err error) { return err } +// Contains fails the test if needle is not contained within haystack, if haystack or needle is +// an empty slice, or if needle is longer than haystack. +func Contains(tb testing.TB, haystack, needle []string) { + _, file, line, _ := runtime.Caller(1) + + if !contains(haystack, needle) { + tb.Fatalf(sprintfWithLimit("\033[31m%s:%d: %#v does not contain %#v\033[39m\n\n", filepath.Base(file), line, haystack, needle)) + } +} + +func contains(haystack, needle []string) bool { + if len(haystack) == 0 || len(needle) == 0 { + return false + } + + if len(haystack) < len(needle) { + return false + } + + for i := 0; i < len(haystack); i++ { + outer := i + + for j := 0; j < len(needle); j++ { + // End of the haystack but not the end of the needle, end + if outer == len(haystack) { + return false + } + + // No match, try the next index of the haystack + if haystack[outer] != needle[j] { + break + } + + // End of the needle and it still matches, end + if j == len(needle)-1 { + return true + } + + // This element matches between the two slices, try the next one + outer++ + } + } + + return false +} + func sprintfWithLimit(act string, v ...interface{}) string { s := fmt.Sprintf(act, v...) if len(s) > 10000 { diff --git a/testutil/testutil_test.go b/testutil/testutil_test.go new file mode 100644 index 0000000..ac42702 --- /dev/null +++ b/testutil/testutil_test.go @@ -0,0 +1,70 @@ +// Copyright (c) The EfficientGo Authors. +// Licensed under the Apache License 2.0. + +package testutil + +import "testing" + +func TestContains(t *testing.T) { + tests := map[string]struct { + haystack []string + needle []string + shouldMatch bool + }{ + "empty haystack": { + haystack: []string{}, + needle: []string{"key1"}, + shouldMatch: false, + }, + + "empty needle": { + haystack: []string{"key1", "key2", "key3"}, + needle: []string{}, + shouldMatch: false, + }, + + "single value needle": { + haystack: []string{"key1", "key2", "key3"}, + needle: []string{"key1"}, + shouldMatch: true, + }, + + "multiple value needle": { + haystack: []string{"key1", "key2", "key3"}, + needle: []string{"key1", "key2"}, + shouldMatch: true, + }, + + "same size needle as haystack": { + haystack: []string{"key1", "key2", "key3"}, + needle: []string{"key1", "key2", "key3"}, + shouldMatch: true, + }, + + "larger needle than haystack": { + haystack: []string{"key1", "key2", "key3"}, + needle: []string{"key1", "key2", "key3", "key4"}, + shouldMatch: false, + }, + + "needle not contained": { + haystack: []string{"key1", "key2", "key3"}, + needle: []string{"key4"}, + shouldMatch: false, + }, + + "haystack ends before needle": { + haystack: []string{"key1", "key2", "key3"}, + needle: []string{"key3", "key4"}, + shouldMatch: false, + }, + } + + for testName, testData := range tests { + t.Run(testName, func(t *testing.T) { + if testData.shouldMatch != contains(testData.haystack, testData.needle) { + t.Fatalf("unexpected result testing contains() with %#v", testData) + } + }) + } +} From 17215cc6e72c7e21e42eb3ce80dc3db37de48754 Mon Sep 17 00:00:00 2001 From: Saswata Mukherjee Date: Thu, 1 Dec 2022 15:39:29 +0530 Subject: [PATCH 2/2] Change to ContainsStringSlice Signed-off-by: Saswata Mukherjee --- merrors/doc.go | 15 +++++++-------- testutil/testutil.go | 4 ++-- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/merrors/doc.go b/merrors/doc.go index 0ea02d3..a670493 100644 --- a/merrors/doc.go +++ b/merrors/doc.go @@ -19,12 +19,11 @@ // // Example 3: // -// func CloseAll(closers []io.Closer) error { -// errs := merrors.New() -// for _ , c := range closers { -// errs.Add(c.Close()) -// } -// return errs.Err() -// } -// +// func CloseAll(closers []io.Closer) error { +// errs := merrors.New() +// for _ , c := range closers { +// errs.Add(c.Close()) +// } +// return errs.Err() +// } package merrors diff --git a/testutil/testutil.go b/testutil/testutil.go index 75ce4ef..c74f368 100644 --- a/testutil/testutil.go +++ b/testutil/testutil.go @@ -92,9 +92,9 @@ func FaultOrPanicToErr(f func()) (err error) { return err } -// Contains fails the test if needle is not contained within haystack, if haystack or needle is +// ContainsStringSlice fails the test if needle is not contained within haystack, if haystack or needle is // an empty slice, or if needle is longer than haystack. -func Contains(tb testing.TB, haystack, needle []string) { +func ContainsStringSlice(tb testing.TB, haystack, needle []string) { _, file, line, _ := runtime.Caller(1) if !contains(haystack, needle) {