StateHelper { public static boolean equalsLoose(Object a, Object b) { if (a == b) { return true; } else if (a instanceof State && b instanceof State || a instanceof State && b == null || a == null && b instanceof State) { return equalsLoose((State) a, (State) b); } else if (a instanceof List && b instanceof List || a instanceof List && b == null || a == null && b instanceof List) { @SuppressWarnings("unchecked") List<Serializable> la = (List<Serializable>) a; @SuppressWarnings("unchecked") List<Serializable> lb = (List<Serializable>) b; return equalsLoose(la, lb); } else if (a instanceof Object[] && b instanceof Object[] || a instanceof Object[] && b == null || a == null && b instanceof Object[]) { return equalsLoose((Object[]) a, (Object[]) b); } else if (a instanceof ListDiff && b instanceof ListDiff) { ListDiff lda = (ListDiff) a; ListDiff ldb = (ListDiff) b; return lda.isArray == ldb.isArray && equalsLoose(lda.diff, ldb.diff) && equalsLoose(lda.rpush, ldb.rpush); } else if (isScalar(a) && isScalar(b)) { return a.equals(b); } else { return false; } } private  StateHelper(); static boolean isScalar(Object value); static boolean equalsStrict(Object a, Object b); static boolean equalsStrict(State a, State b); static boolean equalsStrict(Object[] a, Object[] b); static boolean equalsStrict(List<Serializable> a,
            List<Serializable> b); static boolean equalsLoose(Object a, Object b); static boolean equalsLoose(State a, State b); static boolean equalsLoose(Object[] a, Object[] b); static boolean equalsLoose(List<Serializable> a, List<Serializable> b); static Serializable deepCopy(Object value); static Serializable deepCopy(Object value, boolean threadSafe); static State deepCopy(State state); static State deepCopy(State state, boolean threadSafe); static List<Serializable> deepCopy(List<Serializable> list); static List<Serializable> deepCopy(List<Serializable> list,
            boolean threadSafe); static Serializable diff(Object a, Object b); static Serializable diff(Object[] a, Object[] b); static Serializable diff(List<Object> a, List<Object> b); static StateDiff diff(State a, State b); static void resetDeltas(State state);  }
@Test public void testEqualsLoose() { assertEqualsLoose(null, new String[0]); assertEqualsLoose(new String[0], null); assertEqualsLoose(null, new ArrayList<Serializable>()); assertEqualsLoose(new ArrayList<Serializable>(), null); assertEqualsLoose(new State(), null); assertEqualsLoose(null, new State()); State a = new State(); State b = new State(); assertEqualsLoose(a, b); a.put("foo", null); a.put("bar", null); assertEqualsLoose(a, b); a.put("foo", "bar"); b.put("foo", "bar"); assertEqualsLoose(a, b); b.put("gee", null); assertEqualsLoose(a, b); State c = new State(); assertEqualsLoose(c, null); c.put("foo", list()); assertEqualsLoose(c, null); }