1 /*
  2  * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /*
 25  * @test
 26  * @modules jdk.incubator.jextract
 27  * @library /test/lib
 28  * @build JextractToolRunner
 29  * @run testng/othervm --enable-native-access=jdk.incubator.jextract -Duser.language=en --add-modules jdk.incubator.jextract TestFilters
 30  */
 31 
 32 import org.testng.annotations.Test;
 33 
 34 import java.io.IOException;
 35 import java.nio.file.Files;
 36 import java.nio.file.Path;
 37 import java.util.Iterator;
 38 import java.util.List;
 39 
 40 import static org.testng.Assert.assertNotNull;
 41 import static org.testng.Assert.assertNull;
 42 import static org.testng.Assert.fail;
 43 
 44 public class TestFilters extends JextractToolRunner {
 45     @Test
 46     public void testFilter() {
 47         for (FilterKind expectedKind : FilterKind.values()) {
 48             Path filterOutput = getOutputFilePath("filters_" + expectedKind);
 49             Path filterH = getInputFilePath("filters.h");
 50             run("-d", filterOutput.toString(), expectedKind.filterOption, expectedKind.symbolName, filterH.toString()).checkSuccess();
 51             try (Loader loader = classLoader(filterOutput)) {
 52                 Class<?> cls = loader.loadClass("filters_h");
 53                 for (FilterKind kind : FilterKind.values()) {
 54                     Object res = kind.get(cls);
 55                     if (kind == expectedKind) {
 56                         assertNotNull(res);
 57                     } else {
 58                         assertNull(res);
 59                     }
 60                 }
 61             } finally {
 62                 deleteDir(filterOutput);
 63             }
 64         }
 65     }
 66 
 67     @Test
 68     public void testDumpIncludes() throws IOException {
 69         Path filterOutput = getOutputFilePath("filters_dump");
 70         try {
 71             Files.createDirectory(filterOutput);
 72             Path includes = filterOutput.resolve("test.conf");
 73             Path filterH = getInputFilePath("filters.h");
 74             run("--dump-includes", includes.toString(), filterH.toString()).checkSuccess();
 75             List<String> includeLines = Files.readAllLines(includes);
 76             outer: for (FilterKind kind : FilterKind.values()) {
 77                 String filterLine = kind.filterOption + " " + kind.symbolName;
 78                 Iterator<String> linesIt = includeLines.iterator();
 79                 while (linesIt.hasNext()) {
 80                     String line = linesIt.next();
 81                     if (line.startsWith(filterLine)) {
 82                         linesIt.remove();
 83                         continue outer;
 84                     }
 85                 }
 86                 fail("Filter line not found: " + filterLine);
 87             }
 88         } finally {
 89             deleteDir(filterOutput);
 90         }
 91     }
 92 
 93     enum FilterKind {
 94         VAR("_global", "--include-var"),
 95         FUNCTION("_function", "--include-function"),
 96         CONSTANT("_constant", "--include-macro"),
 97         TYPEDEF("_typedef", "--include-typedef"),
 98         STRUCT("_struct", "--include-struct"),
 99         UNION("_union", "--include-union");
100 
101         final String symbolName;
102         final String filterOption;
103 
104         FilterKind(String symbolName, String filterOption) {
105             this.symbolName = symbolName;
106             this.filterOption = filterOption;
107         }
108 
109         Object get(Class<?> headerClass) {
110             return switch (this) {
111                 case FUNCTION, CONSTANT -> findMethod(headerClass, symbolName);
112                 case VAR -> findMethod(headerClass, symbolName + "$get");
113                 case TYPEDEF -> findField(headerClass, symbolName);
114                 case STRUCT, UNION -> {
115                     try {
116                         yield headerClass.getClassLoader().loadClass(symbolName);
117                     } catch (ReflectiveOperationException ex) {
118                         yield null;
119                     }
120                 }
121             };
122         }
123     }
124 }