1 /*
  2  * Copyright (c) 2020, 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 import java.io.IOException;
 25 import java.nio.file.Files;
 26 import java.nio.file.Path;
 27 
 28 import jdk.incubator.foreign.Addressable;
 29 import jdk.incubator.foreign.MemoryAddress;
 30 
 31 import org.testng.annotations.Test;
 32 import static org.testng.Assert.assertEquals;
 33 import static org.testng.Assert.assertFalse;
 34 import static org.testng.Assert.assertNotNull;
 35 import static org.testng.Assert.assertNull;
 36 import static org.testng.Assert.assertTrue;
 37 
 38 /*
 39  * @test
 40  * @modules jdk.incubator.jextract
 41  * @library /test/lib
 42  * @build JextractToolRunner
 43  * @bug 8240181
 44  * @run testng/othervm --enable-native-access=jdk.incubator.jextract -Duser.language=en --add-modules jdk.incubator.jextract JextractToolProviderTest
 45  */
 46 public class JextractToolProviderTest extends JextractToolRunner {
 47     @Test
 48     public void testHelp() {
 49         run().checkFailure(OPTION_ERROR); // no options
 50         run("--help").checkSuccess();
 51         run("-h").checkSuccess();
 52         run("-?").checkSuccess();
 53     }
 54 
 55     // error for non-existent header file
 56     @Test
 57     public void testNonExistentHeader() {
 58         run(getInputFilePath("non_existent.h").toString())
 59             .checkFailure(INPUT_ERROR)
 60             .checkContainsOutput("cannot read header file");
 61     }
 62 
 63     // error for header including non_existent.h file
 64     @Test
 65     public void testNonExistentIncluder() {
 66         run(getInputFilePath("non_existent_includer.h").toString())
 67             .checkFailure(CLANG_ERROR)
 68             .checkContainsOutput("file not found");
 69     }
 70 
 71     @Test
 72     public void testDirectoryAsHeader() {
 73         run(getInputFilePath("directory.h").toString())
 74             .checkFailure(INPUT_ERROR)
 75             .checkContainsOutput("not a file");
 76     }
 77 
 78     // error for header with parser errors
 79     @Test
 80     public void testHeaderWithDeclarationErrors() {
 81         run(getInputFilePath("illegal_decls.h").toString())
 82             .checkFailure(CLANG_ERROR)
 83             .checkContainsOutput("cannot combine with previous 'short' declaration specifier");
 84     }
 85 
 86     // @bug 8267504: jextract should report unsupported language and exit rather
 87     // than generating partial nonworking code
 88     @Test
 89     public void testUnsupportedLanguage() {
 90         run("-C-xc++", getInputFilePath("unsupported_lang.h").toString())
 91             .checkFailure(RUNTIME_ERROR)
 92             .checkContainsOutput("Unsupported language: C++");
 93     }
 94 
 95     @Test
 96     public void testOutputClass() {
 97         Path helloOutput = getOutputFilePath("hellogen");
 98         Path helloH = getInputFilePath("hello.h");
 99         run("-d", helloOutput.toString(), helloH.toString()).checkSuccess();
100         try(Loader loader = classLoader(helloOutput)) {
101             Class<?> cls = loader.loadClass("hello_h");
102             // check a method for "void func(int)"
103             assertNotNull(findMethod(cls, "func", int.class));
104             // check a method for "int printf(MemoryAddress, Object[])"
105             assertNotNull(findMethod(cls, "printf", Addressable.class, Object[].class));
106         } finally {
107             deleteDir(helloOutput);
108         }
109     }
110 
111     private void testTargetPackage(String targetPkgOption) {
112         Path helloOutput = getOutputFilePath("hellogen");
113         Path helloH = getInputFilePath("hello.h");
114         run(targetPkgOption, "com.acme", "-d",
115             helloOutput.toString(), helloH.toString()).checkSuccess();
116         try(Loader loader = classLoader(helloOutput)) {
117             Class<?> cls = loader.loadClass("com.acme.hello_h");
118             // check a method for "void func(int)"
119             assertNotNull(findMethod(cls, "func", int.class));
120             // check a method for "int printf(MemoryAddress, Object[])"
121             assertNotNull(findMethod(cls, "printf", Addressable.class, Object[].class));
122         } finally {
123             deleteDir(helloOutput);
124         }
125     }
126 
127     @Test
128     public void testTargetPackageOption() {
129         testTargetPackage("-t");
130     }
131 
132     @Test
133     public void testTargetPackageLongOption() {
134         testTargetPackage("--target-package");
135     }
136 
137     @Test
138     public void testHeaderClassName() {
139         Path helloOutput = getOutputFilePath("hellogen");
140         Path helloH = getInputFilePath("hello.h");
141         run("--header-class-name", "MyHello", "-t", "com.acme", "-d",
142             helloOutput.toString(), helloH.toString()).checkSuccess();
143         try(Loader loader = classLoader(helloOutput)) {
144             Class<?> cls = loader.loadClass("com.acme.MyHello");
145             // check a method for "void func(int)"
146             assertNotNull(findMethod(cls, "func", int.class));
147             // check a method for "int printf(MemoryAddress, Object[])"
148             assertNotNull(findMethod(cls, "printf", Addressable.class, Object[].class));
149         } finally {
150             deleteDir(helloOutput);
151         }
152     }
153 }