For loops and too many if else how to test - java

I have a code which goes like this
List insert;
List update;
List delete
for(SomeObject someObj : someObjects){
if(isNew){
insert.add()
}
else if(isUpdate){
update.add();
}
if(isDelete){
delete.add()
}
}
//call update insert delete functions
The problem is this code is untestable because the update insert delete are all void methods.
My question is , should I consider iterating over the loop three times and then get the lists to test if the logic to filter each type of results is working? The cost is not that much since I am expecting <100 elements in the list.

You can check
(sum of lists sizes after) == (sum of lists sizes before) + someObjects.size();

The key here is to be able to control the dependencies and access the state that this method acts upon.
Here is an example that illustrates that:
interface SomeDao {
void add(SomeObject object);
void update(SomeObject object);
void delete(SomeObject object);
}
class SomeDaoStub implements SomeDao {
#Override public void add(SomeObject object) {}
#Override public void update(SomeObject object) {}
#Override public void delete(SomeObject object) {}
}
class SomeObject {
private final boolean isNew;
private final boolean isUpdated;
private final boolean isDeleted;
SomeObject(boolean isNew, boolean isUpdated, boolean isDeleted) {
this.isNew = isNew;
this.isUpdated = isUpdated;
this.isDeleted = isDeleted;
}
public boolean isNew() {
return isNew;
}
public boolean isUpdated() {
return isUpdated;
}
public boolean isDeleted() {
return isDeleted;
}
}
public void doSomethingComplicatedWithListsInAForLoop(Iterable<SomeObject> someObjects, SomeDao dao) {
for (SomeObject someObject : someObjects) {
if (someObject.isNew()) {
dao.add(someObject);
} else if (someObject.isUpdated()) {
dao.update(someObject);
} else if (someObject.isDeleted()) {
dao.delete(someObject);
}
}
}
#Test
public void itDeletesObjectsMarkedToBeDeleted() {
final List<SomeObject> actualDeletedObjects = new ArrayList<>();
List<SomeObject> expectedDeletedObjects = Arrays.asList(
new SomeObject(false, false, true),
new SomeObject(false, false, true),
new SomeObject(false, false, true)
);
SomeDao theDao = new SomeDaoStub() {
#Override
public void delete(SomeObject object) {
actualDeletedObjects.add(object);
}
};
doSomethingComplicatedWithListsInAForLoop(expectedDeletedObjects, theDao);
assertEquals(expectedDeletedObjects, actualDeletedObjects);
}
The only reason that I can figure out what doSomethingComplicatedWithListsInAForLoop manipulated is because I can control its dependencies, namely, in this example, SomeDao.
It is likely that you are finding difficulty testing your method because it makes calls to state which you cannot inject.

Related

Entity cannot be converted to ArrayList<Entity>

I want to read out the first element of an ArrayList. The problem is when i construct a return method i get an error saying 'Entity cannot be converted to ArrayList'. The return function needs to be a public ArrayList, because i'm using a foreach to return the values. Can someone tell me what i'm doing wrong and what i can do to improve this?
Entity manager (public ArrayList) doesn't work.
public class EntityManager {
private Handler handler;
private Player player;
private ArrayList<Entity> entities;
private int counter = 0;
private Comparator<Entity> renderOrder = new Comparator<Entity>(){
#Override
public int compare(Entity a, Entity b) {
if(a.getY() + a.getHeight() < b.getY() + b.getHeight())
return -1;
return 1;
}
};
public EntityManager(Handler handler, Player player){
this.handler = handler;
this.player = player;
entities = new ArrayList<Entity>();
addEntity(player);
}
public void tick(){
Iterator<Entity> it = entities.iterator();
while(it.hasNext()){
Entity e = it.next();
e.tick();
if(!e.isActief()){
it.remove();
counter();
if(counter > entities.size() + 1){
player.eindspel = true;
}
}
}
entities.sort(renderOrder);
}
public void render(Graphics g){
for(Entity e : entities){
e.render(g);
}
player.postRender(g);
}
public ArrayList<Entity> getEntities() {
return entities.get(0);
}
public void counter(){
counter++;
}
public void addEntity(Entity e){
entities.add(e);
}
public void setHandler(Handler handler) {
this.handler = handler;
}
public void setPlayer(Player player) {
this.player = player;
}
public void setEntities(ArrayList<Entity> entities) {
this.entities = entities;
}
public Handler getHandler() {
return handler;
}
public Player getPlayer() {
return player;
}
}
The foreach i'm am using to read out the values from getEntities
for(Entity e : handler.getWereld().getEntityManager().getEntities()){
if(e.equals(this)){
continue;
}
if(e.getCollisionBounds(0, 0).intersects(ar)){
if(opslag.delete()){
e.delete(2);
}
}
}
The outcome i want is when e intersects i want to delete the entity that i get with 'return entities.get(0)', so the first entity of my entities arraylist. only that method won't work and when i use 'return entities' all of my entites get deleted, instead of only the first one.
If you would generalize your external interface to use List instead of ArrayList (see here why that's a good idea), you could just use Collections.singletonList to construct a list containing the first entity.
However, it seems pretty unintuitive to me to have a method called getEntities that just returns one entity. I still don't really get when you want to get all entities, and when just one. Maybe you can edit your question to explain your use case a little more
you are calling delete(int ) method on an Entity
e.delete(2);
and the method is applicable to collection I think it it were your problem comes from.

Enum support and custom logic in setters of realm object class

I'm implementing custom logic in setters and enums in realm object class like this.-
public class SellerProducts extends RealmObject{
public Boolean isValid=true;
public String is_valid="";
public String quantity;
public int quantity_;
public String enumvalue;
public void setIs_valid(String is_valid){
if (is_valid.equals("0")) {
this.isValid = false;
}
this.is_valid=is_valid;
}
public String getIs_valid(){
return this.is_valid;
}
public void setQuantity(String quantity){
this.quantity=quantity;
try {
quantity_ = Integer.parseInt(this.quantity);
} catch (NumberFormatException e) {
e.printStackTrace();
}
if (!this.isValid) {
setEnum(ProductType.IN_ACTIVE);
} else if (this.quantity_ <= 0) {
setEnum(ProductType.OUT_OF_STOCK);
} else {
setEnum(ProductType.ACTIVE);
}
}
public String getQuantity(){
return this.quantity;
}
public enum ProductType {
ACTIVE, IN_ACTIVE, OUT_OF_STOCK
};
public void setEnum(ProductType val) {
this.enumvalue=val.toString().toUpperCase();
}
public ProductType getEnum() {
return ProductType.valueOf(enumvalue);
}
}
when i am calling getEnum from the other fragment class it is returning null exception like this
*java.lang.NullPointerException: name == null
at java.lang.Enum.valueOf(Enum.java:189)
at com.localwizard.realm_db.SellerProducts$ProductType.valueOf(SellerProducts.java:331)
at com.localwizard.realm_db.SellerProducts.getEnum(SellerProducts.java:348)*
I'm new to realm so I don't know where I'm wrong?
Ashish, i think you are not setting the ProductType enum and trying to get it and you geeting the exception. Here is the code which i have tried and it is working fine -
public class OtherFragment {
public static void main(String[] aa)
{
SellerProducts sp = new SellerProducts();
sp.setQuantity("10"); // setting the quantity
System.out.println(sp.getEnum()); // ACTIVE is set as Enum
System.out.println(sp.getQuantity()); // 10
System.out.println(sp.getEnum() == ProductType.ACTIVE); // true
sp.setEnum(ProductType.IN_ACTIVE); // Now IN_ACTIVE is set
System.out.println(sp.getEnum() == ProductType.ACTIVE); // false
}
}
If this is not what you want then please add your peace of code, how you meant to set the quantity and trying to get the enum value.
If it answers your question then please accept the answer.

Unique classes in generic list

I have a generic class with a generic list in it. I want to ensure that the generic list only contains unique classes.
What I have done so far is to compare the class names with reflection (getClass()). But I think that's not a clean solution. Are there any better practices to check?
public class MyGenericClass<T extends MyGenericClass.MyInterface> {
private List<T> members = new ArrayList<>(0);
public void add(T t) {
final boolean[] classInMembers = {false};
members.forEach(member -> {
if (member.getClass().getName().equals(t.getClass().getName())) {
classInMembers[0] = true;
}
});
if (!classInMembers[0]) {
members.add(t);
}
}
public interface MyInterface {
void doSomething(String text);
}
}
public class Main {
public static void main(String[] args) {
MyGenericClass<MyGenericClass.MyInterface> myGenericClass = new MyGenericClass<>();
myGenericClass.add(new Performer1());
myGenericClass.add(new Performer2());
myGenericClass.add(new Performer3());
myGenericClass.add(new Performer3()); // should not be inserted!
}
private static class Performer1 implements MyGenericClass.MyInterface {
#Override
public void doSomething(String text) {
text = "Hi, I am performer 1!";
}
}
private static class Performer2 implements MyGenericClass.MyInterface {
#Override
public void doSomething(String text) {
text = "Hi, I am performer 2!";
}
}
private static class Performer3 implements MyGenericClass.MyInterface {
#Override
public void doSomething(String text) {
text = "Hi, I am performer 3!";
}
}
}
You could subclass a java.util.Set interface implementation. It will likely be easiest to subclass java.util.AbstractSet.
By default 'Set' will compare objects by their .equals() method - In your case, this is not sufficient. You will need to override the contains method to ensure that only instances of a unique class are added.
In your overrideen contains, it's probably the same / easier to compare class instances rather than their stringified package name
I.e. use a.getClass() == b.getClass(), rather than a.getClass().getName()
Don't use a List, use a java.util.Set instead.
A collection that contains no duplicate elements. More formally, sets contain no pair of elements e1 and e2 such that e1.equals(e2), and at most one null element.
If the iteration order is important or if you want to use a custom Comparator, the TreeSet implementation can be used:
A NavigableSet implementation based on a TreeMap. The elements are ordered using their natural ordering, or by a Comparator provided at set creation time, depending on which constructor is used.
Example of a Set using a Comparator:
class MyComparator implements Comparator<Object> {
#Override
public int compare(Object e1, Object e2) {
if (e1.getClass() == e2.getClass())
return 0;
//if you wish to have some extra sort order
return e1.getClass().getName().compareTo(e2.getClass().getName());
}
}
. . .
Set mySet = new TreeSet<Object>(new MyComparator());
mySet.add(new Object());
mySet.add(new Object());//same class already in set
mySet.add("wtf");
//mySet.size() is now 2 - the second "new Object()" was not inserted due to the comparator check
Why so complicated?
public class Main {
public static void main(String[] args) {
final Class<?> helloClass = "Hello".getClass();
final Class<?> worldClass = "World".getClass();
final Class<?> intClass = Integer.class;
System.out.println(helloClass.equals(worldClass)); // -> true
System.out.println(helloClass.equals(intClass)); // -> false
}
}
You could maintain a roster of members in a Set.
public static class MyGenericClass<T extends MyGenericClass.MyInterface> {
private List<T> members = new ArrayList<>(0);
// Add this.
private Set<Class<?>> roster = new HashSet<>();
public void add(T t) {
if (!roster.contains(t.getClass())) {
members.add(t);
roster.add(t.getClass());
}
}
private void soundOff() {
for (T t : members) {
t.doSomething();
}
}
public interface MyInterface {
void doSomething();
}
}
private static class Performer implements MyGenericClass.MyInterface {
final int n;
public Performer(int n) {
this.n = n;
}
#Override
public void doSomething() {
System.out.println("Hi, I am a " + this.getClass().getSimpleName() + "(" + n + ")");
}
}
private static class Performer1 extends Performer {
public Performer1(int n) {
super(n);
}
}
private static class Performer2 extends Performer {
public Performer2(int n) {
super(n);
}
}
private static class Performer3 extends Performer {
public Performer3(int n) {
super(n);
}
}
public void test() {
MyGenericClass<MyGenericClass.MyInterface> myGenericClass = new MyGenericClass<>();
myGenericClass.add(new Performer1(1));
myGenericClass.add(new Performer2(2));
myGenericClass.add(new Performer3(3));
myGenericClass.add(new Performer3(4)); // should not be inserted!
myGenericClass.soundOff();
}
You could implement a Wrapper which provides the necessary comparison and add the wrapped instance to the set. This way you don't have to override equals and hashcode in your concrete Performer classes and you don't have to subclass a concrete Set implementation (which you are coupled to. When you subclass a HashSet, you have to use that concrete class. But what if you want to use a LinkedHashSet at some point? You have to override LinkedHashSet as well) , which may be fragile since you have to make sure that the overridden method is consistent with the rest of the class.
class MyGenericClass<T extends MyInterface> {
private Set<ClassCompareWrapper<T>> members = new HashSet<>();
public void add(T t) {
members.add(new ClassCompareWrapper<T>(t));
}
}
class ClassCompareWrapper<T> {
T t;
public ClassCompareWrapper(T t) {
this.t = t;
}
#Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof ClassCompareWrapper))
return false;
ClassCompareWrapper<?> that = (ClassCompareWrapper<?>) o;
return Objects.equals(t.getClass(), that.t.getClass());
}
#Override
public int hashCode() {
return Objects.hash(t.getClass());
}
#Override
public String toString() {
return "Wrapper{" +
"t=" + t +
'}';
}
}
Here are a few other ideas.
Using streams:
public void add(T t) {
if (!members.stream().anyMatch(m -> m.getClass() == t.getClass())) {
members.add(t);
}
}
Using AbstractSet and HashMap:
class ClassSet<E> extends AbstractSet<E> {
private final Map<Class<?>, E> map = new HashMap<>();
#Override
public boolean add(E e) {
// this can be
// return map.putIfAbsent(e.getClass(), e) != null;
// in Java 8
Class<?> clazz = e.getClass();
if (map.containsKey(clazz)) {
return false;
} else {
map.put(clazz, e);
return true;
}
}
#Override
public boolean remove(Object o) {
return map.remove(o.getClass()) != null;
}
#Override
public boolean contains(Object o) {
return map.containsKey(o.getClass());
}
#Override
public int size() {
return map.size();
}
#Override
public Iterator<E> iterator() {
return map.values().iterator();
}
}
A HashMap could also be used without wrapping it in a Set. The Set interface is defined around equals and hashCode, so any implementation which deviates from this is technically non-contractual. Additionally, you might want to use LinkedHashMap if the values are iterated often.

Mockito matcher that compares items in Set, not the Set reference itself

when(validator.isValid(Sets.newHashSet("valid"))).thenReturn(true);
When validator.isValid(set) is invoked it returns false. It is because the validator implementation creates a new set that is different that the passed one (reference is different) - the items in both sets are same.
I need to return true if sets contains same items regardless of sets instances.
Something similar to org.mockito.Matchers:
public static <T> Set<T> anySetOf(Class<T> clazz) {
return (Set) reportMatcher(Any.ANY).returnSet();
}
except that I would pass instances not Class<T>.class.
And same for verify:
verify(validator, times(1)).isValid(Sets.newHashSet("valid"));
Is there such a matcher?
Apparently JB Nizet is right. There is no need for a specific matcher.
I have tried to use my own matcher and then after removal it worked also:
public static class SetItemMatcher extends ArgumentMatcher<Set<String>> {
public static Set<String> setOf(Set<String> items) {
return argThat(new SetItemMatcher(items));
}
private final Set<String> expected;
public SetItemMatcher(Set<String> expected) {
this.expected = expected;
}
#Override
public boolean matches(Object argument) {
Set<?> actual = (Set<?>) argument;
return actual.size() == expected.size() && containsAllItems(actual);
}
private boolean containsAllItems(Set<?> actual) {
for (Object o : actual) {
if (!expected.contains(o)) {
return false;
}
}
return true;
}
}
While Felix's answer is absolutely correct, I slightly modified it to cover more use-cases (i.e. covering any Collection with builder methods for Set and List):
Work with any collection, not just sets.
Added utility methods to create a list or set based on either just one item or another list/set
public class CollectionItemMatcher<T extends Collection> implements ArgumentMatcher<T> {
public static Set setOf(Object oneItem) {
return setOf(Sets.newHashSet(oneItem));
}
public static Set setOf(Collection items) {
return ArgumentMatchers.argThat(new CollectionItemMatcher<Set>(Sets.newHashSet(items)));
}
public static Set emptySet() {
return setOf(Sets.newHashSet());
}
public static List listOf(Object oneItem) {
return listOf(Lists.newArrayList(oneItem));
}
public static List listOf(Collection items) {
return ArgumentMatchers.argThat(new CollectionItemMatcher<List>(Lists.newArrayList(items)));
}
public static List emptyList() {
return listOf(Lists.newArrayList());
}
private final T expected;
public CollectionItemMatcher(T expected) {
this.expected = expected;
}
#Override
public boolean matches(T actual) {
return actual.size() == expected.size() && containsAllItems(actual);
}
private boolean containsAllItems(T actual) {
for (Object o : actual) {
if (!expected.contains(o)) {
return false;
}
}
return true;
}
}
Then you can do something like this:
verify(validator, times(1)).isValid(CollectionItemMatcher.setOf("valid"));

How would you add a delete and edit function to the Address book program?

So i am practicing TableView through this example:
http://docs.oracle.com/javase/8/javafx/fxml-tutorial/fxml_tutorial_intermediate.htm
I understand everything in it, except I wanted to extend it further and include a delete and edit function as well. Could somebody please help me!? I've been trying for a while now but nothing seems to be working.
This is my add function (which works):
#FXML
protected void addMusic(ActionEvent actionEvent) {
ObservableList<Music> data = tableView.getItems();
data.add(new Music(albumField.getText(),
songField.getText(),
genreField.getText()
));
albumField.setText("");
songField.setText("");
genreField.setText("");
}
my Delete function which doesn't work:
#FXML
protected void deleteMusic(ActionEvent actionEvent) {
ObservableList<Music> data = tableView.getItems();
data.remove(new Music(albumField.deleteText(),
songField.deleteText(),
genreField.deleteText()
));
}
}
Thanks
Changed deleteMusic:
#Override
protected void deleteMusic(ActionEvent actionEvent) {
ObservableList<Music> data = tableView.getItems();
data.remove(equals(Music(albumField.deleteText(), songField.deleteText(), genreField.deleteText());
albumField.setText("");
songField.setText("");
genreField.setText("");
}
Music class:
package sample;
import javafx.beans.property.SimpleStringProperty;
public class Music {
private final SimpleStringProperty album = new SimpleStringProperty("");
private final SimpleStringProperty song = new SimpleStringProperty("");
private final SimpleStringProperty genre = new SimpleStringProperty("");
public Music() {
this("", "", "");
}
public Music(String album, String song, String genre) { //Constructor utilised
setAlbum(album);
setSong(song);
setGenre(genre);
}
public String getAlbum() {
return album.get();
}
public void setAlbum(String sAlbum) {
album.set(sAlbum);
}
public String getSong() {
return song.get();
}
public void setSong(String sAlbum) {
song.set(sAlbum);
}
public String getGenre() {
return genre.get();
}
public void setGenre(String sAlbum) {
genre.set(sAlbum);
}
}
http://i.stack.imgur.com/2SoWs.png
Most java Collections use the equals method to check, if 2 objects are considered to be the same. If the elements of a collection don't override equals, no 2 different objects are considered to be equal, even if they contain equal values in their fields.
You could override equals like this:
...
import java.util.Objects;
public class Music {
...
#Override
public boolean equals(Object obj) {
// make sure equals is symetric
if (obj == null || getClass() != obj.getClass()) {
return false;
}
final Music other = (Music) obj;
// compare strings for equality
return Objects.equals(this.getAlbum(), other.getAlbum())
&& Objects.equals(this.getSong(), other.getSong())
&& Objects.equals(this.getGenre(), other.getGenre());
}
}
You could then use
data.remove(new Music(albumField.getText(), songField.getText(), genreField.getText()));
to remove a Music object from the list.

Categories