mirror of
https://github.com/peterosterlund2/droidfish.git
synced 2025-12-15 02:12:40 +01:00
DroidFish: Fixed crash in android 7 when handling large PGN games.
This commit is contained in:
@@ -1,3 +1,3 @@
|
|||||||
<paths>
|
<paths>
|
||||||
<files-path path="images/" name="myimages"/>
|
<files-path path="shared/" name="myshared"/>
|
||||||
</paths>
|
</paths>
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import java.io.FileWriter;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -225,6 +226,7 @@ public class DroidFish extends Activity
|
|||||||
private ListView rightDrawer;
|
private ListView rightDrawer;
|
||||||
|
|
||||||
private SharedPreferences settings;
|
private SharedPreferences settings;
|
||||||
|
private ObjectCache cache;
|
||||||
|
|
||||||
private float scrollSensitivity;
|
private float scrollSensitivity;
|
||||||
private boolean invertScrollDirection;
|
private boolean invertScrollDirection;
|
||||||
@@ -475,6 +477,7 @@ public class DroidFish extends Activity
|
|||||||
|
|
||||||
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
|
PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
|
||||||
settings = PreferenceManager.getDefaultSharedPreferences(this);
|
settings = PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
|
cache = new ObjectCache();
|
||||||
|
|
||||||
setWakeLock(false);
|
setWakeLock(false);
|
||||||
|
|
||||||
@@ -506,7 +509,9 @@ public class DroidFish extends Activity
|
|||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
int version = 1;
|
int version = 1;
|
||||||
if (savedInstanceState != null) {
|
if (savedInstanceState != null) {
|
||||||
data = savedInstanceState.getByteArray("gameState");
|
byte[] token = savedInstanceState.getByteArray("gameStateT");
|
||||||
|
if (token != null)
|
||||||
|
data = cache.retrieveBytes(token);
|
||||||
version = savedInstanceState.getInt("gameStateVersion", version);
|
version = savedInstanceState.getInt("gameStateVersion", version);
|
||||||
} else {
|
} else {
|
||||||
String dataStr = settings.getString("gameState", null);
|
String dataStr = settings.getString("gameState", null);
|
||||||
@@ -1125,7 +1130,8 @@ public class DroidFish extends Activity
|
|||||||
super.onSaveInstanceState(outState);
|
super.onSaveInstanceState(outState);
|
||||||
if (ctrl != null) {
|
if (ctrl != null) {
|
||||||
byte[] data = ctrl.toByteArray();
|
byte[] data = ctrl.toByteArray();
|
||||||
outState.putByteArray("gameState", data);
|
byte[] token = data == null ? null : cache.storeBytes(data);
|
||||||
|
outState.putByteArray("gameStateT", token);
|
||||||
outState.putInt("gameStateVersion", 3);
|
outState.putInt("gameStateVersion", 3);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1693,7 +1699,8 @@ public class DroidFish extends Activity
|
|||||||
case RESULT_LOAD_PGN:
|
case RESULT_LOAD_PGN:
|
||||||
if (resultCode == RESULT_OK) {
|
if (resultCode == RESULT_OK) {
|
||||||
try {
|
try {
|
||||||
String pgn = data.getAction();
|
String pgnToken = data.getAction();
|
||||||
|
String pgn = cache.retrieveString(pgnToken);
|
||||||
int modeNr = ctrl.getGameMode().getModeNr();
|
int modeNr = ctrl.getGameMode().getModeNr();
|
||||||
if ((modeNr != GameMode.ANALYSIS) && (modeNr != GameMode.EDIT_GAME))
|
if ((modeNr != GameMode.ANALYSIS) && (modeNr != GameMode.EDIT_GAME))
|
||||||
newGameMode(GameMode.EDIT_GAME);
|
newGameMode(GameMode.EDIT_GAME);
|
||||||
@@ -2337,7 +2344,29 @@ public class DroidFish extends Activity
|
|||||||
Intent i = new Intent(Intent.ACTION_SEND);
|
Intent i = new Intent(Intent.ACTION_SEND);
|
||||||
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
|
||||||
i.setType(game ? "application/x-chess-pgn" : "text/plain");
|
i.setType(game ? "application/x-chess-pgn" : "text/plain");
|
||||||
i.putExtra(Intent.EXTRA_TEXT, ctrl.getPGN());
|
String pgn = ctrl.getPGN();
|
||||||
|
if (pgn.length() < 32768) {
|
||||||
|
i.putExtra(Intent.EXTRA_TEXT, pgn);
|
||||||
|
} else {
|
||||||
|
File dir = new File(getFilesDir(), "shared");
|
||||||
|
dir.mkdirs();
|
||||||
|
File file = new File(dir, game ? "game.pgn" : "game.txt");
|
||||||
|
try {
|
||||||
|
FileOutputStream fos = new FileOutputStream(file);
|
||||||
|
OutputStreamWriter ow = new OutputStreamWriter(fos, "UTF-8");
|
||||||
|
try {
|
||||||
|
ow.write(pgn);
|
||||||
|
} finally {
|
||||||
|
ow.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String authority = "org.petero.droidfish.fileprovider";
|
||||||
|
Uri uri = FileProvider.getUriForFile(this, authority, file);
|
||||||
|
i.putExtra(Intent.EXTRA_STREAM, uri);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
startActivity(Intent.createChooser(i, getString(game ? R.string.share_game :
|
startActivity(Intent.createChooser(i, getString(game ? R.string.share_game :
|
||||||
R.string.share_text)));
|
R.string.share_text)));
|
||||||
@@ -2351,7 +2380,7 @@ public class DroidFish extends Activity
|
|||||||
Bitmap.Config.ARGB_8888);
|
Bitmap.Config.ARGB_8888);
|
||||||
Canvas c = new Canvas(b);
|
Canvas c = new Canvas(b);
|
||||||
v.draw(c);
|
v.draw(c);
|
||||||
File imgDir = new File(getFilesDir(), "images");
|
File imgDir = new File(getFilesDir(), "shared");
|
||||||
imgDir.mkdirs();
|
imgDir.mkdirs();
|
||||||
File file = new File(imgDir, "screenshot.png");
|
File file = new File(imgDir, "screenshot.png");
|
||||||
try {
|
try {
|
||||||
@@ -3712,6 +3741,7 @@ public class DroidFish extends Activity
|
|||||||
/** Save current game to a PGN file. */
|
/** Save current game to a PGN file. */
|
||||||
private final void savePGNToFile(String pathName, boolean silent) {
|
private final void savePGNToFile(String pathName, boolean silent) {
|
||||||
String pgn = ctrl.getPGN();
|
String pgn = ctrl.getPGN();
|
||||||
|
String pgnToken = cache.storeString(pgn);
|
||||||
Editor editor = settings.edit();
|
Editor editor = settings.edit();
|
||||||
editor.putString("currentPGNFile", pathName);
|
editor.putString("currentPGNFile", pathName);
|
||||||
editor.putInt("currFT", FT_PGN);
|
editor.putInt("currFT", FT_PGN);
|
||||||
@@ -3719,7 +3749,7 @@ public class DroidFish extends Activity
|
|||||||
Intent i = new Intent(DroidFish.this, EditPGNSave.class);
|
Intent i = new Intent(DroidFish.this, EditPGNSave.class);
|
||||||
i.setAction("org.petero.droidfish.saveFile");
|
i.setAction("org.petero.droidfish.saveFile");
|
||||||
i.putExtra("org.petero.droidfish.pathname", pathName);
|
i.putExtra("org.petero.droidfish.pathname", pathName);
|
||||||
i.putExtra("org.petero.droidfish.pgn", pgn);
|
i.putExtra("org.petero.droidfish.pgn", pgnToken);
|
||||||
i.putExtra("org.petero.droidfish.silent", silent);
|
i.putExtra("org.petero.droidfish.silent", silent);
|
||||||
startActivity(i);
|
startActivity(i);
|
||||||
}
|
}
|
||||||
|
|||||||
175
DroidFish/src/org/petero/droidfish/ObjectCache.java
Normal file
175
DroidFish/src/org/petero/droidfish/ObjectCache.java
Normal file
@@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
DroidFish - An Android chess program.
|
||||||
|
Copyright (C) 2017 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.petero.droidfish;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.RandomAccessFile;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores large objects temporarily in the file system to avoid
|
||||||
|
* too large transactions when communicating between activities.
|
||||||
|
* The cache has a limited size, so trying to retrieve a stored
|
||||||
|
* object can fail in which case null is returned. */
|
||||||
|
public class ObjectCache {
|
||||||
|
public final static int MAX_MEM_SIZE = 16384; // Max size of object to store in memory
|
||||||
|
public final static int MAX_CACHED_OBJS = 10; // Max no of objects to cache in file system
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public ObjectCache() {
|
||||||
|
this(DroidFishApp.getContext());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectCache(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Store a string in the cache and return a token that can be
|
||||||
|
* used to retrieve the original string. */
|
||||||
|
public String storeString(String s) {
|
||||||
|
if (s.length() < MAX_MEM_SIZE) {
|
||||||
|
return "0" + s;
|
||||||
|
} else {
|
||||||
|
long token = storeInCache(s.getBytes());
|
||||||
|
return "1" + Long.toString(token);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retrieve a string from the cache using a token previously
|
||||||
|
* returned by storeString().
|
||||||
|
* @return The string, or null if not found in the cache. */
|
||||||
|
public String retrieveString(String token) {
|
||||||
|
if (token.startsWith("0")) {
|
||||||
|
return token.substring(1);
|
||||||
|
} else {
|
||||||
|
String tokStr = token.substring(1);
|
||||||
|
long longTok = Long.valueOf(tokStr);
|
||||||
|
byte[] buf = retrieveFromCache(longTok);
|
||||||
|
return buf == null ? null : new String(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Store a byte array in the cache and return a token that can be
|
||||||
|
* used to retrieve the original byte array. */
|
||||||
|
public byte[] storeBytes(byte[] b) {
|
||||||
|
if (b.length < MAX_MEM_SIZE) {
|
||||||
|
byte[] ret = new byte[b.length + 1];
|
||||||
|
ret[0] = 0;
|
||||||
|
System.arraycopy(b, 0, ret, 1, b.length);
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
long token = storeInCache(b);
|
||||||
|
byte[] tokBuf = Long.toString(token).getBytes();
|
||||||
|
byte[] ret = new byte[1 + tokBuf.length];
|
||||||
|
ret[0] = 1;
|
||||||
|
System.arraycopy(tokBuf, 0, ret, 1, tokBuf.length);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retrieve a byte array from the cache using a token previously
|
||||||
|
* returned by storeBytes().
|
||||||
|
* @return The byte array, or null if not found in the cache. */
|
||||||
|
public byte[] retrieveBytes(byte[] token) {
|
||||||
|
if (token[0] == 0) {
|
||||||
|
byte[] ret = new byte[token.length - 1];
|
||||||
|
System.arraycopy(token, 1, ret, 0, token.length - 1);
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
String tokStr = new String(token, 1, token.length - 1);
|
||||||
|
long longTok = Long.valueOf(tokStr);
|
||||||
|
return retrieveFromCache(longTok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private final static String cacheDir = "objcache";
|
||||||
|
|
||||||
|
private long storeInCache(byte[] b) {
|
||||||
|
File cd = context.getCacheDir();
|
||||||
|
File dir = new File(cd, cacheDir);
|
||||||
|
if (dir.exists() || dir.mkdir()) {
|
||||||
|
try {
|
||||||
|
File[] files = dir.listFiles();
|
||||||
|
if (files != null) {
|
||||||
|
long[] tokens = new long[files.length];
|
||||||
|
long token = -1;
|
||||||
|
for (int i = 0; i < files.length; i++) {
|
||||||
|
try {
|
||||||
|
tokens[i] = Long.valueOf(files[i].getName());
|
||||||
|
token = Math.max(token, tokens[i]);
|
||||||
|
} catch (NumberFormatException nfe) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Arrays.sort(tokens);
|
||||||
|
for (int i = 0; i < files.length - (MAX_CACHED_OBJS - 1); i++) {
|
||||||
|
File f = new File(dir, String.valueOf(tokens[i]));
|
||||||
|
f.delete();
|
||||||
|
}
|
||||||
|
int maxTries = 10;
|
||||||
|
for (int i = 0; i < maxTries; i++) {
|
||||||
|
token++;
|
||||||
|
File f = new File(dir, String.valueOf(token));
|
||||||
|
if (f.createNewFile()) {
|
||||||
|
FileOutputStream fos = new FileOutputStream(f);
|
||||||
|
try {
|
||||||
|
fos.write(b);
|
||||||
|
return token;
|
||||||
|
} finally {
|
||||||
|
fos.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte[] retrieveFromCache(long token) {
|
||||||
|
File cd = context.getCacheDir();
|
||||||
|
File dir = new File(cd, cacheDir);
|
||||||
|
if (dir.exists()) {
|
||||||
|
File f = new File(dir, String.valueOf(token));
|
||||||
|
try {
|
||||||
|
RandomAccessFile raf = new RandomAccessFile(f, "r");
|
||||||
|
try {
|
||||||
|
int len = (int)raf.length();
|
||||||
|
byte[] buf = new byte[len];
|
||||||
|
int offs = 0;
|
||||||
|
while (offs < len) {
|
||||||
|
int l = raf.read(buf, offs, len - offs);
|
||||||
|
if (l <= 0)
|
||||||
|
return null;
|
||||||
|
offs += l;
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
} finally {
|
||||||
|
raf.close();
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,6 +23,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
import org.petero.droidfish.ColorTheme;
|
import org.petero.droidfish.ColorTheme;
|
||||||
|
import org.petero.droidfish.ObjectCache;
|
||||||
import org.petero.droidfish.R;
|
import org.petero.droidfish.R;
|
||||||
import org.petero.droidfish.Util;
|
import org.petero.droidfish.Util;
|
||||||
import org.petero.droidfish.activities.PGNFile.GameInfo;
|
import org.petero.droidfish.activities.PGNFile.GameInfo;
|
||||||
@@ -160,7 +161,8 @@ public class EditPGN extends ListActivity {
|
|||||||
}
|
}
|
||||||
} else if (action.equals("org.petero.droidfish.saveFile")) {
|
} else if (action.equals("org.petero.droidfish.saveFile")) {
|
||||||
loadGame = false;
|
loadGame = false;
|
||||||
pgnToSave = i.getStringExtra("org.petero.droidfish.pgn");
|
String token = i.getStringExtra("org.petero.droidfish.pgn");
|
||||||
|
pgnToSave = (new ObjectCache()).retrieveString(token);
|
||||||
boolean silent = i.getBooleanExtra("org.petero.droidfish.silent", false);
|
boolean silent = i.getBooleanExtra("org.petero.droidfish.silent", false);
|
||||||
if (silent) { // Silently append to file
|
if (silent) { // Silently append to file
|
||||||
PGNFile pgnFile2 = new PGNFile(fileName);
|
PGNFile pgnFile2 = new PGNFile(fileName);
|
||||||
@@ -466,7 +468,8 @@ public class EditPGN extends ListActivity {
|
|||||||
private final void sendBackResult(GameInfo gi) {
|
private final void sendBackResult(GameInfo gi) {
|
||||||
String pgn = pgnFile.readOneGame(gi);
|
String pgn = pgnFile.readOneGame(gi);
|
||||||
if (pgn != null) {
|
if (pgn != null) {
|
||||||
setResult(RESULT_OK, (new Intent()).setAction(pgn));
|
String pgnToken = (new ObjectCache()).storeString(pgn);
|
||||||
|
setResult(RESULT_OK, (new Intent()).setAction(pgnToken));
|
||||||
finish();
|
finish();
|
||||||
} else {
|
} else {
|
||||||
setResult(RESULT_CANCELED);
|
setResult(RESULT_CANCELED);
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.util.Vector;
|
|||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
|
||||||
import org.petero.droidfish.ColorTheme;
|
import org.petero.droidfish.ColorTheme;
|
||||||
|
import org.petero.droidfish.ObjectCache;
|
||||||
import org.petero.droidfish.R;
|
import org.petero.droidfish.R;
|
||||||
import org.petero.droidfish.Util;
|
import org.petero.droidfish.Util;
|
||||||
|
|
||||||
@@ -371,7 +372,8 @@ public class LoadScid extends ListActivity {
|
|||||||
if (cursor != null && cursor.moveToFirst()) {
|
if (cursor != null && cursor.moveToFirst()) {
|
||||||
String pgn = cursor.getString(cursor.getColumnIndex("pgn"));
|
String pgn = cursor.getString(cursor.getColumnIndex("pgn"));
|
||||||
if (pgn != null && pgn.length() > 0) {
|
if (pgn != null && pgn.length() > 0) {
|
||||||
setResult(RESULT_OK, (new Intent()).setAction(pgn));
|
String pgnToken = (new ObjectCache()).storeString(pgn);
|
||||||
|
setResult(RESULT_OK, (new Intent()).setAction(pgnToken));
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
133
DroidFishTest/src/org/petero/droidfish/ObjectCacheTest.java
Normal file
133
DroidFishTest/src/org/petero/droidfish/ObjectCacheTest.java
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
DroidFish - An Android chess program.
|
||||||
|
Copyright (C) 2017 Peter Österlund, peterosterlund2@gmail.com
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.petero.droidfish;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
|
||||||
|
public class ObjectCacheTest extends TestCase {
|
||||||
|
public ObjectCacheTest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testCache() {
|
||||||
|
ObjectCache cache = new ObjectCache(DroidFishApp.getContext());
|
||||||
|
final int M = ObjectCache.MAX_MEM_SIZE;
|
||||||
|
final int N = ObjectCache.MAX_CACHED_OBJS;
|
||||||
|
{ // Test small string
|
||||||
|
String s0 = "testing";
|
||||||
|
String token = cache.storeString(s0);
|
||||||
|
String s = cache.retrieveString(token);
|
||||||
|
assertEquals(s0, s);
|
||||||
|
}
|
||||||
|
{ // Test small byte array
|
||||||
|
byte[] b0 = {1,2,3,4,5};
|
||||||
|
byte[] token = cache.storeBytes(b0);
|
||||||
|
byte[] b = cache.retrieveBytes(token);
|
||||||
|
assertTrue(Arrays.equals(b0, b));
|
||||||
|
}
|
||||||
|
{ // Test large string
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 0; i < M + 1; i++)
|
||||||
|
sb.append('a');
|
||||||
|
String s0 = sb.toString();
|
||||||
|
String token = cache.storeString(s0);
|
||||||
|
String s = cache.retrieveString(token);
|
||||||
|
assertEquals(s0, s);
|
||||||
|
}
|
||||||
|
{ // Test large byte array
|
||||||
|
byte[] b0 = new byte[M+1];
|
||||||
|
for (int i = 0; i < M + 1; i++)
|
||||||
|
b0[i] = 'a';
|
||||||
|
byte[] token = cache.storeBytes(b0);
|
||||||
|
byte[] b = cache.retrieveBytes(token);
|
||||||
|
assertTrue(Arrays.equals(b0, b));
|
||||||
|
}
|
||||||
|
{ // Test large string objects
|
||||||
|
String[] s0 = new String[N];
|
||||||
|
String[] tokens = new String[N];
|
||||||
|
for (int i = 0; i < N; i++) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int j = 0; j < M + 1 + i * 100; j++)
|
||||||
|
sb.append((char)((i + j) % 255));
|
||||||
|
s0[i] = sb.toString();
|
||||||
|
tokens[i] = cache.storeString(s0[i]);
|
||||||
|
}
|
||||||
|
{ // Small objects must not evict older entries
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
cache.storeString("abc");
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
cache.storeBytes(new byte[]{(byte)i,(byte)(i*2),(byte)(i+1)});
|
||||||
|
}
|
||||||
|
for (int i = 0; i < N; i++) {
|
||||||
|
String s = cache.retrieveString(tokens[i]);
|
||||||
|
assertEquals(s0[i], s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{ // Test large byte arrays
|
||||||
|
byte[][] b0 = new byte[N][];
|
||||||
|
byte[][] tokens = new byte[N][];
|
||||||
|
for (int i = 0; i < N; i++) {
|
||||||
|
byte[] b = new byte[M + 1 + i * 100];
|
||||||
|
for (int j = 0; j < b.length; j++)
|
||||||
|
b[j] = (byte)((i + j) % 255);
|
||||||
|
b0[i] = b;
|
||||||
|
tokens[i] = cache.storeBytes(b0[i]);
|
||||||
|
}
|
||||||
|
{ // Small objects must not evict older entries
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
cache.storeString("abc");
|
||||||
|
for (int i = 0; i < 100; i++)
|
||||||
|
cache.storeBytes(new byte[]{(byte)i,(byte)(i*2),(byte)(i+1)});
|
||||||
|
}
|
||||||
|
for (int i = 0; i < N; i++) {
|
||||||
|
byte[] b = cache.retrieveBytes(tokens[i]);
|
||||||
|
assertTrue(Arrays.equals(b0[i], b));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ // Test that not too many file system objects are used
|
||||||
|
String[] s0 = new String[N];
|
||||||
|
String[] tokens = new String[N];
|
||||||
|
for (int i = 0; i < N; i++) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int j = 0; j < M + 1 + i * 100; j++)
|
||||||
|
sb.append((char)((i + j) % 255));
|
||||||
|
s0[i] = sb.toString();
|
||||||
|
tokens[i] = cache.storeString(s0[i]);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int j = 0; j < M + 1; j++)
|
||||||
|
sb.append((char)((j + 3) % 255));
|
||||||
|
String s = sb.toString();
|
||||||
|
String token = cache.storeString(s);
|
||||||
|
String s1 = cache.retrieveString(token);
|
||||||
|
assertEquals(s, s1);
|
||||||
|
}
|
||||||
|
assertEquals(null, cache.retrieveString(tokens[0]));
|
||||||
|
for (int i = 1; i < N; i++) {
|
||||||
|
String s = cache.retrieveString(tokens[i]);
|
||||||
|
assertEquals(s0[i], s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user