scons_gd/scons/test/Java/multi-step.py
2022-10-15 16:06:26 +02:00

601 lines
16 KiB
Python

#!/usr/bin/env python
#
# MIT License
#
# Copyright The SCons Foundation
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
"""
Real-world test (courtesy Leanid Nazdrynau) of the multi-step
capabilities of the various Java Builders.
TODO: the whole Applet facility is deprecated, need a new test.
"""
import os
import pathlib
import TestSCons
test = TestSCons.TestSCons()
where_javac, java_version = test.java_where_javac()
where_javah = test.java_where_javah()
where_java_include=test.java_where_includes()
swig = test.where_is('swig')
if not swig:
test.skip_test('Can not find installed "swig", skipping test.\n')
# Skip this test on AppVeyor
# Skip this test as SCons doesn't (currently) predict the generated
# inner/anonymous class generated .class files generated by gcj
# and so will always fail
if test.javac_is_gcj:
test.skip_test('Test not valid for gcj (gnu java); skipping test(s).\n')
# TODO rework for 'javac -h', for now skip
# The logical test would be: if java_version > 9:
# but java_where_javah() roots around and will find from an older version
if not test.Environment().WhereIs('javah'):
test.skip_test("No Java javah for version > 9, skipping test.\n")
# On some systems, the alternatives system does not remove javah even if the
# preferred Java doesn't have it, so try another check
javacdir = pathlib.Path(where_javac).parent
javahdir = pathlib.Path(where_javah).parent
if javacdir != javahdir:
test.skip_test("Cannot find Java javah matching javac, skipping test.\n")
test.subdir(
['src'],
['src', 'HelloApplet'],
['src', 'HelloApplet', 'com'],
['src', 'javah'],
['src', 'jni'],
['src', 'server'],
['src', 'server', 'JavaSource'],
['src', 'server', 'JavaSource', 'com'],
['src', 'server', 'JavaSource', 'com', 'gnu'],
['src', 'server', 'JavaSource', 'com', 'gnu', 'scons'],
['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web'],
['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web', 'tools'],
['src', 'server', 'WebContent'],
['src', 'server', 'WebContent', 'META-INF'],
['src', 'server', 'WebContent', 'WEB-INF'],
['src', 'server', 'WebContent', 'WEB-INF', 'conf'],
['src', 'server', 'WebContent', 'WEB-INF', 'lib'],
['src', 'server', 'WebContent', 'theme'],
)
test.write(['SConstruct'], """\
import os, sys
if sys.platform == 'win32':
# Ensure tests don't pick up link from mingw or cygwin
tools = ['msvc', 'mslink', 'jar', 'javac', 'javah', 'swig']
else:
tools = ['default', 'javac', 'javah', 'swig']
env = Environment(tools=tools, CPPPATH=["$JAVAINCLUDES"])
Export('env')
# env.PrependENVPath('PATH',os.environ.get('PATH',[]))
env['INCPREFIX'] = '-I'
env.Append(SWIGFLAGS=['-c++', '$_CPPINCFLAGS'])
# this is for JNI
# env.Append(CCFLAGS=['/IN:/jdk/v1.3.1/include','/IN:/jdk/v1.3.1/include/win32'])
# this for windows only C++ build
# env.Append(CXXFLAGS='-GX')
env.Append(CPPPATH='.')
env.VariantDir('buildout', 'src', duplicate=0)
if sys.platform[:6] == 'darwin':
env.Append(CPPPATH=['/System/Library/Frameworks/JavaVM.framework/Headers'])
# If you do not have swig on your system please remove
# 'buildout/jni/SConscript' line from next call
env.SConscript(
[
'buildout/server/JavaSource/SConscript',
'buildout/HelloApplet/SConscript',
'buildout/jni/SConscript',
'buildout/javah/SConscript',
]
)
""" % locals())
test.write(['src', 'HelloApplet', 'Hello.html'], """\
<HTML>
<HEAD>
<TITLE> Applet Hello </TITLE>
</HEAD>
<BODY>
<CENTER>
<applet name="Hello" archive="HelloApplet.jar" code="com.Hello.Hello.class"
width="800" height="286" MAYSCRIPT>
</applet>
</CENTER>
</BODY>
</HTML>
""")
test.write(['src', 'HelloApplet', 'SConscript'], """\
import os
Import("env")
denv = env.Clone()
classes = denv.Java(target='classes', source=['com'])
# set correct path for jar
denv['JARCHDIR'] = os.path.join(denv.Dir('.').get_abspath(), 'classes')
denv.Jar('HelloApplet', classes)
# To sign applet you have to create keystore before and made a calls like this
# keystore='/path/to/jarsignkey'
# denv['JARSIGNFLAGS']='-keystore '+keystore+' -storepass pass -keypass passkey'
# denv['JARSIGNALIAS']='ALIAS'
# denv['JARCOM']=[denv['JARCOM'],'$JARSIGNCOM']
""")
test.write(['src', 'HelloApplet', 'com', 'Hello.java'], """\
package com.Hello;
import java.awt.*;
import java.applet.*;
public class Hello extends Applet {
static final long serialVersionUID = 0;
public void paint(Graphics g)
{
g.drawString("Hello from SCons signed applet",250,150);
}
}
""")
test.write(['src', 'javah', 'MyID.cc'], """\
#include "MyID.h"
#ifdef _MSC_VER
__declspec(dllexport)
#endif
int getMyID()
{
return 0;
}
""")
test.write(['src', 'javah', 'MyID.java'], """\
public class MyID
{
static private long current = System.currentTimeMillis();
static public String get()
{
current++;
return new Long( current ).toString();
}
}
""")
test.write(['src', 'javah', 'SConscript'], """\
Import('env')
denv = env.Clone()
denv['JARCHDIR'] = denv.Dir('.').get_abspath()
denv.Jar('myid', 'MyID.java')
denv.JavaH(denv.Dir('.').get_abspath(), 'MyID.java')
denv.SharedLibrary('myid', 'MyID.cc')
""")
test.write(['src', 'jni', 'A.java'], """\
package web.jni;
public class A
{
class C
{
void echo2( String text )
{
System.out.println( text+"aa" );
}
}
class B
{
void echo( String text )
{
System.out.println( text );
C c = new C();
c.echo2("from B callin C");
}
}
public void main( String[] x)
{
B b = new B();
b.echo("123");
C c = new C();
c.echo2("456");
}
}
""")
test.write(['src', 'jni', 'JniWrapper.cc'], """\
#include <vector>
#include <iostream>
#include "JniWrapper.h"
JniWrapper::JniWrapper( JNIEnv *pEnv )
: mpEnv( pEnv )
{
}
JniWrapper::JniWrapper( const JniWrapper& rJniWrapper )
: mpEnv( rJniWrapper.mpEnv )
{
}
JniWrapper::~JniWrapper()
{
}
JniWrapper& JniWrapper::operator=( const JniWrapper& rJniWrapper )
{
if ( this != &rJniWrapper )
{
mpEnv = rJniWrapper.mpEnv;
}
return *this;
}
std::string JniWrapper::unmarshalString( jstring value )
{
std::string result;
if( value )
{
const char *pStr = mpEnv->GetStringUTFChars( value, 0 );
result = pStr;
mpEnv->ReleaseStringUTFChars( value, pStr );
}
return result;
}
jobject JniWrapper::marshalDouble( double value )
{
jclass classObject = mpEnv->FindClass( "java/lang/Double" );
jmethodID constructorId = mpEnv->GetMethodID( classObject, "<init>", "(D)V" );
jobject result = mpEnv->NewObject( classObject, constructorId, value );
return result;
}
jobject JniWrapper::getVectorElement( jobject values, int i )
{
jclass vectorClass = mpEnv->FindClass( "java/util/Vector" );
jmethodID methodID = mpEnv->GetMethodID( vectorClass,
"elementAt",
"(I)Ljava/lang/Object;" );
jobject result = mpEnv->CallObjectMethod( values, methodID, i );
return result;
}
jobject JniWrapper::newVector()
{
jclass vectorClass = mpEnv->FindClass( "java/util/Vector" );
jmethodID constructorID = mpEnv->GetMethodID( vectorClass, "<init>", "()V" );
jobject result = mpEnv->NewObject( vectorClass, constructorID );
return result;
}
void JniWrapper::addElement( jobject vector, jobject element )
{
jclass vectorClass = mpEnv->FindClass( "java/util/Vector" );
jmethodID addElementMethodID = mpEnv->GetMethodID( vectorClass,
"addElement",
"(Ljava/lang/Object;)V" );
mpEnv->CallVoidMethod( vector, addElementMethodID, element );
}
jobject JniWrapper::marshalDoubleVector( const std::vector<double>& rVector )
{
jobject result = newVector();
for ( int i = 0; i < rVector.size(); i++ )
{
addElement( result, marshalDouble( rVector[i] ) );
}
return result;
}
std::pair<std::string, std::string> JniWrapper::unmarshalPairString( jobject vector )
{
std::pair<std::string, std::string> result;
result.first = unmarshalString( (jstring)getVectorElement( vector, 0 ) );
result.second = unmarshalString( (jstring)getVectorElement( vector, 1 ) );
return result;
}
""")
test.write(['src', 'jni', 'JniWrapper.h'], """\
#ifndef JniWrapper_h
#define JniWrapper_h
#include <jni.h>
/**
* Provides routines for dealing with JNI translation etc.
*/
class JniWrapper
{
public:
JniWrapper( JNIEnv *pEnv );
JniWrapper( const JniWrapper& rJniWrapper );
virtual ~JniWrapper();
JniWrapper& operator=( const JniWrapper& rJniWrapper );
std::string unmarshalString( jstring value );
jstring marshalString( const std::string& value );
jbyteArray marshalByteArray( const std::string& value );
double unmarshalDouble( jobject value );
jobject marshalDouble( double value );
jobject marshallStringVector( const std::vector<std::string>& rMap );
jobject marshalDoubleVector( const std::vector<double>& rVector );
std::pair<std::string, std::string> unmarshalPairString( jobject );
protected:
JNIEnv *mpEnv;
private:
JniWrapper();
jobject newVector();
void addElement( jobject vector, jobject element );
jobject getVectorElement( jobject values, int i );
};
#endif // JniWrapper_h
""")
test.write(['src', 'jni', 'SConscript'], """\
Import("env")
denv = env.Clone()
denv.Append(SWIGFLAGS=['-java'])
denv.SharedLibrary('scons', ['JniWrapper.cc', 'Sample.i'])
denv['JARCHDIR'] = denv.Dir('.').get_abspath()
denv.Jar(['Sample.i', 'A.java'])
""")
test.write(['src', 'jni', 'Sample.h'], """\
#include <vector>
#include <iostream>
class SampleTest
{
public:
std::vector<double> test1( std::pair<std::string, std::string> param )
{
std::vector<double> result;
result.push_back(10);
return result;
}
};
""")
test.write(['src', 'jni', 'Sample.i'], """\
%module Sample
%{
#include "Sample.h"
#include "JniWrapper.h"
%}
%typemap(jni) std::vector<double>, std::vector<double>& "jobject"
%typemap(jtype) std::vector<double>, std::vector<double>& "java.util.Vector"
%typemap(jstype) std::vector<double>, std::vector<double>& "java.util.Vector"
// return a Vector of Doubles
%typemap(javaout) std::vector<double> {
return $jnicall;
}
%typemap(out) std::vector<double> {
JniWrapper JniWrapper(jenv);
$result = JniWrapper.marshalDoubleVector( $1 );
}
/*********************************************************************
*
* Pairs of String (IN/OUT)
*
*********************************************************************/
%typemap(jni) std::pair<std::string, std::string>, const std::pair<std::string, std::string>& "jobject"
%typemap(jtype) std::pair<std::string, std::string>, const std::pair<std::string, std::string>& "java.util.Vector"
%typemap(jstype) std::pair<std::string, std::string>, const std::pair<std::string, std::string>& "java.util.Vector"
%typemap(javain) std::pair<std::string, std::string>, const std::pair<std::string, std::string>& "$javainput"
// pass in by reference a Vector of std::string
%typemap(in) const std::pair<std::string, std::string>& {
$1 = new std::pair<std::string, std::string>();
JniWrapper JniWrapper(jenv);
*($1) = JniWrapper.unmarshalPairString( $input );
}
//cleanup
%typemap(freearg) const std::pair<std::string, std::string>& {
delete $1;
}
%include "Sample.h"
// generate:Sample.java
// generate:SampleJni.java
// generate:SampleTest.java
""")
test.write(['src', 'server', 'JavaSource', 'SConscript'], """\
import os
Import ("env")
classes=env.Java(target='classes',source=['com'])
HelloApplet=os.path.join('#/buildout/HelloApplet/HelloApplet.jar')
env['WARXFILES']=['SConscript','.cvsignore']
env['WARXDIRS']=['CVS']
#env.War('scons',[classes,Dir('../WebContent'),HelloApplet])
""")
test.write(['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web', 'tools', 'Bool.java'], """\
package com.gnu.scons.web.tools;
public class Bool {
boolean flag;
public Bool()
{
flag = false;
}
public Bool( boolean aFlag )
{
flag = aFlag;
}
public boolean booleanValue()
{
return flag;
}
}
""")
test.write(['src', 'server', 'JavaSource', 'com', 'gnu', 'scons', 'web', 'tools', 'StringUtils.java'], """\
package com.gnu.scons.web.tools;
public class StringUtils
{
public static String toPercent( String value )
{
if ( value.equals("") )
{
return "";
}
else
{
return value + "%";
}
}
}
""")
test.write(['src', 'server', 'WebContent', 'index.html'], """\
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
<META http-equiv="refresh" content="0;URL=go?action=home">
<TITLE>index.html</TITLE>
</HEAD>
<BODY>
<P><a href="go?action=home">go?action=home</a></P>
</BODY>
</HTML>
""")
test.write(['src', 'server', 'WebContent', 'META-INF', 'MANIFEST.MF'], """\
Manifest-Version: 1.0
Class-Path:
""")
test.write(['src', 'server', 'WebContent', 'WEB-INF', 'web.xml'], """\
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app id="WebExample">
<display-name>scons</display-name>
<servlet>
<servlet-name>WebExample</servlet-name>
<display-name>WebExample</display-name>
<servlet-class>com.gnu.scons.web.tool.WebExample</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>WebExample</servlet-name>
<url-pattern>/go</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
</welcome-file-list>
</web-app>
""")
test.write(['src', 'server', 'WebContent', 'WEB-INF', 'conf', 'app.properties'], """\
logging = webExample.Example
""")
test.write(['src', 'server', 'WebContent', 'theme', 'Master.css'], """\
body
{
font-family: Helvetica,Sans-Serif;
font-size: 11pt;
}
""")
test.run(arguments = '.')
test.must_exist(['buildout', 'javah', 'myid.jar'])
test.must_exist(['buildout', 'javah', 'MyID', 'MyID.class'])
test.must_exist(['buildout', 'jni', 'Sample.class'])
test.must_exist(['buildout', 'jni', 'Sample.java'])
test.must_exist(['buildout', 'jni', 'SampleJNI.class'])
test.must_exist(['buildout', 'jni', 'SampleJNI.java'])
test.must_exist(['buildout', 'jni', 'SampleTest.java'])
# Some combinations of Java + SWIG apparently don't actually generate
# a SampleTest.class file, while others do. Only issue a warning if
# it doesn't exist.
p = test.workpath('buildout', 'jni', 'SampleTest.class')
if not os.path.exists(p):
print('Warning: %s does not exist' % p)
test.up_to_date(arguments = '.')
test.pass_test()
# Local Variables:
# tab-width:4
# indent-tabs-mode:nil
# End:
# vim: set expandtab tabstop=4 shiftwidth=4: