content: /*
   *  Licensed to the Apache Software Foundation (ASF) under one or more
   *  contributor license agreements.  See the NOTICE file distributed with
   *  this work for additional information regarding copyright ownership.
   *  The ASF licenses this file to You 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
   *
   *      https://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 org.apache.tools.ant.taskdefs.optional.junitlauncher.confined;
  
  import javax.xml.stream.XMLStreamConstants;
  import javax.xml.stream.XMLStreamException;
  import javax.xml.stream.XMLStreamReader;
  import javax.xml.stream.XMLStreamWriter;
  
  import java.io.File;
  import java.util.Collections;
  import java.util.LinkedHashSet;
  import java.util.List;
  import java.util.Set;
  import java.util.StringTokenizer;
  
  import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_CLASS_NAME;
  import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_EXCLUDE_ENGINES;
  import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_HALT_ON_FAILURE;
  import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_INCLUDE_ENGINES;
  import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_METHODS;
  import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ATTR_OUTPUT_DIRECTORY;
  import static org.apache.tools.ant.taskdefs.optional.junitlauncher.confined.Constants.LD_XML_ELM_TEST;
  
  /**
   * Represents the single {@code test} (class) that's configured to be launched by the {@link JUnitLauncherTask}
   */
  public class SingleTestClass extends TestDefinition implements NamedTest {
  
      private String testClass;
      private Set<String> testMethods;
  
      public SingleTestClass() {
  
      }
  
      public void setName(final String test) {
          if (test == null || test.trim().isEmpty()) {
              throw new IllegalArgumentException("Test name cannot be null or empty string");
          }
          this.testClass = test;
      }
  
      public String getName() {
          return this.testClass;
      }
  
      public void setMethods(final String methods) {
          // parse the comma separated set of methods
          if (methods == null || methods.trim().isEmpty()) {
              this.testMethods = Collections.emptySet();
              return;
          }
          final StringTokenizer tokenizer = new StringTokenizer(methods, ",");
          if (!tokenizer.hasMoreTokens()) {
              this.testMethods = Collections.emptySet();
              return;
          }
          // maintain specified ordering
          this.testMethods = new LinkedHashSet<>();
          while (tokenizer.hasMoreTokens()) {
              final String method = tokenizer.nextToken().trim();
              if (method.isEmpty()) {
                  continue;
              }
              this.testMethods.add(method);
          }
      }
  
      boolean hasMethodsSpecified() {
          return this.testMethods != null && !this.testMethods.isEmpty();
      }
  
      public String[] getMethods() {
          if (!hasMethodsSpecified()) {
              return null;
          }
          return this.testMethods.toArray(new String[0]);
      }
  
      @Override
      protected List<ForkedRepresentation> toForkedRepresentations() throws IllegalStateException {
          if (this.forkDefinition == null) {
              throw new IllegalStateException("tests haven't been configured to run in forked JVM");
          }
          return Collections.singletonList(new SingleTestFork());
      }
  
      private final class SingleTestFork extends ForkedRepresentation {
          @Override
          public void write(final JUnitLauncherTask task, final XMLStreamWriter writer)
                  throws XMLStreamException {
              writer.writeStartElement(LD_XML_ELM_TEST);
              writer.writeAttribute(LD_XML_ATTR_CLASS_NAME, testClass);
              if (testMethods != null) {
                  final StringBuilder sb = new StringBuilder();
                  for (final String method : testMethods) {
                      if (sb.length() != 0) {
                          sb.append(",");
                      }
                      sb.append(method);
                  }
                  writer.writeAttribute(LD_XML_ATTR_METHODS, sb.toString());
              }
              if (haltOnFailure != null) {
                  writer.writeAttribute(LD_XML_ATTR_HALT_ON_FAILURE, haltOnFailure.toString());
              }
              if (outputDir != null) {
                  writer.writeAttribute(LD_XML_ATTR_OUTPUT_DIRECTORY, outputDir.getPath());
              }
              if (includeEngines != null) {
                  writer.writeAttribute(LD_XML_ATTR_INCLUDE_ENGINES, includeEngines);
              }
              if (excludeEngines != null) {
                  writer.writeAttribute(LD_XML_ATTR_EXCLUDE_ENGINES, excludeEngines);
              }
              // listeners for this test
              if (listeners != null) {
                  for (final ListenerDefinition listenerDef : getListeners()) {
                      if (!listenerDef.shouldUse(task.getProject())) {
                          // not applicable
                          continue;
                      }
                      listenerDef.toForkedRepresentation(writer);
                  }
              }
              writer.writeEndElement();
          }
      }
  
      public static TestDefinition fromForkedRepresentation(final XMLStreamReader reader) throws XMLStreamException {
          reader.require(XMLStreamConstants.START_ELEMENT, null, LD_XML_ELM_TEST);
          final SingleTestClass testDefinition = new SingleTestClass();
          final String testClassName = requireAttributeValue(reader, LD_XML_ATTR_CLASS_NAME);
          testDefinition.setName(testClassName);
          final String methodNames = reader.getAttributeValue(null, LD_XML_ATTR_METHODS);
          if (methodNames != null) {
              testDefinition.setMethods(methodNames);
          }
          final String halt = reader.getAttributeValue(null, LD_XML_ATTR_HALT_ON_FAILURE);
          if (halt != null) {
              testDefinition.setHaltOnFailure(Boolean.parseBoolean(halt));
          }
          final String outDir = reader.getAttributeValue(null, LD_XML_ATTR_OUTPUT_DIRECTORY);
          if (outDir != null) {
              testDefinition.setOutputDir(new File(outDir));
          }
          final String includeEngs = reader.getAttributeValue(null, LD_XML_ATTR_INCLUDE_ENGINES);
          if (includeEngs != null) {
              testDefinition.setIncludeEngines(includeEngs);
          }
          final String excludeEngs = reader.getAttributeValue(null, LD_XML_ATTR_EXCLUDE_ENGINES);
          if (excludeEngs != null) {
              testDefinition.setExcludeEngines(excludeEngs);
          }
          while (reader.nextTag() != XMLStreamConstants.END_ELEMENT) {
              reader.require(XMLStreamConstants.START_ELEMENT, null, Constants.LD_XML_ELM_LISTENER);
              testDefinition.addConfiguredListener(ListenerDefinition.fromForkedRepresentation(reader));
          }
          return testDefinition;
      }
  
      private static String requireAttributeValue(final XMLStreamReader reader, final String attrName) throws XMLStreamException {
          final String val = reader.getAttributeValue(null, attrName);
          if (val != null) {
              return val;
          }
          throw new XMLStreamException("Attribute " + attrName + " is missing at " + reader.getLocation());
      }
  }
  