/* * Copyright 2000-2017 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.buildServer.server.rest.data; import jetbrains.buildServer.parameters.ParametersProvider; import jetbrains.buildServer.parameters.impl.MapParametersProviderImpl; import jetbrains.buildServer.server.rest.errors.BadRequestException; import jetbrains.buildServer.server.rest.errors.LocatorProcessException; import jetbrains.buildServer.serverSide.impl.BaseServerTestCase; import jetbrains.buildServer.util.CollectionsUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.testng.annotations.Test; import static jetbrains.buildServer.util.Util.map; /** * @author Yegor.Yarko * Date: 22/04/2016 */ public class ParameterConditionTest extends BaseServerTestCase { //need to extend BaseServerTestCase at least to get TeamCityProperties @Test public void testBasic() { assertNull(ParameterCondition.create((String)null)); exception(LocatorProcessException.class, ""); exception(LocatorProcessException.class, "name:a,some:b"); exception(LocatorProcessException.class, "some:b"); exception(BadRequestException.class, "name:a,value:b,matchType:abra"); } @Test public void testName() { matchesFalse("name:aaa"); matchesTrue("name:aaa", "aaa", "value"); matchesTrue("name:aaa", "aaa", ""); matchesFalse("name:aaa", "aaaa", "value"); matchesFalse("name:aaa", "aa", "value"); matchesFalse("name:aaa", "x", "aaa"); matchesFalse("name:aaa", "aa", ""); matchesFalse("name:a", "A", "value"); matchesFalse("name:A", "a", "value"); matchesTrue("a", "a", "value"); matchesFalse("a", "aa", "a"); matchesFalse("a"); matchesFalse("A", "a", "value"); } @Test public void testValue() { matchesFalse("value:aaa"); matchesTrue("value:aaa", "x", "aaa"); matchesTrue("value:aaa", "", "aaa"); matchesFalse("value:aaa", "x", "aaaa"); matchesTrue("value:aaa,matchType:contains", "x", "aaaa"); matchesFalse("value:aaa", "x", "baaa"); matchesTrue("value:aaa,matchType:contains", "x", "baaa"); matchesFalse("value:aaa", "x", "aaac"); matchesTrue("value:aaa,matchType:contains", "x", "aaac"); matchesFalse("value:aaa", "x", "baaac"); matchesTrue("value:aaa,matchType:contains", "x", "baaac"); matchesFalse("value:aaa", "x", "AAA"); matchesFalse("value:aaa", "x", "aa"); } @Test public void testNameValue() { matchesFalse("name:xxx,value:aaa"); matchesTrue("name:xxx,value:aaa", "xxx", "aaa"); matchesFalse("name:xxx,value:aaa", "xxx", "baaac"); matchesTrue("name:xxx,value:aaa,matchType:contains", "xxx", "baaac"); matchesFalse("name:xxx,value:aaa", "xxx", "AAA"); matchesFalse("name:xxx,value:aaa", "xxxx", "AAA"); matchesFalse("name:xxx,value:aaa", "xxxx", ""); matchesFalse("name:xxx,value:aaa", "", "aaa"); } @Test public void testMatches() { matchesFalse("matchType:exists"); //todo ? matchesTrue("matchType:exists", "a", "b"); //todo ? matchesFalse("matchType:not-exists"); //todo ? exception(BadRequestException.class, "matchType:matches"); exception(BadRequestException.class, "matchType:does-not-match"); exception(BadRequestException.class, "matchType:equals"); exception(BadRequestException.class, "name:xxx,matchType:matches"); matchesFalse("value:x.x,matchType:matches", "a", "z", "b", "zzz"); //at least some parameter should match matchesTrue("value:x.x,matchType:matches", "a", "x", "b", "xxx"); matchesFalse("value:x.x,matchType:matches,matchScope:all", "a", "x", "b", "xxx"); matchesTrue("value:x.x,matchType:matches,matchScope:all", "a", "xXx", "b", "xxx"); matchesFalse("name:xxx,value:aaa,matchType:matches"); matchesTrue("name:xxx,value:aaa,matchType:matches", "xxx", "aaa"); matchesFalse("name:xxx,value:aaa,matchType:matches", "xxx", "aaaa"); matchesFalse("name:xxx,value:aaa,matchType:matches", "yyy", "aaa"); matchesFalse("name:xxx,value:aaa,matchType:matches", "", "aaa"); matchesTrue("name:xxx,value:.,matchType:matches", "xxx", "a"); matchesTrue("name:xxx,value:.,matchType:matches", "xxx", "A"); matchesTrue("name:xxx,value:.,matchType:matches", "xxx", "."); matchesFalse("name:xxx,value:.,matchType:matches", "xxx", "aa"); exception(BadRequestException.class, "name:xxx,value:.,matchType:Matches"); matchesTrue("name:xxx,value:a.c,matchType:matches", "xxx", "abc", "yyy", "ccc"); matchesFalse("name:xxx,value:a.c,matchType:matches", "xxx", "abb", "yyy", "ccc"); matchesTrue("name:xxx,matchType:exists", "xxx", "abc", "yyy", "ccc"); matchesTrue("name:xxx,value:mmm,matchType:exists", "xxx", "abc", "yyy", "ccc"); matchesFalse("name:xxx,matchType:exists", "xxxy", "abc", "yyy", "ccc"); matchesFalse("name:xxx,matchType:not-exists", "xxx", "abc", "yyy", "ccc"); matchesFalse("name:xxx,value:mmm,matchType:not-exists", "xxx", "abc", "yyy", "ccc"); matchesTrue("name:xxx,matchType:not-exists", "xxxy", "abc", "yyy", "ccc"); matchesTrue("name:xxx,value:abc,matchType:equals", "xxx", "abc", "yyy", "ccc"); matchesFalse("name:xxx,value:abc,matchType:equals", "xxx", "abcc", "yyy", "abc"); matchesFalse("name:xxx,value:abc,matchType:does-not-equal", "xxx", "abc", "yyy", "ccc"); matchesTrue("name:xxx,value:abc,matchType:does-not-equal", "xxx", "abcc", "yyy", "abc"); exception(BadRequestException.class, "name:xxx,matchType:more-than"); matchesFalse("name:xxx,value:a,matchType:more-than", "xxx", "b", "yyy", "ccc"); //should report error? matchesTrue("name:xxx,value:1.5,matchType:more-than", "xxx", "1.5005", "yyy", "ccc"); matchesFalse("name:xxx,value:1.5,matchType:more-than", "xxx", "1.4995", "yyy", "ccc"); matchesFalse("name:xxx,value:1.5,matchType:more-than", "xxx", "-2", "yyy", "ccc"); matchesFalse("name:xxx,value:(1,5),matchType:more-than", "xxx", "5", "yyy", "ccc"); //should report error? matchesTrue("name:xxx,value:-5,matchType:more-than", "xxx", "0", "yyy", "ccc"); matchesFalse("name:xxx,value:-5,matchType:more-than", "xxx", "-5", "yyy", "ccc"); matchesFalse("name:xxx,value:-5,matchType:more-than", "xxx", "-15", "yyy", "ccc"); matchesFalse("name:xxx,value:-5,matchType:more-than", "xxx", "-900000000000000000000000000000000000000000000", "yyy", "ccc"); matchesTrue("name:xxx,value:-5,matchType:more-than", "xxx", "900000000000000000000000000000000000000000000", "yyy", "ccc"); matchesFalse("name:xxx,value:-5,matchType:no-more-than", "xxx", "0", "yyy", "ccc"); matchesTrue("name:xxx,value:-5,matchType:no-more-than", "xxx", "-5", "yyy", "ccc"); matchesTrue("name:xxx,value:-5,matchType:no-more-than", "xxx", "-15", "yyy", "ccc"); matchesTrue("value:a,matchType:any", "xxx", "abc", "yyy", "ccc"); matchesTrue("name:xxx,matchType:any", "xxx", "abc", "yyy", "ccc"); matchesTrue("name:xxx,value:abc,matchType:any", "xxx", "abc", "yyy", "ccc"); matchesTrue("name:xxx,value:abc,matchType:any"); } @Test public void testInheritable() { assertTrue(matchesWithOwn("name:a", new MapParametersProviderImpl(map("a", "b", "x", "y")), new MapParametersProviderImpl(map("x", "y")))); assertTrue(matchesWithOwn("name:x", new MapParametersProviderImpl(map("a", "b", "x", "y")), new MapParametersProviderImpl(map("x", "y")))); assertTrue(matchesWithOwn("name:a,inherited:true", new MapParametersProviderImpl(map("a", "b", "x", "y")), new MapParametersProviderImpl(map("x", "y")))); assertFalse(matchesWithOwn("name:a,inherited:false", new MapParametersProviderImpl(map("a", "b", "x", "y")), new MapParametersProviderImpl(map("x", "y")))); assertFalse(matchesWithOwn("name:x,inherited:true", new MapParametersProviderImpl(map("a", "b", "x", "y")), new MapParametersProviderImpl(map("x", "y")))); assertTrue(matchesWithOwn("name:x,inherited:false", new MapParametersProviderImpl(map("a", "b", "x", "y")), new MapParametersProviderImpl(map("x", "y")))); assertTrue(matchesWithOwn("name:x,value:y,inherited:false", new MapParametersProviderImpl(map("a", "b", "x", "y")), new MapParametersProviderImpl(map("x", "y")))); assertFalse(matchesWithOwn("name:a,value:y,inherited:true", new MapParametersProviderImpl(map("a", "b", "x", "y")), new MapParametersProviderImpl(map("x", "y")))); } @Test public void testNameMatchType() { matchesFalse("name:(value:xxx,matchType:contains),value:aaa,matchType:equals", "xx", "aaa", "xxy", "bbb"); matchesTrue("name:(value:xxx,matchType:contains),value:aaa,matchType:equals", "xxx", "aaa", "xxy", "bbb"); matchesTrue("name:(value:xxx,matchType:contains),value:aaa,matchType:equals", "xxy", "bbb", "xxx", "aaa"); matchesFalse("name:(value:xxx,matchType:contains),value:aaa,matchType:equals", "xxx", "bbb", "xxy", "bbb"); matchesFalse("name:(value:xxx,matchType:contains),value:aaa,matchType:equals", "xxx", "bbb", "xxy", "bbb"); matchesTrue("name:(value:xxx,matchType:contains),value:aaa,matchType:equals", "xxx", "bbb", "xxxy", "aaa"); matchesTrue("name:(value:xxx,matchType:contains),value:aaa,matchType:equals", "xxx", "aaa", "xxxy", "aaa"); matchesTrue("name:(value:xxx,matchType:contains),value:aaa,matchType:equals,matchScope:any", "xxx", "aaa", "xxxy", "aaa"); matchesTrue("name:(value:xxx,matchType:contains),value:aaa,matchType:equals,matchScope:all", "xxx", "aaa", "xxy", "aaa"); matchesTrue("name:(value:xxx,matchType:contains),value:aaa,matchType:equals", "xxx", "aaa", "xxy", "aaa", "xxxy", "bbb"); matchesTrue("name:(value:xxx,matchType:contains),value:aaa,matchType:equals,matchScope:any", "xxx", "aaa", "xxy", "aaa", "xxxy", "bbb"); matchesFalse("name:(value:xxx,matchType:contains),value:aaa,matchType:equals,matchScope:all", "xxx", "aaa", "xxy", "aaa", "xxxy", "bbb"); matchesTrue("name:(value:xxx,matchType:contains),value:aaa,matchType:equals,matchScope:all", "xxx", "aaa", "xxxy", "aaa"); matchesFalse("name:(value:xxx,matchType:contains),value:aaa,matchType:equals,matchScope:all", "xxx", "aaa", "xxxy", "bbb"); matchesTrue("name:xxx,value:aaa,matchScope:all", "xxx", "aaa", "xxxy", "bbb"); //or should report error? matchesTrue("name:(value:.*,matchType:matches),value:aaa,matchType:equals,matchScope:all", "xxx", "aaa", "xxxy", "aaa"); matchesFalse("name:(value:.*,matchType:matches),value:aaa,matchType:equals,matchScope:all", "xxx", "aaa", "xxxy", "aaab"); matchesFalse("name:(value:.*,matchType:matches),value:aaa,matchType:equals,matchScope:all", "xxx", "aaa", "xxxy", "aaaB"); exception(BadRequestException.class, "name:(value:xxx,matchType:contains),value:aaa,matchType:equals,matchScope:aaa"); exception(BadRequestException.class, "name:(value:xxx,matchType:Contains),value:aaa,matchType:equals,matchScope:aaa"); exception(BadRequestException.class, "name:(value:xxx,matchType:bbb),value:aaa,matchType:equals,matchScope:aaa"); exception(BadRequestException.class, "name:(matchType:contains),value:aaa,matchType:equals"); exception(BadRequestException.class, "name:(matchType:contains),value:aaa,matchType:equals,matchScope:all"); matchesFalse("value:aaa,matchScope:all", "xxx", "aaa", "xxxy", "bbb"); matchesFalse("value:aaa,matchScope:all", "xxx", "aaa", "xxxy", "bbaaab"); matchesTrue("value:aaa,matchScope:all,matchType:contains", "xxx", "aaa", "xxxy", "bbaaab"); } @Test public void testIgnoreCase() { matchesFalse("name:A,value:x,matchType:equals", "a", "x", "A", "X"); matchesTrue("name:A,value:x,matchType:equals,ignoreCase:true", "a", "x", "A", "X"); matchesTrue("name:(value:a,matchType:equals),value:x,matchType:equals,matchScope:all", "a", "x", "A", "X"); matchesFalse("name:(value:a,matchType:equals,ignoreCase:true),value:x,matchType:equals,matchScope:all", "a", "x", "A", "X"); matchesTrue("name:(value:a,matchType:contains),value:x,matchType:equals,matchScope:all", "a", "x", "A", "X"); matchesFalse("name:(value:a,matchType:contains,ignoreCase:true),value:x,matchType:equals,matchScope:all", "a", "x", "A", "X"); matchesFalse("name:(matchType:any),value:x,matchType:equals,matchScope:all", "a", "x", "A", "X"); matchesTrue("name:(matchType:any),value:x,matchType:equals,matchScope:all,ignoreCase:true", "a", "x", "A", "X"); matchesSingleFalse("value:x", "X"); matchesSingleTrue("value:x,ignoreCase:true", "X"); matchesSingleTrue("matchType:matches,value:[abc]", "a"); matchesSingleFalse("matchType:matches,value:[abc]", "A"); matchesSingleTrue("matchType:matches,value:[abc],ignoreCase:true", "a"); matchesSingleTrue("matchType:matches,value:[abc],ignoreCase:true", "A"); matchesSingleTrue("matchType:matches,value:[ABC]", "A"); matchesSingleFalse("matchType:matches,value:[ABC]", "a"); exceptionSingle(BadRequestException.class, "matchType:matchesAbra,value:[ABC]"); // matches and does-not-match are special cases and the value is not affected by ignoreCase:true matchesSingleFalse("matchType:matches,value:[ABC],ignoreCase:true", "A"); matchesSingleFalse("matchType:matches,value:[ABC],ignoreCase:true", "a"); matchesSingleTrue("matchType:does-not-match,value:[ABC],ignoreCase:true", "a"); matchesSingleTrue("matchType:matches,value:\\w", "a"); //word character matchesSingleFalse("matchType:matches,value:\\w", " "); matchesSingleTrue("matchType:matches,value:\\w,ignoreCase:true", "a"); matchesSingleFalse("matchType:matches,value:\\w,ignoreCase:true", " "); matchesSingleTrue("matchType:matches,value:\\W", " "); //non-word character matchesSingleFalse("matchType:matches,value:\\W", "a"); matchesSingleTrue("matchType:matches,value:\\W,ignoreCase:true", " "); matchesSingleFalse("matchType:matches,value:\\W,ignoreCase:true", "a"); matchesSingleTrue("matchType:does-not-match,value:\\W,ignoreCase:true", "a"); } @Test public void testSingleValueMatching() { matchesSingleTrue("aaa", "aaa"); matchesSingleFalse("aaa", "aaaa"); matchesSingleFalse("aaa", "bbb"); matchesSingleFalse("value:aaa", null); matchesSingleTrue("value:aaa", "aaa"); matchesSingleFalse("value:aaa", "xxaaayy"); matchesSingleTrue("value:aaa,matchType:contains", "xxaaayy"); matchesSingleFalse("value:aaa", "AAA"); matchesSingleFalse("value:aaa", "aa"); exceptionSingle(BadRequestException.class, "matchType:exists"); exceptionSingle(BadRequestException.class, "matchType:exists,value:a"); exceptionSingle(BadRequestException.class, "matchType:not-exists"); exceptionSingle(BadRequestException.class, "matchType:matches"); exceptionSingle(BadRequestException.class, "matchType:does-not-match"); matchesSingleFalse("value:aaa,matchType:equals", null); matchesSingleTrue("value:aaa,matchType:equals", "aaa"); matchesSingleFalse("value:aaa,matchType:equals", "aaaa"); matchesSingleTrue("value:.,matchType:matches", "a"); matchesSingleTrue("value:.,matchType:matches", "A"); matchesSingleTrue("value:.,matchType:matches", "."); matchesSingleFalse("value:.,matchType:matches", "aa"); exceptionSingle(BadRequestException.class, "value:aaa,matchType:exists"); exceptionSingle(BadRequestException.class, "value:aaa,matchType:not-exists"); assertNull(ParameterCondition.createValueCondition((String)null)); exceptionSingle(LocatorProcessException.class, ""); exceptionSingle(LocatorProcessException.class, "name:a,some:b"); exceptionSingle(LocatorProcessException.class, "name:a"); exceptionSingle(LocatorProcessException.class, "some:b"); exceptionSingle(LocatorProcessException.class, "name:xxx,value:aaa"); exceptionSingle(LocatorProcessException.class, "name:a,value:b,matchType:contains"); exceptionSingle(BadRequestException.class, "name:a,value:b,matchType:abra"); exceptionSingle(LocatorProcessException.class, "name:xxx,value:aaa,matchType:equals,nameMatchType:contains"); exceptionSingle(LocatorProcessException.class, "name:xxx,value:aaa,matchType:equals,matchScope:any"); } // ============================== private static void matchesTrue(@NotNull final String propertyConditionLocator, @NotNull String... args) { assertTrue(matches(propertyConditionLocator, args)); } private static void matchesFalse(@NotNull final String propertyConditionLocator, @NotNull String... args) { assertFalse(matches(propertyConditionLocator, args)); } private static boolean matches(@NotNull final String propertyConditionLocator, @NotNull String... args) { return ParameterCondition.create(propertyConditionLocator).matches(new MapParametersProviderImpl(CollectionsUtil.asMap(args))); } private static boolean matchesWithOwn(@NotNull final String propertyConditionLocator, @NotNull final ParametersProvider parametersProvider, @NotNull final ParametersProvider ownParametersProvider) { return ParameterCondition.create(propertyConditionLocator).matches(parametersProvider, ownParametersProvider); } private static void matchesSingleTrue(@NotNull final String propertyConditionLocator, @Nullable String value) { assertEquals("Matching value '" + value + "' by condition '" + propertyConditionLocator + "'", true, matchesSingle(propertyConditionLocator, value)); } private static void matchesSingleFalse(@NotNull final String propertyConditionLocator, @Nullable String value) { assertEquals("Matching value '" + value + "' by condition '" + propertyConditionLocator + "'", false, matchesSingle(propertyConditionLocator, value)); } private static boolean matchesSingle(@NotNull final String propertyConditionLocator, @Nullable String value) { return ParameterCondition.createValueCondition(propertyConditionLocator).matches(value); } private static void exception(final Class exception, @NotNull final String propertyConditionLocator) { //noinspection ThrowableResultOfMethodCallIgnored BaseFinderTest.checkException(exception, new Runnable() { @Override public void run() { ParameterCondition.create(propertyConditionLocator); } }, null); } private static void exceptionSingle(final Class exception, @NotNull final String propertyConditionLocator) { //noinspection ThrowableResultOfMethodCallIgnored BaseFinderTest.checkException(exception, new Runnable() { @Override public void run() { ParameterCondition.createValueCondition(propertyConditionLocator); } }, null); } }