001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.assertions; 014 015import static java.util.Arrays.*; 016import static java.util.stream.Collectors.*; 017import static org.apache.juneau.common.internal.StringUtils.*; 018import static org.apache.juneau.internal.CollectionUtils.*; 019 020import java.io.*; 021import java.util.*; 022import java.util.function.*; 023 024import org.apache.juneau.common.internal.*; 025import org.apache.juneau.cp.*; 026import org.apache.juneau.internal.*; 027import org.apache.juneau.serializer.*; 028 029/** 030 * Used for fluent assertion calls against lists. 031 * 032 * <h5 class='section'>Test Methods:</h5> 033 * <p> 034 * <ul class='javatree'> 035 * <li class='jc'>{@link FluentListAssertion} 036 * <ul class='javatreec'> 037 * <li class='jm'>{@link FluentListAssertion#isHas(Object...) isHas(Object...)} 038 * <li class='jm'>{@link FluentListAssertion#isEach(Predicate...) isEach(Predicate...)} 039 * </ul> 040 * <li class='jc'>{@link FluentCollectionAssertion} 041 * <ul class='javatreec'> 042 * <li class='jm'>{@link FluentCollectionAssertion#isEmpty() isEmpty()} 043 * <li class='jm'>{@link FluentCollectionAssertion#isNotEmpty() isNotEmpty()} 044 * <li class='jm'>{@link FluentCollectionAssertion#isContains(Object) isContains(Object)} 045 * <li class='jm'>{@link FluentCollectionAssertion#isNotContains(Object) isNotContains(Object)} 046 * <li class='jm'>{@link FluentCollectionAssertion#isAny(Predicate) isAny(Predicate)} 047 * <li class='jm'>{@link FluentCollectionAssertion#isAll(Predicate) isAll(Predicate)} 048 * <li class='jm'>{@link FluentCollectionAssertion#isSize(int size) isSize(int size)} 049 * </ul> 050 * <li class='jc'>{@link FluentObjectAssertion} 051 * <ul class='javatreec'> 052 * <li class='jm'>{@link FluentObjectAssertion#isExists() isExists()} 053 * <li class='jm'>{@link FluentObjectAssertion#is(Object) is(Object)} 054 * <li class='jm'>{@link FluentObjectAssertion#is(Predicate) is(Predicate)} 055 * <li class='jm'>{@link FluentObjectAssertion#isNot(Object) isNot(Object)} 056 * <li class='jm'>{@link FluentObjectAssertion#isAny(Object...) isAny(Object...)} 057 * <li class='jm'>{@link FluentObjectAssertion#isNotAny(Object...) isNotAny(Object...)} 058 * <li class='jm'>{@link FluentObjectAssertion#isNull() isNull()} 059 * <li class='jm'>{@link FluentObjectAssertion#isNotNull() isNotNull()} 060 * <li class='jm'>{@link FluentObjectAssertion#isString(String) isString(String)} 061 * <li class='jm'>{@link FluentObjectAssertion#isJson(String) isJson(String)} 062 * <li class='jm'>{@link FluentObjectAssertion#isSame(Object) isSame(Object)} 063 * <li class='jm'>{@link FluentObjectAssertion#isSameJsonAs(Object) isSameJsonAs(Object)} 064 * <li class='jm'>{@link FluentObjectAssertion#isSameSortedJsonAs(Object) isSameSortedJsonAs(Object)} 065 * <li class='jm'>{@link FluentObjectAssertion#isSameSerializedAs(Object, WriterSerializer) isSameSerializedAs(Object, WriterSerializer)} 066 * <li class='jm'>{@link FluentObjectAssertion#isType(Class) isType(Class)} 067 * <li class='jm'>{@link FluentObjectAssertion#isExactType(Class) isExactType(Class)} 068 * </ul> 069 * </ul> 070 * 071 * <h5 class='section'>Transform Methods:</h5> 072 * <p> 073 * <ul class='javatree'> 074 * <li class='jc'>{@link FluentListAssertion} 075 * <ul class='javatreec'> 076 * <li class='jm'>{@link FluentListAssertion#asStrings() asStrings()} 077 * <li class='jm'>{@link FluentListAssertion#asStrings(Function) asStrings(Function)} 078 * <li class='jm'>{@link FluentListAssertion#asCdl() asCdl()} 079 * <li class='jm'>{@link FluentListAssertion#asCdl(Function) asCdl(Function)} 080 * <li class='jm'>{@link FluentListAssertion#asItem(int) asItem(int)} 081 * <li class='jm'>{@link FluentListAssertion#asSorted() asSorted()} 082 * <li class='jm'>{@link FluentListAssertion#asSorted(Comparator) asSorted(Comparator)} 083 * </ul> 084 * <li class='jc'>{@link FluentCollectionAssertion} 085 * <ul class='javatreec'> 086 * <li class='jm'>{@link FluentCollectionAssertion#asStrings() asStrings()} 087 * <li class='jm'>{@link FluentCollectionAssertion#asSize() asSize()} 088 * </ul> 089* <li class='jc'>{@link FluentObjectAssertion} 090 * <ul class='javatreec'> 091 * <li class='jm'>{@link FluentObjectAssertion#asString() asString()} 092 * <li class='jm'>{@link FluentObjectAssertion#asString(WriterSerializer) asString(WriterSerializer)} 093 * <li class='jm'>{@link FluentObjectAssertion#asString(Function) asString(Function)} 094 * <li class='jm'>{@link FluentObjectAssertion#asJson() asJson()} 095 * <li class='jm'>{@link FluentObjectAssertion#asJsonSorted() asJsonSorted()} 096 * <li class='jm'>{@link FluentObjectAssertion#asTransformed(Function) asApplied(Function)} 097 * <li class='jm'>{@link FluentObjectAssertion#asAny() asAny()} 098 * </ul> 099 * </ul> 100 * 101 * <h5 class='section'>Configuration Methods:</h5> 102 * <p> 103 * <ul class='javatree'> 104 * <li class='jc'>{@link Assertion} 105 * <ul class='javatreec'> 106 * <li class='jm'>{@link Assertion#setMsg(String, Object...) setMsg(String, Object...)} 107 * <li class='jm'>{@link Assertion#setOut(PrintStream) setOut(PrintStream)} 108 * <li class='jm'>{@link Assertion#setSilent() setSilent()} 109 * <li class='jm'>{@link Assertion#setStdOut() setStdOut()} 110 * <li class='jm'>{@link Assertion#setThrowable(Class) setThrowable(Class)} 111 * </ul> 112 * </ul> 113 * 114 * <h5 class='section'>See Also:</h5><ul> 115 * <li class='link'><a class="doclink" href="../../../../index.html#ja.Overview">Overview > juneau-assertions > Overview</a> 116 * </ul> 117 * 118 * @param <E> The element type. 119 * @param <R> The return type. 120 */ 121@FluentSetters(returns="FluentListAssertion<E,R>") 122public class FluentListAssertion<E,R> extends FluentCollectionAssertion<E,R> { 123 124 //----------------------------------------------------------------------------------------------------------------- 125 // Static 126 //----------------------------------------------------------------------------------------------------------------- 127 128 private static final Messages MESSAGES = Messages.of(FluentListAssertion.class, "Messages"); 129 private static final String 130 MSG_listDidNotContainExpectedValueAt = MESSAGES.getString("listDidNotContainExpectedValueAt"); 131 132 //----------------------------------------------------------------------------------------------------------------- 133 // Instance 134 //----------------------------------------------------------------------------------------------------------------- 135 136 /** 137 * Constructor. 138 * 139 * @param value 140 * The object being tested. 141 * <br>Can be <jk>null</jk>. 142 * @param returns 143 * The object to return after a test method is called. 144 * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be 145 * used on the same assertion. 146 */ 147 public FluentListAssertion(List<E> value, R returns) { 148 this(null, value, returns); 149 } 150 151 /** 152 * Chained constructor. 153 * 154 * <p> 155 * Used when transforming one assertion into another so that the assertion config can be used by the new assertion. 156 * 157 * @param creator 158 * The assertion that created this assertion. 159 * <br>Should be <jk>null</jk> if this is the top-level assertion. 160 * @param value 161 * The object being tested. 162 * <br>Can be <jk>null</jk>. 163 * @param returns 164 * The object to return after a test method is called. 165 * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be 166 * used on the same assertion. 167 */ 168 public FluentListAssertion(Assertion creator, List<E> value, R returns) { 169 super(creator, value, returns); 170 } 171 172 //----------------------------------------------------------------------------------------------------------------- 173 // Transform methods 174 //----------------------------------------------------------------------------------------------------------------- 175 176 /** 177 * Applies a transform on the inner object and returns a new inner object. 178 * 179 * @param function The transform to apply. 180 * @return A new assertion. 181 */ 182 public FluentListAssertion<E,R> asApplied2(Function<List<E>,List<E>> function) { 183 return new FluentListAssertion<>(this, function.apply((List<E>)orElse(null)), returns()); 184 } 185 186 /** 187 * Returns an object assertion on the item specified at the specified index. 188 * 189 * <p> 190 * If the list is <jk>null</jk> or the index is out-of-bounds, the returned assertion is a null assertion 191 * (meaning {@link FluentAnyAssertion#isExists()} returns <jk>false</jk>). 192 * 193 * @param index The index of the item to retrieve from the list. 194 * @return A new assertion. 195 */ 196 public FluentAnyAssertion<E,R> asItem(int index) { 197 return new FluentAnyAssertion<>(this, at(index), returns()); 198 } 199 200 /** 201 * Sorts the entries in this list. 202 * 203 * @return A new list assertion. The contents of the original list remain unchanged. 204 */ 205 public FluentListAssertion<E,R> asSorted() { 206 return new FluentListAssertion<>(this, toSortedList(null), returns()); 207 } 208 209 /** 210 * Sorts the entries in this list using the specified comparator. 211 * 212 * @param comparator The comparator to use to sort the list. 213 * @return A new list assertion. The contents of the original list remain unchanged. 214 */ 215 public FluentListAssertion<E,R> asSorted(Comparator<E> comparator) { 216 return new FluentListAssertion<>(this, toSortedList(comparator), returns()); 217 } 218 219 /** 220 * Returns the first entry from this list. 221 * 222 * @return A new list assertion. 223 */ 224 public FluentAnyAssertion<E,R> asFirst() { 225 return asItem(0); 226 } 227 228 /** 229 * Returns the last entry from this list. 230 * 231 * @return A new list assertion. 232 */ 233 public FluentAnyAssertion<E,R> asLast() { 234 return asItem(getSize()-1); 235 } 236 237 /** 238 * Returns the first X number of entries from this list. 239 * 240 * @param count The number of entries in the list to retrieve. 241 * @return A new list assertion. The contents of the original list remain unchanged. 242 */ 243 public FluentListAssertion<E,R> asFirst(int count) { 244 return new FluentListAssertion<>(this, valueIsNull() ? null : value().subList(0, count), returns()); 245 } 246 247 /** 248 * Returns the first X number of entries from this list. 249 * 250 * @param count The number of entries in the list to retrieve. 251 * @return A new list assertion. The contents of the original list remain unchanged. 252 */ 253 public FluentListAssertion<E,R> asLast(int count) { 254 return new FluentListAssertion<>(this, valueIsNull() ? null : value().subList(getSize()-count, getSize()), returns()); 255 } 256 257 /** 258 * Returns a sublist of the entries in this list. 259 * 260 * @param start The start index (inclusive). 261 * @param end The end index (exclusive). 262 * @return A new list assertion. The contents of the original list remain unchanged. 263 */ 264 public FluentListAssertion<E,R> asSublist(int start, int end) { 265 return new FluentListAssertion<>(this, valueIsNull() ? null : value().subList(start, end), returns()); 266 } 267 268 /** 269 * Runs the stringify function against all values in this list and returns it as a fluent string list assertion. 270 * 271 * @param function The function to apply to all values in this list. 272 * @return A new fluent string list assertion. Never <jk>null</jk>. 273 */ 274 public FluentStringListAssertion<R> asStrings(Function<E,String> function) { 275 List<String> l = valueIsNull() ? null : value().stream().map(x -> function.apply(x)).collect(toList()); 276 return new FluentStringListAssertion<>(this, l, returns()); 277 } 278 279 /** 280 * Converts the entries in this list to a simple comma-delimited list and returns the value as a fluent string assertion. 281 * 282 * @return A fluent string assertion. Never <jk>null</jk>. 283 */ 284 public FluentStringAssertion<R> asCdl() { 285 return new FluentStringAssertion<>(this, valueIsNull() ? null : StringUtils.join(value(), ','), returns()); 286 } 287 288 /** 289 * Converts the entries to strings using the specified stringify function, combines them into a simple comma-delimited list, and returns the value as a fluent string assertion. 290 * 291 * @param function The function to apply to all values in this list. 292 * @return A fluent string assertion. Never <jk>null</jk>. 293 */ 294 public FluentStringAssertion<R> asCdl(Function<E,String> function) { 295 List<String> l = valueIsNull() ? null : value().stream().map(x -> function.apply(x)).collect(toList()); 296 return new FluentStringAssertion<>(this, join(l, ','), returns()); 297 } 298 299 //----------------------------------------------------------------------------------------------------------------- 300 // Test methods 301 //----------------------------------------------------------------------------------------------------------------- 302 303 /** 304 * Asserts that the contents of this list contain the specified values. 305 * 306 * @param entries The expected entries in this list. 307 * @return The fluent return object. 308 * @throws AssertionError If assertion failed. 309 */ 310 @SuppressWarnings("unchecked") 311 public R isHas(E...entries) throws AssertionError { 312 Predicate<E>[] p = stream(entries).map(AssertionPredicates::eq).toArray(Predicate[]::new); 313 return isEach(p); 314 } 315 316 /** 317 * Asserts that the contents of this list pass the specified tests. 318 * 319 * @param tests 320 * The tests to run. 321 * <jk>null</jk> predicates are ignored. 322 * @return The fluent return object. 323 * @throws AssertionError If assertion failed. 324 */ 325 @SafeVarargs 326 public final R isEach(Predicate<E>...tests) throws AssertionError { 327 isSize(tests.length); 328 for (int i = 0, j = getSize(); i < j; i++) { 329 Predicate<E> t = tests[i]; 330 if (t != null && ! t.test(at(i))) 331 throw error(MSG_listDidNotContainExpectedValueAt, i, getFailureMessage(t, at(i))); 332 } 333 return returns(); 334 } 335 336 //----------------------------------------------------------------------------------------------------------------- 337 // Fluent setters 338 //----------------------------------------------------------------------------------------------------------------- 339 340 // <FluentSetters> 341 342 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 343 public FluentListAssertion<E,R> setMsg(String msg, Object...args) { 344 super.setMsg(msg, args); 345 return this; 346 } 347 348 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 349 public FluentListAssertion<E,R> setOut(PrintStream value) { 350 super.setOut(value); 351 return this; 352 } 353 354 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 355 public FluentListAssertion<E,R> setSilent() { 356 super.setSilent(); 357 return this; 358 } 359 360 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 361 public FluentListAssertion<E,R> setStdOut() { 362 super.setStdOut(); 363 return this; 364 } 365 366 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 367 public FluentListAssertion<E,R> setThrowable(Class<? extends java.lang.RuntimeException> value) { 368 super.setThrowable(value); 369 return this; 370 } 371 372 // </FluentSetters> 373 374 //----------------------------------------------------------------------------------------------------------------- 375 // Utility methods 376 //----------------------------------------------------------------------------------------------------------------- 377 378 @Override 379 protected List<E> value() throws AssertionError { 380 return (List<E>)super.value(); 381 } 382 383 private E at(int index) throws AssertionError { 384 return valueIsNull() || index < 0 || index >= getSize() ? null : value().get(index); 385 } 386 387 private List<E> toSortedList(Comparator<E> comparator) { 388 return valueIsNull() ? null : sortedList(comparator, value()); 389 } 390}