001 // Copyright 2007-2009 Waterken Inc. under the terms of the MIT X license 002 // found at http://www.opensource.org/licenses/mit-license.html 003 package org.waterken.eq; 004 005 import static org.ref_send.promise.Eventual.ref; 006 import static org.ref_send.test.Logic.join; 007 008 import java.io.Serializable; 009 010 import org.ref_send.list.List; 011 import org.ref_send.promise.Deferred; 012 import org.ref_send.promise.Do; 013 import org.ref_send.promise.Eventual; 014 import org.ref_send.promise.Promise; 015 import org.ref_send.promise.Receiver; 016 017 /** 018 * Checks invariants of the ref_send API. 019 */ 020 public final class 021 SoundCheck { 022 private SoundCheck() {} 023 024 /** 025 * Runs a unit test. 026 * @param _ eventual operator 027 */ 028 static public Promise<?> 029 make(final Eventual _) throws Exception { 030 final Deferred<?> x = _.defer(); 031 return join(_, testNormal(_, x.resolver), 032 testNull(_, null), 033 testDouble(_), 034 testFloat(_)); 035 } 036 037 /** 038 * Tests promises for a normal reference. 039 */ 040 static private <T extends Receiver<?>> Promise<?> 041 testNormal(final Eventual _, final T x) throws Exception { 042 final Promise<T> p = ref(x); 043 check(p.equals(p)); 044 check(ref(x).equals(p)); 045 check(x.equals(p.call())); 046 class EQ extends Do<T,Promise<Boolean>> implements Serializable { 047 static private final long serialVersionUID = 1L; 048 049 public Promise<Boolean> 050 fulfill(final T arg) throws Exception { 051 check(x.equals(arg)); 052 return ref(true); 053 } 054 } 055 final Promise<?> a = _.when(p, new EQ()); 056 final Promise<?> b = _.when(x, new EQ()); 057 final Promise<?> c = _.when(new Sneaky<T>(x), new EQ()); 058 059 final T x_ = _._(x); 060 check(x_.equals(x_)); 061 check(_._(x_).equals(x_)); 062 check(_._(x).equals(x_)); 063 check(ref(x_).equals(p)); 064 final Promise<?> d = _.when(x_, new EQ()); 065 066 return join(_, a, b, c, d); 067 } 068 069 /** 070 * Tests promises for a <code>null</code>. 071 */ 072 static private <T extends Receiver<?>> Promise<?> 073 testNull(final Eventual _, final T x) throws Exception { 074 final Promise<T> p = ref(x); 075 check(null == p); 076 class NE extends Do<T,Promise<Boolean>> implements Serializable { 077 static private final long serialVersionUID = 1L; 078 079 public Promise<Boolean> 080 fulfill(final T arg) throws Exception { throw new Exception(); } 081 082 public Promise<Boolean> 083 reject(final Exception reason) throws Exception { 084 if (reason instanceof NullPointerException) {return ref(true);} 085 throw reason; 086 } 087 } 088 final Promise<?> a = _.when(p, new NE()); 089 final Promise<?> b = _.when(x, new NE()); 090 final Promise<?> c = _.when(new Sneaky<T>(x), new NE()); 091 092 final T x_ = Eventual.cast(Receiver.class, p); 093 check(null == x_); 094 check(null == ref(x_)); 095 final Promise<?> d = _.when(x_, new NE()); 096 097 return join(_, a, b, c, d); 098 } 099 100 static private <T> Promise<?> 101 testNaN(final Eventual _, final T x) throws Exception { 102 final Promise<T> p = ref(x); 103 check(p.equals(p)); 104 check(!p.equals(ref(x))); 105 try { 106 p.call(); 107 check(false); 108 } catch (final ArithmeticException e) { /* expected */ } 109 class ENaN extends Do<T,Promise<Boolean>> implements Serializable { 110 static private final long serialVersionUID = 1L; 111 112 public Promise<Boolean> 113 fulfill(final T arg) throws Exception { throw new Exception(); } 114 115 public Promise<Boolean> 116 reject(final Exception reason) throws Exception { 117 if (reason instanceof ArithmeticException) { return ref(true); } 118 throw reason; 119 } 120 } 121 final Promise<?> a = _.when(p, new ENaN()); 122 final Promise<?> b = _.when(x, new ENaN()); 123 final Promise<?> c = _.when(new Sneaky<T>(x), new ENaN()); 124 125 return join(_, a, b, c); 126 } 127 128 /** 129 * Tests promises for {@link Double}. 130 */ 131 static private Promise<?> 132 testDouble(final Eventual _) throws Exception { 133 // check normal handling 134 final Promise<Double> pMin = ref(Double.MIN_VALUE); 135 check(pMin.equals(pMin)); 136 check(ref(Double.MIN_VALUE).equals(pMin)); 137 check(Double.MIN_VALUE == pMin.call()); 138 class EQ extends Do<Double,Promise<Boolean>> implements Serializable { 139 static private final long serialVersionUID = 1L; 140 141 public Promise<Boolean> 142 fulfill(final Double arg) throws Exception { 143 check(Double.MIN_VALUE == arg); 144 return ref(true); 145 } 146 } 147 final Promise<?> a = _.when(pMin, new EQ()); 148 final Promise<?> b = _.when(Double.MIN_VALUE, new EQ()); 149 150 final Promise<?> c = testNaN(_, Double.NaN); 151 final Promise<?> d = testNaN(_, Double.NEGATIVE_INFINITY); 152 final Promise<?> e = testNaN(_, Double.POSITIVE_INFINITY); 153 154 return join(_, a, b, c, d, e); 155 } 156 157 /** 158 * Tests promises for {@link Float}. 159 */ 160 static private Promise<?> 161 testFloat(final Eventual _) throws Exception { 162 // check normal handling 163 final Promise<Float> pMin = ref(Float.MIN_VALUE); 164 check(pMin.equals(pMin)); 165 check(ref(Float.MIN_VALUE).equals(pMin)); 166 check(Float.MIN_VALUE == pMin.call()); 167 class EQ extends Do<Float,Promise<Boolean>> implements Serializable { 168 static private final long serialVersionUID = 1L; 169 170 public Promise<Boolean> 171 fulfill(final Float arg) throws Exception { 172 check(Float.MIN_VALUE == arg); 173 return ref(true); 174 } 175 } 176 final Promise<?> a = _.when(pMin, new EQ()); 177 final Promise<?> b = _.when(Float.MIN_VALUE, new EQ()); 178 179 final Promise<?> c = testNaN(_, Float.NaN); 180 final Promise<?> d = testNaN(_, Float.NEGATIVE_INFINITY); 181 final Promise<?> e = testNaN(_, Float.POSITIVE_INFINITY); 182 183 return join(_, a, b, c, d, e); 184 } 185 186 static protected void 187 check(final boolean valid) throws Exception { 188 if (!valid) { throw new Exception(); } 189 } 190 191 // Command line interface 192 193 /** 194 * Executes the test. 195 * @param args ignored 196 * @throws Exception test failed 197 */ 198 static public void 199 main(final String[] args) throws Exception { 200 final List<Promise<?>> work = List.list(); 201 final Promise<?> result = make(new Eventual(work.appender())); 202 while (!work.isEmpty()) { work.pop().call(); } 203 result.call(); 204 } 205 }