forked from upstream-mirrors/OpenTracks
Fix for the signed/unsigned ANT+ device-id bug
This commit is contained in:
@@ -0,0 +1,267 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.backup;
|
||||
|
||||
import com.google.android.apps.mytracks.content.ContentTypeIds;
|
||||
|
||||
import android.database.MatrixCursor;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests for {@link DatabaseDumper}.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class DatabaseDumperTest extends TestCase {
|
||||
/**
|
||||
* This class is the same as {@link MatrixCursor}, except this class
|
||||
* implements {@link #getBlob} ({@link MatrixCursor} leaves it
|
||||
* unimplemented).
|
||||
*/
|
||||
private class BlobAwareMatrixCursor extends MatrixCursor {
|
||||
public BlobAwareMatrixCursor(String[] columnNames) {
|
||||
super(columnNames);
|
||||
}
|
||||
|
||||
@Override public byte[] getBlob(int columnIndex) {
|
||||
return getString(columnIndex).getBytes();
|
||||
}
|
||||
}
|
||||
|
||||
private static final String[] COLUMN_NAMES = {
|
||||
"intCol", "longCol", "floatCol", "doubleCol", "stringCol", "boolCol", "blobCol"
|
||||
};
|
||||
private static final byte[] COLUMN_TYPES = {
|
||||
ContentTypeIds.INT_TYPE_ID, ContentTypeIds.LONG_TYPE_ID,
|
||||
ContentTypeIds.FLOAT_TYPE_ID, ContentTypeIds.DOUBLE_TYPE_ID,
|
||||
ContentTypeIds.STRING_TYPE_ID, ContentTypeIds.BOOLEAN_TYPE_ID,
|
||||
ContentTypeIds.BLOB_TYPE_ID
|
||||
};
|
||||
private static final String[][] FAKE_DATA = {
|
||||
{ "42", "123456789", "3.1415", "2.72", "lolcat", "1", "blob" },
|
||||
{ null, "123456789", "3.1415", "2.72", "lolcat", "1", "blob" },
|
||||
{ "42", null, "3.1415", "2.72", "lolcat", "1", "blob" },
|
||||
{ "42", "123456789", null, "2.72", "lolcat", "1", "blob" },
|
||||
{ "42", "123456789", "3.1415", null, "lolcat", "1", "blob" },
|
||||
{ "42", "123456789", "3.1415", "2.72", null, "1", "blob" },
|
||||
{ "42", "123456789", "3.1415", "2.72", "lolcat", null, "blob" },
|
||||
{ "42", "123456789", "3.1415", "2.72", "lolcat", "1", null },
|
||||
};
|
||||
private static final long[] EXPECTED_FIELD_SETS = {
|
||||
0x7F, 0x7E, 0x7D, 0x7B, 0x77, 0x6F, 0x5F, 0x3F
|
||||
};
|
||||
|
||||
private BlobAwareMatrixCursor cursor;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
// Add fake data to the cursor
|
||||
cursor = new BlobAwareMatrixCursor(COLUMN_NAMES);
|
||||
for (String[] row : FAKE_DATA) {
|
||||
cursor.addRow(row);
|
||||
}
|
||||
}
|
||||
|
||||
public void testWriteAllRows_noNulls() throws Exception {
|
||||
testWriteAllRows(false);
|
||||
}
|
||||
|
||||
public void testWriteAllRows_withNulls() throws Exception {
|
||||
testWriteAllRows(true);
|
||||
}
|
||||
|
||||
private void testWriteAllRows(boolean hasNullFields) throws Exception {
|
||||
// Dump it
|
||||
DatabaseDumper dumper = new DatabaseDumper(COLUMN_NAMES, COLUMN_TYPES, hasNullFields);
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024);
|
||||
DataOutputStream writer = new DataOutputStream(outStream );
|
||||
dumper.writeAllRows(cursor, writer);
|
||||
|
||||
// Read the results
|
||||
byte[] result = outStream.toByteArray();
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(result);
|
||||
DataInputStream reader = new DataInputStream(inputStream);
|
||||
|
||||
// Verify the header
|
||||
assertHeader(reader);
|
||||
|
||||
// Verify the number of rows
|
||||
assertEquals(FAKE_DATA.length, reader.readInt());
|
||||
|
||||
// Row 0 -- everything populated
|
||||
assertEquals(EXPECTED_FIELD_SETS[0], reader.readLong());
|
||||
assertEquals(42, reader.readInt());
|
||||
assertEquals(123456789L, reader.readLong());
|
||||
assertEquals(3.1415f, reader.readFloat());
|
||||
assertEquals(2.72, reader.readDouble());
|
||||
assertEquals("lolcat", reader.readUTF());
|
||||
assertTrue(reader.readBoolean());
|
||||
assertEquals(4, reader.readInt());
|
||||
assertEquals("blob", readBlob(reader, 4));
|
||||
|
||||
// Row 1 -- no int
|
||||
assertEquals(EXPECTED_FIELD_SETS[1], reader.readLong());
|
||||
if (hasNullFields) reader.readInt();
|
||||
assertEquals(123456789L, reader.readLong());
|
||||
assertEquals(3.1415f, reader.readFloat());
|
||||
assertEquals(2.72, reader.readDouble());
|
||||
assertEquals("lolcat", reader.readUTF());
|
||||
assertTrue(reader.readBoolean());
|
||||
assertEquals(4, reader.readInt());
|
||||
assertEquals("blob", readBlob(reader, 4));
|
||||
|
||||
// Row 2 -- no long
|
||||
assertEquals(EXPECTED_FIELD_SETS[2], reader.readLong());
|
||||
assertEquals(42, reader.readInt());
|
||||
if (hasNullFields) reader.readLong();
|
||||
assertEquals(3.1415f, reader.readFloat());
|
||||
assertEquals(2.72, reader.readDouble());
|
||||
assertEquals("lolcat", reader.readUTF());
|
||||
assertTrue(reader.readBoolean());
|
||||
assertEquals(4, reader.readInt());
|
||||
assertEquals("blob", readBlob(reader, 4));
|
||||
|
||||
// Row 3 -- no float
|
||||
assertEquals(EXPECTED_FIELD_SETS[3], reader.readLong());
|
||||
assertEquals(42, reader.readInt());
|
||||
assertEquals(123456789L, reader.readLong());
|
||||
if (hasNullFields) reader.readFloat();
|
||||
assertEquals(2.72, reader.readDouble());
|
||||
assertEquals("lolcat", reader.readUTF());
|
||||
assertTrue(reader.readBoolean());
|
||||
assertEquals(4, reader.readInt());
|
||||
assertEquals("blob", readBlob(reader, 4));
|
||||
|
||||
// Row 4 -- no double
|
||||
assertEquals(EXPECTED_FIELD_SETS[4], reader.readLong());
|
||||
assertEquals(42, reader.readInt());
|
||||
assertEquals(123456789L, reader.readLong());
|
||||
assertEquals(3.1415f, reader.readFloat());
|
||||
if (hasNullFields) reader.readDouble();
|
||||
assertEquals("lolcat", reader.readUTF());
|
||||
assertTrue(reader.readBoolean());
|
||||
assertEquals(4, reader.readInt());
|
||||
assertEquals("blob", readBlob(reader, 4));
|
||||
|
||||
// Row 5 -- no string
|
||||
assertEquals(EXPECTED_FIELD_SETS[5], reader.readLong());
|
||||
assertEquals(42, reader.readInt());
|
||||
assertEquals(123456789L, reader.readLong());
|
||||
assertEquals(3.1415f, reader.readFloat());
|
||||
assertEquals(2.72, reader.readDouble());
|
||||
if (hasNullFields) reader.readUTF();
|
||||
assertTrue(reader.readBoolean());
|
||||
assertEquals(4, reader.readInt());
|
||||
assertEquals("blob", readBlob(reader, 4));
|
||||
|
||||
// Row 6 -- no boolean
|
||||
assertEquals(EXPECTED_FIELD_SETS[6], reader.readLong());
|
||||
assertEquals(42, reader.readInt());
|
||||
assertEquals(123456789L, reader.readLong());
|
||||
assertEquals(3.1415f, reader.readFloat());
|
||||
assertEquals(2.72, reader.readDouble());
|
||||
assertEquals("lolcat", reader.readUTF());
|
||||
if (hasNullFields) reader.readBoolean();
|
||||
assertEquals(4, reader.readInt());
|
||||
assertEquals("blob", readBlob(reader, 4));
|
||||
|
||||
// Row 7 -- no blob
|
||||
assertEquals(EXPECTED_FIELD_SETS[7], reader.readLong());
|
||||
assertEquals(42, reader.readInt());
|
||||
assertEquals(123456789L, reader.readLong());
|
||||
assertEquals(3.1415f, reader.readFloat());
|
||||
assertEquals(2.72, reader.readDouble());
|
||||
assertEquals("lolcat", reader.readUTF());
|
||||
assertTrue(reader.readBoolean());
|
||||
if (hasNullFields) {
|
||||
int length = reader.readInt();
|
||||
readBlob(reader, length);
|
||||
}
|
||||
}
|
||||
|
||||
public void testFewerRows() throws Exception {
|
||||
// Dump only the first two rows
|
||||
DatabaseDumper dumper = new DatabaseDumper(COLUMN_NAMES, COLUMN_TYPES, false);
|
||||
ByteArrayOutputStream outStream = new ByteArrayOutputStream(1024);
|
||||
DataOutputStream writer = new DataOutputStream(outStream);
|
||||
|
||||
dumper.writeHeaders(cursor, 2, writer);
|
||||
cursor.moveToFirst();
|
||||
dumper.writeOneRow(cursor, writer);
|
||||
cursor.moveToNext();
|
||||
dumper.writeOneRow(cursor, writer);
|
||||
|
||||
// Read the results
|
||||
byte[] result = outStream.toByteArray();
|
||||
ByteArrayInputStream inputStream = new ByteArrayInputStream(result);
|
||||
DataInputStream reader = new DataInputStream(inputStream);
|
||||
|
||||
// Verify the header
|
||||
assertHeader(reader);
|
||||
|
||||
// Verify the number of rows
|
||||
assertEquals(2, reader.readInt());
|
||||
|
||||
// Row 0
|
||||
assertEquals(EXPECTED_FIELD_SETS[0], reader.readLong());
|
||||
assertEquals(42, reader.readInt());
|
||||
assertEquals(123456789L, reader.readLong());
|
||||
assertEquals(3.1415f, reader.readFloat());
|
||||
assertEquals(2.72, reader.readDouble());
|
||||
assertEquals("lolcat", reader.readUTF());
|
||||
assertTrue(reader.readBoolean());
|
||||
assertEquals(4, reader.readInt());
|
||||
assertEquals("blob", readBlob(reader, 4));
|
||||
|
||||
// Row 1
|
||||
assertEquals(EXPECTED_FIELD_SETS[1], reader.readLong());
|
||||
// Null field not read
|
||||
assertEquals(123456789L, reader.readLong());
|
||||
assertEquals(3.1415f, reader.readFloat());
|
||||
assertEquals(2.72, reader.readDouble());
|
||||
assertEquals("lolcat", reader.readUTF());
|
||||
assertTrue(reader.readBoolean());
|
||||
assertEquals(4, reader.readInt());
|
||||
assertEquals("blob", readBlob(reader, 4));
|
||||
}
|
||||
|
||||
private void assertHeader(DataInputStream reader) throws IOException {
|
||||
assertEquals(COLUMN_NAMES.length, reader.readInt());
|
||||
for (int i = 0; i < COLUMN_NAMES.length; i++) {
|
||||
assertEquals(COLUMN_NAMES[i], reader.readUTF());
|
||||
assertEquals(COLUMN_TYPES[i], reader.readByte());
|
||||
}
|
||||
}
|
||||
|
||||
private String readBlob(InputStream reader, int length) throws Exception {
|
||||
if (length == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
byte[] blob = new byte[length];
|
||||
assertEquals(length, reader.read(blob));
|
||||
return new String(blob);
|
||||
}
|
||||
}
|
||||
+293
@@ -0,0 +1,293 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.backup;
|
||||
|
||||
import com.google.android.apps.mytracks.content.ContentTypeIds;
|
||||
|
||||
import android.content.ContentValues;
|
||||
import android.net.Uri;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests for {@link DatabaseImporter}.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class DatabaseImporterTest extends TestCase {
|
||||
|
||||
private static final Uri DESTINATION_URI = Uri.parse("http://www.google.com/");
|
||||
private static final int TEST_BULK_SIZE = 10;
|
||||
private ArrayList<ContentValues> insertedValues;
|
||||
|
||||
private class TestableDatabaseImporter extends DatabaseImporter {
|
||||
public TestableDatabaseImporter(boolean readNullFields) {
|
||||
super(DESTINATION_URI, null, readNullFields, TEST_BULK_SIZE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBulkInsert(ContentValues[] values) {
|
||||
insertedValues.ensureCapacity(insertedValues.size() + values.length);
|
||||
|
||||
// We need to make a copy of the values since the objects are re-used
|
||||
for (ContentValues contentValues : values) {
|
||||
insertedValues.add(new ContentValues(contentValues));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
insertedValues = new ArrayList<ContentValues>();
|
||||
}
|
||||
|
||||
public void testImportAllRows() throws Exception {
|
||||
testImportAllRows(false);
|
||||
}
|
||||
|
||||
public void testImportAllRows_readNullFields() throws Exception {
|
||||
testImportAllRows(true);
|
||||
}
|
||||
|
||||
private void testImportAllRows(boolean readNullFields) throws Exception {
|
||||
// Create a fake data stream to be read
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
|
||||
DataOutputStream writer = new DataOutputStream(outputStream);
|
||||
|
||||
writeFullHeader(writer);
|
||||
|
||||
// Add the number of rows
|
||||
writer.writeInt(2);
|
||||
|
||||
// Add a row with all fields present
|
||||
writer.writeLong(0x7F);
|
||||
writer.writeInt(42);
|
||||
writer.writeBoolean(true);
|
||||
writer.writeUTF("lolcat");
|
||||
writer.writeFloat(3.1415f);
|
||||
writer.writeDouble(2.72);
|
||||
writer.writeLong(123456789L);
|
||||
writer.writeInt(4);
|
||||
writer.writeBytes("blob");
|
||||
|
||||
// Add a row with some missing fields
|
||||
writer.writeLong(0x15);
|
||||
writer.writeInt(42);
|
||||
if (readNullFields) writer.writeBoolean(false);
|
||||
writer.writeUTF("lolcat");
|
||||
if (readNullFields) writer.writeFloat(0.0f);
|
||||
writer.writeDouble(2.72);
|
||||
if (readNullFields) writer.writeLong(0L);
|
||||
if (readNullFields) writer.writeInt(0); // empty blob
|
||||
|
||||
writer.flush();
|
||||
|
||||
// Do the importing
|
||||
DatabaseImporter importer = new TestableDatabaseImporter(readNullFields);
|
||||
byte[] dataBytes = outputStream.toByteArray();
|
||||
importer.importAllRows(new DataInputStream(new ByteArrayInputStream(dataBytes)));
|
||||
|
||||
assertEquals(2, insertedValues.size());
|
||||
|
||||
// Verify the first row
|
||||
ContentValues value = insertedValues.get(0);
|
||||
assertEquals(value.toString(), 7, value.size());
|
||||
|
||||
assertValue(42, "col1", value);
|
||||
assertValue(true, "col2", value);
|
||||
assertValue("lolcat", "col3", value);
|
||||
assertValue(3.1415f, "col4", value);
|
||||
assertValue(2.72, "col5", value);
|
||||
assertValue(123456789L, "col6", value);
|
||||
assertBlobValue("blob", "col7", value);
|
||||
|
||||
// Verify the second row
|
||||
value = insertedValues.get(1);
|
||||
assertEquals(value.toString(), 3, value.size());
|
||||
|
||||
assertValue(42, "col1", value);
|
||||
assertValue("lolcat", "col3", value);
|
||||
assertValue(2.72, "col5", value);
|
||||
}
|
||||
|
||||
public void testImportAllRows_noRows() throws Exception {
|
||||
// Create a fake data stream to be read
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
|
||||
DataOutputStream writer = new DataOutputStream(outputStream);
|
||||
|
||||
writeFullHeader(writer);
|
||||
|
||||
// Add the number of rows
|
||||
writer.writeInt(0);
|
||||
|
||||
writer.flush();
|
||||
|
||||
// Do the importing
|
||||
DatabaseImporter importer = new TestableDatabaseImporter(false);
|
||||
byte[] dataBytes = outputStream.toByteArray();
|
||||
importer.importAllRows(new DataInputStream(new ByteArrayInputStream(dataBytes)));
|
||||
|
||||
assertTrue(insertedValues.isEmpty());
|
||||
}
|
||||
|
||||
public void testImportAllRows_emptyRows() throws Exception {
|
||||
testImportAllRowsWithEmptyRows(false);
|
||||
}
|
||||
|
||||
public void testImportAllRows_emptyRowsWithNulls() throws Exception {
|
||||
testImportAllRowsWithEmptyRows(true);
|
||||
}
|
||||
|
||||
private void testImportAllRowsWithEmptyRows(boolean readNullFields) throws Exception {
|
||||
// Create a fake data stream to be read
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
|
||||
DataOutputStream writer = new DataOutputStream(outputStream);
|
||||
|
||||
writeFullHeader(writer);
|
||||
|
||||
// Add the number of rows
|
||||
writer.writeInt(3);
|
||||
|
||||
// Add 2 rows with no fields
|
||||
for (int i = 0; i < 2; i++) {
|
||||
writer.writeLong(0);
|
||||
if (readNullFields) {
|
||||
writer.writeInt(0);
|
||||
writer.writeBoolean(false);
|
||||
writer.writeUTF("");
|
||||
writer.writeFloat(0.0f);
|
||||
writer.writeDouble(0.0);
|
||||
writer.writeLong(0L);
|
||||
writer.writeInt(0); // empty blob
|
||||
}
|
||||
}
|
||||
|
||||
// Add a row with some missing fields
|
||||
writer.writeLong(0x15);
|
||||
writer.writeInt(42);
|
||||
if (readNullFields) writer.writeBoolean(false);
|
||||
writer.writeUTF("lolcat");
|
||||
if (readNullFields) writer.writeFloat(0.0f);
|
||||
writer.writeDouble(2.72);
|
||||
if (readNullFields) writer.writeLong(0L);
|
||||
if (readNullFields) writer.writeInt(0); // empty blob
|
||||
|
||||
writer.flush();
|
||||
|
||||
// Do the importing
|
||||
DatabaseImporter importer = new TestableDatabaseImporter(readNullFields);
|
||||
byte[] dataBytes = outputStream.toByteArray();
|
||||
importer.importAllRows(new DataInputStream(new ByteArrayInputStream(dataBytes)));
|
||||
|
||||
assertEquals(insertedValues.toString(), 3, insertedValues.size());
|
||||
|
||||
ContentValues value = insertedValues.get(0);
|
||||
assertEquals(value.toString(), 0, value.size());
|
||||
|
||||
value = insertedValues.get(1);
|
||||
assertEquals(value.toString(), 0, value.size());
|
||||
|
||||
// Verify the third row (only one with values)
|
||||
value = insertedValues.get(2);
|
||||
assertEquals(value.toString(), 3, value.size());
|
||||
|
||||
assertFalse(value.containsKey("col2"));
|
||||
assertFalse(value.containsKey("col4"));
|
||||
assertFalse(value.containsKey("col6"));
|
||||
|
||||
assertValue(42, "col1", value);
|
||||
assertValue("lolcat", "col3", value);
|
||||
assertValue(2.72, "col5", value);
|
||||
}
|
||||
|
||||
public void testImportAllRows_bulks() throws Exception {
|
||||
// Create a fake data stream to be read
|
||||
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(1024);
|
||||
DataOutputStream writer = new DataOutputStream(outputStream);
|
||||
|
||||
// Add the header
|
||||
writer.writeInt(2);
|
||||
writer.writeUTF("col1");
|
||||
writer.writeByte(ContentTypeIds.INT_TYPE_ID);
|
||||
writer.writeUTF("col2");
|
||||
writer.writeByte(ContentTypeIds.STRING_TYPE_ID);
|
||||
|
||||
// Add lots of rows (so the insertions are split in multiple bulks)
|
||||
int numRows = TEST_BULK_SIZE * 5 / 2;
|
||||
writer.writeInt(numRows);
|
||||
for (int i = 0; i < numRows; i++) {
|
||||
writer.writeLong(3);
|
||||
writer.writeInt(i);
|
||||
writer.writeUTF(Integer.toString(i * 2));
|
||||
}
|
||||
|
||||
writer.flush();
|
||||
|
||||
// Do the importing
|
||||
DatabaseImporter importer = new TestableDatabaseImporter(false);
|
||||
byte[] dataBytes = outputStream.toByteArray();
|
||||
importer.importAllRows(new DataInputStream(new ByteArrayInputStream(dataBytes)));
|
||||
|
||||
// Verify the rows
|
||||
assertEquals(numRows, insertedValues.size());
|
||||
for (int i = 0; i < numRows; i++) {
|
||||
ContentValues value = insertedValues.get(i);
|
||||
assertEquals(value.toString(), 2, value.size());
|
||||
assertValue(i, "col1", value);
|
||||
assertValue(Integer.toString(i * 2), "col2", value);
|
||||
}
|
||||
}
|
||||
|
||||
private void writeFullHeader(DataOutputStream writer) throws IOException {
|
||||
// Add the header
|
||||
writer.writeInt(7);
|
||||
writer.writeUTF("col1");
|
||||
writer.writeByte(ContentTypeIds.INT_TYPE_ID);
|
||||
writer.writeUTF("col2");
|
||||
writer.writeByte(ContentTypeIds.BOOLEAN_TYPE_ID);
|
||||
writer.writeUTF("col3");
|
||||
writer.writeByte(ContentTypeIds.STRING_TYPE_ID);
|
||||
writer.writeUTF("col4");
|
||||
writer.writeByte(ContentTypeIds.FLOAT_TYPE_ID);
|
||||
writer.writeUTF("col5");
|
||||
writer.writeByte(ContentTypeIds.DOUBLE_TYPE_ID);
|
||||
writer.writeUTF("col6");
|
||||
writer.writeByte(ContentTypeIds.LONG_TYPE_ID);
|
||||
writer.writeUTF("col7");
|
||||
writer.writeByte(ContentTypeIds.BLOB_TYPE_ID);
|
||||
}
|
||||
|
||||
private <T> void assertValue(T expectedValue, String name, ContentValues values) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T value = (T) values.get(name);
|
||||
assertNotNull(value);
|
||||
assertEquals(expectedValue, value);
|
||||
}
|
||||
|
||||
private void assertBlobValue(String expectedValue, String name, ContentValues values ){
|
||||
byte[] blob = values.getAsByteArray(name);
|
||||
assertEquals(expectedValue, new String(blob));
|
||||
}
|
||||
}
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.backup;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests for {@link PreferenceBackupHelper}.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class PreferenceBackupHelperTest extends TestCase {
|
||||
private Map<String, ?> preferenceValues;
|
||||
private SharedPreferences preferences;
|
||||
private PreferenceBackupHelper preferenceBackupHelper;
|
||||
|
||||
/**
|
||||
* Mock shared preferences editor which does not persist state.
|
||||
*/
|
||||
private class MockPreferenceEditor implements SharedPreferences.Editor {
|
||||
private Map<String, Object> newPreferences = new HashMap<String, Object>(preferenceValues);
|
||||
|
||||
@Override
|
||||
public Editor clear() {
|
||||
newPreferences.clear();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean commit() {
|
||||
preferenceValues = newPreferences;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply() {
|
||||
commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editor putBoolean(String key, boolean value) {
|
||||
return put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editor putFloat(String key, float value) {
|
||||
return put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editor putInt(String key, int value) {
|
||||
return put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editor putLong(String key, long value) {
|
||||
return put(key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editor putString(String key, String value) {
|
||||
return put(key, value);
|
||||
}
|
||||
|
||||
public Editor putStringSet(String key, Set<String> value) {
|
||||
return put(key, value);
|
||||
}
|
||||
|
||||
private <T> Editor put(String key, T value) {
|
||||
newPreferences.put(key, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editor remove(String key) {
|
||||
newPreferences.remove(key);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock shared preferences which does not persist state.
|
||||
*/
|
||||
private class MockPreferences implements SharedPreferences {
|
||||
@Override
|
||||
public boolean contains(String key) {
|
||||
return preferenceValues.containsKey(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Editor edit() {
|
||||
return new MockPreferenceEditor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ?> getAll() {
|
||||
return preferenceValues;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(String key, boolean defValue) {
|
||||
return get(key, defValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFloat(String key, float defValue) {
|
||||
return get(key, defValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getInt(String key, int defValue) {
|
||||
return get(key, defValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLong(String key, long defValue) {
|
||||
return get(key, defValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString(String key, String defValue) {
|
||||
return get(key, defValue);
|
||||
}
|
||||
|
||||
public Set<String> getStringSet(String key, Set<String> defValue) {
|
||||
return get(key, defValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerOnSharedPreferenceChangeListener(
|
||||
OnSharedPreferenceChangeListener listener) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterOnSharedPreferenceChangeListener(
|
||||
OnSharedPreferenceChangeListener listener) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T get(String key, T defValue) {
|
||||
Object value = preferenceValues.get(key);
|
||||
if (value == null) return defValue;
|
||||
return (T) value;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
preferenceValues = new HashMap<String, Object>();
|
||||
preferences = new MockPreferences();
|
||||
preferenceBackupHelper = new PreferenceBackupHelper();
|
||||
}
|
||||
|
||||
public void testExportImportPreferences() throws Exception {
|
||||
// Populate with some initial values
|
||||
Editor editor = preferences.edit();
|
||||
editor.clear();
|
||||
editor.putBoolean("bool1", true);
|
||||
editor.putBoolean("bool2", false);
|
||||
editor.putFloat("flt1", 3.14f);
|
||||
editor.putInt("int1", 42);
|
||||
editor.putLong("long1", 123456789L);
|
||||
editor.putString("str1", "lolcat");
|
||||
editor.commit();
|
||||
|
||||
// Export it
|
||||
byte[] exported = preferenceBackupHelper.exportPreferences(preferences);
|
||||
|
||||
// Mess with the previous values
|
||||
editor = preferences.edit();
|
||||
editor.clear();
|
||||
editor.putString("str2", "Shouldn't be there after restore");
|
||||
editor.putBoolean("bool2", true);
|
||||
editor.commit();
|
||||
|
||||
// Import it back
|
||||
preferenceBackupHelper.importPreferences(exported, preferences);
|
||||
|
||||
assertFalse(preferences.contains("str2"));
|
||||
assertTrue(preferences.getBoolean("bool1", false));
|
||||
assertFalse(preferences.getBoolean("bool2", true));
|
||||
assertEquals(3.14f, preferences.getFloat("flt1", 0.0f));
|
||||
assertEquals(42, preferences.getInt("int1", 0));
|
||||
assertEquals(123456789L, preferences.getLong("long1", 0));
|
||||
assertEquals("lolcat", preferences.getString("str1", ""));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.docs;
|
||||
|
||||
import com.google.android.apps.mytracks.io.gdata.GDataWrapper;
|
||||
import com.google.wireless.gdata.client.GDataServiceClient;
|
||||
|
||||
import android.content.Context;
|
||||
import android.test.mock.MockContext;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Tests for {@link DocsHelper}, with the exception of
|
||||
* {@link DocsHelper#addTrackRow}, which is in
|
||||
* {@link DocsHelper_AddTrackRowTest}.
|
||||
*
|
||||
* @author Matthew Simmons
|
||||
*/
|
||||
public class DocsHelperTest extends TestCase {
|
||||
private Context mockContext = new MockContext();
|
||||
|
||||
// TODO(simmonmt): Use AndroidMock to mock this class. We do it the hard
|
||||
// way because use of AndroidMock to mock GDataWrapper triggers a compile
|
||||
// error in an unrelated file. Specifically, it causes a NoClassDefFound
|
||||
// exception for com.google.wireless.gdata2.client.AuthenticationException,
|
||||
// (wrongly) attributed to the first source file in the project. Using the
|
||||
// @UsesMocks(GDataWrapper.class) annotation is enough -- you don't have to
|
||||
// touch AndroidMock at all to get this failure.
|
||||
// The bug is filed with Android Mock as
|
||||
// http://code.google.com/p/android-mock/issues/detail?id=3
|
||||
private class MockGDataWrapper extends GDataWrapper<GDataServiceClient> {
|
||||
private final boolean returnValue;
|
||||
|
||||
MockGDataWrapper(boolean returnValue) {
|
||||
this.returnValue = returnValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean runQuery(QueryFunction<GDataServiceClient> queryFunction) {
|
||||
return returnValue;
|
||||
}
|
||||
}
|
||||
|
||||
public void testCreateSpreadsheet_noException() throws Exception {
|
||||
// Our mock GDataWrapper isn't able to affect the return value from
|
||||
// DocsHelper#createSpreadsheet. As such, we're only able to simulate the
|
||||
// case where there weren't any GData errors, but not spreadsheet ID was
|
||||
// actually returned. createSpreadsheet is defined to return null in that
|
||||
// situation.
|
||||
assertNull(new DocsHelper().createSpreadsheet(
|
||||
mockContext, new MockGDataWrapper(true), "sheetName"));
|
||||
}
|
||||
|
||||
public void testCreateSpreadsheet_exception() throws Exception {
|
||||
try {
|
||||
new DocsHelper().createSpreadsheet(
|
||||
mockContext, new MockGDataWrapper(false), "sheetName");
|
||||
fail();
|
||||
} catch (IOException expected) {}
|
||||
}
|
||||
|
||||
public void testRequestSpreadsheetId_noException() throws Exception {
|
||||
assertNull(new DocsHelper().requestSpreadsheetId(
|
||||
new MockGDataWrapper(true), "sheetName"));
|
||||
}
|
||||
|
||||
public void testRequestSpreadsheetId_exception() throws Exception {
|
||||
try {
|
||||
new DocsHelper().requestSpreadsheetId(new MockGDataWrapper(false),
|
||||
"sheetName");
|
||||
fail();
|
||||
} catch (IOException expected) {}
|
||||
}
|
||||
|
||||
public void testGetWorksheetId_noException() throws Exception {
|
||||
assertNull(new DocsHelper().getWorksheetId(new MockGDataWrapper(true),
|
||||
"sheetId"));
|
||||
}
|
||||
|
||||
public void testGetWorksheetId_exception() throws Exception {
|
||||
try {
|
||||
new DocsHelper().getWorksheetId(new MockGDataWrapper(false), "sheetId");
|
||||
fail();
|
||||
} catch (IOException expected) {}
|
||||
}
|
||||
}
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.docs;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.io.AuthManager;
|
||||
import com.google.android.apps.mytracks.stats.TripStatistics;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
import com.google.android.testing.mocking.AndroidMock;
|
||||
import com.google.android.testing.mocking.UsesMocks;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.test.mock.MockContext;
|
||||
import android.test.mock.MockResources;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* Tests for {@link DocsHelper#addTrackRow}
|
||||
*
|
||||
* @author Matthew Simmons
|
||||
*/
|
||||
public class DocsHelper_AddTrackRowTest extends TestCase {
|
||||
private static final long TIME = 1288721514000L;
|
||||
private static final DateFormat DATE_FORMAT = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
|
||||
|
||||
private static class StringWritingDocsHelper extends DocsHelper {
|
||||
String writtenSheetUri = null;
|
||||
String writtenData = null;
|
||||
|
||||
@Override
|
||||
protected void writeRowData(AuthManager trixAuth, String worksheetUri,
|
||||
String postText) {
|
||||
writtenSheetUri = worksheetUri;
|
||||
writtenData = postText;
|
||||
}
|
||||
}
|
||||
|
||||
public void testAddTrackRow_imperial() throws Exception {
|
||||
StringWritingDocsHelper docsHelper = new StringWritingDocsHelper() {
|
||||
@Override
|
||||
protected String getDisplayDate(Context context, long time) {
|
||||
return DATE_FORMAT.format(new Date(TIME));
|
||||
}
|
||||
};
|
||||
addTrackRow(docsHelper, false);
|
||||
|
||||
String expectedData =
|
||||
"<entry xmlns='http://www.w3.org/2005/Atom' "
|
||||
+ "xmlns:gsx='http://schemas.google.com/spreadsheets/2006/extended'>"
|
||||
+ "<gsx:name><![CDATA[trackName]]></gsx:name>"
|
||||
+ "<gsx:description><![CDATA[trackDescription]]></gsx:description>"
|
||||
+ "<gsx:date><![CDATA[" + DATE_FORMAT.format(new Date(TIME)) + "]]></gsx:date>"
|
||||
+ "<gsx:totaltime><![CDATA[0:00:05]]></gsx:totaltime>"
|
||||
+ "<gsx:movingtime><![CDATA[0:00:04]]></gsx:movingtime>"
|
||||
+ "<gsx:distance><![CDATA[12.43]]></gsx:distance>"
|
||||
+ "<gsx:distanceunit><![CDATA[mile]]></gsx:distanceunit>"
|
||||
+ "<gsx:averagespeed><![CDATA[8,947.75]]></gsx:averagespeed>"
|
||||
+ "<gsx:averagemovingspeed><![CDATA[11,184.68]]>"
|
||||
+ "</gsx:averagemovingspeed>"
|
||||
+ "<gsx:maxspeed><![CDATA[3,355.40]]></gsx:maxspeed>"
|
||||
+ "<gsx:speedunit><![CDATA[mph]]></gsx:speedunit>"
|
||||
+ "<gsx:elevationgain><![CDATA[19,685]]></gsx:elevationgain>"
|
||||
+ "<gsx:minelevation><![CDATA[-1,640]]></gsx:minelevation>"
|
||||
+ "<gsx:maxelevation><![CDATA[1,804]]></gsx:maxelevation>"
|
||||
+ "<gsx:elevationunit><![CDATA[feet]]></gsx:elevationunit>"
|
||||
+ "<gsx:map>"
|
||||
+ "<![CDATA[https://maps.google.com/maps/ms?msa=0&msid=trackMapId]]>"
|
||||
+ "</gsx:map>"
|
||||
+ "</entry>";
|
||||
|
||||
assertEquals(
|
||||
"https://spreadsheets.google.com/feeds/list/ssid/wsid/private/full",
|
||||
docsHelper.writtenSheetUri);
|
||||
assertEquals(expectedData, docsHelper.writtenData);
|
||||
}
|
||||
|
||||
public void testAddTrackRow_metric() throws Exception {
|
||||
StringWritingDocsHelper docsHelper = new StringWritingDocsHelper() {
|
||||
@Override
|
||||
protected String getDisplayDate(Context context, long time) {
|
||||
return DATE_FORMAT.format(new Date(TIME));
|
||||
}
|
||||
};
|
||||
addTrackRow(docsHelper, true);
|
||||
|
||||
// The imperial test verifies that the tags come out in the proper order,
|
||||
// and with the proper names. We need only verify that the labels are
|
||||
// correct, and that at least one of the unit-dependent value tags is
|
||||
// correct.
|
||||
assertTrue(docsHelper.writtenData.contains(
|
||||
"<gsx:distanceunit><![CDATA[km]]></gsx:distanceunit>"));
|
||||
assertTrue(docsHelper.writtenData.contains(
|
||||
"<gsx:speedunit><![CDATA[kph]]></gsx:speedunit>"));
|
||||
assertTrue(docsHelper.writtenData.contains(
|
||||
"<gsx:elevationunit><![CDATA[meter]]></gsx:elevationunit>"));
|
||||
|
||||
assertTrue(docsHelper.writtenData.contains(
|
||||
"<gsx:distance><![CDATA[20.00]]></gsx:distance>"));
|
||||
}
|
||||
|
||||
/** Adds a row to the spreadsheet, using the provided helper. */
|
||||
@UsesMocks({AuthManager.class, MockResources.class, Track.class})
|
||||
private void addTrackRow(DocsHelper docsHelper, boolean useMetric)
|
||||
throws IOException {
|
||||
final Resources mockResources = AndroidMock.createMock(MockResources.class);
|
||||
|
||||
if (useMetric) {
|
||||
AndroidMock.expect(mockResources.getString(R.string.unit_kilometer))
|
||||
.andReturn("km");
|
||||
AndroidMock.expect(mockResources.getString(R.string.kilometer_per_hour))
|
||||
.andReturn("kph");
|
||||
AndroidMock.expect(mockResources.getString(R.string.unit_meter))
|
||||
.andReturn("meter");
|
||||
} else {
|
||||
AndroidMock.expect(mockResources.getString(R.string.unit_mile))
|
||||
.andReturn("mile");
|
||||
AndroidMock.expect(mockResources.getString(R.string.mile_per_hour))
|
||||
.andReturn("mph");
|
||||
AndroidMock.expect(mockResources.getString(R.string.unit_feet))
|
||||
.andReturn("feet");
|
||||
}
|
||||
AndroidMock.replay(mockResources);
|
||||
|
||||
Context mockContext = new MockContext() {
|
||||
@Override
|
||||
public Resources getResources() {
|
||||
return mockResources;
|
||||
}
|
||||
};
|
||||
|
||||
AuthManager mockAuthManager = AndroidMock.createMock(AuthManager.class);
|
||||
AndroidMock.replay(mockAuthManager);
|
||||
|
||||
TripStatistics stats = new TripStatistics();
|
||||
stats.setStartTime(TIME);
|
||||
stats.setTotalTime(5000);
|
||||
stats.setMovingTime(4000);
|
||||
stats.setTotalDistance(20000);
|
||||
stats.setMaxSpeed(1500);
|
||||
stats.setTotalElevationGain(6000);
|
||||
stats.setMinElevation(-500);
|
||||
stats.setMaxElevation(550);
|
||||
|
||||
Track track = new Track();
|
||||
track.setName("trackName");
|
||||
track.setDescription("trackDescription");
|
||||
track.setMapId("trackMapId");
|
||||
track.setStatistics(stats);
|
||||
|
||||
docsHelper.addTrackRow(mockContext, mockAuthManager, "ssid", "wsid",
|
||||
track, useMetric);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.docs;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
/**
|
||||
* This class tests {@link DocsTagBuilder}
|
||||
*
|
||||
* @author Matthew Simmons
|
||||
*/
|
||||
public class DocsTagBuilderTest extends TestCase {
|
||||
public void testAppend() {
|
||||
assertEquals("<gsx:tag><![CDATA[value]]></gsx:tag>",
|
||||
new DocsTagBuilder(false).append("tag", "value").build());
|
||||
}
|
||||
|
||||
public void testMultiAppend() {
|
||||
String actual = new DocsTagBuilder(false)
|
||||
.append("tag1", "value1")
|
||||
.append("tag2", "value2")
|
||||
.build();
|
||||
|
||||
assertEquals("<gsx:tag1><![CDATA[value1]]></gsx:tag1>"
|
||||
+ "<gsx:tag2><![CDATA[value2]]></gsx:tag2>", actual);
|
||||
}
|
||||
|
||||
public void testAppendLargeUnits_imperial() {
|
||||
assertEquals("<gsx:tag><![CDATA[62.14]]></gsx:tag>",
|
||||
new DocsTagBuilder(false).appendLargeUnits("tag", 100.0).build());
|
||||
}
|
||||
|
||||
public void testAppendLargeUnits_metric() {
|
||||
assertEquals("<gsx:tag><![CDATA[100.00]]></gsx:tag>",
|
||||
new DocsTagBuilder(true).appendLargeUnits("tag", 100.0).build());
|
||||
}
|
||||
|
||||
public void testAppendSmallUnits_imperial() {
|
||||
assertEquals("<gsx:tag><![CDATA[328]]></gsx:tag>",
|
||||
new DocsTagBuilder(false).appendSmallUnits("tag", 100.0).build());
|
||||
}
|
||||
|
||||
public void testAppendSmallUnits_metric() {
|
||||
assertEquals("<gsx:tag><![CDATA[100]]></gsx:tag>",
|
||||
new DocsTagBuilder(true).appendSmallUnits("tag", 100.0).build());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
// Copyright 2010 Google Inc. All Rights Reserved.
|
||||
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
/**
|
||||
* Tests for the CSV track exporter.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class CsvTrackWriterTest extends TrackFormatWriterTest {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,295 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import static com.google.android.testing.mocking.AndroidMock.eq;
|
||||
import static com.google.android.testing.mocking.AndroidMock.expect;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.TracksColumns;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
|
||||
import com.google.android.apps.mytracks.io.file.GpxImporter;
|
||||
import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory;
|
||||
import com.google.android.testing.mocking.AndroidMock;
|
||||
import com.google.android.testing.mocking.UsesMocks;
|
||||
|
||||
import android.content.ContentUris;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.net.Uri;
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Arrays;
|
||||
import java.util.SimpleTimeZone;
|
||||
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.easymock.Capture;
|
||||
import org.easymock.IArgumentMatcher;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Tests for the GPX importer.
|
||||
*
|
||||
* @author Steffen Horlacher
|
||||
*/
|
||||
public class GpxImporterTest extends AndroidTestCase {
|
||||
|
||||
private static final String TRACK_NAME = "blablub";
|
||||
private static final String TRACK_DESC = "s'Laebe isch koi Schlotzer";
|
||||
|
||||
private static final String TRACK_LAT_1 = "48.768364";
|
||||
private static final String TRACK_LON_1 = "9.177886";
|
||||
private static final String TRACK_ELE_1 = "324.0";
|
||||
private static final String TRACK_TIME_1 = "2010-04-22T18:21:00Z";
|
||||
|
||||
private static final String TRACK_LAT_2 = "48.768374";
|
||||
private static final String TRACK_LON_2 = "9.177816";
|
||||
private static final String TRACK_ELE_2 = "333.0";
|
||||
private static final String TRACK_TIME_2 = "2010-04-22T18:21:50.123";
|
||||
|
||||
private static final SimpleDateFormat DATE_FORMAT1 =
|
||||
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
|
||||
private static final SimpleDateFormat DATE_FORMAT2 =
|
||||
new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
|
||||
static {
|
||||
// We can't omit the timezones in the test, otherwise it'll use the local
|
||||
// timezone and fail depending on where the test runner is.
|
||||
SimpleTimeZone utc = new SimpleTimeZone(0, "UTC");
|
||||
DATE_FORMAT1.setTimeZone(utc);
|
||||
DATE_FORMAT2.setTimeZone(utc);
|
||||
}
|
||||
|
||||
// TODO: use real files from different sources with more track points.
|
||||
private static final String VALID_TEST_GPX = "<gpx><trk><name><![CDATA["
|
||||
+ TRACK_NAME + "]]></name><desc><![CDATA[" + TRACK_DESC
|
||||
+ "]]></desc><trkseg>" + "<trkpt lat=\"" + TRACK_LAT_1 + "\" lon=\""
|
||||
+ TRACK_LON_1 + "\"><ele>" + TRACK_ELE_1 + "</ele><time>" + TRACK_TIME_1
|
||||
+ "</time></trkpt> +" + "<trkpt lat=\"" + TRACK_LAT_2 + "\" lon=\""
|
||||
+ TRACK_LON_2 + "\"><ele>" + TRACK_ELE_2 + "</ele><time>" + TRACK_TIME_2
|
||||
+ "</time></trkpt>" + "</trkseg></trk></gpx>";
|
||||
|
||||
// invalid xml
|
||||
private static final String INVALID_XML_TEST_GPX = VALID_TEST_GPX.substring(
|
||||
0, VALID_TEST_GPX.length() - 50);
|
||||
private static final String INVALID_LOCATION_TEST_GPX = VALID_TEST_GPX
|
||||
.replaceAll(TRACK_LAT_1, "1000.0");
|
||||
private static final String INVALID_TIME_TEST_GPX = VALID_TEST_GPX
|
||||
.replaceAll(TRACK_TIME_1, "invalid");
|
||||
private static final String INVALID_ALTITUDE_TEST_GPX = VALID_TEST_GPX
|
||||
.replaceAll(TRACK_ELE_1, "invalid");
|
||||
private static final String INVALID_LATITUDE_TEST_GPX = VALID_TEST_GPX
|
||||
.replaceAll(TRACK_LAT_1, "invalid");
|
||||
private static final String INVALID_LONGITUDE_TEST_GPX = VALID_TEST_GPX
|
||||
.replaceAll(TRACK_LON_1, "invalid");
|
||||
|
||||
private static final long TRACK_ID = 1;
|
||||
private static final long TRACK_POINT_ID_1 = 1;
|
||||
private static final long TRACK_POINT_ID_2 = 2;
|
||||
|
||||
private static final Uri TRACK_ID_URI = ContentUris.appendId(
|
||||
TracksColumns.CONTENT_URI.buildUpon(), TRACK_ID).build();
|
||||
|
||||
private MyTracksProviderUtils providerUtils;
|
||||
|
||||
private Factory oldProviderUtilsFactory;
|
||||
|
||||
@UsesMocks(MyTracksProviderUtils.class)
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
providerUtils = AndroidMock.createMock(MyTracksProviderUtils.class);
|
||||
oldProviderUtilsFactory =
|
||||
TestingProviderUtilsFactory.installWithInstance(providerUtils);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
TestingProviderUtilsFactory.restoreOldFactory(oldProviderUtilsFactory);
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test import success.
|
||||
*/
|
||||
public void testImportSuccess() throws Exception {
|
||||
Capture<Track> trackParam = new Capture<Track>();
|
||||
|
||||
Location loc1 = new Location(LocationManager.GPS_PROVIDER);
|
||||
loc1.setTime(DATE_FORMAT2.parse(TRACK_TIME_1).getTime());
|
||||
loc1.setLatitude(Double.parseDouble(TRACK_LAT_1));
|
||||
loc1.setLongitude(Double.parseDouble(TRACK_LON_1));
|
||||
loc1.setAltitude(Double.parseDouble(TRACK_ELE_1));
|
||||
|
||||
Location loc2 = new Location(LocationManager.GPS_PROVIDER);
|
||||
loc2.setTime(DATE_FORMAT1.parse(TRACK_TIME_2).getTime());
|
||||
loc2.setLatitude(Double.parseDouble(TRACK_LAT_2));
|
||||
loc2.setLongitude(Double.parseDouble(TRACK_LON_2));
|
||||
loc2.setAltitude(Double.parseDouble(TRACK_ELE_2));
|
||||
|
||||
expect(providerUtils.insertTrack(AndroidMock.capture(trackParam)))
|
||||
.andReturn(TRACK_ID_URI);
|
||||
|
||||
expect(providerUtils.getLastLocationId(TRACK_ID)).andReturn(TRACK_POINT_ID_1).andReturn(TRACK_POINT_ID_2);
|
||||
|
||||
// A flush happens after the first insertion to get the starting point ID,
|
||||
// which is why we get two calls
|
||||
expect(providerUtils.bulkInsertTrackPoints(LocationsMatcher.eqLoc(loc1),
|
||||
eq(1), eq(TRACK_ID))).andReturn(1);
|
||||
expect(providerUtils.bulkInsertTrackPoints(LocationsMatcher.eqLoc(loc2),
|
||||
eq(1), eq(TRACK_ID))).andReturn(1);
|
||||
|
||||
providerUtils.updateTrack(AndroidMock.capture(trackParam));
|
||||
|
||||
AndroidMock.replay(providerUtils);
|
||||
|
||||
InputStream is = new ByteArrayInputStream(VALID_TEST_GPX.getBytes());
|
||||
GpxImporter.importGPXFile(is, providerUtils);
|
||||
|
||||
AndroidMock.verify(providerUtils);
|
||||
|
||||
// verify track parameter
|
||||
Track track = trackParam.getValue();
|
||||
assertEquals(TRACK_NAME, track.getName());
|
||||
assertEquals(TRACK_DESC, track.getDescription());
|
||||
assertEquals(DATE_FORMAT2.parse(TRACK_TIME_1).getTime(), track.getStatistics()
|
||||
.getStartTime());
|
||||
assertNotSame(-1, track.getStartId());
|
||||
assertNotSame(-1, track.getStopId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test with invalid location - track should be deleted.
|
||||
*/
|
||||
public void testImportLocationFailure() throws ParserConfigurationException, IOException {
|
||||
testInvalidXML(INVALID_LOCATION_TEST_GPX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test with invalid time - track should be deleted.
|
||||
*/
|
||||
public void testImportTimeFailure() throws ParserConfigurationException, IOException {
|
||||
testInvalidXML(INVALID_TIME_TEST_GPX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test with invalid xml - track should be deleted.
|
||||
*/
|
||||
public void testImportXMLFailure() throws ParserConfigurationException, IOException {
|
||||
testInvalidXML(INVALID_XML_TEST_GPX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test with invalid altitude - track should be deleted.
|
||||
*/
|
||||
public void testImportInvalidAltitude() throws ParserConfigurationException, IOException {
|
||||
testInvalidXML(INVALID_ALTITUDE_TEST_GPX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test with invalid latitude - track should be deleted.
|
||||
*/
|
||||
public void testImportInvalidLatitude() throws ParserConfigurationException, IOException {
|
||||
testInvalidXML(INVALID_LATITUDE_TEST_GPX);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test with invalid longitude - track should be deleted.
|
||||
*/
|
||||
public void testImportInvalidLongitude() throws ParserConfigurationException, IOException {
|
||||
testInvalidXML(INVALID_LONGITUDE_TEST_GPX);
|
||||
}
|
||||
|
||||
private void testInvalidXML(String xml) throws ParserConfigurationException,
|
||||
IOException {
|
||||
expect(providerUtils.insertTrack((Track) AndroidMock.anyObject()))
|
||||
.andReturn(TRACK_ID_URI);
|
||||
|
||||
expect(providerUtils.bulkInsertTrackPoints((Location[]) AndroidMock.anyObject(),
|
||||
AndroidMock.anyInt(), AndroidMock.anyLong())).andStubReturn(1);
|
||||
expect(providerUtils.getLastLocationId(TRACK_ID)).andStubReturn(TRACK_POINT_ID_1);
|
||||
|
||||
providerUtils.deleteTrack(TRACK_ID);
|
||||
|
||||
AndroidMock.replay(providerUtils);
|
||||
|
||||
InputStream is = new ByteArrayInputStream(xml.getBytes());
|
||||
try {
|
||||
GpxImporter.importGPXFile(is, providerUtils);
|
||||
} catch (SAXException e) {
|
||||
// expected exception
|
||||
}
|
||||
|
||||
AndroidMock.verify(providerUtils);
|
||||
}
|
||||
|
||||
/**
|
||||
* Workaround because of capture bug 2617107 in easymock:
|
||||
* http://sourceforge.net
|
||||
* /tracker/?func=detail&aid=2617107&group_id=82958&atid=567837
|
||||
*/
|
||||
private static class LocationsMatcher implements IArgumentMatcher {
|
||||
private final Location[] matchLocs;
|
||||
|
||||
private LocationsMatcher(Location[] expected) {
|
||||
this.matchLocs = expected;
|
||||
}
|
||||
|
||||
public static Location[] eqLoc(Location[] expected) {
|
||||
IArgumentMatcher matcher = new LocationsMatcher(expected);
|
||||
AndroidMock.reportMatcher(matcher);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Location[] eqLoc(Location expected) {
|
||||
return eqLoc(new Location[] { expected});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuffer buf) {
|
||||
buf.append("eqLoc(").append(Arrays.toString(matchLocs)).append(")");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object obj) {
|
||||
if (! (obj instanceof Location[])) { return false; }
|
||||
Location[] locs = (Location[]) obj;
|
||||
if (locs.length < matchLocs.length) { return false; }
|
||||
|
||||
// Only check the first elements (those that will be taken into account)
|
||||
for (int i = 0; i < matchLocs.length; i++) {
|
||||
if (!locationsMatch(locs[i], matchLocs[i])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean locationsMatch(Location loc1, Location loc2) {
|
||||
return (loc1.getTime() == loc2.getTime()) &&
|
||||
(loc1.getLatitude() == loc2.getLatitude()) &&
|
||||
(loc1.getLongitude() == loc2.getLongitude()) &&
|
||||
(loc1.getAltitude() == loc2.getAltitude());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2010 Google Inc. All Rights Reserved.
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import com.google.android.apps.mytracks.io.file.GpxTrackWriter;
|
||||
import com.google.android.apps.mytracks.io.file.TrackFormatWriter;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Tests for the GPX track exporter.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class GpxTrackWriterTest extends TrackFormatWriterTest {
|
||||
|
||||
public void testXmlOutput() throws Exception {
|
||||
TrackFormatWriter writer = new GpxTrackWriter();
|
||||
String result = writeTrack(writer);
|
||||
Document doc = parseXmlDocument(result);
|
||||
|
||||
Element gpxTag = getChildElement(doc, "gpx");
|
||||
Element trackTag = getChildElement(gpxTag, "trk");
|
||||
assertEquals(TRACK_NAME, getChildTextValue(trackTag, "name"));
|
||||
assertEquals(TRACK_DESCRIPTION, getChildTextValue(trackTag, "desc"));
|
||||
assertEquals(Long.toString(TRACK_ID),
|
||||
getChildTextValue(trackTag, "number"));
|
||||
List<Element> segmentTags = getChildElements(trackTag, "trkseg", 2);
|
||||
List<Element> segPointTags = getChildElements(segmentTags.get(0), "trkpt", 2);
|
||||
assertTagMatchesLocation(segPointTags.get(0),
|
||||
"0", "0", "1970-01-01T02:46:40Z", "0");
|
||||
assertTagMatchesLocation(segPointTags.get(1),
|
||||
"1", "-1", "1970-01-01T02:46:41Z", "5000000");
|
||||
|
||||
segPointTags = getChildElements(segmentTags.get(1), "trkpt", 2);
|
||||
assertTagMatchesLocation(segPointTags.get(0),
|
||||
"2", "-2", "1970-01-01T02:46:42Z", "10000000");
|
||||
assertTagMatchesLocation(segPointTags.get(1),
|
||||
"3", "-3", "1970-01-01T02:46:43Z", "15000000");
|
||||
|
||||
List<Element> waypointTags = getChildElements(gpxTag, "wpt", 2);
|
||||
Element wptTag = waypointTags.get(0);
|
||||
assertEquals(WAYPOINT1_NAME, getChildTextValue(wptTag, "name"));
|
||||
assertEquals(WAYPOINT1_DESCRIPTION, getChildTextValue(wptTag, "desc"));
|
||||
assertTagMatchesLocation(wptTag,
|
||||
"1", "-1", "1970-01-01T02:46:41Z", "5000000");
|
||||
|
||||
wptTag = waypointTags.get(1);
|
||||
assertEquals(WAYPOINT2_NAME, getChildTextValue(wptTag, "name"));
|
||||
assertEquals(WAYPOINT2_DESCRIPTION, getChildTextValue(wptTag, "desc"));
|
||||
assertTagMatchesLocation(wptTag,
|
||||
"2", "-2", "1970-01-01T02:46:42Z", "10000000");
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given tag describes the location given by the
|
||||
* Strings lat, lon, time, and ele.
|
||||
*/
|
||||
private void assertTagMatchesLocation(Element tag, String lat,
|
||||
String lon, String time, String ele) {
|
||||
assertEquals(lat, tag.getAttribute("lat"));
|
||||
assertEquals(lon, tag.getAttribute("lon"));
|
||||
assertEquals(time, getChildTextValue(tag, "time"));
|
||||
assertEquals(ele, getChildTextValue(tag, "ele"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
// Copyright 2010 Google Inc. All Rights Reserved.
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.io.file.KmlTrackWriter;
|
||||
import com.google.android.apps.mytracks.util.StringUtils;
|
||||
|
||||
import android.location.Location;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Tests for the KML track exporter.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class KmlTrackWriterTest extends TrackFormatWriterTest {
|
||||
private static final String FULL_TRACK_DESCRIPTION = "full track description";
|
||||
|
||||
/**
|
||||
* A fake version of {@link StringUtils} which returns a fixed track
|
||||
* description, thus not depending on the context.
|
||||
*/
|
||||
private class FakeStringUtils extends StringUtils {
|
||||
public FakeStringUtils() {
|
||||
super(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateTrackDescription(Track trackToDescribe,
|
||||
Vector<Double> distances, Vector<Double> elevations) {
|
||||
assertSame(KmlTrackWriterTest.super.track, trackToDescribe);
|
||||
assertTrue(distances.isEmpty());
|
||||
assertTrue(elevations.isEmpty());
|
||||
return FULL_TRACK_DESCRIPTION;
|
||||
}
|
||||
}
|
||||
|
||||
public void testXmlOutput() throws Exception {
|
||||
KmlTrackWriter writer = new KmlTrackWriter(new FakeStringUtils());
|
||||
String result = writeTrack(writer);
|
||||
Document doc = parseXmlDocument(result);
|
||||
|
||||
Element kmlTag = getChildElement(doc, "kml");
|
||||
Element docTag = getChildElement(kmlTag, "Document");
|
||||
assertEquals(TRACK_NAME, getChildTextValue(docTag, "name"));
|
||||
assertEquals(TRACK_DESCRIPTION, getChildTextValue(docTag, "description"));
|
||||
|
||||
// There are 5 placemarks - start, segments, end, waypoint 1, waypoint 2
|
||||
List<Element> placemarkTags = getChildElements(docTag, "Placemark", 5);
|
||||
assertTagIsPlacemark(placemarkTags.get(0),
|
||||
"(Start)", TRACK_DESCRIPTION, location1);
|
||||
assertTagIsPlacemark(placemarkTags.get(2),
|
||||
"(End)", FULL_TRACK_DESCRIPTION, location4);
|
||||
assertTagIsPlacemark(placemarkTags.get(3),
|
||||
WAYPOINT1_NAME, WAYPOINT1_DESCRIPTION, location2);
|
||||
assertTagIsPlacemark(placemarkTags.get(4),
|
||||
WAYPOINT2_NAME, WAYPOINT2_DESCRIPTION, location3);
|
||||
|
||||
Element trackPlacemarkTag = placemarkTags.get(1);
|
||||
assertEquals(TRACK_NAME, getChildTextValue(trackPlacemarkTag, "name"));
|
||||
assertEquals(TRACK_DESCRIPTION,
|
||||
getChildTextValue(trackPlacemarkTag, "description"));
|
||||
Element geometryTag = getChildElement(trackPlacemarkTag, "MultiGeometry");
|
||||
List<Element> segmentTags = getChildElements(geometryTag, "LineString", 2);
|
||||
assertTagHasPoints(segmentTags.get(0), location1, location2);
|
||||
assertTagHasPoints(segmentTags.get(1), location3, location4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given XML tag is a placemark with the given properties.
|
||||
*
|
||||
* @param tag the tag to analyze
|
||||
* @param name the expected name for the placemark
|
||||
* @param description the expected description for the placemark
|
||||
* @param location the expected location of the placemark
|
||||
*/
|
||||
private void assertTagIsPlacemark(Element tag, String name,
|
||||
String description, Location location) {
|
||||
assertEquals(name, getChildTextValue(tag, "name"));
|
||||
assertEquals(description, getChildTextValue(tag, "description"));
|
||||
Element pointTag = getChildElement(tag, "Point");
|
||||
String expectedCoords =
|
||||
location.getLongitude() + "," + location.getLatitude();
|
||||
String actualCoords = getChildTextValue(pointTag, "coordinates");
|
||||
assertEquals(expectedCoords, actualCoords);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given tag has a "coordinates" subtag with the given
|
||||
* locations.
|
||||
*
|
||||
* @param tag the tag to analyze
|
||||
* @param locs the locations to expect in the coordinates
|
||||
*/
|
||||
private void assertTagHasPoints(Element tag, Location... locs) {
|
||||
StringBuilder expectedBuilder = new StringBuilder();
|
||||
for (Location loc : locs) {
|
||||
expectedBuilder.append(loc.getLongitude());
|
||||
expectedBuilder.append(',');
|
||||
expectedBuilder.append(loc.getLatitude());
|
||||
expectedBuilder.append(',');
|
||||
expectedBuilder.append(loc.getAltitude());
|
||||
expectedBuilder.append(' ');
|
||||
}
|
||||
String expectedCoordinates = expectedBuilder.toString().trim();
|
||||
String actualCoordinates = getChildTextValue(tag, "coordinates").trim();
|
||||
assertEquals(expectedCoordinates, actualCoordinates);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* A simple, fake {@link TrackWriter} subclass with all methods mocked out.
|
||||
* Tests are expected to override {@link #writeTrack} and/or
|
||||
* {@link #writeTrackAsync}, at the very least.
|
||||
*
|
||||
* @author Matthew Simmons
|
||||
*
|
||||
*/
|
||||
public class MockTrackWriter implements TrackWriter {
|
||||
public OnCompletionListener onCompletionListener;
|
||||
public OnWriteListener onWriteListener;
|
||||
|
||||
@Override
|
||||
public void setOnCompletionListener(OnCompletionListener onCompletionListener) {
|
||||
this.onCompletionListener = onCompletionListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOnWriteListener(OnWriteListener onWriteListener) {
|
||||
this.onWriteListener = onWriteListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDirectory(File directory) {
|
||||
throw new UnsupportedOperationException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAbsolutePath() {
|
||||
throw new UnsupportedOperationException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTrackAsync() {
|
||||
throw new UnsupportedOperationException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeTrack() {
|
||||
throw new UnsupportedOperationException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopWriteTrack() {
|
||||
throw new UnsupportedOperationException("not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean wasSuccess() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getErrorMessage() {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
// Copyright 2010 Google Inc. All Rights Reserved.
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.io.file.TcxTrackWriter;
|
||||
import com.google.android.apps.mytracks.io.file.TrackFormatWriter;
|
||||
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Tests for the GPX track exporter.
|
||||
*
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class TcxTrackWriterTest extends TrackFormatWriterTest {
|
||||
private DateFormat timestampFormatter;
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
timestampFormatter = new SimpleDateFormat(TcxTrackWriter.TIMESTAMP_FORMAT);
|
||||
timestampFormatter.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
}
|
||||
|
||||
public void testXmlOutput() throws Exception {
|
||||
TrackFormatWriter writer = new TcxTrackWriter(getContext());
|
||||
String result = writeTrack(writer);
|
||||
Document doc = parseXmlDocument(result);
|
||||
|
||||
Element root = getChildElement(doc, "TrainingCenterDatabase");
|
||||
Element activitiesTag = getChildElement(root, "Activities");
|
||||
Element activityTag = getChildElement(activitiesTag, "Activity");
|
||||
Element lapTag = getChildElement(activityTag, "Lap");
|
||||
|
||||
List<Element> segmentTags = getChildElements(lapTag, "Track", 2);
|
||||
Element segment1Tag = segmentTags.get(0);
|
||||
Element segment2Tag = segmentTags.get(1);
|
||||
List<Element> seg1PointTags = getChildElements(segment1Tag, "Trackpoint", 2);
|
||||
List<Element> seg2PointTags = getChildElements(segment2Tag, "Trackpoint", 2);
|
||||
assertTagsMatchPoints(seg1PointTags, location1, location2);
|
||||
assertTagsMatchPoints(seg2PointTags, location3, location4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given tags describe the given points, in the same order.
|
||||
*/
|
||||
private void assertTagsMatchPoints(List<Element> tags, MyTracksLocation... locs) {
|
||||
assertEquals(locs.length, tags.size());
|
||||
for (int i = 0; i < locs.length; i++) {
|
||||
Element tag = tags.get(i);
|
||||
MyTracksLocation loc = locs[i];
|
||||
|
||||
assertTagMatchesLocation(tag, loc);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given tag describes the given location.
|
||||
*/
|
||||
private void assertTagMatchesLocation(Element tag, MyTracksLocation loc) {
|
||||
Element posTag = getChildElement(tag, "Position");
|
||||
assertEquals(Double.toString(loc.getLatitude()),
|
||||
getChildTextValue(posTag, "LatitudeDegrees"));
|
||||
assertEquals(Double.toString(loc.getLongitude()),
|
||||
getChildTextValue(posTag, "LongitudeDegrees"));
|
||||
|
||||
assertEquals(timestampFormatter.format(loc.getTime()),
|
||||
getChildTextValue(tag, "Time"));
|
||||
assertEquals(Double.toString(loc.getAltitude()),
|
||||
getChildTextValue(tag, "AltitudeMeters"));
|
||||
assertTrue(loc.getSensorDataSet() != null);
|
||||
Sensor.SensorDataSet sds = loc.getSensorDataSet();
|
||||
|
||||
List<Element> bpm = getChildElements(tag, "HeartRateBpm", 1);
|
||||
assertEquals(Integer.toString(sds.getHeartRate().getValue()),
|
||||
getChildTextValue(bpm.get(0), "Value"));
|
||||
|
||||
List<Element> ext = getChildElements(tag, "Extensions", 1);
|
||||
List<Element> tpx = getChildElements(ext.get(0), "TPX", 1);
|
||||
assertEquals(Integer.toString(sds.getPower().getValue()),
|
||||
getChildTextValue(tpx.get(0), "Watts"));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2010 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import static com.google.android.testing.mocking.AndroidMock.expect;
|
||||
|
||||
import com.google.android.apps.mytracks.io.file.TempFileCleaner;
|
||||
import com.google.android.testing.mocking.AndroidMock;
|
||||
import com.google.android.testing.mocking.UsesMocks;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class TempFileCleanerTest extends AndroidTestCase {
|
||||
|
||||
@UsesMocks({
|
||||
File.class,
|
||||
})
|
||||
|
||||
public void test_noDir() {
|
||||
File dir = AndroidMock.createMock(File.class, "/no_file");
|
||||
TempFileCleaner cleaner = new TempFileCleaner(0);
|
||||
expect(dir.exists()).andStubReturn(false);
|
||||
AndroidMock.replay(dir);
|
||||
assertEquals(0, cleaner.cleanTmpDirectory(dir));
|
||||
AndroidMock.verify(dir);
|
||||
}
|
||||
|
||||
public void test_emptyDir() {
|
||||
File dir = AndroidMock.createMock(File.class, "/no_file");
|
||||
TempFileCleaner cleaner = new TempFileCleaner(0);
|
||||
expect(dir.exists()).andStubReturn(true);
|
||||
expect(dir.listFiles()).andStubReturn(new File[0]);
|
||||
AndroidMock.replay(dir);
|
||||
assertEquals(0, cleaner.cleanTmpDirectory(dir));
|
||||
AndroidMock.verify(dir);
|
||||
}
|
||||
|
||||
public void test_newFile() {
|
||||
File dir = AndroidMock.createMock(File.class, "/no_file");
|
||||
long now = 100000000;
|
||||
TempFileCleaner cleaner = new TempFileCleaner(now);
|
||||
expect(dir.exists()).andStubReturn(true);
|
||||
File file = AndroidMock.createMock(File.class, "/no_file/foo");
|
||||
expect(file.lastModified()).andStubReturn(now);
|
||||
File[] list = { file };
|
||||
expect(dir.listFiles()).andStubReturn(list);
|
||||
|
||||
AndroidMock.replay(dir, file);
|
||||
assertEquals(0, cleaner.cleanTmpDirectory(dir));
|
||||
AndroidMock.verify(dir, file);
|
||||
}
|
||||
|
||||
public void test_oldFile() {
|
||||
File dir = AndroidMock.createMock(File.class, "/no_file");
|
||||
long now = 100000000;
|
||||
TempFileCleaner cleaner = new TempFileCleaner(now);
|
||||
expect(dir.exists()).andStubReturn(true);
|
||||
File file = AndroidMock.createMock(File.class, "/no_file/foo");
|
||||
expect(file.lastModified()).andStubReturn(now - 3600001);
|
||||
expect(file.delete()).andStubReturn(true);
|
||||
File[] list = { file };
|
||||
expect(dir.listFiles()).andStubReturn(list);
|
||||
|
||||
AndroidMock.replay(dir, file);
|
||||
assertEquals(1, cleaner.cleanTmpDirectory(dir));
|
||||
AndroidMock.verify(dir, file);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
// Copyright 2010 Google Inc. All Rights Reserved.
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksLocation;
|
||||
import com.google.android.apps.mytracks.content.Sensor;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
|
||||
import android.test.AndroidTestCase;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.FactoryConfigurationError;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.w3c.dom.Text;
|
||||
import org.xml.sax.InputSource;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
/**
|
||||
* Base class for track format writer tests, which sets up a fake track and
|
||||
* gives auxiliary methods for verifying XML output.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public abstract class TrackFormatWriterTest extends AndroidTestCase {
|
||||
|
||||
// All the user-provided strings have "]]>" to ensure that proper escaping is
|
||||
// being done.
|
||||
protected static final String TRACK_NAME = "Home]]>";
|
||||
protected static final String TRACK_DESCRIPTION = "The long ]]> journey home";
|
||||
protected static final String WAYPOINT1_NAME = "point]]>1";
|
||||
protected static final String WAYPOINT1_DESCRIPTION = "point 1]]>description";
|
||||
protected static final String WAYPOINT2_NAME = "point]]>2";
|
||||
protected static final String WAYPOINT2_DESCRIPTION = "point 2]]>description";
|
||||
private static final int BUFFER_SIZE = 10240;
|
||||
protected static final long TRACK_ID = 12345L;
|
||||
protected Track track;
|
||||
protected MyTracksLocation location1, location2, location3, location4;
|
||||
protected Waypoint wp1, wp2;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
track = new Track();
|
||||
track.setId(TRACK_ID);
|
||||
track.setName(TRACK_NAME);
|
||||
track.setDescription(TRACK_DESCRIPTION);
|
||||
|
||||
location1 = new MyTracksLocation("mock");
|
||||
location2 = new MyTracksLocation("mock");
|
||||
location3 = new MyTracksLocation("mock");
|
||||
location4 = new MyTracksLocation("mock");
|
||||
populateLocations(location1, location2, location3, location4);
|
||||
|
||||
wp1 = new Waypoint();
|
||||
wp2 = new Waypoint();
|
||||
wp1.setLocation(location2);
|
||||
wp1.setName(WAYPOINT1_NAME);
|
||||
wp1.setDescription(WAYPOINT1_DESCRIPTION);
|
||||
wp2.setLocation(location3);
|
||||
wp2.setName(WAYPOINT2_NAME);
|
||||
wp2.setDescription(WAYPOINT2_DESCRIPTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Populates the given locations with coordinates and time.
|
||||
*/
|
||||
protected void populateLocations(MyTracksLocation... locs) {
|
||||
for (int i = 0; i < locs.length; i++) {
|
||||
MyTracksLocation loc = locs[i];
|
||||
loc.setAltitude(i * 5000000);
|
||||
loc.setLatitude(i);
|
||||
loc.setLongitude(-i);
|
||||
loc.setTime(10000000 + i * 1000);
|
||||
Sensor.SensorData.Builder hr = Sensor.SensorData.newBuilder()
|
||||
.setValue(100 + i)
|
||||
.setState(Sensor.SensorState.SENDING);
|
||||
Sensor.SensorData.Builder power = Sensor.SensorData.newBuilder()
|
||||
.setValue(400 + i)
|
||||
.setState(Sensor.SensorState.SENDING);
|
||||
Sensor.SensorDataSet sds =
|
||||
Sensor.SensorDataSet.newBuilder().setHeartRate(hr.build())
|
||||
.setPower(power)
|
||||
.build();
|
||||
loc.setSensorData(sds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes the right sequence of calls to the writer in order to write the fake
|
||||
* track in {@link #track}.
|
||||
*
|
||||
* @param writer the writer to write to
|
||||
* @return the written contents
|
||||
*/
|
||||
protected String writeTrack(TrackFormatWriter writer) throws Exception {
|
||||
OutputStream output = new ByteArrayOutputStream(BUFFER_SIZE);
|
||||
writer.prepare(track, output);
|
||||
writer.writeHeader();
|
||||
writer.writeBeginTrack(location1);
|
||||
writer.writeOpenSegment();
|
||||
writer.writeLocation(location1);
|
||||
writer.writeLocation(location2);
|
||||
writer.writeCloseSegment();
|
||||
writer.writeOpenSegment();
|
||||
writer.writeLocation(location3);
|
||||
writer.writeLocation(location4);
|
||||
writer.writeCloseSegment();
|
||||
writer.writeEndTrack(location4);
|
||||
writer.writeWaypoint(wp1);
|
||||
writer.writeWaypoint(wp2);
|
||||
writer.writeFooter();
|
||||
writer.close();
|
||||
return output.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text data contained inside a tag.
|
||||
*
|
||||
* @param parent the parent of the tag containing the text
|
||||
* @param elementName the name of the tag containing the text
|
||||
* @return the text contents
|
||||
*/
|
||||
protected String getChildTextValue(Element parent, String elementName) {
|
||||
Element child = getChildElement(parent, elementName);
|
||||
assertTrue(child.hasChildNodes());
|
||||
NodeList children = child.getChildNodes();
|
||||
int length = children.getLength();
|
||||
assertTrue(length > 0);
|
||||
|
||||
// The children may be a sucession of text elements, just concatenate them
|
||||
String result = "";
|
||||
for (int i = 0; i < length; i++) {
|
||||
Text textNode = (Text) children.item(i);
|
||||
result += textNode.getNodeValue();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all child elements of a given parent which have the given name.
|
||||
*
|
||||
* @param parent the parent to get children from
|
||||
* @param elementName the element name to look for
|
||||
* @param expectedChildren the number of children we're expected to find
|
||||
* @return a list of the found elements
|
||||
*/
|
||||
protected List<Element> getChildElements(Node parent, String elementName,
|
||||
int expectedChildren) {
|
||||
assertTrue(parent.hasChildNodes());
|
||||
NodeList children = parent.getChildNodes();
|
||||
int length = children.getLength();
|
||||
List<Element> result = new ArrayList<Element>();
|
||||
for (int i = 0; i < length; i++) {
|
||||
Node childNode = children.item(i);
|
||||
if (childNode.getNodeType() == Node.ELEMENT_NODE
|
||||
&& childNode.getNodeName().equalsIgnoreCase(elementName)) {
|
||||
result.add((Element) childNode);
|
||||
}
|
||||
}
|
||||
assertTrue(children.toString(), result.size() == expectedChildren);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the single child element of the given parent with the given type.
|
||||
*
|
||||
* @param parent the parent to get a child from
|
||||
* @param elementName the name of the child to look for
|
||||
* @return the child element
|
||||
*/
|
||||
protected Element getChildElement(Node parent, String elementName) {
|
||||
return getChildElements(parent, elementName, 1).get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given XML contents and returns a DOM {@link Document} for it.
|
||||
*/
|
||||
protected Document parseXmlDocument(String contents)
|
||||
throws FactoryConfigurationError, ParserConfigurationException,
|
||||
SAXException, IOException {
|
||||
DocumentBuilderFactory builderFactory =
|
||||
DocumentBuilderFactory.newInstance();
|
||||
builderFactory.setCoalescing(true);
|
||||
// TODO: Somehow do XML validation on Android
|
||||
// builderFactory.setValidating(true);
|
||||
builderFactory.setNamespaceAware(true);
|
||||
builderFactory.setIgnoringComments(true);
|
||||
builderFactory.setIgnoringElementContentWhitespace(true);
|
||||
DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder();
|
||||
Document doc = documentBuilder.parse(
|
||||
new InputSource(new StringReader(contents)));
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,407 @@
|
||||
// Copyright 2010 Google Inc. All Rights Reserved.
|
||||
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
|
||||
import com.google.android.apps.mytracks.content.MyTracksProvider;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils;
|
||||
import com.google.android.apps.mytracks.content.MyTracksProviderUtils.Factory;
|
||||
import com.google.android.apps.mytracks.content.Track;
|
||||
import com.google.android.apps.mytracks.content.Waypoint;
|
||||
import com.google.android.apps.mytracks.services.TrackRecordingServiceTest.MockContext;
|
||||
import com.google.android.apps.mytracks.testing.TestingProviderUtilsFactory;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.location.Location;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.test.RenamingDelegatingContext;
|
||||
import android.test.mock.MockContentResolver;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.easymock.EasyMock;
|
||||
import org.easymock.IAnswer;
|
||||
import org.easymock.IArgumentMatcher;
|
||||
import org.easymock.IMocksControl;
|
||||
|
||||
/**
|
||||
* Tests for the track writer.
|
||||
*
|
||||
* @author Rodrigo Damazio
|
||||
*/
|
||||
public class TrackWriterTest extends AndroidTestCase {
|
||||
/**
|
||||
* {@link TrackWriterImpl} subclass which mocks out methods called from
|
||||
* {@link TrackWriterImpl#openFile}.
|
||||
*/
|
||||
private static final class OpenFileTrackWriter extends TrackWriterImpl {
|
||||
private final ByteArrayOutputStream stream;
|
||||
private final boolean canWrite;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param stream the stream to return from
|
||||
* {@link TrackWriterImpl#newOutputStream}, or null to throw a
|
||||
* {@link FileNotFoundException}
|
||||
* @param canWrite the value that {@link TrackWriterImpl#canWriteFile} will
|
||||
* return
|
||||
*/
|
||||
private OpenFileTrackWriter(Context context,
|
||||
MyTracksProviderUtils providerUtils, Track track,
|
||||
TrackFormatWriter writer, ByteArrayOutputStream stream,
|
||||
boolean canWrite) {
|
||||
super(context, providerUtils, track, writer);
|
||||
|
||||
this.stream = stream;
|
||||
this.canWrite = canWrite;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canWriteFile() {
|
||||
return canWrite;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OutputStream newOutputStream(String fileName)
|
||||
throws FileNotFoundException {
|
||||
assertEquals(FULL_TRACK_NAME, fileName);
|
||||
|
||||
if (stream == null) {
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link TrackWriterImpl} subclass which mocks out methods called from
|
||||
* {@link TrackWriterImpl#writeTrack}.
|
||||
*/
|
||||
private final class WriteTracksTrackWriter extends TrackWriterImpl {
|
||||
private final boolean openResult;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param openResult the return value for {@link TrackWriterImpl#openFile}
|
||||
*/
|
||||
private WriteTracksTrackWriter(Context context,
|
||||
MyTracksProviderUtils providerUtils, Track track,
|
||||
TrackFormatWriter writer, boolean openResult) {
|
||||
super(context, providerUtils, track, writer);
|
||||
this.openResult = openResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean openFile() {
|
||||
openFileCalls++;
|
||||
return openResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
void writeDocument() {
|
||||
writeDocumentCalls++;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void runOnUiThread(Runnable runnable) {
|
||||
runnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
private static final long TRACK_ID = 1234567L;
|
||||
private static final String EXTENSION = "ext";
|
||||
private static final String TRACK_NAME = "Swimming across the pacific";
|
||||
private static final String FULL_TRACK_NAME =
|
||||
"Swimming across the pacific.ext";
|
||||
|
||||
private Track track;
|
||||
private TrackFormatWriter formatWriter;
|
||||
private TrackWriterImpl writer;
|
||||
private IMocksControl mocksControl;
|
||||
private MyTracksProviderUtils providerUtils;
|
||||
private Factory oldProviderUtilsFactory;
|
||||
|
||||
// State used in specific tests
|
||||
private int writeDocumentCalls;
|
||||
private int openFileCalls;
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
MockContentResolver mockContentResolver = new MockContentResolver();
|
||||
RenamingDelegatingContext targetContext = new RenamingDelegatingContext(
|
||||
getContext(), getContext(), "test.");
|
||||
Context context = new MockContext(mockContentResolver, targetContext);
|
||||
MyTracksProvider provider = new MyTracksProvider();
|
||||
provider.attachInfo(context, null);
|
||||
mockContentResolver.addProvider(MyTracksProviderUtils.AUTHORITY, provider);
|
||||
setContext(context);
|
||||
providerUtils = MyTracksProviderUtils.Factory.get(context);
|
||||
oldProviderUtilsFactory = TestingProviderUtilsFactory.installWithInstance(providerUtils);
|
||||
|
||||
mocksControl = EasyMock.createStrictControl();
|
||||
formatWriter = mocksControl.createMock(TrackFormatWriter.class);
|
||||
expect(formatWriter.getExtension()).andStubReturn(EXTENSION);
|
||||
|
||||
track = new Track();
|
||||
track.setName(TRACK_NAME);
|
||||
track.setId(TRACK_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
TestingProviderUtilsFactory.restoreOldFactory(oldProviderUtilsFactory);
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testWriteTrack() {
|
||||
writer = new WriteTracksTrackWriter(getContext(), providerUtils, track,
|
||||
formatWriter, true);
|
||||
|
||||
// Expect the completion listener to be run
|
||||
TrackWriter.OnCompletionListener completionListener
|
||||
= mocksControl.createMock(TrackWriter.OnCompletionListener.class);
|
||||
completionListener.onComplete();
|
||||
|
||||
mocksControl.replay();
|
||||
writer.setOnCompletionListener(completionListener);
|
||||
writer.writeTrack();
|
||||
|
||||
assertEquals(1, writeDocumentCalls);
|
||||
assertEquals(1, openFileCalls);
|
||||
mocksControl.verify();
|
||||
}
|
||||
|
||||
public void testWriteTrack_cancelled() throws Exception {
|
||||
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
writer = new OpenFileTrackWriter(
|
||||
getContext(), providerUtils, track, formatWriter, stream, true);
|
||||
|
||||
formatWriter.prepare(track, stream);
|
||||
|
||||
final Location[] locs = {
|
||||
new Location("fake0"),
|
||||
new Location("fake1"),
|
||||
};
|
||||
fillLocations(locs);
|
||||
assertEquals(locs.length, providerUtils.bulkInsertTrackPoints(locs, locs.length, TRACK_ID));
|
||||
|
||||
formatWriter.writeHeader();
|
||||
formatWriter.writeBeginTrack(locEq(locs[0]));
|
||||
formatWriter.writeOpenSegment();
|
||||
|
||||
formatWriter.writeLocation(locEq(locs[0]));
|
||||
//EasyMock.expectLastCall().andThrow(new InterruptedException());
|
||||
EasyMock.expectLastCall().andAnswer(new IAnswer<Object>() {
|
||||
@Override
|
||||
public Object answer() throws Throwable {
|
||||
throw new InterruptedException();
|
||||
}
|
||||
});
|
||||
|
||||
mocksControl.replay();
|
||||
|
||||
writer.writeTrack();
|
||||
|
||||
mocksControl.verify();
|
||||
|
||||
assertFalse(writer.wasSuccess());
|
||||
assertEquals(R.string.error_export_operation_canceled, writer.getErrorMessage());
|
||||
}
|
||||
|
||||
public void testWriteTrack_openFails() {
|
||||
writer = new WriteTracksTrackWriter(getContext(), providerUtils, track,
|
||||
formatWriter, false);
|
||||
|
||||
// Expect the completion listener to be run
|
||||
TrackWriter.OnCompletionListener completionListener
|
||||
= mocksControl.createMock(TrackWriter.OnCompletionListener.class);
|
||||
completionListener.onComplete();
|
||||
|
||||
mocksControl.replay();
|
||||
writer.setOnCompletionListener(completionListener);
|
||||
writer.writeTrack();
|
||||
|
||||
assertEquals(0, writeDocumentCalls);
|
||||
assertEquals(1, openFileCalls);
|
||||
mocksControl.verify();
|
||||
}
|
||||
|
||||
public void testOpenFile() {
|
||||
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
writer = new OpenFileTrackWriter(
|
||||
getContext(), providerUtils, track, formatWriter, stream, true);
|
||||
|
||||
formatWriter.prepare(track, stream);
|
||||
|
||||
mocksControl.replay();
|
||||
assertTrue(writer.openFile());
|
||||
mocksControl.verify();
|
||||
}
|
||||
|
||||
public void testOpenFile_cantWrite() {
|
||||
final ByteArrayOutputStream stream = new ByteArrayOutputStream();
|
||||
writer = new OpenFileTrackWriter(
|
||||
getContext(), providerUtils, track, formatWriter, stream, false);
|
||||
|
||||
mocksControl.replay();
|
||||
assertFalse(writer.openFile());
|
||||
mocksControl.verify();
|
||||
}
|
||||
|
||||
public void testOpenFile_streamError() {
|
||||
writer = new OpenFileTrackWriter(
|
||||
getContext(), providerUtils, track, formatWriter, null, true);
|
||||
|
||||
mocksControl.replay();
|
||||
assertFalse(writer.openFile());
|
||||
mocksControl.verify();
|
||||
}
|
||||
|
||||
public void testWriteDocument_emptyTrack() throws Exception {
|
||||
writer = new TrackWriterImpl(getContext(), providerUtils, track, formatWriter);
|
||||
|
||||
// Set expected mock behavior
|
||||
formatWriter.writeHeader();
|
||||
formatWriter.writeFooter();
|
||||
formatWriter.close();
|
||||
|
||||
mocksControl.replay();
|
||||
writer.writeDocument();
|
||||
|
||||
assertTrue(writer.wasSuccess());
|
||||
mocksControl.verify();
|
||||
}
|
||||
|
||||
public void testWriteDocument() throws Exception {
|
||||
writer = new TrackWriterImpl(getContext(), providerUtils, track, formatWriter);
|
||||
|
||||
final Location[] locs = {
|
||||
new Location("fake0"),
|
||||
new Location("fake1"),
|
||||
new Location("fake2"),
|
||||
new Location("fake3"),
|
||||
new Location("fake4"),
|
||||
new Location("fake5")
|
||||
};
|
||||
Waypoint[] wps = { new Waypoint(), new Waypoint(), new Waypoint() };
|
||||
|
||||
// Fill locations with valid values
|
||||
fillLocations(locs);
|
||||
|
||||
// Make location 3 invalid
|
||||
locs[2].setLatitude(100);
|
||||
|
||||
assertEquals(locs.length, providerUtils.bulkInsertTrackPoints(locs, locs.length, TRACK_ID));
|
||||
for (int i = 0; i < wps.length; ++i) {
|
||||
Waypoint wpt = wps[i];
|
||||
wpt.setTrackId(TRACK_ID);
|
||||
assertNotNull(providerUtils.insertWaypoint(wpt));
|
||||
wpt.setId(i + 1);
|
||||
}
|
||||
|
||||
formatWriter.writeHeader();
|
||||
|
||||
// Expect reading/writing of the waypoints (except the first)
|
||||
formatWriter.writeWaypoint(wptEq(wps[1]));
|
||||
formatWriter.writeWaypoint(wptEq(wps[2]));
|
||||
|
||||
// Begin the track
|
||||
formatWriter.writeBeginTrack(locEq(locs[0]));
|
||||
|
||||
// Write locations 1-2
|
||||
formatWriter.writeOpenSegment();
|
||||
formatWriter.writeLocation(locEq(locs[0]));
|
||||
formatWriter.writeLocation(locEq(locs[1]));
|
||||
formatWriter.writeCloseSegment();
|
||||
|
||||
// Location 3 is not written - it's invalid
|
||||
|
||||
// Write locations 4-6
|
||||
formatWriter.writeOpenSegment();
|
||||
formatWriter.writeLocation(locEq(locs[3]));
|
||||
formatWriter.writeLocation(locEq(locs[4]));
|
||||
formatWriter.writeLocation(locEq(locs[5]));
|
||||
formatWriter.writeCloseSegment();
|
||||
|
||||
// End the track
|
||||
formatWriter.writeEndTrack(locEq(locs[5]));
|
||||
|
||||
formatWriter.writeFooter();
|
||||
formatWriter.close();
|
||||
|
||||
mocksControl.replay();
|
||||
writer.writeDocument();
|
||||
|
||||
assertTrue(writer.wasSuccess());
|
||||
mocksControl.verify();
|
||||
}
|
||||
|
||||
private static Waypoint wptEq(final Waypoint wpt) {
|
||||
EasyMock.reportMatcher(new IArgumentMatcher() {
|
||||
@Override
|
||||
public boolean matches(Object wptObj2) {
|
||||
if (wptObj2 == null || wpt == null) return wpt == wptObj2;
|
||||
Waypoint wpt2 = (Waypoint) wptObj2;
|
||||
|
||||
return wpt.getId() == wpt2.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuffer buffer) {
|
||||
buffer.append("wptEq(");
|
||||
buffer.append(wpt);
|
||||
buffer.append(")");
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Location locEq(final Location loc) {
|
||||
EasyMock.reportMatcher(new IArgumentMatcher() {
|
||||
@Override
|
||||
public boolean matches(Object locObj2) {
|
||||
if (locObj2 == null || loc == null) return loc == locObj2;
|
||||
Location loc2 = (Location) locObj2;
|
||||
|
||||
return loc.hasAccuracy() == loc2.hasAccuracy()
|
||||
&& (!loc.hasAccuracy() || loc.getAccuracy() == loc2.getAccuracy())
|
||||
&& loc.hasAltitude() == loc2.hasAltitude()
|
||||
&& (!loc.hasAltitude() || loc.getAltitude() == loc2.getAltitude())
|
||||
&& loc.hasBearing() == loc2.hasBearing()
|
||||
&& (!loc.hasBearing() || loc.getBearing() == loc2.getBearing())
|
||||
&& loc.hasSpeed() == loc2.hasSpeed()
|
||||
&& (!loc.hasSpeed() || loc.getSpeed() == loc2.getSpeed())
|
||||
&& loc.getLatitude() == loc2.getLatitude()
|
||||
&& loc.getLongitude() == loc2.getLongitude()
|
||||
&& loc.getTime() == loc2.getTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendTo(StringBuffer buffer) {
|
||||
buffer.append("locEq(");
|
||||
buffer.append(loc);
|
||||
buffer.append(")");
|
||||
}
|
||||
});
|
||||
return null;
|
||||
}
|
||||
|
||||
private void fillLocations(Location... locs) {
|
||||
assertTrue(locs.length < 90);
|
||||
for (int i = 0; i < locs.length; i++) {
|
||||
Location location = locs[i];
|
||||
location.setLatitude(i + 1);
|
||||
location.setLongitude(i + 1);
|
||||
location.setTime(i + 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.file;
|
||||
|
||||
import android.app.ProgressDialog;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
|
||||
import java.util.concurrent.Semaphore;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* Tests {@link WriteProgressController}.
|
||||
*
|
||||
* @author Matthew Simmons
|
||||
*/
|
||||
public class WriteProgressControllerTest extends ActivityInstrumentationTestCase2<SaveActivity> {
|
||||
public WriteProgressControllerTest() {
|
||||
super(SaveActivity.class);
|
||||
}
|
||||
|
||||
private static void assertProgress(ProgressDialog dialog, int expectedProgress,
|
||||
int expectedMax) {
|
||||
assertEquals(expectedProgress, dialog.getProgress());
|
||||
assertEquals(expectedMax, dialog.getMax());
|
||||
}
|
||||
|
||||
public void testSimple() throws Exception {
|
||||
final AtomicReference<ProgressDialog> dialogRef = new AtomicReference<ProgressDialog>();
|
||||
final AtomicReference<Boolean> controllerDoneRef = new AtomicReference<Boolean>();
|
||||
final Semaphore writerDone = new Semaphore(0);
|
||||
|
||||
TrackWriter mockWriter = new MockTrackWriter() {
|
||||
@Override
|
||||
public void writeTrackAsync() {
|
||||
onWriteListener.onWrite(1000, 10000);
|
||||
assertProgress(dialogRef.get(), 1000, 10000);
|
||||
|
||||
onCompletionListener.onComplete();
|
||||
writerDone.release();
|
||||
}
|
||||
};
|
||||
|
||||
final WriteProgressController controller = new WriteProgressController(
|
||||
getActivity(), mockWriter, SaveActivity.PROGRESS_DIALOG);
|
||||
controller.setOnCompletionListener(new WriteProgressController.OnCompletionListener() {
|
||||
@Override
|
||||
public void onComplete() {
|
||||
controllerDoneRef.set(true);
|
||||
}
|
||||
});
|
||||
|
||||
/*
|
||||
* The WriteProgressController constructor calls the mockWriter's
|
||||
* setOnCompletionListener method with a listener that dismisses the
|
||||
* progress dialog. However, this unit test only tests the
|
||||
* WriteProgressController and doesn't actually show any progress dialog.
|
||||
* Thus after the WriteProgressController is setup, we need to call the
|
||||
* mockWriter's setOnCompletionListener method again with an listener that
|
||||
* doesn't dismiss dialog.
|
||||
*/
|
||||
mockWriter.setOnCompletionListener(new TrackWriter.OnCompletionListener() {
|
||||
@Override
|
||||
public void onComplete() {
|
||||
controller.getOnCompletionListener().onComplete();
|
||||
}
|
||||
});
|
||||
|
||||
dialogRef.set(controller.createProgressDialog());
|
||||
|
||||
controller.startWrite();
|
||||
|
||||
// wait for the writer to finish
|
||||
writerDone.acquire();
|
||||
|
||||
assertTrue(controllerDoneRef.get());
|
||||
}
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.sendtogoogle;
|
||||
|
||||
import com.google.android.apps.mytracks.MyTracks;
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.view.View;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Tests {@link ResultDialogFactory}.
|
||||
*
|
||||
* @author Matthew Simmons
|
||||
*/
|
||||
public class ResultDialogFactoryTest extends ActivityInstrumentationTestCase2<MyTracks> {
|
||||
public ResultDialogFactoryTest() {
|
||||
super(MyTracks.class);
|
||||
}
|
||||
|
||||
private List<SendResult> makeResults(SendResult... results) {
|
||||
List<SendResult> resultsList = new ArrayList<SendResult>();
|
||||
for (SendResult result : results) {
|
||||
resultsList.add(result);
|
||||
}
|
||||
return resultsList;
|
||||
}
|
||||
|
||||
private DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {}
|
||||
};
|
||||
|
||||
private MyTracks myTracks;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myTracks = getActivity();
|
||||
};
|
||||
|
||||
public void testSuccess_noShare() {
|
||||
List<SendResult> results = makeResults(new SendResult(SendType.MYMAPS, true),
|
||||
new SendResult(SendType.DOCS, true));
|
||||
|
||||
AlertDialog dialog = ResultDialogFactory.makeDialog(
|
||||
myTracks, results, clickListener, null, null);
|
||||
dialog.show();
|
||||
|
||||
ListView listView = (ListView) dialog.findViewById(R.id.send_to_google_result_list);
|
||||
ListAdapter listAdapter = listView.getAdapter();
|
||||
assertEquals(2, listAdapter.getCount());
|
||||
|
||||
assertEquals(SendType.MYMAPS, ((SendResult) listAdapter.getItem(0)).getType());
|
||||
assertEquals(SendType.DOCS, ((SendResult) listAdapter.getItem(1)).getType());
|
||||
|
||||
// Checking the return code of Dialog#getButton doesn't appear to be
|
||||
// sufficient, as a Button will be returned even if it doesn't appear in
|
||||
// the rendered dialog.
|
||||
assertEquals(View.VISIBLE, dialog.getButton(AlertDialog.BUTTON_POSITIVE).getVisibility());
|
||||
assertEquals(View.GONE, dialog.getButton(AlertDialog.BUTTON_NEUTRAL).getVisibility());
|
||||
|
||||
assertEquals(View.VISIBLE,
|
||||
dialog.findViewById(R.id.send_to_google_result_comment).getVisibility());
|
||||
assertEquals(View.GONE,
|
||||
dialog.findViewById(R.id.send_to_google_result_error).getVisibility());
|
||||
|
||||
// TODO: Test correct listener invocation. Neither TouchUtils#clickView
|
||||
// nor Button#performClick appear to cause listener invocation. This
|
||||
// might be Android bug
|
||||
// http://code.google.com/p/android/issues/detail?id=6564
|
||||
}
|
||||
|
||||
public void testSuccess_share() {
|
||||
List<SendResult> results = makeResults(
|
||||
new SendResult(SendType.MYMAPS, true), new SendResult(SendType.DOCS, true));
|
||||
|
||||
AlertDialog dialog = ResultDialogFactory.makeDialog(
|
||||
myTracks, results, clickListener, clickListener, null);
|
||||
dialog.show();
|
||||
|
||||
assertEquals(View.VISIBLE, dialog.getButton(AlertDialog.BUTTON_POSITIVE).getVisibility());
|
||||
assertEquals(View.VISIBLE, dialog.getButton(AlertDialog.BUTTON_NEGATIVE).getVisibility());
|
||||
}
|
||||
|
||||
public void testFailure_noShare() {
|
||||
List<SendResult> results = makeResults(new SendResult(SendType.MYMAPS, true),
|
||||
new SendResult(SendType.DOCS, false));
|
||||
|
||||
AlertDialog dialog = ResultDialogFactory.makeDialog(
|
||||
myTracks, results, clickListener, null, null);
|
||||
dialog.show();
|
||||
|
||||
assertEquals(View.GONE,
|
||||
dialog.findViewById(R.id.send_to_google_result_comment).getVisibility());
|
||||
assertEquals(View.VISIBLE,
|
||||
dialog.findViewById(R.id.send_to_google_result_error).getVisibility());
|
||||
}
|
||||
|
||||
public void testFailure_share() {
|
||||
List<SendResult> results = makeResults(new SendResult(SendType.MYMAPS, true),
|
||||
new SendResult(SendType.DOCS, false));
|
||||
|
||||
AlertDialog dialog = ResultDialogFactory.makeDialog(
|
||||
myTracks, results, clickListener, clickListener, null);
|
||||
dialog.show();
|
||||
|
||||
assertEquals(View.VISIBLE, dialog.getButton(AlertDialog.BUTTON_POSITIVE).getVisibility());
|
||||
assertEquals(View.VISIBLE, dialog.getButton(AlertDialog.BUTTON_NEGATIVE).getVisibility());
|
||||
}
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright 2011 Google Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package com.google.android.apps.mytracks.io.sendtogoogle;
|
||||
|
||||
import com.google.android.maps.mytracks.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.test.AndroidTestCase;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Tests {@link ResultListAdapter}.
|
||||
*
|
||||
* @author Matthew Simmons
|
||||
*/
|
||||
public class ResultListAdapterTest extends AndroidTestCase {
|
||||
private static class TestResultListAdapter extends ResultListAdapter {
|
||||
public View contentView;
|
||||
public int drawableId;
|
||||
public int nameId;
|
||||
public int urlId;
|
||||
|
||||
public TestResultListAdapter(Context context, List<SendResult> results) {
|
||||
super(context, 0, results);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setImage(View content, int drawableId) {
|
||||
saveContentView(content);
|
||||
this.drawableId = drawableId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setName(View content, int nameId) {
|
||||
saveContentView(content);
|
||||
this.nameId = nameId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUrl(View content, int urlId) {
|
||||
saveContentView(content);
|
||||
this.urlId = urlId;
|
||||
}
|
||||
|
||||
@SuppressWarnings("hiding")
|
||||
private void saveContentView(View contentView) {
|
||||
if (this.contentView == null) {
|
||||
this.contentView = contentView;
|
||||
} else {
|
||||
AndroidTestCase.assertEquals(this.contentView, contentView);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final SendType sendType = SendType.MYMAPS;
|
||||
|
||||
private View inflateContentView(int viewId) {
|
||||
LayoutInflater layoutInflater
|
||||
= (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
return layoutInflater.inflate(viewId, null);
|
||||
}
|
||||
|
||||
private List<SendResult> makeResult(SendType type, boolean success) {
|
||||
List<SendResult> results = new ArrayList<SendResult>();
|
||||
results.add(new SendResult(type, success));
|
||||
return results;
|
||||
}
|
||||
|
||||
public void testSuccess_createsNewView() {
|
||||
TestResultListAdapter adapter = new TestResultListAdapter(getContext(),
|
||||
makeResult(sendType, true));
|
||||
adapter.getView(0, null, null);
|
||||
|
||||
assertEquals(R.drawable.success, adapter.drawableId);
|
||||
assertEquals(sendType.getServiceName(), adapter.nameId);
|
||||
assertEquals(sendType.getServiceUrl(), adapter.urlId);
|
||||
}
|
||||
|
||||
public void testSuccess_reusesView() {
|
||||
View contentView = inflateContentView(R.layout.send_to_google_result_list_item);
|
||||
TestResultListAdapter adapter = new TestResultListAdapter(getContext(),
|
||||
makeResult(sendType, true));
|
||||
adapter.getView(0, contentView, null);
|
||||
|
||||
assertEquals(contentView, adapter.contentView);
|
||||
assertEquals(R.drawable.success, adapter.drawableId);
|
||||
assertEquals(sendType.getServiceName(), adapter.nameId);
|
||||
assertEquals(sendType.getServiceUrl(), adapter.urlId);
|
||||
}
|
||||
|
||||
public void testFailure() {
|
||||
TestResultListAdapter adapter = new TestResultListAdapter(getContext(),
|
||||
makeResult(sendType, false));
|
||||
adapter.getView(0, null, null);
|
||||
|
||||
assertEquals(R.drawable.failure, adapter.drawableId);
|
||||
assertEquals(sendType.getServiceName(), adapter.nameId);
|
||||
assertEquals(sendType.getServiceUrl(), adapter.urlId);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user