diff --git a/TextFilter.Test/TextFilterTests.cs b/TextFilter.Test/TextFilterTests.cs index e74ca60..a892f07 100644 --- a/TextFilter.Test/TextFilterTests.cs +++ b/TextFilter.Test/TextFilterTests.cs @@ -521,6 +521,27 @@ public void DoesMatchGlobWithByWordAllOptionReturnsFalse() Assert.IsFalse(result, "Not all words matching with ByWordAll option should return false."); } + [TestMethod] + public void DoesMatchGlobWithRequiredTokenByWordAllReturnsTrue() + { + bool result = TextFilter.DoesMatchGlob("hello world", "hello* +world", TextFilterMatchOptions.ByWordAll); + Assert.IsTrue(result, "A required token present among the text's words should return true under ByWordAll."); + } + + [TestMethod] + public void DoesMatchGlobWithAllRequiredTokensByWordAllReturnsTrue() + { + bool result = TextFilter.DoesMatchGlob("hello world", "+hello +world", TextFilterMatchOptions.ByWordAll); + Assert.IsTrue(result, "Every required token being present should return true under ByWordAll."); + } + + [TestMethod] + public void DoesMatchGlobWithMissingRequiredTokenByWordAllReturnsFalse() + { + bool result = TextFilter.DoesMatchGlob("hello world", "hello* +missing", TextFilterMatchOptions.ByWordAll); + Assert.IsFalse(result, "A required token absent from the text should still return false under ByWordAll."); + } + [TestMethod] public void DoesMatchGlobHandlesPartialFilter() { diff --git a/TextFilter/TextFilter.cs b/TextFilter/TextFilter.cs index 408752a..8b0c24a 100644 --- a/TextFilter/TextFilter.cs +++ b/TextFilter/TextFilter.cs @@ -283,11 +283,11 @@ public static bool DoesMatchGlob(string text, string filter, TextFilterMatchOpti return false; // optional tokens were set but text does not contain any optional tokens } - Func, bool> requiredMatchFunc = textFilterMatchOptions is TextFilterMatchOptions.ByWordAny - ? AnyTokenMatchesGlobFilter - : AllTokensMatchGlobFilter; - - bool allRequiredMatches = requiredTokens.All(filterToken => requiredMatchFunc(filterToken, textTokens)); + // A required token asks whether it appears among the text's words, which is the same + // question the excluded tokens above ask, so it uses the same function under every match + // option. Matching it with AllTokensMatchGlobFilter under ByWordAll would instead demand + // that every word in the text match the one required token, which no multi-word text can do. + bool allRequiredMatches = requiredTokens.All(filterToken => AnyTokenMatchesGlobFilter(filterToken, textTokens)); if (!allRequiredMatches) {