Technology definitions loader

* Added "dummy" data file for technologies (for now it simply copies the
old, line-based technologies) and corresponding XML schema

* Added missing SQL stored procedure to clear all dependencies and
reverse dependencies from a technology

* Added import classes, loader and import tool for the technology graph

* Added tech graph import tool to post-build tests
This commit is contained in:
Emmanuel BENOîT 2012-02-27 20:04:02 +01:00
parent c5464212bc
commit 1f3c7a9202
24 changed files with 1731 additions and 43 deletions

View file

@ -33,6 +33,7 @@ EOF
java legacyworlds-server-main-*.jar --run-tool ImportText data/i18n-text.xml || exit 1
java legacyworlds-server-main-*.jar --run-tool ImportResources data/resources.xml || exit 1
java legacyworlds-server-main-*.jar --run-tool ImportTechs data/techs.xml || exit 1
java legacyworlds-server-main-*.jar --run-tool ImportTechGraph data/tech-graph.xml || exit 1
java legacyworlds-server-main-*.jar --run-tool ImportBuildables data/buildables.xml || exit 1
java legacyworlds-server-main-*.jar &

View file

@ -324,6 +324,47 @@ GRANT EXECUTE
/*
* Remove all dependencies for a technology
* -----------------------------------------
*
* This stored procedure removes all dependencies and reverse dependencies for
* some technology.
*
* Parameters:
* _technology The name of the technology
*/
DROP FUNCTION IF EXISTS defs.techdep_clear( TEXT );
CREATE FUNCTION defs.techdep_clear( _technology TEXT )
RETURNS VOID
LANGUAGE SQL
STRICT VOLATILE
SECURITY DEFINER
AS $techdep_clear$
DELETE FROM defs.technology_dependencies
WHERE technology_name_id = (
SELECT id FROM defs.strings
WHERE name = $1
);
DELETE FROM defs.technology_dependencies
WHERE technology_name_id_depends = (
SELECT id FROM defs.strings
WHERE name = $1
);
$techdep_clear$;
REVOKE EXECUTE
ON FUNCTION defs.techdep_clear( TEXT )
FROM PUBLIC;
GRANT EXECUTE
ON FUNCTION defs.techdep_clear( TEXT )
TO :dbuser;
-- ********************************************************
-- OLD CODE BELOW
-- ********************************************************

View file

@ -0,0 +1,58 @@
/*
* Test the defs.techdep_clear() function
*/
BEGIN;
\i utils/strings.sql
-- Make the columns we don't use in the technology definition table NULL-able
ALTER TABLE defs.technologies
ALTER technology_category_id DROP NOT NULL ,
ALTER technology_discovery_id DROP NOT NULL ,
ALTER technology_description_id DROP NOT NULL ,
ALTER technology_price DROP NOT NULL ,
ALTER technology_points DROP NOT NULL;
-- Create strings to use as the technologies' names
SELECT _create_test_strings( 4 , 'tech' );
-- Insert the technologies
INSERT INTO defs.technologies ( technology_name_id )
VALUES ( _get_string( 'tech1' ) ) ,
( _get_string( 'tech2' ) ) ,
( _get_string( 'tech3' ) ) ,
( _get_string( 'tech4' ) );
-- Add a chain of dependencies
INSERT INTO defs.technology_dependencies(
technology_name_id , technology_name_id_depends
) VALUES ( _get_string( 'tech2' ) , _get_string( 'tech1' ) ) ,
( _get_string( 'tech3' ) , _get_string( 'tech2' ) ) ,
( _get_string( 'tech4' ) , _get_string( 'tech3' ) );
-- ***** TESTS BEGIN HERE *****
SELECT plan( 4 );
SELECT diag_test_name( 'defs.techdep_clear() - No failure on invalid technology name' );
SELECT lives_ok( $$
SELECT defs.techdep_clear( 'does not exist' )
$$ );
SELECT diag_test_name( 'defs.techdep_clear() - Successful call' );
SELECT lives_ok( $$
SELECT defs.techdep_clear( 'tech2' )
$$ );
SELECT diag_test_name( 'defs.techdep_clear() - Cleared technology has no dependencies' );
SELECT is_empty( $$
SELECT * FROM defs.technology_dependencies
WHERE technology_name_id = _get_string( 'tech2' );
$$ );
SELECT diag_test_name( 'defs.techdep_clear() - Cleared technology has no reverse dependencies' );
SELECT is_empty( $$
SELECT * FROM defs.technology_dependencies
WHERE technology_name_id_depends = _get_string( 'tech2' );
$$ );
SELECT * FROM finish( );
ROLLBACK;

View file

@ -0,0 +1,13 @@
/*
* Test privileges on defs.techdep_remove()
*/
BEGIN;
SELECT plan( 1 );
SELECT diag_test_name( 'defs.techdep_clear() - EXECUTE privilege' );
SELECT lives_ok( $$
SELECT defs.techdep_clear( '' );
$$ );
SELECT * FROM finish( );
ROLLBACK;

View file

@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8"?>
<lw-tech-graph xmlns="http://www.deepclone.com/lw/b6/m2/tech-graph"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.deepclone.com/lw/b6/m2/tech-graph tech-graph.xsd">
<!-- Military technologies (cruisers, battle cruisers, dreadnoughts) -->
<technology name="cruisersTech" category="milTech"
description="cruisersTechDescription" discovery="cruisersTechDescription"
points="25000" cost="10000" />
<technology name="bCruisersTech" category="milTech"
description="bCruisersTechDescription" discovery="bCruisersTechDescription"
points="900000" cost="400000">
<depends-on>cruisersTech</depends-on>
</technology>
<technology name="dreadnoughtsTech" category="milTech"
description="dreadnoughtsTechDescription" discovery="dreadnoughtsTechDescription"
points="2250000" cost="1012500">
<depends-on>bCruisersTech</depends-on>
</technology>
<!-- Civilian technologies (industrial factories, corpse re-animation, bio-turrets -->
<technology name="indFactTech" category="civTech"
description="indFactTechDescription" discovery="indFactTechDescription"
points="10000" cost="5000" />
<technology name="reanimationTech" category="civTech"
description="reanimationTechDescription" discovery="reanimationTechDescription"
points="562500" cost="281250">
<depends-on>indFactTech</depends-on>
</technology>
<technology name="superTurretTech" category="civTech"
description="superTurretTechDescription" discovery="superTurretTechDescription"
points="1350000" cost="607500">
<depends-on>reanimationTech</depends-on>
</technology>
</lw-tech-graph>

View file

@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns="http://www.deepclone.com/lw/b6/m2/tech-graph"
targetNamespace="http://www.deepclone.com/lw/b6/m2/tech-graph"
xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xs:element name="lw-tech-graph">
<xs:complexType>
<xs:sequence>
<xs:element name="technology" type="technology-description"
minOccurs="1" maxOccurs="unbounded">
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:simpleType name="positive-long">
<xs:restriction base="xs:long">
<xs:minExclusive value="0"></xs:minExclusive>
</xs:restriction>
</xs:simpleType>
<xs:complexType name="technology-description">
<xs:sequence>
<xs:element name="depends-on" type="xs:token" minOccurs="0"
maxOccurs="unbounded" />
</xs:sequence>
<xs:attribute name="name" use="required" type="xs:token" />
<xs:attribute name="category" use="required" type="xs:token" />
<xs:attribute name="description" use="required" type="xs:token" />
<xs:attribute name="discovery" use="required" type="xs:token" />
<xs:attribute name="cost" use="required" type="positive-long" />
<xs:attribute name="points" use="required" type="positive-long" />
</xs:complexType>
</xs:schema>

View file

@ -0,0 +1,326 @@
package com.deepclone.lw.cli;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import org.apache.log4j.Logger;
import org.postgresql.util.PGobject;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import com.deepclone.lw.cli.xmlimport.TechnologyLoader;
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
import com.deepclone.lw.cli.xmlimport.data.techs.Technologies;
import com.deepclone.lw.cli.xmlimport.data.techs.Technology;
import com.deepclone.lw.cli.xmlimport.data.techs.TechnologyDefinitionResult;
import com.deepclone.lw.utils.StoredProc;
/**
* Technology graph import tool
*
* <p>
* This class defines the body of the technology graph import tool. It loads the data file specified
* on the command line, validates it and then loads the technology definitions and dependencies into
* the database.
*
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
*/
public class ImportTechGraph
extends CLITool
{
/** Logging system */
private final Logger logger = Logger.getLogger( ImportTechGraph.class );
/** File to read the definitions from */
private File file;
/** Spring transaction template */
private TransactionTemplate tTemplate;
/** Technology creation or update stored procedure */
private StoredProc fUocTechnology;
/** Stored procedure that removes all dependencies from a technology */
private StoredProc fTechdepClear;
/** Stored procedure that adds a dependency to a technology */
private StoredProc fTechdepAdd;
/**
* Create the Spring context
*
* <p>
* Load the definition of the data source as a Spring context, then adds the transaction
* management component.
*
* @return the Spring application context
*/
private ClassPathXmlApplicationContext createContext( )
{
FileSystemXmlApplicationContext ctx = new FileSystemXmlApplicationContext( new String[] {
this.getDataSource( )
} );
ctx.refresh( );
return new ClassPathXmlApplicationContext( new String[] {
"configuration/transactions.xml"
} , true , ctx );
}
/**
* Create database access templates
*
* <p>
* Initialise the transaction template and the stored procedure wrappers.
*
* @param ctx
* the Spring application context
*/
private void createTemplates( ApplicationContext ctx )
{
DataSource dSource = ctx.getBean( DataSource.class );
PlatformTransactionManager tManager = ctx.getBean( PlatformTransactionManager.class );
this.fUocTechnology = new StoredProc( dSource , "defs" , "uoc_technology" )
.addParameter( "_name" , java.sql.Types.VARCHAR ).addParameter( "_category" , java.sql.Types.VARCHAR )
.addParameter( "_discovery" , java.sql.Types.VARCHAR )
.addParameter( "_description" , java.sql.Types.VARCHAR )
.addParameter( "_price" , java.sql.Types.BIGINT ).addParameter( "_points" , java.sql.Types.BIGINT )
.addOutput( "_result" , java.sql.Types.OTHER );
this.fTechdepClear = new StoredProc( dSource , "defs" , "techdep_clear" ).addParameter( "_tech" ,
java.sql.Types.VARCHAR );
this.fTechdepAdd = new StoredProc( dSource , "defs" , "techdep_add" )
.addParameter( "_dependent" , java.sql.Types.VARCHAR )
.addParameter( "_dependency" , java.sql.Types.VARCHAR ).addOutput( "_result" , java.sql.Types.OTHER );
this.tTemplate = new TransactionTemplate( tManager );
}
/**
* Import all technology definitions
*
* <p>
* Import all technology definitions from the top-level {@link Technologies}, creating a map of
* dependencies. Once all definitions have been imported, add all dependencies.
*
* @param data
* the top level {@link Technologies} data instance
*
* @throws DataImportException
* when some technology definition or dependency cannot be imported
*/
private void importTechnologies( Technologies data )
throws DataImportException
{
Map< String , List< String > > dependencies = new HashMap< String , List< String > >( );
for ( Technology technology : data ) {
this.importTechnologyDefinition( technology );
dependencies.put( technology.getName( ) , technology.getDependencies( ) );
}
for ( Map.Entry< String , List< String > > techDeps : dependencies.entrySet( ) ) {
for ( String dependency : techDeps.getValue( ) ) {
this.importDependency( techDeps.getKey( ) , dependency );
}
}
}
/**
* Import a technology definition
*
* <p>
* Import the definition, and if there was already a definition by that name, clear its
* dependencies.
*
* @param technology
* the definition to import
* @throws DataImportException
* when the update or creation stored procedure returns anything other than
* <code>CREATED</code> or <code>UPDATED</code>
*/
private void importTechnologyDefinition( Technology technology )
throws DataImportException
{
this.logger.info( "Importing technology '" + technology.getName( ) + "'" );
TechnologyDefinitionResult result = this.getResultOf( this.fUocTechnology.execute( technology.getName( ) ,
technology.getCategory( ) , technology.getDiscovery( ) , technology.getDescription( ) ,
technology.getCost( ) , technology.getPoints( ) ) );
if ( result == TechnologyDefinitionResult.UPDATED ) {
this.fTechdepClear.execute( technology.getName( ) );
} else if ( result != TechnologyDefinitionResult.CREATED ) {
throw new DataImportException( "Error while importing technology '" + technology.getName( ) + "': "
+ result );
}
}
/**
* Import a dependency between two technologies
*
* <p>
* Attempt to add a dependency from a technology to another.
*
* @param dependent
* the dependent technology
* @param dependency
* the technology to depend on
*
* @throws DataImportException
* if dependency creation fails
*/
private void importDependency( String dependent , String dependency )
throws DataImportException
{
this.logger.info( "Importing dependency from " + dependent + " to " + dependency );
TechnologyDefinitionResult result = this.getResultOf( this.fTechdepAdd.execute( dependent , dependency ) );
switch ( result ) {
case CREATED:
return;
case REDUNDANT:
throw new DataImportException( "( " + dependent + " -> " + dependency + " ) is redundant" );
case BAD_STRINGS:
throw new DataImportException( "( " + dependent + " -> " + dependency + " ): undefined technology" );
case CYCLE:
throw new DataImportException( "( " + dependent + " -> " + dependency + " ) would create a cycle" );
default:
throw new DataImportException( "( " + dependent + " -> " + dependency + " ): unexpected error code "
+ result );
}
}
/**
* Helper method for stored procedure results
*
* <p>
* This method converts the map returned by one of the definition stored procedures into a
* {@link TechnologyDefinitionResult} value.
*
* @param spResult
* the return value of {@link StoredProc#execute(Object...)}
*
* @return the converted value of the _result field
*/
private TechnologyDefinitionResult getResultOf( Map< String , Object > spResult )
{
return TechnologyDefinitionResult.valueOf( ( (PGobject) spResult.get( "_result" ) ).getValue( ) );
}
/**
* Run the technology definitions import tool
*
* <p>
* Loads the data file, the connects to the database and creates or updates all definitions.
*/
@Override
public void run( )
{
Technologies data;
try {
data = new TechnologyLoader( this.file ).load( );
} catch ( DataImportException e ) {
this.logger.error( "Error while loading technology definitions" , e );
return;
}
AbstractApplicationContext ctx = this.createContext( );
this.createTemplates( ctx );
this.executeImportTransaction( data );
ToolBase.destroyContext( ctx );
}
/**
* Execute the technology definitions importation transaction
*
* <p>
* Run a transaction and execute the importation code inside it. Roll back if anything goes
* wrong.
*
* @param data
* the {@link Technologies} definitions instance
*/
private void executeImportTransaction( final Technologies data )
{
boolean rv = this.tTemplate.execute( new TransactionCallback< Boolean >( ) {
@Override
public Boolean doInTransaction( TransactionStatus status )
{
boolean rv = ImportTechGraph.this.doTransaction( data );
if ( !rv ) {
status.setRollbackOnly( );
}
return rv;
}
} );
if ( rv ) {
this.logger.info( "Technology import successful" );
}
}
/**
* Import transaction body
*
* <p>
* Import all definitions and handle exceptions.
*
* @param data
* the {@link Technologies} definitions instance
* @return
*/
private boolean doTransaction( Technologies data )
{
try {
this.importTechnologies( data );
return true;
} catch ( RuntimeException e ) {
this.logger.error( "Caught runtime exception" , e );
} catch ( DataImportException e ) {
this.logger.error( e.getMessage( ) );
}
return false;
}
/**
* Obtain the name of the definitions file
*
* <p>
* Check the command line options, setting the definitions file accordingly.
*/
@Override
public boolean setOptions( String... options )
{
if ( options.length != 1 ) {
return false;
}
this.file = new File( options[ 0 ] );
if ( ! ( this.file.isFile( ) && this.file.canRead( ) ) ) {
return false;
}
return true;
}
}

View file

@ -0,0 +1,116 @@
package com.deepclone.lw.cli.xmlimport;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
import com.deepclone.lw.cli.xmlimport.data.techs.Technologies;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.XStreamException;
/**
* Technology Loader
*
* <p>
* This class can be used to load all technology definitions. It extracts them from the XML file and
* verifies them.
*
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
*/
public class TechnologyLoader
{
/** The file to read the XML from */
private final File file;
/**
* Initialise the loader
*
* @param file
* the XML file that contains the definitions
*/
public TechnologyLoader( File file )
{
this.file = file.getAbsoluteFile( );
}
/**
* Initialise the necessary XStream instance
*
* <p>
* Initialise the XStream instance by processing the annotations of all the technology
* importable data classes.
*
* @return the XStream instance to use when loading the data
*/
private XStream initXStream( )
{
XStream xstream = new XStream( );
xstream.processAnnotations( Technologies.class );
return xstream;
}
/**
* Load the technology definitions
*
* <p>
* Load the XML file and process the definitions using XStream.
*
* @return the top-level importable data instance
*
* @throws DataImportException
* if reading from the file or parsing its contents fail
*/
private Technologies loadXMLFile( )
throws DataImportException
{
FileInputStream fis;
try {
fis = new FileInputStream( this.file );
} catch ( FileNotFoundException e ) {
throw new DataImportException( "Unable to load technology definitions" , e );
}
try {
try {
XStream xstream = this.initXStream( );
return (Technologies) xstream.fromXML( fis );
} finally {
fis.close( );
}
} catch ( IOException e ) {
throw new DataImportException( "Input error while loading technology definitions" , e );
} catch ( XStreamException e ) {
throw new DataImportException( "XML error while loading technology definitions" , e );
}
}
/**
* Load and process technology definitions
*
* <p>
* Attempt to load all technology definitions, ensure they are valid, then set the original
* file's path.
*
* @return the top-level importable data instance
*
* @throws DataImportException
* if loading or verifying the data fails
*/
public Technologies load( )
throws DataImportException
{
Technologies techs = this.loadXMLFile( );
techs.verifyData( );
techs.setReadFrom( this.file );
return techs;
}
}

View file

@ -64,9 +64,9 @@ public class BasicResource
throw new DataImportException( "Missing name string" );
}
if ( this.description == null || "".equals( this.description.trim( ) ) ) {
throw new DataImportException( "Missing name string" );
throw new DataImportException( "Missing description string" );
}
if ( this.category != null && "".equals( this.description.trim( ) ) ) {
if ( this.category != null && "".equals( this.category.trim( ) ) ) {
throw new DataImportException( "Category invalid" );
}
if ( this.weight == null ) {

View file

@ -0,0 +1,98 @@
package com.deepclone.lw.cli.xmlimport.data.techs;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
import com.deepclone.lw.cli.xmlimport.data.ImportableData;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
/**
* Technology definitions data
*
* <p>
* This class represents the contents of a technology definition XML file. It contains a list of
* technology definitions.
*
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
*/
@SuppressWarnings( "serial" )
@XStreamAlias( "lw-tech-graph" )
public class Technologies
extends ImportableData
implements Iterable< Technology >
{
/** All present technology definitions */
@XStreamImplicit( itemFieldName = "technology" )
private final List< Technology > technologies = new LinkedList< Technology >( );
/**
* Check the technology data
*
* <p>
* Check whether there is a list of technologies, then check each definition to make sure that
* it is valid and that its name is unique.
*/
@Override
public void verifyData( )
throws DataImportException
{
if ( this.technologies == null ) {
throw new DataImportException( "No technology definitions" );
}
HashSet< String > names = new HashSet< String >( );
for ( Technology tech : this.technologies ) {
tech.verifyData( );
this.checkUniqueItem( names , tech.getName( ) );
}
}
/**
* Checks that the name of a technology is unique
*
* <p>
* This helper method is used by {@link #verifyData()} to make sure technology names are unique.
*
* @param existing
* the existing set of names
* @param value
* the name to check
*
* @throws DataImportException
* if the name is already present in the set of existing names
*/
public void checkUniqueItem( HashSet< String > existing , String value )
throws DataImportException
{
if ( existing.contains( value ) ) {
throw new DataImportException( "Duplicate technology name '" + value + "'" );
}
existing.add( value );
}
/**
* Technology definition iterator
*
* <p>
* Grant access to the list of technologies in read-only mode.
*
* @return a read-only iterator on the list of technologies.
*/
@Override
public Iterator< Technology > iterator( )
{
return Collections.unmodifiableList( this.technologies ).iterator( );
}
}

View file

@ -0,0 +1,183 @@
package com.deepclone.lw.cli.xmlimport.data.techs;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
import com.deepclone.lw.cli.xmlimport.data.ImportableData;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamImplicit;
/**
* A technology definition
*
* <p>
* This class represents a technology definition that can be imported from the data file. It
* contains all required technology attributes, as well as a list of strings for the dependencies.
*
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
*/
@SuppressWarnings( "serial" )
public class Technology
extends ImportableData
{
/** Identifier of the name string */
@XStreamAsAttribute
private String name;
/** Identifier of the category string */
@XStreamAsAttribute
private String category;
/** Identifier of the description string */
@XStreamAsAttribute
private String description;
/** Identifier of the string to display on technology discovery */
@XStreamAsAttribute
private String discovery;
/** Monetary cost of the technology */
@XStreamAsAttribute
private Long cost;
/** Required amount of research points */
@XStreamAsAttribute
private Long points;
/** List of technology name string identifiers describing the dependencies */
@XStreamImplicit( itemFieldName = "depends-on" )
private final List< String > dependencies = new LinkedList< String >( );
/**
* Technology definition verifier
*
* <p>
* Make sure that all technology definition fields are both present and valid. If dependencies
* exist, also verify the names' validity.
*/
@Override
public void verifyData( )
throws DataImportException
{
if ( this.name == null || "".equals( this.name.trim( ) ) ) {
throw new DataImportException( "Missing name string" );
}
if ( this.category == null || "".equals( this.category.trim( ) ) ) {
throw new DataImportException( "Missing category string in " + this.name );
}
if ( this.description == null || "".equals( this.description.trim( ) ) ) {
throw new DataImportException( "Missing description string in " + this.name );
}
if ( this.discovery == null || "".equals( this.discovery.trim( ) ) ) {
throw new DataImportException( "Missing discovery string in " + this.name );
}
if ( this.points == null ) {
throw new DataImportException( "Missing research points in " + this.name );
} else if ( this.points <= 0 ) {
throw new DataImportException( "Invalid research points in " + this.name );
}
if ( this.cost == null ) {
throw new DataImportException( "Missing cost in " + this.name );
} else if ( this.cost <= 0 ) {
throw new DataImportException( "Invalid cost in " + this.name );
}
if ( this.dependencies != null ) {
for ( String dep : this.dependencies ) {
if ( dep == null || "".equals( dep.trim( ) ) ) {
throw new DataImportException( "Empty dependency name in " + this.name );
}
}
}
}
/**
* Gets the identifier of the name string.
*
* @return the identifier of the name string
*/
public String getName( )
{
return this.name;
}
/**
* Gets the identifier of the category string.
*
* @return the identifier of the category string
*/
public String getCategory( )
{
return this.category;
}
/**
* Gets the identifier of the description string.
*
* @return the identifier of the description string
*/
public String getDescription( )
{
return this.description;
}
/**
* Gets the identifier of the string to display on technology discovery.
*
* @return the identifier of the string to display on technology discovery
*/
public String getDiscovery( )
{
return this.discovery;
}
/**
* Gets the monetary cost of the technology.
*
* @return the monetary cost of the technology
*/
public Long getCost( )
{
return this.cost;
}
/**
* Gets the required amount of research points.
*
* @return the required amount of research points
*/
public Long getPoints( )
{
return this.points;
}
/**
* Gets the list of technology name string identifiers describing the dependencies.
*
* @return the list of technology name string identifiers describing the dependencies
*/
public List< String > getDependencies( )
{
if ( this.dependencies == null ) {
return Collections.emptyList( );
}
return Collections.unmodifiableList( this.dependencies );
}
}

View file

@ -0,0 +1,47 @@
package com.deepclone.lw.cli.xmlimport.data.techs;
/**
* Return codes for technology definition manipulation stored procedures
*
* <p>
* This enumeration represents the various values which can be returned by the stored procedures
* which manipulate technology definitions and technology dependencies.
*
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
*/
public enum TechnologyDefinitionResult {
/** The technology definition or dependency was created */
CREATED ,
/** The technology definition was updated */
UPDATED ,
/** The dependency was deleted */
DELETED ,
/** The specified dependency does not exist */
MISSING ,
/** One (or more) of the numeric parameters is invalid */
BAD_VALUE ,
/**
* The name, description, discovery or category string identifiers were not valid string
* identifiers.
*/
BAD_STRINGS ,
/**
* The specified description and/or discovery string was in use by another technology.
*/
DUP_STRING ,
/** The dependency would cause a cycle */
CYCLE ,
/** The dependency would be redundant */
REDUNDANT
}

View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<lw-tech-graph>
<does-not-exist />
</lw-tech-graph>

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<lw-tech-graph xmlns="http://www.deepclone.com/lw/b6/m2/tech-graph"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.deepclone.com/lw/b6/m2/tech-graph tech-graph.xsd">
<technology />
</lw-tech-graph>

View file

@ -0,0 +1,2 @@
This is not an XML file, obviously.
We'll make that even more confusing: <<<<<< & >>!!!

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<lw-tech-graph xmlns="http://www.deepclone.com/lw/b6/m2/tech-graph"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.deepclone.com/lw/b6/m2/tech-graph tech-graph.xsd">
<technology name="test" category="test" discovery="test"
description="test" cost="12" points="34" />
</lw-tech-graph>

View file

@ -1,7 +1,11 @@
package com.deepclone.lw.cli.xmlimport;
import static org.junit.Assert.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
@ -11,7 +15,6 @@ import org.junit.Test;
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
import com.deepclone.lw.cli.xmlimport.data.i18n.I18NText;
import com.deepclone.lw.cli.xmlimport.data.i18n.LanguageDefinition;
import com.deepclone.lw.cli.xmlimport.data.i18n.StringDefinition;
import com.thoughtworks.xstream.converters.ConversionException;
import com.thoughtworks.xstream.io.StreamException;
@ -129,22 +132,8 @@ public class TestI18NLoader
assertNotNull( text );
int lCount = 0;
for ( LanguageDefinition ld : text ) {
assertEquals( "test" , ld.getId( ) );
assertEquals( "test" , ld.getName( ) );
int tCount = 0;
for ( StringDefinition sd : ld ) {
assertEquals( "test" , sd.getId( ) );
try {
assertEquals( "test" , sd.getString( ).trim( ) );
} catch ( DataImportException e ) {
fail( "could not load string: " + e.getMessage( ) );
}
tCount++;
}
assertEquals( 1 , tCount );
for ( @SuppressWarnings( "unused" )
LanguageDefinition ld : text ) {
lCount++;
}
assertEquals( 1 , lCount );

View file

@ -14,7 +14,6 @@ import org.junit.Test;
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
import com.deepclone.lw.cli.xmlimport.data.resources.BasicResource;
import com.deepclone.lw.cli.xmlimport.data.resources.NaturalResource;
import com.deepclone.lw.cli.xmlimport.data.resources.Resources;
import com.thoughtworks.xstream.converters.ConversionException;
import com.thoughtworks.xstream.io.StreamException;
@ -127,27 +126,8 @@ public class TestResourceLoader
// Not sure if this is the best way to code for the two different resource types...
int rCount = 0;
for ( BasicResource br : resources ) {
if ( rCount == 0 ) {
assertEquals( "money" , br.getName( ) );
assertEquals( "moneyDescription" , br.getDescription( ) );
assertEquals( new Integer( 0 ) , br.getWeight( ) );
assertEquals( null , br.getCategory( ) );
} else if ( rCount == 1 ) {
// This isn't retarded is it?
NaturalResource nr = (NaturalResource) br;
assertEquals( "titanium" , nr.getName( ) );
assertEquals( "titaniumDescription" , nr.getDescription( ) );
assertEquals( new Integer( 1 ) , nr.getWeight( ) );
assertEquals( "minerals" , nr.getCategory( ) );
assertEquals( new Double( 0.8 ) , nr.getPresenceProbability( ) );
assertEquals( new Double( 5000 ) , nr.getQuantity( ).getAverage( ) );
assertEquals( new Double( 1500 ) , nr.getQuantity( ).getDeviation( ) );
assertEquals( new Double( 0.1 ) , nr.getDifficulty( ).getAverage( ) );
assertEquals( new Double( 0.05 ) , nr.getDifficulty( ).getDeviation( ) );
assertEquals( new Double( 0.4 ) , nr.getRecovery( ).getAverage( ) );
assertEquals( new Double( 0.05 ) , nr.getRecovery( ).getDeviation( ) );
}
for ( @SuppressWarnings( "unused" )
BasicResource br : resources ) {
rCount++;
}
assertEquals( 2 , rCount );

View file

@ -0,0 +1,132 @@
package com.deepclone.lw.cli.xmlimport;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
import org.junit.Test;
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
import com.deepclone.lw.cli.xmlimport.data.techs.Technologies;
import com.deepclone.lw.cli.xmlimport.data.techs.Technology;
import com.thoughtworks.xstream.converters.ConversionException;
import com.thoughtworks.xstream.io.StreamException;
/**
* Unit tests for the {@link TechnologyLoader} class.
*
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
*/
public class TestTechnologyLoader
{
/**
* Try initialising the loader with a <code>null</code> file instance.
*
* @throws NullPointerException
* when the constructor is executed
*/
@Test( expected = NullPointerException.class )
public void testNullFile( )
throws NullPointerException
{
new TechnologyLoader( null );
}
/** Try loading a file that does not exist */
@Test
public void testMissingFile( )
{
TechnologyLoader loader = new TechnologyLoader( new File( "does-not-exist" ) );
try {
loader.load( );
} catch ( DataImportException e ) {
assertTrue( "cause is a" + e.getCause( ).getClass( ).getName( ) , e.getCause( ) instanceof IOException );
return;
}
fail( "no exception after trying to load a missing file" );
}
/** Try loading a file that contains something that is not XML. */
@Test
public void testBadXML( )
{
TechnologyLoader loader = new TechnologyLoader( new File( "TestFiles/technology-loader/bad-xml.xml" ) );
try {
loader.load( );
} catch ( DataImportException e ) {
assertTrue( "cause is a " + e.getCause( ).getClass( ).getName( ) , e.getCause( ) instanceof StreamException );
return;
}
fail( "no exception after loading stuff that isn't XML" );
}
/**
* Test loading a file that contains XML but which cannot be deserialised to a
* {@link Technologies} instance.
*/
@Test
public void testBadContents( )
{
TechnologyLoader loader = new TechnologyLoader( new File( "TestFiles/technology-loader/bad-contents.xml" ) );
try {
loader.load( );
} catch ( DataImportException e ) {
assertTrue( "cause is a " + e.getCause( ).getClass( ).getName( ) ,
e.getCause( ) instanceof ConversionException );
return;
}
fail( "no exception after loading bad XML" );
}
/**
* Try loading a file that contains valid XML for a {@link Technologies} instance with semantic
* errors.
*/
@Test
public void testBadData( )
{
TechnologyLoader loader = new TechnologyLoader( new File( "TestFiles/technology-loader/bad-data.xml" ) );
try {
loader.load( );
} catch ( DataImportException e ) {
assertNull( e.getCause( ) );
return;
}
fail( "no exception after loading bad data" );
}
/** Try loading valid data, make sure that it contains one record */
@Test
public void testGoodData( )
{
TechnologyLoader loader = new TechnologyLoader( new File( "TestFiles/technology-loader/good-data.xml" ) );
Technologies technologies;
try {
technologies = loader.load( );
} catch ( DataImportException e ) {
fail( "could not load valid file" );
return;
}
assertNotNull( technologies );
int rCount = 0;
for ( @SuppressWarnings( "unused" )
Technology tech : technologies ) {
rCount++;
}
assertEquals( 1 , rCount );
}
}

View file

@ -22,7 +22,7 @@ import com.thoughtworks.xstream.XStreamException;
*
*/
abstract public class BaseTest
abstract class BaseTest
{
/**
* Escape &amp;, &lt; and &gt; in XML strings

View file

@ -0,0 +1,175 @@
package com.deepclone.lw.cli.xmlimport.data.techs;
import com.deepclone.lw.cli.xmlimport.data.ImportableData;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.XStreamException;
/**
* Base class for testing technology importation
*
* <p>
* This class is used as a parent for tests of the technology import structures. It includes the
* code used to actually create these technology definitions, as this can normally only be done
* through XStream.
*
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
*
*/
abstract class BaseTest
{
/**
* Escape &amp;, &lt; and &gt; in XML strings
*
* @param string
* the string to escape
*
* @return the escaped string
*/
private String xmlString( String string )
{
return string.replace( "&" , "&amp;" ).replace( "<" , "&lt;" ).replace( ">" , "&gt;" );
}
/**
* Escape &amp;, &lt; and &gt;, ' and " in XML strings
*
* @param string
* the string to escape
*
* @return the escaped string
*/
private String quoteString( String string )
{
return "\"" + this.xmlString( string ).replace( "\"" , "&quot;" ).replace( "'" , "&apos;" ) + "\"";
}
/**
* Create the XML code for a technology definition
*
* <p>
* This method generates the XML code for a technology definition, which can then be imported
* using XStream into a {@link Technology} instance. It is capable of generating instances with
* various fields set to <code>null</code>.
*
* @param name
* identifier of the technology's name string
* @param category
* identifier of the technology's category string
* @param discovery
* identifier of the technology's discovery string
* @param description
* identifier of the technology's description string
* @param cost
* monetary cost of implementing the technology
* @param points
* amount of research points required
* @param dependencies
* dependencies as an array of strings
* @return
*/
protected String createTechnology( String name , String category , String discovery , String description ,
Long cost , Long points , String... dependencies )
{
StringBuilder builder = new StringBuilder( "<technology" );
if ( name != null ) {
builder.append( " name=" ).append( this.quoteString( name ) );
}
if ( category != null ) {
builder.append( " category=" ).append( this.quoteString( category ) );
}
if ( discovery != null ) {
builder.append( " discovery=" ).append( this.quoteString( discovery ) );
}
if ( description != null ) {
builder.append( " description=" ).append( this.quoteString( description ) );
}
if ( cost != null ) {
builder.append( " cost=\"" ).append( cost ).append( "\"" );
}
if ( points != null ) {
builder.append( " points=\"" ).append( points ).append( "\"" );
}
if ( dependencies.length == 0 ) {
builder.append( " />" );
} else {
builder.append( ">" );
for ( String dep : dependencies ) {
builder.append( "<depends-on>" );
if ( dep != null ) {
builder.append( this.xmlString( dep ) );
}
builder.append( "</depends-on>" );
}
builder.append( "</technology>" );
}
return builder.toString( );
}
/**
* Creates the XML code for a top-level technology definition element
*
* @param resources
* XML definitions of technologies
*
* @return the top-level element's XML code
*/
protected String createTopLevel( String... technologies )
{
StringBuilder str = new StringBuilder( );
str.append( "<lw-tech-graph>" );
for ( String technology : technologies ) {
str.append( technology );
}
str.append( "</lw-tech-graph>" );
return str.toString( );
}
/**
* Create the necessary XStream instance
*
* <p>
* Initialise an XStream instance and set it up so it can process technology data definitions.
* This includes annotation processing, of course, but also generating an alias allowing the
* &lt;technology&gt; tag to be recognised on its own.
*/
private XStream createXStreamInstance( )
{
XStream xstream = new XStream( );
xstream.processAnnotations( Technologies.class );
xstream.alias( "technology" , Technology.class );
return xstream;
}
/**
* Create a resource object from its XML code
*
* @param xml
* the XML code
* @param cls
* the class of the object
*
* @return the object that was created from the code
*
* @throws ClassCastException
* if the code corresponds to some other type of object
* @throws XStreamException
* if some error occurred while deserialising the object
*/
protected < T extends ImportableData > T createObject( String xml , Class< T > cls )
throws ClassCastException , XStreamException
{
return cls.cast( this.createXStreamInstance( ).fromXML( xml ) );
}
}

View file

@ -0,0 +1,96 @@
package com.deepclone.lw.cli.xmlimport.data.techs;
import static org.junit.Assert.*;
import org.junit.Test;
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
/**
* Unit tests for the {@link Technologies} class
*
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
*/
public class TestTechnologies
extends BaseTest
{
/**
* Test loading an empty list of technologies
*
* <p>
* {@link Technologies#iterator()} will throw {@link NullPointerException} when there are no
* definitions. Use that to determine if it is empty.
*/
@Test( expected = NullPointerException.class )
public void testEmpty( )
{
String defs = this.createTopLevel( );
Technologies techs = this.createObject( defs , Technologies.class );
techs.iterator( );
}
/**
* Test loading a list of technologies
*/
@Test
public void testTechs( )
{
String tDef = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L );
String defs = this.createTopLevel( tDef );
Technologies techs = this.createObject( defs , Technologies.class );
int i = 0;
for ( Technology technology : techs ) {
assertNotNull( technology );
assertEquals( 0 , i );
i++;
}
}
/**
* Test verifying an empty list of technologies
*/
@Test( expected = DataImportException.class )
public void testVerifyEmpty( )
throws DataImportException
{
String defs = this.createTopLevel( );
Technologies techs = this.createObject( defs , Technologies.class );
techs.verifyData( );
}
/**
* Test verifying a list of technologies with an invalid technology in it
*/
@Test( expected = DataImportException.class )
public void testVerifyInvalid( )
throws DataImportException
{
String tDef = this.createTechnology( null , "category" , "discovery" , "description" , 12L , 34L );
String defs = this.createTopLevel( tDef );
Technologies techs = this.createObject( defs , Technologies.class );
techs.verifyData( );
}
/**
* Test verifying a valid list of technologies
*/
@Test
public void testVerifyOk( )
throws DataImportException
{
String tDef = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L );
String defs = this.createTopLevel( tDef );
Technologies techs = this.createObject( defs , Technologies.class );
techs.verifyData( );
}
}

View file

@ -0,0 +1,329 @@
package com.deepclone.lw.cli.xmlimport.data.techs;
import static org.junit.Assert.*;
import org.junit.Test;
import com.deepclone.lw.cli.xmlimport.data.DataImportException;
/**
* Test the {@link Technology} class
*
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
*/
public class TestTechnology
extends BaseTest
{
/**
* Test loading a definition with no dependencies
*/
@Test
public void testLoadNoDeps( )
{
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L );
Technology technology = this.createObject( definition , Technology.class );
assertNotNull( technology );
assertEquals( "name" , technology.getName( ) );
assertEquals( "category" , technology.getCategory( ) );
assertEquals( "discovery" , technology.getDiscovery( ) );
assertEquals( "description" , technology.getDescription( ) );
assertEquals( new Long( 12 ) , technology.getCost( ) );
assertEquals( new Long( 34 ) , technology.getPoints( ) );
assertNotNull( technology.getDependencies( ) );
assertTrue( technology.getDependencies( ).isEmpty( ) );
}
/**
* Test loading a definition with dependencies
*/
@Test
public void testLoadDeps( )
{
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L ,
"dep1" , "dep2" );
Technology technology = this.createObject( definition , Technology.class );
assertNotNull( technology );
assertEquals( "name" , technology.getName( ) );
assertEquals( "category" , technology.getCategory( ) );
assertEquals( "discovery" , technology.getDiscovery( ) );
assertEquals( "description" , technology.getDescription( ) );
assertEquals( new Long( 12 ) , technology.getCost( ) );
assertEquals( new Long( 34 ) , technology.getPoints( ) );
assertNotNull( technology.getDependencies( ) );
assertEquals( 2 , technology.getDependencies( ).size( ) );
assertEquals( "dep1" , technology.getDependencies( ).get( 0 ) );
assertEquals( "dep2" , technology.getDependencies( ).get( 1 ) );
}
/**
* Test {@link Technology#verifyData()} when the name is null
*/
@Test( expected = DataImportException.class )
public void testVerifyNameNull( )
throws DataImportException
{
String definition = this.createTechnology( null , "category" , "discovery" , "description" , 12L , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the name is empty
*/
@Test( expected = DataImportException.class )
public void testVerifyNameEmpty( )
throws DataImportException
{
String definition = this.createTechnology( "" , "category" , "discovery" , "description" , 12L , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the name consists of spaces only
*/
@Test( expected = DataImportException.class )
public void testVerifyNameSpaces( )
throws DataImportException
{
String definition = this.createTechnology( " " , "category" , "discovery" , "description" , 12L , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the category is null
*/
@Test( expected = DataImportException.class )
public void testVerifyCategoryNull( )
throws DataImportException
{
String definition = this.createTechnology( "name" , null , "discovery" , "description" , 12L , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the category is empty
*/
@Test( expected = DataImportException.class )
public void testVerifyCategoryEmpty( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "" , "discovery" , "description" , 12L , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the category consists of spaces only
*/
@Test( expected = DataImportException.class )
public void testVerifyCategorySpaces( )
throws DataImportException
{
String definition = this.createTechnology( "name" , " " , "discovery" , "description" , 12L , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the discovery string is null
*/
@Test( expected = DataImportException.class )
public void testVerifyDiscoveryNull( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "category" , null , "description" , 12L , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the discovery string is empty
*/
@Test( expected = DataImportException.class )
public void testVerifyDiscoveryEmpty( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "category" , "" , "description" , 12L , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the discovery string consists of spaces only
*/
@Test( expected = DataImportException.class )
public void testVerifyDiscoverySpaces( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "category" , " " , "description" , 12L , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the description is null
*/
@Test( expected = DataImportException.class )
public void testVerifyDescriptionNull( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "category" , "discovery" , null , 12L , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the description is empty
*/
@Test( expected = DataImportException.class )
public void testVerifyDescriptionEmpty( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "category" , "discovery" , "" , 12L , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the description consists of spaces only
*/
@Test( expected = DataImportException.class )
public void testVerifyDescriptionSpaces( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "category" , "discovery" , " " , 12L , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the cost is null
*/
@Test( expected = DataImportException.class )
public void testVerifyCostNull( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , null , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the cost is 0
*/
@Test( expected = DataImportException.class )
public void testVerifyCostZero( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 0L , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the amount of points is null
*/
@Test( expected = DataImportException.class )
public void testVerifyPointsNull( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , null );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when the amount of points is 0
*/
@Test( expected = DataImportException.class )
public void testVerifyPointsZero( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 0L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} on a valid definition with no dependencies
*/
@Test
public void testVerifyValidNoDeps( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when a dependency is empty
*/
@Test( expected = DataImportException.class )
public void testVerifyDepsEmpty( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L , "" );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} when a dependency consists of spaces only
*/
@Test( expected = DataImportException.class )
public void testVerifyDepsSpaces( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L ,
" " );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
/**
* Test {@link Technology#verifyData()} on a valid definition with dependencies
*/
@Test
public void testVerifyValidDeps( )
throws DataImportException
{
String definition = this.createTechnology( "name" , "category" , "discovery" , "description" , 12L , 34L ,
"dep1" , "dep2" );
Technology technology = this.createObject( definition , Technology.class );
technology.verifyData( );
}
}

View file

@ -41,6 +41,8 @@ from the root of the server's distribution:
--run-tool ImportText data/i18n-text.xml
java -jar legacyworlds-server-main-1.0.0-0.jar \
--run-tool ImportTechs data/techs.xml
java -jar legacyworlds-server-main-1.0.0-0.jar \
--run-tool ImportTechGraph data/tech-graph.xml
java -jar legacyworlds-server-main-1.0.0-0.jar \
--run-tool ImportResources data/resources.xml
java -jar legacyworlds-server-main-1.0.0-0.jar \