diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/database/AndroidDatabaseTest.java b/uhabits-android/src/androidTest/java/org/isoron/uhabits/database/AndroidDatabaseTest.java new file mode 100644 index 000000000..24ca2e975 --- /dev/null +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/database/AndroidDatabaseTest.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2015-2017 Álinson Santos Xavier + * + * 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 . + */ + +package org.isoron.uhabits.database; + +import android.database.sqlite.*; + +import org.isoron.uhabits.*; +import org.isoron.uhabits.core.database.*; +import org.junit.*; + +import java.util.*; + +import static org.hamcrest.MatcherAssert.*; +import static org.hamcrest.core.IsEqual.*; + + +public class AndroidDatabaseTest extends BaseAndroidTest +{ + private AndroidDatabase db; + + @Override + public void setUp() + { + super.setUp(); + db = new AndroidDatabase(SQLiteDatabase.create(null)); + db.execute("create table test(color int, name string)"); + } + + @Test + public void testInsert() throws Exception + { + HashMap map = new HashMap<>(); + map.put("name", "asd"); + map.put("color", null); + db.insert("test", map); + + Cursor c = db.query("select * from test"); + c.moveToNext(); + assertNull(c.getInt(0)); + assertThat(c.getString(1), equalTo("asd")); + } +} diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidCursor.java b/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidCursor.java index cbc8a6a58..c3c43fe5f 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidCursor.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidCursor.java @@ -21,6 +21,8 @@ package org.isoron.uhabits.database; +import android.support.annotation.*; + import org.isoron.uhabits.core.database.*; public class AndroidCursor implements Cursor @@ -45,26 +47,34 @@ public class AndroidCursor implements Cursor } @Override + @Nullable public Integer getInt(int index) { - return cursor.getInt(index); + if(cursor.isNull(index)) return null; + else return cursor.getInt(index); } @Override + @Nullable public Long getLong(int index) { - return cursor.getLong(index); + if(cursor.isNull(index)) return null; + else return cursor.getLong(index); } @Override + @Nullable public Double getDouble(int index) { - return cursor.getDouble(index); + if(cursor.isNull(index)) return null; + else return cursor.getDouble(index); } @Override + @Nullable public String getString(int index) { - return cursor.getString(index); + if(cursor.isNull(index)) return null; + else return cursor.getString(index); } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabase.java b/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabase.java index 419a190f5..b6bdd1fa4 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabase.java +++ b/uhabits-android/src/main/java/org/isoron/uhabits/database/AndroidDatabase.java @@ -107,8 +107,9 @@ public class AndroidDatabase implements Database ContentValues values = new ContentValues(); for (Map.Entry entry : map.entrySet()) { - if (entry.getValue() == null) continue; - if (entry.getValue() instanceof Integer) + if (entry.getValue() == null) + values.putNull(entry.getKey()); + else if (entry.getValue() instanceof Integer) values.put(entry.getKey(), (Integer) entry.getValue()); else if (entry.getValue() instanceof Long) values.put(entry.getKey(), (Long) entry.getValue()); diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/database/Cursor.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/database/Cursor.java index 7e7ef0b67..4085c86b1 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/database/Cursor.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/database/Cursor.java @@ -19,18 +19,50 @@ package org.isoron.uhabits.core.database; +import android.support.annotation.*; + public interface Cursor extends AutoCloseable { @Override void close(); + /** + * Moves the cursor forward one row from its current position. Returns + * true if the current position is valid, or false if the cursor is already + * past the last row. The cursor start at position -1, so this method must + * be called first. + */ boolean moveToNext(); + /** + * Retrieves the value of the designated column in the current row of this + * Cursor as an Integer. If the value is null, returns null. The first + * column has index zero. + */ + @Nullable Integer getInt(int index); + /** + * Retrieves the value of the designated column in the current row of this + * Cursor as a Long. If the value is null, returns null. The first + * column has index zero. + */ + @Nullable Long getLong(int index); + /** + * Retrieves the value of the designated column in the current row of this + * Cursor as a Double. If the value is null, returns null. The first + * column has index zero. + */ + @Nullable Double getDouble(int index); + /** + * Retrieves the value of the designated column in the current row of this + * Cursor as a String. If the value is null, returns null. The first + * column has index zero. + */ + @Nullable String getString(int index); } diff --git a/uhabits-core/src/main/java/org/isoron/uhabits/core/database/JdbcCursor.java b/uhabits-core/src/main/java/org/isoron/uhabits/core/database/JdbcCursor.java index 94740f086..3e3797d9d 100644 --- a/uhabits-core/src/main/java/org/isoron/uhabits/core/database/JdbcCursor.java +++ b/uhabits-core/src/main/java/org/isoron/uhabits/core/database/JdbcCursor.java @@ -63,7 +63,9 @@ public class JdbcCursor implements Cursor { try { - return resultSet.getInt(index + 1); + Integer value = resultSet.getInt(index + 1); + if(resultSet.wasNull()) return null; + else return value; } catch (SQLException e) { @@ -76,7 +78,9 @@ public class JdbcCursor implements Cursor { try { - return resultSet.getLong(index + 1); + Long value = resultSet.getLong(index + 1); + if(resultSet.wasNull()) return null; + else return value; } catch (SQLException e) { @@ -89,7 +93,9 @@ public class JdbcCursor implements Cursor { try { - return resultSet.getDouble(index + 1); + Double value = resultSet.getDouble(index + 1); + if(resultSet.wasNull()) return null; + else return value; } catch (SQLException e) { @@ -102,7 +108,9 @@ public class JdbcCursor implements Cursor { try { - return resultSet.getString(index + 1); + String value = resultSet.getString(index + 1); + if(resultSet.wasNull()) return null; + else return value; } catch (SQLException e) { diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/database/RepositoryTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/database/RepositoryTest.java index 94872ed2f..fe5f7782c 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/database/RepositoryTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/database/RepositoryTest.java @@ -47,7 +47,7 @@ public class RepositoryTest extends BaseUnitTest db.execute("create table tests(" + "id integer not null primary key autoincrement, " + "color_number integer not null, score float not null, " + - "name string not null)"); + "name string)"); } @Test @@ -82,6 +82,21 @@ public class RepositoryTest extends BaseUnitTest assertThat(record, equalTo(repository.find(50L))); } + @Test + public void testSave_withNull() throws Exception + { + ThingRecord record = new ThingRecord(); + record.color = 50; + record.name = null; + record.score = 12.0; + repository.save(record); + + ThingRecord retrieved = repository.find(record.id); + assertNotNull(retrieved); + assertNull(retrieved.name); + assertThat(record, equalTo(retrieved)); + } + @Test public void testSave_withoutId() throws Exception { diff --git a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.java b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.java index 09d8f958d..30b92af0a 100644 --- a/uhabits-core/src/test/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.java +++ b/uhabits-core/src/test/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecordTest.java @@ -32,7 +32,7 @@ public class HabitRecordTest extends BaseUnitTest { @Test - public void testCopyFrom() + public void testCopyRestore1() { Habit original = modelFactory.buildHabit(); original.setName("Hello world"); @@ -52,4 +52,30 @@ public class HabitRecordTest extends BaseUnitTest assertThat(original.getData(), equalTo(duplicate.getData())); } + + @Test + public void testCopyRestore2() + { + Habit original = modelFactory.buildHabit(); + original.setName("Hello world"); + original.setDescription("Did you greet the world today?"); + original.setColor(5); + original.setArchived(false); + original.setFrequency(Frequency.DAILY); + original.setReminder(null); + original.setId(1L); + original.setPosition(15); + original.setType(Habit.NUMBER_HABIT); + original.setTargetValue(100); + original.setTargetType(Habit.AT_LEAST); + original.setUnit("miles"); + + HabitRecord record = new HabitRecord(); + record.copyFrom(original); + + Habit duplicate = modelFactory.buildHabit(); + record.copyTo(duplicate); + + assertThat(original.getData(), equalTo(duplicate.getData())); + } }