@Test
  public void testResultNumReturnedIsZero()
      throws WfsException, TransformerConfigurationException, UnsupportedQueryException {
    // Setup
    final String TITLE = "title";
    final String searchPhrase = "*";
    final int pageSize = 1;

    WfsSource source =
        getWfsSource(
            ONE_TEXT_PROPERTY_SCHEMA,
            MockWfsServer.getFilterCapabilities(),
            Wfs20Constants.EPSG_4326_URN,
            3,
            false,
            true,
            0);

    QueryImpl query =
        new QueryImpl(builder.attribute(Metacard.ANY_TEXT).is().like().text(searchPhrase));
    query.setPageSize(pageSize);
    SortBy sortBy = new SortByImpl(TITLE, SortOrder.DESCENDING);
    query.setSortBy(sortBy);
    QueryRequestImpl queryReq = new QueryRequestImpl(query);

    // Perform test
    SourceResponse resp = source.query(queryReq);
    assertEquals(3, resp.getResults().size());
  }
  /**
   * Given 10 features (and metacards) exist that match search criteria, since page size=4 and
   * startIndex=0, should get 4 results back - metacards 1 thru 4.
   *
   * @throws WfsException
   * @throws TransformerConfigurationException
   * @throws UnsupportedQueryException
   */
  @Test
  public void testPagingStartIndexZero()
      throws WfsException, TransformerConfigurationException, UnsupportedQueryException {

    // Setup
    int pageSize = 4;
    int startIndex = 0;

    WfsSource source =
        getWfsSource(
            ONE_TEXT_PROPERTY_SCHEMA,
            MockWfsServer.getFilterCapabilities(),
            Wfs20Constants.EPSG_4326_URN,
            10,
            false);
    Filter filter = builder.attribute(Metacard.ANY_TEXT).is().like().text(LITERAL);
    Query query = new QueryImpl(filter, startIndex, pageSize, null, false, 0);

    // Execute
    GetFeatureType featureType = source.buildGetFeatureRequest(query);
    BigInteger startIndexGetFeature = featureType.getStartIndex();
    BigInteger countGetFeature = featureType.getCount();

    // Verify
    assertThat(countGetFeature.intValue(), is(pageSize));
    assertThat(startIndexGetFeature.intValue(), is(startIndex));
  }
  @Test
  public void testConfigureFeatureTypesDescribeFeatureException() throws WfsException {
    ArgumentCaptor<DescribeFeatureTypeRequest> captor =
        ArgumentCaptor.forClass(DescribeFeatureTypeRequest.class);

    WfsSource source =
        getWfsSource(
            ONE_TEXT_PROPERTY_SCHEMA,
            MockWfsServer.getFilterCapabilities(),
            Wfs20Constants.EPSG_4326_URN,
            1,
            true);

    final String SAMPLE_FEATURE_NAME0 = SAMPLE_FEATURE_NAME + "0";

    verify(mockWfs).describeFeatureType(captor.capture());

    DescribeFeatureTypeRequest describeFeatureType = captor.getValue();

    // sample feature 0 does not have a prefix
    assertThat(SAMPLE_FEATURE_NAME0, equalTo(describeFeatureType.getTypeName()));

    assertTrue(source.featureTypeFilters.isEmpty());

    assertTrue(source.getContentTypes().isEmpty());
  }
  @Test
  public void testSortingNoSortBySortingSupported() throws Exception {
    // Setup
    final String searchPhrase = "*";
    final int pageSize = 1;

    WfsSource source =
        getWfsSource(
            ONE_TEXT_PROPERTY_SCHEMA,
            MockWfsServer.getFilterCapabilities(),
            Wfs20Constants.EPSG_4326_URN,
            1,
            false,
            false,
            0);

    QueryImpl query =
        new QueryImpl(builder.attribute(Metacard.ANY_TEXT).is().like().text(searchPhrase));
    query.setPageSize(pageSize);

    // Perform Test
    GetFeatureType featureType = source.buildGetFeatureRequest(query);

    // Verify
    QueryType queryType = (QueryType) featureType.getAbstractQueryExpression().get(0).getValue();
    assertFalse(queryType.isSetAbstractSortingClause());
  }
  @Test
  public void testConfigureFeatureTypes() throws WfsException {
    ArgumentCaptor<DescribeFeatureTypeRequest> captor =
        ArgumentCaptor.forClass(DescribeFeatureTypeRequest.class);

    WfsSource source =
        getWfsSource(
            ONE_TEXT_PROPERTY_SCHEMA,
            MockWfsServer.getFilterCapabilities(),
            Wfs20Constants.EPSG_4326_URN,
            1);

    final String SAMPLE_FEATURE_NAME0 = SAMPLE_FEATURE_NAME + "0";

    verify(mockWfs).describeFeatureType(captor.capture());

    DescribeFeatureTypeRequest describeFeatureType = captor.getValue();

    // sample feature 0 does not have a prefix
    assertThat(SAMPLE_FEATURE_NAME0, equalTo(describeFeatureType.getTypeName()));

    assertTrue(source.isAvailable());
    assertThat(source.featureTypeFilters.size(), is(1));
    WfsFilterDelegate delegate = source.featureTypeFilters.get(new QName(SAMPLE_FEATURE_NAME0));
    assertThat(delegate, notNullValue());

    assertThat(source.getContentTypes().size(), is(1));

    List<ContentType> types = new ArrayList<ContentType>();
    types.addAll(source.getContentTypes());

    assertTrue(SAMPLE_FEATURE_NAME0.equals(types.get(0).getName()));
  }
  @Test
  public void testSearchByMultipleTypes() throws Exception {
    // Setup
    int startIndex = 0;
    int pageSize = 10;
    WfsSource source =
        getWfsSource(
            ONE_TEXT_PROPERTY_SCHEMA,
            MockWfsServer.getFilterCapabilities(),
            Wfs20Constants.EPSG_4326_URN,
            10,
            false);
    Filter filter0 =
        builder.attribute(Metacard.CONTENT_TYPE).is().equalTo().text(SAMPLE_FEATURE_NAME + "8");
    Filter filter1 =
        builder.attribute(Metacard.CONTENT_TYPE).is().equalTo().text(SAMPLE_FEATURE_NAME + "9");
    Filter filter2 = builder.attribute(Metacard.ANY_TEXT).is().like().text("*");

    Filter typeSearchFilters = builder.anyOf(filter0, filter1);

    QueryImpl query = new QueryImpl(builder.allOf(filter2, typeSearchFilters));
    query.setPageSize(pageSize);

    // Execute
    GetFeatureType featureType = source.buildGetFeatureRequest(query);
    int numTypes = featureType.getAbstractQueryExpression().size();

    // Validate
    assertEquals(2, numTypes);
  }
  @Test
  public void testParseCapabilitiesNoFilterCapabilities() throws WfsException {
    WfsSource source =
        getWfsSource(ONE_TEXT_PROPERTY_SCHEMA, null, Wfs20Constants.EPSG_4326_URN, 1);

    assertTrue(source.isAvailable());
    assertThat(source.featureTypeFilters.size(), is(0));
  }
  @Test
  public void testParseCapabilitiesNoFeatures() throws WfsException {
    WfsSource source =
        getWfsSource("", MockWfsServer.getFilterCapabilities(), Wfs20Constants.EPSG_4326_URN, 0);

    assertTrue(source.isAvailable());
    assertThat(source.featureTypeFilters.size(), is(0));
  }
 @Test
 public void testAvailability() throws WfsException {
   WfsSource source =
       getWfsSource(
           ONE_TEXT_PROPERTY_SCHEMA,
           MockWfsServer.getFilterCapabilities(),
           Wfs20Constants.EPSG_4326_URN,
           1);
   assertTrue(source.isAvailable());
 }
  /**
   * Verify that the SortBy is NOT set. In this case, sorting is not supported in the capabilities.
   */
  @Test
  public void testSortingAscendingSortingNotSupported() throws Exception {
    // Setup
    final String searchPhrase = "*";
    final String mockTemporalFeatureProperty = "myTemporalFeatureProperty";
    final String mockFeatureType = "{http://example.com}" + SAMPLE_FEATURE_NAME + 0;
    final int pageSize = 1;

    // Set ImplementsSorting to FALSE (sorting not supported)
    FilterCapabilities mockCapabilitiesSortingNotSupported = MockWfsServer.getFilterCapabilities();
    ConformanceType conformance = mockCapabilitiesSortingNotSupported.getConformance();
    List<DomainType> domainTypes = conformance.getConstraint();
    for (DomainType domainType : domainTypes) {
      if (StringUtils.equals(domainType.getName(), "ImplementsSorting")) {
        ValueType valueType = new ValueType();
        valueType.setValue("FALSE");
        domainType.setDefaultValue(valueType);
        break;
      }
    }

    WfsSource source =
        getWfsSource(
            ONE_TEXT_PROPERTY_SCHEMA,
            mockCapabilitiesSortingNotSupported,
            Wfs20Constants.EPSG_4326_URN,
            1,
            false,
            false,
            0);
    MetacardMapper mockMetacardMapper = mock(MetacardMapper.class);
    when(mockMetacardMapper.getFeatureType()).thenReturn(mockFeatureType);
    when(mockMetacardMapper.getSortByTemporalFeatureProperty())
        .thenReturn(mockTemporalFeatureProperty);
    List<MetacardMapper> mappers = new ArrayList<MetacardMapper>(1);
    mappers.add(mockMetacardMapper);
    source.setMetacardToFeatureMapper(mappers);

    QueryImpl query =
        new QueryImpl(builder.attribute(Metacard.ANY_TEXT).is().like().text(searchPhrase));
    query.setPageSize(pageSize);
    SortBy sortBy = new SortByImpl(Result.TEMPORAL, SortOrder.ASCENDING);
    query.setSortBy(sortBy);

    // Perform Test
    GetFeatureType featureType = source.buildGetFeatureRequest(query);

    // Verify
    QueryType queryType = (QueryType) featureType.getAbstractQueryExpression().get(0).getValue();
    assertFalse(queryType.isSetAbstractSortingClause());
  }
  @Test
  public void testParseCapabilities() throws WfsException {
    WfsSource source =
        getWfsSource(
            ONE_TEXT_PROPERTY_SCHEMA,
            MockWfsServer.getFilterCapabilities(),
            Wfs20Constants.EPSG_4326_URN,
            1);

    assertTrue(source.isAvailable());
    assertThat(source.featureTypeFilters.size(), is(1));
    WfsFilterDelegate delegate =
        source.featureTypeFilters.get(new QName(SAMPLE_FEATURE_NAME + "0"));
    assertThat(delegate, notNullValue());
  }
  /**
   * Verify that the SortBy is set with the mapped Feature Property and a DESC sort order. In this
   * case, the incoming sort property of TEMPORAL is mapped to myTemporalFeatureProperty.
   *
   * <p><?xml version="1.0" encoding="UTF-8" standalone="yes"?> <ns5:GetFeature startIndex="1"
   * count="1" service="WFS" version="2.0.0" xmlns:ns2="http://www.opengis.net/ows/1.1"
   * xmlns="http://www.opengis.net/fes/2.0" xmlns:ns4="http://www.opengis.net/gml"
   * xmlns:ns3="http://www.w3.org/1999/xlink" xmlns:ns5="http://www.opengis.net/wfs/2.0"> <ns5:Query
   * typeNames="SampleFeature0" handle="SampleFeature0"> <Filter> <PropertyIsLike wildCard="*"
   * singleChar="?" escapeChar="!"> <Literal>*</Literal> <ValueReference>title</ValueReference>
   * </PropertyIsLike> </Filter> <SortBy> <SortProperty>
   * <ValueReference>myTemporalFeatureProperty</ValueReference> <SortOrder>DESC</SortOrder>
   * </SortProperty> </SortBy> </ns5:Query> </ns5:GetFeature>
   */
  @Test
  public void testSortingDescendingSortingSupported() throws Exception {
    // Setup
    final String searchPhrase = "*";
    final String mockTemporalFeatureProperty = "myTemporalFeatureProperty";
    final String mockFeatureType = "{http://example.com}" + SAMPLE_FEATURE_NAME + 0;
    final int pageSize = 1;

    WfsSource source =
        getWfsSource(
            ONE_TEXT_PROPERTY_SCHEMA,
            MockWfsServer.getFilterCapabilities(),
            Wfs20Constants.EPSG_4326_URN,
            1,
            false,
            false,
            0);
    MetacardMapper mockMetacardMapper = mock(MetacardMapper.class);
    when(mockMetacardMapper.getFeatureType()).thenReturn(mockFeatureType);
    when(mockMetacardMapper.getSortByTemporalFeatureProperty())
        .thenReturn(mockTemporalFeatureProperty);
    List<MetacardMapper> mappers = new ArrayList<MetacardMapper>(1);
    mappers.add(mockMetacardMapper);
    source.setMetacardToFeatureMapper(mappers);

    QueryImpl query =
        new QueryImpl(builder.attribute(Metacard.ANY_TEXT).is().like().text(searchPhrase));
    query.setPageSize(pageSize);
    SortBy sortBy = new SortByImpl(Result.TEMPORAL, SortOrder.DESCENDING);
    query.setSortBy(sortBy);

    // Perform Test
    GetFeatureType featureType = source.buildGetFeatureRequest(query);

    // Verify
    QueryType queryType = (QueryType) featureType.getAbstractQueryExpression().get(0).getValue();
    JAXBElement<?> abstractSortingClause = queryType.getAbstractSortingClause();
    SortByType sortByType = (SortByType) abstractSortingClause.getValue();
    assertThat(
        sortByType.getSortProperty().get(0).getValueReference(), is(mockTemporalFeatureProperty));
    assertThat(
        sortByType.getSortProperty().get(0).getSortOrder().name(), is(SortOrderType.DESC.value()));
  }
  /**
   * Verify that, per DDF Query API Javadoc, if the startIndex is negative, the WfsSource throws an
   * UnsupportedQueryException.
   *
   * @throws WfsException
   * @throws TransformerConfigurationException
   * @throws UnsupportedQueryException
   */
  @Test(expected = UnsupportedQueryException.class)
  public void testPagingPageSizeNegative()
      throws WfsException, TransformerConfigurationException, UnsupportedQueryException {
    // Setup
    int pageSize = -4;
    int startIndex = 0;

    WfsSource source =
        getWfsSource(
            ONE_TEXT_PROPERTY_SCHEMA,
            MockWfsServer.getFilterCapabilities(),
            Wfs20Constants.EPSG_4326_URN,
            10,
            false);
    Filter filter = builder.attribute(Metacard.ANY_TEXT).is().like().text(LITERAL);
    Query query = new QueryImpl(filter, startIndex, pageSize, null, false, 0);

    // Execute
    GetFeatureType featureType = source.buildGetFeatureRequest(query);
  }
  @Test
  public void testTimeoutConfiguration() throws WfsException {
    WfsSource source =
        getWfsSource(
            ONE_TEXT_PROPERTY_SCHEMA,
            MockWfsServer.getFilterCapabilities(),
            Wfs20Constants.EPSG_4326_URN,
            1,
            false,
            false,
            0);

    source.setConnectionTimeout(10000);
    source.setReceiveTimeout(10000);

    // Perform test
    source.updateTimeouts();

    verify(mockWfs, atLeastOnce()).setTimeouts(any(Integer.class), any(Integer.class));
  }
  @Test
  public void testTypeNameHasNoPrefix() throws WfsException, UnsupportedQueryException {

    // Setup
    final String TITLE = "title";
    final String searchPhrase = "*";
    final int pageSize = 1;

    WfsSource source =
        getWfsSource(
            ONE_TEXT_PROPERTY_SCHEMA,
            MockWfsServer.getFilterCapabilities(),
            Wfs20Constants.EPSG_4326_URN,
            3,
            false,
            false,
            3);

    QueryImpl query =
        new QueryImpl(builder.attribute(Metacard.ANY_TEXT).is().like().text(searchPhrase));
    query.setPageSize(pageSize);
    SortBy sortBy = new SortByImpl(TITLE, SortOrder.DESCENDING);
    query.setSortBy(sortBy);

    // Perform test
    GetFeatureType featureType = source.buildGetFeatureRequest(query);

    // Validate
    List<JAXBElement<?>> queryList = featureType.getAbstractQueryExpression();
    for (JAXBElement<?> queryType : queryList) {
      Object val = queryType.getValue();
      QueryType queryTypeVal = (QueryType) val;
      assertThat(queryTypeVal.getTypeNames().get(0), containsString("SampleFeature"));
      assertThat(queryTypeVal.getTypeNames().get(0), is(not(containsString("Prefix"))));
      assertThat(queryTypeVal.getTypeNames().get(0), is(not(containsString(":"))));
    }
  }
  @Test
  public void testSearchByType() throws Exception {
    // Setup
    int startIndex = 0;
    int pageSize = 10;
    WfsSource source =
        getWfsSource(
            ONE_TEXT_PROPERTY_SCHEMA,
            MockWfsServer.getFilterCapabilities(),
            Wfs20Constants.EPSG_4326_URN,
            10,
            false);
    Filter filter =
        builder.attribute(Metacard.CONTENT_TYPE).is().equalTo().text(SAMPLE_FEATURE_NAME + "0");
    QueryImpl query = new QueryImpl(filter);
    query.setPageSize(pageSize);

    // Execute
    GetFeatureType featureType = source.buildGetFeatureRequest(query);
    QueryType queryType = (QueryType) featureType.getAbstractQueryExpression().get(0).getValue();

    // Validate
    assertEquals(SAMPLE_FEATURE_NAME + "0", queryType.getTypeNames().get(0));
  }
  public WfsSource getWfsSource(
      final String schema,
      final FilterCapabilities filterCapabilities,
      final String srsName,
      final int numFeatures,
      final boolean throwExceptionOnDescribeFeatureType)
      throws WfsException {

    // GetCapabilities Response
    when(mockWfs.getCapabilities(any(GetCapabilitiesRequest.class))).thenReturn(mockCapabilites);

    mockCapabilites.setFilterCapabilities(filterCapabilities);

    when(mockAvailabilityTask.isAvailable()).thenReturn(true);

    mockCapabilites.setFeatureTypeList(new FeatureTypeListType());
    for (int ii = 0; ii < numFeatures; ii++) {
      FeatureTypeType feature = new FeatureTypeType();
      QName qName;
      if (ii == 0) {
        qName = new QName(SAMPLE_FEATURE_NAME + ii);
      } else {
        qName = new QName("http://example.com", SAMPLE_FEATURE_NAME + ii, "Prefix" + ii);
      }
      feature.setName(qName);
      feature.setDefaultCRS(Wfs20Constants.EPSG_4326_URN);
      mockCapabilites.getFeatureTypeList().getFeatureType().add(feature);
    }

    XmlSchema xmlSchema = null;
    if (StringUtils.isNotBlank(schema)) {
      XmlSchemaCollection schemaCollection = new XmlSchemaCollection();
      WfsUriResolver wfsUriResolver = new WfsUriResolver();
      wfsUriResolver.setGmlNamespace(Wfs20Constants.GML_3_2_NAMESPACE);
      wfsUriResolver.setWfsNamespace(Wfs20Constants.WFS_2_0_NAMESPACE);
      schemaCollection.setSchemaResolver(wfsUriResolver);
      xmlSchema =
          schemaCollection.read(new StreamSource(new ByteArrayInputStream(schema.getBytes())));
    }

    if (throwExceptionOnDescribeFeatureType) {
      when(mockWfs.describeFeatureType(any(DescribeFeatureTypeRequest.class)))
          .thenThrow(new WfsException(""));

    } else {
      when(mockWfs.describeFeatureType(any(DescribeFeatureTypeRequest.class)))
          .thenReturn(xmlSchema);
    }
    when(mockWfs.getFeatureCollectionReader()).thenReturn(mockReader);

    // GetFeature Response
    when(mockWfs.getFeature(any(GetFeatureType.class))).thenReturn(mockFeatureCollection);

    when(mockFeatureCollection.getNumberReturned()).thenReturn(BigInteger.valueOf(numFeatures));

    when(mockFeatureCollection.getMembers())
        .thenAnswer(
            new Answer<List<Metacard>>() {
              @Override
              public List<Metacard> answer(InvocationOnMock invocation) {
                // Create as many metacards as there are features
                List<Metacard> metacards = new ArrayList<Metacard>(numFeatures);
                for (int i = 0; i < numFeatures; i++) {
                  MetacardImpl mc = new MetacardImpl();
                  mc.setId("ID_" + String.valueOf(i + 1));
                  metacards.add(mc);
                }

                return metacards;
              }
            });

    MetacardMapper mockMapper = mock(MetacardMapper.class);
    List<MetacardMapper> mappers = new ArrayList<MetacardMapper>(1);
    mappers.add(mockMapper);

    WfsSource source =
        new WfsSource(mockWfs, new GeotoolsFilterAdapterImpl(), mockContext, mockAvailabilityTask);

    source.setMetacardToFeatureMapper(mappers);
    return source;
  }