From d11b5025eb2ec4686ac09d2e867fe7e1f72c2f2e Mon Sep 17 00:00:00 2001 From: Michalis Zampetakis Date: Fri, 28 Jan 2022 13:20:39 +0200 Subject: [PATCH] Add IsSubstringOf assertion (#45) --- README.md | 2 +- assert/error_messages.go | 4 +++ assert/string.go | 10 +++++++ assert/string_test.go | 44 +++++++++++++++++++++++++++++ internal/pkg/values/string_value.go | 5 ++++ 5 files changed, 64 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7ec8fd2..45b0163 100644 --- a/README.md +++ b/README.md @@ -95,5 +95,5 @@ For the following types basic assertions are supported * [x] IsLowerCase * [x] IsNotEqualToIgnoringCase * [x] IsNotEqualToIgnoringWhitespace - * [ ] IsSubstringOf + * [x] IsSubstringOf * [x] IsUpperCase diff --git a/assert/error_messages.go b/assert/error_messages.go index 235c7e8..addb28b 100644 --- a/assert/error_messages.go +++ b/assert/error_messages.go @@ -113,6 +113,10 @@ func shouldNotContain(actual types.Assertable, elements interface{}) string { return fmt.Sprintf("assertion failed: containable [%v] should not contain [%+v], but it does", actual.Value(), elements) } +func shouldBeSubstringOf(actual types.Assertable, elements interface{}) string { + return fmt.Sprintf("assertion failed: containable [%v] should be substring of [%+v], but it does", actual.Value(), elements) +} + func shouldBeMap(actual types.Assertable) string { return fmt.Sprintf("assertion failed: assertable should be a map but it is %T", reflect.ValueOf(actual.Value()).Kind()) } diff --git a/assert/string.go b/assert/string.go index d423385..b777cb9 100644 --- a/assert/string.go +++ b/assert/string.go @@ -195,6 +195,16 @@ func (a AssertableString) DoesNotContain(substring string) AssertableString { return a } +// IsSubstringOf asserts if the assertable string is a substring of the given element +// It errors the test if it does not contain it. +func (a AssertableString) IsSubstringOf(someString string) AssertableString { + a.t.Helper() + if !a.actual.IsSubstringOf(someString) { + a.t.Error(shouldBeSubstringOf(a.actual, someString)) + } + return a +} + // StartsWith asserts if the assertable string starts with the given substring // It errors the test if it doesn't start with the given substring. func (a AssertableString) StartsWith(substring string) AssertableString { diff --git a/assert/string_test.go b/assert/string_test.go index ca8617b..0877d7e 100644 --- a/assert/string_test.go +++ b/assert/string_test.go @@ -527,6 +527,50 @@ func TestAssertableString_DoesNotContain(t *testing.T) { } } +func TestAssertableString_IsSubstringOf(t *testing.T) { + tests := []struct { + name string + actual string + containerString string + shouldFail bool + stringOpts []StringOpt + }{ + { + name: "should succeed if it does not contain the expected sub-string", + actual: "happy man", + containerString: "I'm a happy man", + shouldFail: false, + }, + { + name: "should fail if it is substring of the containerString", + actual: "I'M a HAPPY", + containerString: "I'm a happy man", + shouldFail: true, + }, + { + name: "should succeed if it is substring of the containerString with ignoring case", + actual: "I'M a HAPPY", + containerString: "I'm a happy man", + shouldFail: false, + stringOpts: []StringOpt{IgnoringCase()}, + }, + { + name: "should succeed if is is an empty string", + actual: "", + containerString: "I'm a happy man", + shouldFail: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + test := &testing.T{} + ft := NewFluentT(test) + ft.AssertThatString(tt.actual, tt.stringOpts...).IsSubstringOf(tt.containerString) + ThatBool(t, test.Failed()).IsEqualTo(tt.shouldFail) + }) + } +} + func TestAssertableString_StartsWith(t *testing.T) { tests := []struct { name string diff --git a/internal/pkg/values/string_value.go b/internal/pkg/values/string_value.go index 03dbee6..301ea5d 100644 --- a/internal/pkg/values/string_value.go +++ b/internal/pkg/values/string_value.go @@ -75,6 +75,11 @@ func (s StringValue) DoesNotContain(expected interface{}) bool { return !s.Contains(s.decoratedValue(expected)) } +// IsSubstringOf returns true if the string is substring of the given string. +func (s StringValue) IsSubstringOf(expected interface{}) bool { + return strings.Contains(NewStringValue(s.decoratedValue(expected)).value, s.DecoratedValue()) +} + // HasSize returns true if the string has the expected size else false. func (s StringValue) HasSize(length int) bool { return s.Size() == length