/*******************************************************************************
* Copyright 2014 JHC Systems Limited
*
* 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 jhc.redsniff.webdriver.table.matchers;
import static com.google.common.collect.Lists.transform;
import static java.util.Arrays.asList;
import static jhc.redsniff.core.Describer.newDescription;
import static jhc.redsniff.internal.matchers.MatcherUtil.matchAndDiagnose;
import static jhc.redsniff.webdriver.table.matchers.IsTableCellWithText.TO_CELL_MATCHER;
import java.util.List;
import jhc.redsniff.html.tables.TableCell;
import jhc.redsniff.html.tables.TableRow;
import org.hamcrest.Description;
import org.hamcrest.Factory;
import org.hamcrest.Matcher;
/**
* A matcher of {@link TableRows} that matches if each cell matcher matches the respective cell
* @see {@link IsTableRowIncluding}
* @author InfanteN
*
*/
public class IsTableRowConsistingOf extends TableRowMatcher{
private List<Matcher<TableCell>> cellContentsMatchers;
public IsTableRowConsistingOf(List<Matcher<TableCell>> cellMatchers){
this.cellContentsMatchers = cellMatchers;
}
public void describeTo(Description description) {
for(Matcher<TableCell> cellMatcher:cellContentsMatchers)
description.appendDescriptionOf(cellMatcher).appendText(",");
}
@Override
protected boolean matchesSafely(TableRow actualRow, Description mismatchDescription) {
if(cellContentsMatchers.size()!=actualRow.cells().size()){
mismatchDescription.appendText("with " + actualRow.cells().size() + " cells instead of " + cellContentsMatchers.size()+":\n");
mismatchDescription.appendText("Actual Row:\n" +actualRow.toString());
return false;
}
for(int i=0;i<cellContentsMatchers.size();i++){
TableCell actualCell = actualRow.cell(i);
Matcher<TableCell> cellMatcher = cellContentsMatchers.get(i);
if(!matchAndDiagnose(cellMatcher, actualCell, mismatchDescription,
newDescription()
.appendText("cell in column: ")
.appendText(actualCell.columnDescription())
.appendText(", expected to be ")
.appendDescriptionOf(cellMatcher).toString()))
return false;
}
return true;
}
//has to accept Object since we might want to mix and match Strings and cell matchers
@SuppressWarnings("unchecked")
@Factory
public static Matcher<TableRow> rowConsistingOf(Object... fields){
if(fields.length==1 && fields[0] instanceof List )
return rowConsistingOfList((List<Matcher<TableCell>>) fields[0]);
else {
checkFieldTypes(fields);
return rowConsistingOfList(transform(asList(fields),TO_CELL_MATCHER));
}
}
private static void checkFieldTypes(Object[] fields) {
for(Object field:fields){
if(field == null)
throw new IllegalArgumentException("rowConsistingOf can only accept Strings or TableCell matchers - received null");
if(!(field instanceof String|| field instanceof Matcher) )
throw new IllegalArgumentException("rowConsistingOf can only accept Strings or TableCell matchers - received " + field.getClass().getName() + field.toString());
}
}
private static Matcher<TableRow> rowConsistingOfList(List<Matcher<TableCell>> cellMatcherList){
return new IsTableRowConsistingOf(cellMatcherList);
}
@Override
public IndexCellMatcher indexedBy() {
return new IndexCellMatcher(cellContentsMatchers.subList(0, 1)); // default to index on the first column mentioned in the expectation - not ideal for this kind of search
}
}