Javadocs and unit tests.

This commit is contained in:
akwizgran
2011-07-01 12:07:00 +01:00
parent b29a024c2a
commit 0ed2a7c9e7
23 changed files with 235 additions and 59 deletions

View File

@@ -1,6 +1,6 @@
package net.sf.briar.api.db; package net.sf.briar.api.db;
/** Uniquely identifies a contact. */ /** Type-safe wrapper for an integer that uniquely identifies a contact. */
public class ContactId { public class ContactId {
private final int id; private final int id;

View File

@@ -35,7 +35,10 @@ public interface DatabaseComponent {
/** Adds a locally generated message to the database. */ /** Adds a locally generated message to the database. */
void addLocallyGeneratedMessage(Message m) throws DbException; void addLocallyGeneratedMessage(Message m) throws DbException;
/** Generates a bundle of messages for the given contact. */ /**
* Generates a bundle of acknowledgements, subscriptions, and batches of
* messages for the given contact.
*/
void generateBundle(ContactId c, Bundle b) throws DbException; void generateBundle(ContactId c, Bundle b) throws DbException;
/** Returns the user's rating for the given author. */ /** Returns the user's rating for the given author. */
@@ -45,8 +48,9 @@ public interface DatabaseComponent {
Set<GroupId> getSubscriptions() throws DbException; Set<GroupId> getSubscriptions() throws DbException;
/** /**
* Processes a bundle of messages received from the given contact. Some * Processes a bundle of acknowledgements, subscriptions, and batches of
* or all of the messages in the bundle may be stored. * messages received from the given contact. Some or all of the messages
* in the bundle may be stored.
*/ */
void receiveBundle(ContactId c, Bundle b) throws DbException; void receiveBundle(ContactId c, Bundle b) throws DbException;

View File

@@ -1,13 +1,12 @@
package net.sf.briar.api.i18n; package net.sf.briar.api.i18n;
import java.awt.Font; import java.awt.Font;
import java.io.IOException;
import java.util.Locale; import java.util.Locale;
public interface FontManager { public interface FontManager {
/** Initializes the FontManager for the given locale. */ /** Initializes the FontManager for the given locale. */
void initialize(Locale locale) throws IOException; void initialize(Locale locale);
/** Returns the appropriate font for the given language. */ /** Returns the appropriate font for the given language. */
Font getFontForLanguage(String language); Font getFontForLanguage(String language);

View File

@@ -2,7 +2,7 @@ package net.sf.briar.api.protocol;
import java.util.Arrays; import java.util.Arrays;
/** Uniquely identifies a pseudonymous author. */ /** Type-safe wrapper for a byte array that uniquely identifies an author. */
public class AuthorId { public class AuthorId {
public static final int LENGTH = 32; public static final int LENGTH = 32;

View File

@@ -2,7 +2,10 @@ package net.sf.briar.api.protocol;
import java.util.Arrays; import java.util.Arrays;
/** Uniquely identifies a batch of messages. */ /**
* Type-safe wrapper for a byte array that uniquely identifies a batch of
* messages.
*/
public class BatchId { public class BatchId {
public static final int LENGTH = 32; public static final int LENGTH = 32;

View File

@@ -2,6 +2,10 @@ package net.sf.briar.api.protocol;
import java.util.Arrays; import java.util.Arrays;
/**
* Type-safe wrapper for a byte array that uniquely identifies a bundle of
* acknowledgements, subscriptions, and batches of messages.
*/
public class BundleId { public class BundleId {
public static final BundleId NONE = new BundleId(new byte[] { public static final BundleId NONE = new BundleId(new byte[] {

View File

@@ -2,7 +2,10 @@ package net.sf.briar.api.protocol;
import java.util.Arrays; import java.util.Arrays;
/** Uniquely identifies a group to which a user may subscribe. */ /**
* Type-safe wrapper for a byte array that uniquely identifies a group to which
* users may subscribe.
*/
public class GroupId { public class GroupId {
public static final int LENGTH = 32; public static final int LENGTH = 32;

View File

@@ -2,7 +2,7 @@ package net.sf.briar.api.protocol;
import java.util.Arrays; import java.util.Arrays;
/** Uniquely identifies a message. */ /** Type-safe wrapper for a byte array that uniquely identifies a message. */
public class MessageId { public class MessageId {
/** Used to indicate that the first message in a thread has no parent. */ /** Used to indicate that the first message in a thread has no parent. */

View File

@@ -15,6 +15,10 @@ import net.sf.briar.api.protocol.MessageId;
import com.google.inject.Provider; import com.google.inject.Provider;
/**
* Abstract superclass containing code shared by ReadWriteLockDatabaseComponent
* and SynchronizedDatabaseComponent.
*/
abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent { abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
private static final Logger LOG = private static final Logger LOG =
@@ -35,9 +39,17 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
startCleaner(); startCleaner();
} }
/**
* Removes the oldest messages from the database, with a total size less
* than or equal to the given size.
*/
protected abstract void expireMessages(long size) throws DbException; protected abstract void expireMessages(long size) throws DbException;
// Locking: messages write /**
* Calculates and returns the sendability score of a message.
* <p>
* Locking: messages write.
*/
private int calculateSendability(Txn txn, Message m) throws DbException { private int calculateSendability(Txn txn, Message m) throws DbException {
int sendability = 0; int sendability = 0;
// One point for a good rating // One point for a good rating
@@ -51,6 +63,12 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
return sendability; return sendability;
} }
/**
* Checks how much free storage space is available to the database, and if
* necessary expires old messages until the free space is at least
* MIN_FREE_SPACE. While the free space is less than CRITICAL_FREE_SPACE,
* operations that attempt to store messages in the database will block.
*/
private void checkFreeSpaceAndClean() throws DbException { private void checkFreeSpaceAndClean() throws DbException {
long freeSpace = db.getFreeSpace(); long freeSpace = db.getFreeSpace();
while(freeSpace < MIN_FREE_SPACE) { while(freeSpace < MIN_FREE_SPACE) {
@@ -74,7 +92,11 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
} }
} }
// Locking: contacts read /**
* Returns true iff the database contains the given contact.
* <p>
* Locking: contacts read.
*/
protected boolean containsContact(ContactId c) throws DbException { protected boolean containsContact(ContactId c) throws DbException {
Txn txn = db.startTransaction(); Txn txn = db.startTransaction();
try { try {
@@ -87,14 +109,24 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
} }
} }
// Locking: contacts read, messages write, messageStatuses write /**
* Removes the given message (and all associated state) from the database.
* <p>
* Locking: contacts read, messages write, messageStatuses write.
*/
protected void removeMessage(Txn txn, MessageId id) throws DbException { protected void removeMessage(Txn txn, MessageId id) throws DbException {
Integer sendability = db.getSendability(txn, id); Integer sendability = db.getSendability(txn, id);
assert sendability != null; assert sendability != null;
// If the message is sendable, deleting it may affect its ancestors'
// sendability (backward inclusion)
if(sendability > 0) updateAncestorSendability(txn, id, false); if(sendability > 0) updateAncestorSendability(txn, id, false);
db.removeMessage(txn, id); db.removeMessage(txn, id);
} }
/**
* Returns true iff the amount of free storage space available to the
* database should be checked.
*/
private boolean shouldCheckFreeSpace() { private boolean shouldCheckFreeSpace() {
synchronized(spaceLock) { synchronized(spaceLock) {
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
@@ -117,6 +149,12 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
return false; return false;
} }
/**
* Starts a new thread to monitor the amount of free storage space
* available to the database and expire old messages as necessary.
* <p>
* FIXME: The thread implementation should be factored out.
*/
private void startCleaner() { private void startCleaner() {
Runnable cleaner = new Runnable() { Runnable cleaner = new Runnable() {
public void run() { public void run() {
@@ -140,7 +178,14 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
new Thread(cleaner).start(); new Thread(cleaner).start();
} }
// Locking: contacts read, messages write, messageStatuses write /**
* If the given message is already in the database, marks it as seen by the
* sender and returns false. Otherwise stores the message, updates the
* sendability of its ancestors if necessary, marks the message as seen by
* the sender and unseen by all other contacts, and returns true.
* <p>
* Locking: contacts read, messages write, messageStatuses write.
*/
protected boolean storeMessage(Txn txn, Message m, ContactId sender) protected boolean storeMessage(Txn txn, Message m, ContactId sender)
throws DbException { throws DbException {
boolean added = db.addMessage(txn, m); boolean added = db.addMessage(txn, m);
@@ -164,7 +209,15 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
return added; return added;
} }
// Locking: messages write /**
* Iteratively updates the sendability of a message's ancestors to reflect
* a change in the message's sendability. Returns the number of ancestors
* that have changed from sendable to not sendable, or vice versa.
* <p>
* Locking: messages write.
* @param increment True if the message's sendability has changed from 0 to
* greater than 0, or false if it has changed from greater than 0 to 0.
*/
private int updateAncestorSendability(Txn txn, MessageId m, private int updateAncestorSendability(Txn txn, MessageId m,
boolean increment) throws DbException { boolean increment) throws DbException {
int affected = 0; int affected = 0;
@@ -191,7 +244,14 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
return affected; return affected;
} }
// Locking: messages write /**
* Updates the sendability of all messages written by the given author, and
* the ancestors of those messages if necessary.
* <p>
* Locking: messages write.
* @param increment True if the user's rating for the author has changed
* from not good to good, or false if it has changed from good to not good.
*/
protected void updateAuthorSendability(Txn txn, AuthorId a, protected void updateAuthorSendability(Txn txn, AuthorId a,
boolean increment) throws DbException { boolean increment) throws DbException {
int direct = 0, indirect = 0; int direct = 0, indirect = 0;
@@ -217,6 +277,11 @@ abstract class DatabaseComponentImpl<Txn> implements DatabaseComponent {
+ indirect + " indirectly"); + indirect + " indirectly");
} }
/**
* Blocks until messages are allowed to be stored in the database. The
* storage of messages is not allowed while the amount of free storage
* space available to the database is less than CRITICAL_FREE_SPACE.
*/
protected void waitForPermissionToWrite() { protected void waitForPermissionToWrite() {
synchronized(writeLock) { synchronized(writeLock) {
while(!writesAllowed) { while(!writesAllowed) {

View File

@@ -21,6 +21,10 @@ import net.sf.briar.api.protocol.MessageId;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
/**
* An implementation of DatabaseComponent using reentrant read-write locks.
* This implementation can allow writers to starve.
*/
class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
private static final Logger LOG = private static final Logger LOG =
@@ -28,8 +32,7 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
/* /*
* Locks must always be acquired in alphabetical order. See the Database * Locks must always be acquired in alphabetical order. See the Database
* interface to find out which calls require which locks. Note: this * interface to find out which calls require which locks.
* implementation can allow writers to starve.
*/ */
private final ReentrantReadWriteLock contactLock = private final ReentrantReadWriteLock contactLock =
@@ -112,6 +115,8 @@ class ReadWriteLockDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
try { try {
Txn txn = db.startTransaction(); Txn txn = db.startTransaction();
try { try {
// Don't store the message if the user has
// unsubscribed from the group
if(db.containsSubscription(txn, m.getGroup())) { if(db.containsSubscription(txn, m.getGroup())) {
boolean added = storeMessage(txn, m, null); boolean added = storeMessage(txn, m, null);
assert added; assert added;

View File

@@ -20,6 +20,10 @@ import net.sf.briar.api.protocol.MessageId;
import com.google.inject.Inject; import com.google.inject.Inject;
import com.google.inject.Provider; import com.google.inject.Provider;
/**
* An implementation of DatabaseComponent using Java synchronization. This
* implementation does not distinguish between readers and writers.
*/
class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> { class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
private static final Logger LOG = private static final Logger LOG =
@@ -80,6 +84,8 @@ class SynchronizedDatabaseComponent<Txn> extends DatabaseComponentImpl<Txn> {
synchronized(subscriptionLock) { synchronized(subscriptionLock) {
Txn txn = db.startTransaction(); Txn txn = db.startTransaction();
try { try {
// Don't store the message if the user has
// unsubscribed from the group
if(db.containsSubscription(txn, m.getGroup())) { if(db.containsSubscription(txn, m.getGroup())) {
boolean added = storeMessage(txn, m, null); boolean added = storeMessage(txn, m, null);
assert added; assert added;

View File

@@ -12,6 +12,8 @@ import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.UIManager; import javax.swing.UIManager;
@@ -20,19 +22,32 @@ import net.sf.briar.util.FileUtils;
public class FontManagerImpl implements FontManager { public class FontManagerImpl implements FontManager {
private static final Logger LOG =
Logger.getLogger(FontManagerImpl.class.getName());
/**
* Each bundled font is associated with a size, which is meant to occupy
* roughly the same amount of space as the default font (12 point sans),
* and a list of languages for which the bundled font should be used.
*/
private static final BundledFont[] BUNDLED_FONTS = { private static final BundledFont[] BUNDLED_FONTS = {
// Use TibetanMachineUni for Tibetan
new BundledFont("TibetanMachineUni.ttf", 14f, new String[] { "bo" }), new BundledFont("TibetanMachineUni.ttf", 14f, new String[] { "bo" }),
// Use Padauk for Burmese
new BundledFont("Padauk.ttf", 14f, new String[] { "my" }), new BundledFont("Padauk.ttf", 14f, new String[] { "my" }),
}; };
// Map from languages to fonts
private final Map<String, Font> fonts = new TreeMap<String, Font>(); private final Map<String, Font> fonts = new TreeMap<String, Font>();
private volatile Font defaultFont = null, uiFont = null; private volatile Font defaultFont = null, uiFont = null;
public void initialize(Locale locale) throws IOException { public void initialize(Locale locale) {
try { // Look for bundled fonts in the jar and the filesystem. If any fonts
ClassLoader loader = getClass().getClassLoader(); // are missing or fail to load, fall back to the default font.
for(BundledFont bf : BUNDLED_FONTS) { ClassLoader loader = getClass().getClassLoader();
for(BundledFont bf : BUNDLED_FONTS) {
try {
InputStream in = loader.getResourceAsStream(bf.filename); InputStream in = loader.getResourceAsStream(bf.filename);
if(in == null) { if(in == null) {
File root = FileUtils.getBriarDirectory(); File root = FileUtils.getBriarDirectory();
@@ -42,9 +57,13 @@ public class FontManagerImpl implements FontManager {
Font font = Font.createFont(Font.TRUETYPE_FONT, in); Font font = Font.createFont(Font.TRUETYPE_FONT, in);
font = font.deriveFont(bf.size); font = font.deriveFont(bf.size);
for(String language : bf.languages) fonts.put(language, font); for(String language : bf.languages) fonts.put(language, font);
} catch(FontFormatException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning("Could not load font: " + e.getMessage());
} catch(IOException e) {
if(LOG.isLoggable(Level.WARNING))
LOG.warning("Could not load font: " + e.getMessage());
} }
} catch(FontFormatException e) {
throw new IOException(e);
} }
defaultFont = getFont("Sans", 12f); defaultFont = getFont("Sans", 12f);
assert defaultFont != null; // FIXME: This is failing on Windows assert defaultFont != null; // FIXME: This is failing on Windows

View File

@@ -23,6 +23,11 @@ import net.sf.briar.util.FileUtils;
public class I18nImpl implements I18n { public class I18nImpl implements I18n {
/**
* Property keys for strings used in the JRE's built-in dialogs. Values
* assigned to these keys in i18n properties files will override the
* built-in values.
*/
private static final String[] uiManagerKeys = { private static final String[] uiManagerKeys = {
"FileChooser.acceptAllFileFilterText", "FileChooser.acceptAllFileFilterText",
"FileChooser.cancelButtonText", "FileChooser.cancelButtonText",
@@ -87,6 +92,7 @@ public class I18nImpl implements I18n {
synchronized(bundleLock) { synchronized(bundleLock) {
if(bundle == null) { if(bundle == null) {
bundle = ResourceBundle.getBundle("i18n", locale, loader); bundle = ResourceBundle.getBundle("i18n", locale, loader);
assert bundle != null;
for(String key : uiManagerKeys) { for(String key : uiManagerKeys) {
try { try {
UIManager.put(key, bundle.getString(key)); UIManager.put(key, bundle.getString(key));
@@ -106,6 +112,7 @@ public class I18nImpl implements I18n {
Font uiFont = fontManager.getUiFont(); Font uiFont = fontManager.getUiFont();
synchronized(bundleLock) { synchronized(bundleLock) {
this.locale = locale; this.locale = locale;
Locale.setDefault(locale);
bundle = null; bundle = null;
synchronized(listeners) { synchronized(listeners) {
for(Listener l : listeners) l.localeChanged(uiFont); for(Listener l : listeners) l.localeChanged(uiFont);
@@ -116,7 +123,7 @@ public class I18nImpl implements I18n {
public void loadLocale() throws IOException { public void loadLocale() throws IOException {
File root = FileUtils.getBriarDirectory(); File root = FileUtils.getBriarDirectory();
Scanner s = new Scanner(new File(root, "Data/locale.cfg")); Scanner s = new Scanner(new File(root, "Data/locale.cfg"));
if(s.hasNextLine()) locale = new Locale(s.nextLine()); if(s.hasNextLine()) setLocale(new Locale(s.nextLine()));
s.close(); s.close();
} }

View File

@@ -41,18 +41,11 @@ class InvitationWorker implements Runnable {
List<File> files = new ArrayList<File>(); List<File> files = new ArrayList<File>();
try { try {
if(callback.isCancelled()) return; if(callback.isCancelled()) return;
File invitationDat = createInvitationDat(dir); files.add(createInvitationDat(dir));
files.add(invitationDat);
if(callback.isCancelled()) return; if(callback.isCancelled()) return;
if(parameters.shouldCreateExe()) { if(parameters.shouldCreateExe()) files.add(createBriarExe(dir));
File briarExe = createBriarExe(dir);
files.add(briarExe);
}
if(callback.isCancelled()) return; if(callback.isCancelled()) return;
if(parameters.shouldCreateJar()) { if(parameters.shouldCreateJar()) files.add(createBriarJar(dir));
File briarJar = createBriarJar(dir);
files.add(briarJar);
}
} catch(IOException e) { } catch(IOException e) {
callback.error(e.getMessage()); callback.error(e.getMessage());
return; return;
@@ -69,8 +62,7 @@ class InvitationWorker implements Runnable {
// FIXME: Create a real invitation // FIXME: Create a real invitation
try { try {
Thread.sleep(2000); Thread.sleep(2000);
} catch(InterruptedException ignored) { } catch(InterruptedException ignored) {}
}
Arrays.fill(password, (char) 0); Arrays.fill(password, (char) 0);
FileOutputStream out = new FileOutputStream(invitationDat); FileOutputStream out = new FileOutputStream(invitationDat);
byte[] buf = new byte[1024]; byte[] buf = new byte[1024];

View File

@@ -8,6 +8,7 @@ import net.sf.briar.api.protocol.Batch;
import net.sf.briar.api.protocol.BatchId; import net.sf.briar.api.protocol.BatchId;
import net.sf.briar.api.protocol.Message; import net.sf.briar.api.protocol.Message;
/** A simple in-memory implementation of a batch. */
class BatchImpl implements Batch { class BatchImpl implements Batch {
private final List<Message> messages = new ArrayList<Message>(); private final List<Message> messages = new ArrayList<Message>();

View File

@@ -1,7 +1,7 @@
<project name='test' default='test'> <project name='test' default='test'>
<import file='../build-common.xml'/> <import file='../build-common.xml'/>
<target name='test' depends='depend'> <target name='test' depends='depend'>
<junit printsummary='on'> <junit printsummary='on' showoutput='true'>
<classpath> <classpath>
<fileset refid='bundled-jars'/> <fileset refid='bundled-jars'/>
<fileset refid='test-jars'/> <fileset refid='test-jars'/>
@@ -10,6 +10,8 @@
<path refid='test-classes'/> <path refid='test-classes'/>
<path refid='util-classes'/> <path refid='util-classes'/>
</classpath> </classpath>
<test name='net.sf.briar.i18n.FontManagerImplTest'/>
<test name='net.sf.briar.invitation.InvitationWorkerTest'/>
<test name='net.sf.briar.setup.SetupWorkerTest'/> <test name='net.sf.briar.setup.SetupWorkerTest'/>
<test name='net.sf.briar.util.FileUtilsTest'/> <test name='net.sf.briar.util.FileUtilsTest'/>
<test name='net.sf.briar.util.StringUtilsTest'/> <test name='net.sf.briar.util.StringUtilsTest'/>

View File

@@ -11,7 +11,7 @@ public class TestUtils {
private static final AtomicInteger nextTestDir = private static final AtomicInteger nextTestDir =
new AtomicInteger((int) (Math.random() * 1000 * 1000)); new AtomicInteger((int) (Math.random() * 1000 * 1000));
public static void delete(File f) throws IOException { public static void delete(File f) {
if(f.isDirectory()) for(File child : f.listFiles()) delete(child); if(f.isDirectory()) for(File child : f.listFiles()) delete(child);
f.delete(); f.delete();
} }
@@ -29,4 +29,8 @@ public class TestUtils {
File testDir = new File("test.tmp/" + name); File testDir = new File("test.tmp/" + name);
return testDir; return testDir;
} }
public static void deleteTestDirectories() {
delete(new File("test.tmp"));
}
} }

View File

@@ -0,0 +1,69 @@
package net.sf.briar.i18n;
import java.awt.Font;
import java.util.Locale;
import junit.framework.TestCase;
import net.sf.briar.i18n.FontManagerImpl;
import org.junit.Test;
public class FontManagerImplTest extends TestCase {
@Test
public void testBundledFontsAreLoaded() {
FontManagerImpl fontManager = new FontManagerImpl();
fontManager.initialize(Locale.UK);
Font font = fontManager.getFontForLanguage("en"); // English
assertEquals(12, font.getSize());
font = fontManager.getFontForLanguage("bo"); // Tibetan
assertEquals("Tibetan Machine Uni", font.getFamily());
assertEquals(14, font.getSize());
font = fontManager.getFontForLanguage("my"); // Burmese
assertEquals("Padauk", font.getFamily());
assertEquals(14, font.getSize());
}
@Test
public void testInternationalCharactersCanBeDisplayed() {
FontManagerImpl fontManager = new FontManagerImpl();
fontManager.initialize(Locale.UK);
Font font = fontManager.getFontForLanguage("en"); // English
assertTrue(font.canDisplay('a'));
font = fontManager.getFontForLanguage("ar"); // Arabic
assertTrue(font.canDisplay('\u0627')); // An Arabic character
font = fontManager.getFontForLanguage("bo"); // Tibetan
assertTrue(font.canDisplay('\u0f00')); // A Tibetan character
font = fontManager.getFontForLanguage("fa"); // Persian
assertTrue(font.canDisplay('\ufb56')); // A Persian character
font = fontManager.getFontForLanguage("my"); // Burmese
assertTrue(font.canDisplay('\u1000')); // A Burmese character
font = fontManager.getFontForLanguage("zh"); // Chinese
assertTrue(font.canDisplay('\u4e00')); // A Chinese character
}
@Test
public void testSetAndGetUiFont() {
FontManagerImpl fontManager = new FontManagerImpl();
fontManager.initialize(Locale.UK);
Font font = fontManager.getUiFont();
assertEquals(12, font.getSize());
fontManager.setUiFontForLanguage("bo");
font = fontManager.getUiFont();
assertEquals("Tibetan Machine Uni", font.getFamily());
assertEquals(14, font.getSize());
fontManager.setUiFontForLanguage("en");
font = fontManager.getUiFont();
assertEquals(12, font.getSize());
}
}

View File

@@ -147,7 +147,7 @@ public class InvitationWorkerTest extends TestCase {
} }
@After @After
public void tearDown() throws IOException { public void tearDown() {
TestUtils.delete(testDir); TestUtils.deleteTestDirectories();
} }
} }

View File

@@ -165,7 +165,7 @@ public class SetupWorkerTest extends TestCase {
} }
@After @After
public void tearDown() throws IOException { public void tearDown() {
TestUtils.delete(testDir); TestUtils.deleteTestDirectories();
} }
} }

View File

@@ -159,7 +159,7 @@ public class FileUtilsTest extends TestCase {
} }
@After @After
public void tearDown() throws IOException { public void tearDown() {
TestUtils.delete(testDir); TestUtils.deleteTestDirectories();
} }
} }

View File

@@ -195,7 +195,7 @@ public class ZipUtilsTest extends TestCase {
} }
@After @After
public void tearDown() throws IOException { public void tearDown() {
TestUtils.delete(testDir); TestUtils.deleteTestDirectories();
} }
} }

View File

@@ -18,19 +18,12 @@ public class FileUtils {
assert f.exists(); assert f.exists();
if(f.isFile()) { if(f.isFile()) {
// Running from a jar - return the jar's grandparent // Running from a jar - return the jar's grandparent
try { f = f.getParentFile().getParentFile();
f = f.getCanonicalFile().getParentFile().getParentFile();
} catch(IOException e) {
throw new RuntimeException(e);
}
} else { } else {
// Running from Eclipse // Running from Eclipse or ant
try { f = new File(f.getParentFile(), "Briar");
f = new File(f.getCanonicalFile().getParentFile(), "Briar"); if(!f.exists())
} catch(IOException e) { f = new File(f.getParentFile().getParentFile(), "Briar"); // Ant
throw new RuntimeException(e);
}
f.mkdir();
} }
assert f.exists(); assert f.exists();
assert f.isDirectory(); assert f.isDirectory();