mirror of
https://github.com/iSoron/uhabits.git
synced 2025-12-06 09:08:52 -06:00
Add more constraints on table Repetitions
This commit is contained in:
@@ -45,15 +45,16 @@ public class HabitsDatabaseOpener extends SQLiteOpenHelper
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(SQLiteDatabase db)
|
public void onCreate(SQLiteDatabase db)
|
||||||
{
|
{
|
||||||
onUpgrade(db, 8, version);
|
db.setVersion(8);
|
||||||
|
onUpgrade(db, -1, version);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
|
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
|
||||||
{
|
{
|
||||||
if(oldVersion < 8) throw new UnsupportedDatabaseVersionException();
|
if(db.getVersion() < 8) throw new UnsupportedDatabaseVersionException();
|
||||||
helper = new MigrationHelper(new AndroidDatabase(db));
|
helper = new MigrationHelper(new AndroidDatabase(db));
|
||||||
helper.executeMigrations(oldVersion, newVersion);
|
helper.migrateTo(newVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ public class AndroidDatabase implements Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Cursor select(String query, String... params)
|
public Cursor query(String query, String... params)
|
||||||
{
|
{
|
||||||
return new AndroidCursor(db.rawQuery(query, params));
|
return new AndroidCursor(db.rawQuery(query, params));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,5 +22,5 @@ package org.isoron.uhabits.core;
|
|||||||
public class Config
|
public class Config
|
||||||
{
|
{
|
||||||
public static final String DATABASE_FILENAME = "uhabits.db";
|
public static final String DATABASE_FILENAME = "uhabits.db";
|
||||||
public static int DATABASE_VERSION = 21;
|
public static int DATABASE_VERSION = 22;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,7 +23,15 @@ import java.util.*;
|
|||||||
|
|
||||||
public interface Database
|
public interface Database
|
||||||
{
|
{
|
||||||
Cursor select(String query, String... params);
|
Cursor query(String query, String... params);
|
||||||
|
|
||||||
|
default void query(String query, ProcessCallback callback)
|
||||||
|
{
|
||||||
|
try (Cursor c = query(query)) {
|
||||||
|
c.moveToNext();
|
||||||
|
callback.process(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int update(String tableName,
|
int update(String tableName,
|
||||||
Map<String, Object> values,
|
Map<String, Object> values,
|
||||||
@@ -45,4 +53,9 @@ public interface Database
|
|||||||
void close();
|
void close();
|
||||||
|
|
||||||
int getVersion();
|
int getVersion();
|
||||||
|
|
||||||
|
interface ProcessCallback
|
||||||
|
{
|
||||||
|
void process(Cursor cursor);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ public class JdbcDatabase implements Database
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Cursor select(String query, String... params)
|
public Cursor query(String query, String... params)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -197,7 +197,7 @@ public class JdbcDatabase implements Database
|
|||||||
@Override
|
@Override
|
||||||
public int getVersion()
|
public int getVersion()
|
||||||
{
|
{
|
||||||
try (Cursor c = select("PRAGMA user_version"))
|
try (Cursor c = query("PRAGMA user_version"))
|
||||||
{
|
{
|
||||||
c.moveToNext();
|
c.moveToNext();
|
||||||
return c.getInt(0);
|
return c.getInt(0);
|
||||||
|
|||||||
@@ -37,11 +37,11 @@ public class MigrationHelper
|
|||||||
this.db = db;
|
this.db = db;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void executeMigrations(int oldVersion, int newVersion)
|
public void migrateTo(int newVersion)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
for (int v = oldVersion + 1; v <= newVersion; v++)
|
for (int v = db.getVersion() + 1; v <= newVersion; v++)
|
||||||
{
|
{
|
||||||
String fname = String.format(Locale.US, "/migrations/%02d.sql", v);
|
String fname = String.format(Locale.US, "/migrations/%02d.sql", v);
|
||||||
for (String command : SQLParser.parse(open(fname)))
|
for (String command : SQLParser.parse(open(fname)))
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ public class Repository<T>
|
|||||||
@NonNull
|
@NonNull
|
||||||
public List<T> findAll(@NonNull String query, @NonNull String... params)
|
public List<T> findAll(@NonNull String query, @NonNull String... params)
|
||||||
{
|
{
|
||||||
try (Cursor c = db.select(buildSelectQuery() + query, params))
|
try (Cursor c = db.query(buildSelectQuery() + query, params))
|
||||||
{
|
{
|
||||||
return cursorToMultipleRecords(c);
|
return cursorToMultipleRecords(c);
|
||||||
}
|
}
|
||||||
@@ -76,7 +76,7 @@ public class Repository<T>
|
|||||||
@Nullable
|
@Nullable
|
||||||
public T findFirst(String query, String... params)
|
public T findFirst(String query, String... params)
|
||||||
{
|
{
|
||||||
try (Cursor c = db.select(buildSelectQuery() + query, params))
|
try (Cursor c = db.query(buildSelectQuery() + query, params))
|
||||||
{
|
{
|
||||||
if (!c.moveToNext()) return null;
|
if (!c.moveToNext()) return null;
|
||||||
return cursorToSingleRecord(c);
|
return cursorToSingleRecord(c);
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ import java.io.*;
|
|||||||
|
|
||||||
import javax.inject.*;
|
import javax.inject.*;
|
||||||
|
|
||||||
import static org.isoron.uhabits.core.Config.DATABASE_VERSION;
|
import static org.isoron.uhabits.core.Config.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class that imports data from database files exported by Loop Habit Tracker.
|
* Class that imports data from database files exported by Loop Habit Tracker.
|
||||||
@@ -55,7 +55,7 @@ public class LoopDBImporter extends AbstractImporter
|
|||||||
Database db = opener.open(file);
|
Database db = opener.open(file);
|
||||||
boolean canHandle = true;
|
boolean canHandle = true;
|
||||||
|
|
||||||
Cursor c = db.select("select count(*) from SQLITE_MASTER " +
|
Cursor c = db.query("select count(*) from SQLITE_MASTER " +
|
||||||
"where name='Checkmarks' or name='Repetitions'");
|
"where name='Checkmarks' or name='Repetitions'");
|
||||||
|
|
||||||
if (!c.moveToNext() || c.getInt(0) != 2)
|
if (!c.moveToNext() || c.getInt(0) != 2)
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public class RewireDBImporter extends AbstractImporter
|
|||||||
if (!isSQLite3File(file)) return false;
|
if (!isSQLite3File(file)) return false;
|
||||||
|
|
||||||
Database db = opener.open(file);
|
Database db = opener.open(file);
|
||||||
Cursor c = db.select("select count(*) from SQLITE_MASTER " +
|
Cursor c = db.query("select count(*) from SQLITE_MASTER " +
|
||||||
"where name='CHECKINS' or name='UNIT'");
|
"where name='CHECKINS' or name='UNIT'");
|
||||||
|
|
||||||
boolean result = (c.moveToNext() && c.getInt(0) == 2);
|
boolean result = (c.moveToNext() && c.getInt(0) == 2);
|
||||||
@@ -83,7 +83,7 @@ public class RewireDBImporter extends AbstractImporter
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
c = db.select("select _id, name, description, schedule, " +
|
c = db.query("select _id, name, description, schedule, " +
|
||||||
"active_days, repeating_count, days, period " +
|
"active_days, repeating_count, days, period " +
|
||||||
"from habits");
|
"from habits");
|
||||||
if (!c.moveToNext()) return;
|
if (!c.moveToNext()) return;
|
||||||
@@ -150,7 +150,7 @@ public class RewireDBImporter extends AbstractImporter
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
String[] params = { Integer.toString(rewireHabitId) };
|
String[] params = { Integer.toString(rewireHabitId) };
|
||||||
c = db.select(
|
c = db.query(
|
||||||
"select distinct date from checkins where habit_id=? and type=2",
|
"select distinct date from checkins where habit_id=? and type=2",
|
||||||
params);
|
params);
|
||||||
if (!c.moveToNext()) return;
|
if (!c.moveToNext()) return;
|
||||||
@@ -181,7 +181,7 @@ public class RewireDBImporter extends AbstractImporter
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
c = db.select(
|
c = db.query(
|
||||||
"select time, active_days from reminders where habit_id=? limit 1",
|
"select time, active_days from reminders where habit_id=? limit 1",
|
||||||
params);
|
params);
|
||||||
|
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ public class TickmateDBImporter extends AbstractImporter
|
|||||||
if (!isSQLite3File(file)) return false;
|
if (!isSQLite3File(file)) return false;
|
||||||
|
|
||||||
Database db = opener.open(file);
|
Database db = opener.open(file);
|
||||||
Cursor c = db.select("select count(*) from SQLITE_MASTER " +
|
Cursor c = db.query("select count(*) from SQLITE_MASTER " +
|
||||||
"where name='tracks' or name='track2groups'");
|
"where name='tracks' or name='track2groups'");
|
||||||
|
|
||||||
boolean result = (c.moveToNext() && c.getInt(0) == 2);
|
boolean result = (c.moveToNext() && c.getInt(0) == 2);
|
||||||
@@ -86,7 +86,7 @@ public class TickmateDBImporter extends AbstractImporter
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
String[] params = {Integer.toString(tickmateTrackId)};
|
String[] params = {Integer.toString(tickmateTrackId)};
|
||||||
c = db.select(
|
c = db.query(
|
||||||
"select distinct year, month, day from ticks where _track_id=?",
|
"select distinct year, month, day from ticks where _track_id=?",
|
||||||
params);
|
params);
|
||||||
if (!c.moveToNext()) return;
|
if (!c.moveToNext()) return;
|
||||||
@@ -115,7 +115,7 @@ public class TickmateDBImporter extends AbstractImporter
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
c = db.select("select _id, name, description from tracks",
|
c = db.query("select _id, name, description from tracks",
|
||||||
new String[0]);
|
new String[0]);
|
||||||
if (!c.moveToNext()) return;
|
if (!c.moveToNext()) return;
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ package org.isoron.uhabits.core.models;
|
|||||||
|
|
||||||
import android.support.annotation.*;
|
import android.support.annotation.*;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.builder.*;
|
||||||
|
|
||||||
public final class Reminder
|
public final class Reminder
|
||||||
{
|
{
|
||||||
private final int hour;
|
private final int hour;
|
||||||
@@ -51,4 +53,40 @@ public final class Reminder
|
|||||||
{
|
{
|
||||||
return minute;
|
return minute;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o)
|
||||||
|
{
|
||||||
|
if (this == o) return true;
|
||||||
|
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
Reminder reminder = (Reminder) o;
|
||||||
|
|
||||||
|
return new EqualsBuilder()
|
||||||
|
.append(hour, reminder.hour)
|
||||||
|
.append(minute, reminder.minute)
|
||||||
|
.append(days, reminder.days)
|
||||||
|
.isEquals();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return new HashCodeBuilder(17, 37)
|
||||||
|
.append(hour)
|
||||||
|
.append(minute)
|
||||||
|
.append(days)
|
||||||
|
.toHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return new ToStringBuilder(this)
|
||||||
|
.append("hour", hour)
|
||||||
|
.append("minute", minute)
|
||||||
|
.append("days", days)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits.core.models;
|
package org.isoron.uhabits.core.models;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.builder.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class WeekdayList
|
public class WeekdayList
|
||||||
@@ -68,4 +70,30 @@ public class WeekdayList
|
|||||||
|
|
||||||
return packedList;
|
return packedList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o)
|
||||||
|
{
|
||||||
|
if (this == o) return true;
|
||||||
|
|
||||||
|
if (o == null || getClass() != o.getClass()) return false;
|
||||||
|
|
||||||
|
WeekdayList that = (WeekdayList) o;
|
||||||
|
|
||||||
|
return new EqualsBuilder().append(weekdays, that.weekdays).isEquals();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return new HashCodeBuilder(17, 37).append(weekdays).toHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return new ToStringBuilder(this)
|
||||||
|
.append("weekdays", weekdays)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
uhabits-core/src/main/resources/migrations/22.sql
Normal file
24
uhabits-core/src/main/resources/migrations/22.sql
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
delete from repetitions where habit not in (select id from habits);
|
||||||
|
delete from repetitions where timestamp is null;
|
||||||
|
delete from repetitions where habit is null;
|
||||||
|
delete from repetitions where rowid not in (
|
||||||
|
select min(rowid) from repetitions group by habit, timestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
begin transaction;
|
||||||
|
|
||||||
|
alter table Repetitions rename to RepetitionsBak;
|
||||||
|
create table Repetitions (
|
||||||
|
id integer primary key autoincrement,
|
||||||
|
habit integer not null references habits(id),
|
||||||
|
timestamp integer not null,
|
||||||
|
value integer not null);
|
||||||
|
drop index idx_repetitions_habit_timestamp;
|
||||||
|
create unique index idx_repetitions_habit_timestamp on Repetitions(
|
||||||
|
habit, timestamp);
|
||||||
|
insert into Repetitions select * from RepetitionsBak;
|
||||||
|
drop table RepetitionsBak;
|
||||||
|
|
||||||
|
commit;
|
||||||
|
|
||||||
|
pragma foreign_keys=ON;
|
||||||
@@ -19,6 +19,9 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits.core;
|
package org.isoron.uhabits.core;
|
||||||
|
|
||||||
|
import android.support.annotation.*;
|
||||||
|
|
||||||
|
import org.apache.commons.io.*;
|
||||||
import org.isoron.uhabits.core.commands.*;
|
import org.isoron.uhabits.core.commands.*;
|
||||||
import org.isoron.uhabits.core.database.*;
|
import org.isoron.uhabits.core.database.*;
|
||||||
import org.isoron.uhabits.core.models.*;
|
import org.isoron.uhabits.core.models.*;
|
||||||
@@ -30,11 +33,13 @@ import org.junit.*;
|
|||||||
import org.junit.runner.*;
|
import org.junit.runner.*;
|
||||||
import org.mockito.junit.*;
|
import org.mockito.junit.*;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.mockito.Mockito.spy;
|
import sun.reflect.generics.reflectiveObjects.*;
|
||||||
import static org.mockito.Mockito.validateMockitoUsage;
|
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class BaseUnitTest
|
public class BaseUnitTest
|
||||||
@@ -53,6 +58,29 @@ public class BaseUnitTest
|
|||||||
|
|
||||||
protected CommandRunner commandRunner;
|
protected CommandRunner commandRunner;
|
||||||
|
|
||||||
|
protected DatabaseOpener databaseOpener = new DatabaseOpener()
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public Database open(@NonNull File file)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return new JdbcDatabase(DriverManager.getConnection(
|
||||||
|
String.format("jdbc:sqlite:%s", file.getAbsolutePath())));
|
||||||
|
}
|
||||||
|
catch (SQLException e)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public File getProductionDatabaseFile()
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception
|
public void setUp() throws Exception
|
||||||
{
|
{
|
||||||
@@ -91,8 +119,9 @@ public class BaseUnitTest
|
|||||||
{
|
{
|
||||||
Database db = new JdbcDatabase(
|
Database db = new JdbcDatabase(
|
||||||
DriverManager.getConnection("jdbc:sqlite::memory:"));
|
DriverManager.getConnection("jdbc:sqlite::memory:"));
|
||||||
|
db.execute("pragma user_version=8;");
|
||||||
MigrationHelper helper = new MigrationHelper(db);
|
MigrationHelper helper = new MigrationHelper(db);
|
||||||
helper.executeMigrations(8, 21);
|
helper.migrateTo(21);
|
||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
catch (SQLException e)
|
catch (SQLException e)
|
||||||
@@ -100,4 +129,33 @@ public class BaseUnitTest
|
|||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void copyAssetToFile(String assetPath, File dst)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
|
IOUtils.copy(openAsset(assetPath), new FileOutputStream(dst));
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
protected InputStream openAsset(String assetPath) throws IOException
|
||||||
|
{
|
||||||
|
InputStream in = getClass().getResourceAsStream(assetPath);
|
||||||
|
if (in != null) return in;
|
||||||
|
|
||||||
|
String basePath = "uhabits-core/src/test/resources/";
|
||||||
|
File file = new File(basePath + assetPath);
|
||||||
|
if (file.exists() && file.canRead()) in = new FileInputStream(file);
|
||||||
|
if (in != null) return in;
|
||||||
|
|
||||||
|
throw new IllegalStateException("asset not found: " + assetPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Database openDatabaseResource(String path) throws IOException
|
||||||
|
{
|
||||||
|
InputStream original = openAsset(path);
|
||||||
|
File tmpDbFile = File.createTempFile("database", ".db");
|
||||||
|
tmpDbFile.deleteOnExit();
|
||||||
|
IOUtils.copy(original, new FileOutputStream(tmpDbFile));
|
||||||
|
return databaseOpener.open(tmpDbFile);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,179 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2017 Álinson Santos Xavier <isoron@gmail.com>
|
||||||
|
*
|
||||||
|
* This file is part of Loop Habit Tracker.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by the
|
||||||
|
* Free Software Foundation, either version 3 of the License, or (at your
|
||||||
|
* option) any later version.
|
||||||
|
*
|
||||||
|
* Loop Habit Tracker is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||||
|
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License along
|
||||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.isoron.uhabits.core.database.migrations;
|
||||||
|
|
||||||
|
import org.isoron.uhabits.core.*;
|
||||||
|
import org.isoron.uhabits.core.database.*;
|
||||||
|
import org.isoron.uhabits.core.models.*;
|
||||||
|
import org.isoron.uhabits.core.models.sqlite.*;
|
||||||
|
import org.isoron.uhabits.core.test.*;
|
||||||
|
import org.junit.*;
|
||||||
|
import org.junit.rules.*;
|
||||||
|
|
||||||
|
import static junit.framework.TestCase.*;
|
||||||
|
import static org.hamcrest.MatcherAssert.*;
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
public class Version22Test extends BaseUnitTest
|
||||||
|
{
|
||||||
|
@Rule
|
||||||
|
public ExpectedException exception = ExpectedException.none();
|
||||||
|
|
||||||
|
private Database db;
|
||||||
|
|
||||||
|
private MigrationHelper helper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception
|
||||||
|
{
|
||||||
|
super.setUp();
|
||||||
|
db = openDatabaseResource("/databases/021.db");
|
||||||
|
helper = new MigrationHelper(db);
|
||||||
|
modelFactory = new SQLModelFactory(db);
|
||||||
|
habitList = modelFactory.buildHabitList();
|
||||||
|
fixtures = new HabitFixtures(modelFactory);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKeepValidReps() throws Exception
|
||||||
|
{
|
||||||
|
db.query("select count(*) from repetitions",
|
||||||
|
(c) -> assertThat(c.getInt(0), equalTo(3)));
|
||||||
|
|
||||||
|
helper.migrateTo(22);
|
||||||
|
|
||||||
|
db.query("select count(*) from repetitions",
|
||||||
|
(c) -> assertThat(c.getInt(0), equalTo(3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveRepsWithInvalidId() throws Exception
|
||||||
|
{
|
||||||
|
db.execute("insert into Repetitions(habit, timestamp, value) " +
|
||||||
|
"values (99999, 100, 2)");
|
||||||
|
db.query("select count(*) from repetitions where habit = 99999",
|
||||||
|
(c) -> assertThat(c.getInt(0), equalTo(1)));
|
||||||
|
|
||||||
|
helper.migrateTo(22);
|
||||||
|
|
||||||
|
db.query("select count(*) from repetitions where habit = 99999",
|
||||||
|
(c) -> assertThat(c.getInt(0), equalTo(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisallowNewRepsWithInvalidRef() throws Exception
|
||||||
|
{
|
||||||
|
helper.migrateTo(22);
|
||||||
|
exception.expectMessage(containsString("FOREIGNKEY"));
|
||||||
|
db.execute("insert into Repetitions(habit, timestamp, value) " +
|
||||||
|
"values (99999, 100, 2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveRepetitionsWithNullTimestamp() throws Exception
|
||||||
|
{
|
||||||
|
db.execute("insert into repetitions(habit, value) values (0, 2)");
|
||||||
|
db.query("select count(*) from repetitions where timestamp is null",
|
||||||
|
(c) -> assertThat(c.getInt(0), equalTo(1)));
|
||||||
|
|
||||||
|
helper.migrateTo(22);
|
||||||
|
|
||||||
|
db.query("select count(*) from repetitions where timestamp is null",
|
||||||
|
(c) -> assertThat(c.getInt(0), equalTo(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisallowNullTimestamp() throws Exception
|
||||||
|
{
|
||||||
|
helper.migrateTo(22);
|
||||||
|
exception.expectMessage(containsString("SQLITE_CONSTRAINT_NOTNULL"));
|
||||||
|
db.execute("insert into Repetitions(habit, value) " + "values (0, 2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveRepetitionsWithNullHabit() throws Exception
|
||||||
|
{
|
||||||
|
db.execute("insert into repetitions(timestamp, value) values (0, 2)");
|
||||||
|
db.query("select count(*) from repetitions where habit is null",
|
||||||
|
(c) -> assertThat(c.getInt(0), equalTo(1)));
|
||||||
|
|
||||||
|
helper.migrateTo(22);
|
||||||
|
|
||||||
|
db.query("select count(*) from repetitions where habit is null",
|
||||||
|
(c) -> assertThat(c.getInt(0), equalTo(0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisallowNullHabit() throws Exception
|
||||||
|
{
|
||||||
|
helper.migrateTo(22);
|
||||||
|
exception.expectMessage(containsString("SQLITE_CONSTRAINT_NOTNULL"));
|
||||||
|
db.execute(
|
||||||
|
"insert into Repetitions(timestamp, value) " + "values (5, 2)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRemoveDuplicateRepetitions() throws Exception
|
||||||
|
{
|
||||||
|
db.execute("insert into repetitions(habit, timestamp, value)" +
|
||||||
|
"values (0, 100, 2)");
|
||||||
|
db.execute("insert into repetitions(habit, timestamp, value)" +
|
||||||
|
"values (0, 100, 5)");
|
||||||
|
db.execute("insert into repetitions(habit, timestamp, value)" +
|
||||||
|
"values (0, 100, 10)");
|
||||||
|
db.query(
|
||||||
|
"select count(*) from repetitions where timestamp=100 and habit=0",
|
||||||
|
(c) -> assertThat(c.getInt(0), equalTo(3)));
|
||||||
|
|
||||||
|
helper.migrateTo(22);
|
||||||
|
|
||||||
|
db.query(
|
||||||
|
"select count(*) from repetitions where timestamp=100 and habit=0",
|
||||||
|
(c) -> assertThat(c.getInt(0), equalTo(1)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDisallowNewDuplicateTimestamps() throws Exception
|
||||||
|
{
|
||||||
|
helper.migrateTo(22);
|
||||||
|
db.execute("insert into repetitions(habit, timestamp, value)" +
|
||||||
|
"values (0, 100, 2)");
|
||||||
|
exception.expectMessage(containsString("SQLITE_CONSTRAINT_UNIQUE"));
|
||||||
|
db.execute("insert into repetitions(habit, timestamp, value)" +
|
||||||
|
"values (0, 100, 5)");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testKeepHabitsUnchanged() throws Exception
|
||||||
|
{
|
||||||
|
Habit original = fixtures.createLongHabit();
|
||||||
|
Reminder reminder = new Reminder(8, 30, new WeekdayList(100));
|
||||||
|
original.setReminder(reminder);
|
||||||
|
habitList.update(original);
|
||||||
|
|
||||||
|
helper.migrateTo(22);
|
||||||
|
|
||||||
|
((SQLiteHabitList) habitList).reload();
|
||||||
|
Habit modified = habitList.getById(original.getId());
|
||||||
|
assertNotNull(modified);
|
||||||
|
|
||||||
|
assertThat(original.getData(), equalTo(modified.getData()));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,25 +19,18 @@
|
|||||||
|
|
||||||
package org.isoron.uhabits.core.io;
|
package org.isoron.uhabits.core.io;
|
||||||
|
|
||||||
import android.support.annotation.*;
|
|
||||||
|
|
||||||
import org.apache.commons.io.*;
|
|
||||||
import org.isoron.uhabits.core.*;
|
import org.isoron.uhabits.core.*;
|
||||||
import org.isoron.uhabits.core.database.*;
|
|
||||||
import org.isoron.uhabits.core.models.*;
|
import org.isoron.uhabits.core.models.*;
|
||||||
import org.isoron.uhabits.core.utils.*;
|
import org.isoron.uhabits.core.utils.*;
|
||||||
import org.junit.*;
|
import org.junit.*;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.sql.*;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import sun.reflect.generics.reflectiveObjects.*;
|
|
||||||
|
|
||||||
import static junit.framework.TestCase.assertFalse;
|
import static junit.framework.TestCase.assertFalse;
|
||||||
import static org.hamcrest.MatcherAssert.*;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.core.IsEqual.*;
|
import static org.hamcrest.core.IsEqual.*;
|
||||||
import static org.isoron.uhabits.core.models.Frequency.THREE_TIMES_PER_WEEK;
|
import static org.isoron.uhabits.core.models.Frequency.*;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
public class ImportTest extends BaseUnitTest
|
public class ImportTest extends BaseUnitTest
|
||||||
@@ -67,6 +60,7 @@ public class ImportTest extends BaseUnitTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore
|
||||||
public void testLoopDB() throws IOException
|
public void testLoopDB() throws IOException
|
||||||
{
|
{
|
||||||
importFromFile("loop.db");
|
importFromFile("loop.db");
|
||||||
@@ -131,17 +125,6 @@ public class ImportTest extends BaseUnitTest
|
|||||||
return h.getRepetitions().containsTimestamp(date.getTimeInMillis());
|
return h.getRepetitions().containsTimestamp(date.getTimeInMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void copyAssetToFile(String assetPath, File dst) throws IOException
|
|
||||||
{
|
|
||||||
InputStream in = getClass().getResourceAsStream(assetPath);
|
|
||||||
if(in == null) {
|
|
||||||
File file = new File("uhabits-core/src/test/resources/" + assetPath);
|
|
||||||
if(file.exists()) in = new FileInputStream(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
IOUtils.copy(in, new FileOutputStream(dst));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void importFromFile(String assetFilename) throws IOException
|
private void importFromFile(String assetFilename) throws IOException
|
||||||
{
|
{
|
||||||
File file = File.createTempFile("asset", "");
|
File file = File.createTempFile("asset", "");
|
||||||
@@ -149,31 +132,10 @@ public class ImportTest extends BaseUnitTest
|
|||||||
assertTrue(file.exists());
|
assertTrue(file.exists());
|
||||||
assertTrue(file.canRead());
|
assertTrue(file.canRead());
|
||||||
|
|
||||||
DatabaseOpener opener = new DatabaseOpener() {
|
|
||||||
@Override
|
|
||||||
public Database open(@NonNull File file)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return new JdbcDatabase(DriverManager.getConnection(
|
|
||||||
String.format("jdbc:sqlite:%s", file.getAbsolutePath())));
|
|
||||||
}
|
|
||||||
catch (SQLException e)
|
|
||||||
{
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public File getProductionDatabaseFile()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
GenericImporter importer = new GenericImporter(habitList,
|
GenericImporter importer = new GenericImporter(habitList,
|
||||||
new LoopDBImporter(habitList, opener),
|
new LoopDBImporter(habitList, databaseOpener),
|
||||||
new RewireDBImporter(habitList, modelFactory, opener),
|
new RewireDBImporter(habitList, modelFactory, databaseOpener),
|
||||||
new TickmateDBImporter(habitList, modelFactory, opener),
|
new TickmateDBImporter(habitList, modelFactory, databaseOpener),
|
||||||
new HabitBullCSVImporter(habitList, modelFactory));
|
new HabitBullCSVImporter(habitList, modelFactory));
|
||||||
|
|
||||||
assertTrue(importer.canHandle(file));
|
assertTrue(importer.canHandle(file));
|
||||||
|
|||||||
BIN
uhabits-core/src/test/resources/databases/021.db
Normal file
BIN
uhabits-core/src/test/resources/databases/021.db
Normal file
Binary file not shown.
Reference in New Issue
Block a user