View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.rat.config.parameters;
20  
21  import static java.lang.String.format;
22  import static org.junit.jupiter.api.Assertions.assertEquals;
23  import static org.junit.jupiter.api.Assertions.assertNotNull;
24  import static org.junit.jupiter.api.Assertions.assertTrue;
25  import static org.junit.jupiter.api.Assertions.fail;
26  
27  import java.io.File;
28  import java.lang.reflect.Method;
29  import java.net.URISyntaxException;
30  import java.net.URL;
31  import java.util.ArrayList;
32  import java.util.List;
33  
34  import java.util.SortedSet;
35  import java.util.TreeSet;
36  import java.util.function.Consumer;
37  import java.util.stream.Stream;
38  import org.apache.rat.BuilderParams;
39  import org.apache.rat.analysis.matchers.AndMatcher;
40  import org.apache.rat.analysis.matchers.CopyrightMatcher;
41  import org.apache.rat.api.Document;
42  import org.apache.rat.document.DocumentName;
43  import org.apache.rat.document.DocumentNameMatcher;
44  import org.apache.rat.document.FileDocument;
45  import org.junit.jupiter.api.Test;
46  import org.junit.jupiter.params.ParameterizedTest;
47  import org.junit.jupiter.params.provider.Arguments;
48  import org.junit.jupiter.params.provider.MethodSource;
49  
50  public class DescriptionBuilderTest {
51  
52      @Test
53      public void matcherMapBuildTest() {
54          Description underTest = DescriptionBuilder.buildMap(CopyrightMatcher.class);
55          assertEquals(ComponentType.MATCHER, underTest.getType());
56          assertEquals("copyright", underTest.getCommonName());
57          assertNotNull(underTest.getDescription());
58          assertEquals(4, underTest.getChildren().size());
59          assertTrue(underTest.getChildren().containsKey("id"));
60          assertTrue(underTest.getChildren().containsKey("start"));
61          assertTrue(underTest.getChildren().containsKey("end"));
62          assertTrue(underTest.getChildren().containsKey("owner"));
63  
64          underTest = DescriptionBuilder.buildMap(AndMatcher.class);
65          assertEquals(ComponentType.MATCHER, underTest.getType());
66          assertEquals("all", underTest.getCommonName());
67          assertNotNull(underTest.getDescription());
68          assertEquals(3, underTest.getChildren().size());
69          assertTrue(underTest.getChildren().containsKey("id"));
70          assertTrue(underTest.getChildren().containsKey("resource"));
71          assertTrue(underTest.getChildren().containsKey("enclosed"));
72          Description desc = underTest.getChildren().get("enclosed");
73      }
74  
75      /**
76       * Test to verify that all Description based inspection invoked methods exist.
77       * @param clazz The class to check
78       * @param desc The description of an element in that class.
79       */
80      @ParameterizedTest
81      @MethodSource("descriptionSource")
82      public void textConfigParameters(Class<?> clazz, Description desc) {
83          if (desc.getType() == ComponentType.BUILD_PARAMETER) {
84              try {
85                  Method m = BuilderParams.class.getMethod(desc.getCommonName());
86                  assertNotNull(m);
87              } catch (NoSuchMethodException e) {
88                  fail(format("BuilderParams does not have a %s method", desc.getCommonName()), e);
89              }
90          } else {
91              try {
92                  // verify that the class has the getter for the description.
93                  assertNotNull(desc.getter(clazz));
94              } catch (NoSuchMethodException e) {
95                  fail(format("Missing method: %s.%s", clazz, desc.methodName("get")), e);
96              }
97          }
98      }
99  
100     /** Class to build a list of documents that are class files. */
101     private static class DocumentProcessor implements Consumer<Document> {
102         final SortedSet<Document> documents = new TreeSet<>();
103         @Override
104         public void accept(Document document) {
105             if (document.isDirectory()) {
106                 document.listChildren().forEach(this);
107             } else {
108                 if (document.getName().getName().endsWith(".class")) {
109                     documents.add(document);
110                 }
111             }
112         }
113     }
114 
115     /**
116      * Scans the build classes directory to locate all class files that have Description annotations and ensure its validity.
117      * @return A stream of class and descriptions to validate.
118      * @throws URISyntaxException if URI is incorrect.
119      * @throws ClassNotFoundException if class can not be found.
120      */
121     public static Stream<Arguments> descriptionSource() throws URISyntaxException, ClassNotFoundException {
122         List<Arguments> arguments = new ArrayList<>();
123         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
124         URL url = classLoader.getResource("");
125         File baseDir = new File(url.toURI());
126         baseDir = new File(baseDir.getParent(), "classes");
127         DocumentName documentName = DocumentName.builder(baseDir).build();
128         FileDocument fileDocument =  new FileDocument(documentName, baseDir, DocumentNameMatcher.MATCHES_ALL);
129         DocumentProcessor processor = new DocumentProcessor();
130         processor.accept(fileDocument);
131 
132         for (Document document : processor.documents) {
133             String className = document.getName().localized(".");
134             className = className.substring(1, className.length() - ".class".length());
135             Class<?> clazz = Class.forName(className);
136             List<Description> descriptionList = DescriptionBuilder.getConfigComponents(clazz);
137             if (descriptionList != null) {
138                 descriptionList.forEach( desc -> arguments.add(Arguments.of(clazz, desc)));
139             }
140         }
141 
142         return arguments.stream();
143     }
144 }