some util classes stolen from webfunds
[cacert-birdshack.git] / Business Logic / trunk / src / org / cacert / birdshack / util / Junk.java
1 /*
2 * Was webfunds.util.Example, contributed.
3 */
4 package org.cacert.birdshack.util;
5
6 import java.math.BigInteger;
7 import java.io.InputStream;
8 import java.io.ByteArrayInputStream;
9 import java.io.IOException;
10 import java.lang.reflect.Constructor;
11 import java.lang.reflect.Method;
12 import java.lang.reflect.InvocationTargetException;
13
14 /**
15 * A set of example, junk data fields, used for example() methods.
16 *
17 * NONE of these routines are cryptographically secure,
18 * in fact they are not even vaguely random, and only
19 * intended for class unit tests.
20 *
21 * Also, a set of reflection methods for constructing
22 * unit tests that read, write and compare examples.
23 */
24 public class Junk
25 {
26 private Junk() {}
27
28
29 private static long seed = 0;
30
31 /**
32 * Return data byte(s) that is rubbish.
33 *
34 * All Junk routines are built upon exampleByte().
35 *
36 * @return an example byte
37 */
38 public static byte exampleByte()
39 {
40 if (seed == 0)
41 seed = System.currentTimeMillis();
42
43 seed = (seed * 0x5DEECE66DL + 0xBL) & ((1L << 48) - 1);
44 return (byte) (seed >>> (48 - 8));
45
46 /*
47 * Another one, apparently called a TYPE_0 generator:
48 * i' = (i * 1103515245 + 12345) & 0x7fffffff
49 */
50 }
51
52 /** @return example boolean, true or false */
53 public static boolean exampleBool()
54 {
55 if (seed == 0)
56 seed = System.currentTimeMillis();
57
58 return (exampleByte() & 0x01) == 0x01;
59 }
60
61 /** @return example int, between min and max */
62 public static int exampleInt(int min, int max)
63 {
64 if (min == max)
65 return min;
66
67 if (min > max) // swap
68 {
69 int x = min;
70 min = max;
71 max = x;
72 }
73 long min2 = min;
74 long max2 = max;
75 long offset = 0;
76 if (min2 < 0) // move numbers to 0..n
77 {
78 offset = (-min2);
79 max2 += offset;
80 min2 = 0;
81 }
82 long l = exampleLong();
83 if (l < 0)
84 l = -l;
85 // whoops this was limited it to max-1
86 int ex = (int) ( ( l % (max2 - min2 + 1) ) + min2 - offset );
87 if (ex < min || ex > max)
88 throw new RuntimeException("ex out of min,max: "+
89 ex+" "+min+","+max+ " ["+min2+","+max2+"] ("+l+","+offset+")" );
90 return ex;
91 }
92
93 /**
94 * This returns a long that is biased to small numbers.
95 * @see exampleTimeMillis() for a time biased example long,
96 * @see exampleBigLong() for an unbiased long.
97 * @return example long, made of 8 example bytes, biased to small
98 */
99 public static long exampleLong()
100 {
101 long l = 0;
102 for (int i = (exampleByte() & 0x07); i >=0; i--)
103 { // kilted towards low numbers
104 l <<= 8;
105 l |= exampleByte() & 0xFF;
106 }
107 return l ;
108 }
109
110 /**
111 * This returns a long that is biased to time.
112 public static long exampleTimeMillis()
113 {
114 return BaseTime.ex();
115 }
116 */
117
118 /** @return junk char, made of 2 example bytes */
119 public static char junkChar()
120 {
121 int i = ((exampleByte() & 0xFF) << 8) | (exampleByte() & 0xFF);
122 return (char)i ;
123 }
124
125 // static java.nio.charset.Charset utf8charset;
126 // static java.nio.charset.CharsetDecoder utf8decoder;
127 // static java.nio.charset.CharsetEncoder utf8encoder;
128 //
129 // /** @return example char, made of 2 example bytes, should be good UTF-8 */
130 // static
131 // {
132 // try {
133 // utf8charset = java.nio.charset.Charset.forName("UTF-8");
134 // utf8encoder = utf8charset.newEncoder();
135 // // utf8encoder.substitute(null); // throw exceptions on duds.
136 //
137 // if (!utf8charset.canEncode())
138 // throw new Panic("can't encode?");
139 //
140 // int c;
141 // char[] chars = new char[1];
142 // for (int i = 0; i < 10 ; i++)
143 // {
144 // c = i << 8;
145 // System.err.print("" + c);
146 // for (int j = 20; j < 90 ; j += 10)
147 // {
148 // char c2 = (char)(c | j);
149 // chars[0] = c2;
150 // String s = new String(chars);
151 // dumpUTF(s);
152 // }
153 // System.err.println("!");
154 // }
155 //
156 // } catch (Exception ex) {
157 // throw new Panic(ex);
158 // }
159 // }
160
161 /*
162 * This returns a hopefully printable UTF-8 char.
163 * Unprintables in US-ASCII are eliminated,
164 * as are illegals in UTF-8 ('\uFFFE', '\uFFFF').
165 */
166 public static char exampleChar()
167 {
168 int i = 0;
169 char c;
170 while (true)
171 {
172 c = junkChar();
173 if (c < '\u0020') // no, \r doesn't count :)
174 continue;
175 if (c == '\u00FF') // nor del
176 continue;
177 if (c == '\uFFFE' || c == '\uFFFF') // illegal in UTF-8
178 continue;
179
180 break;
181 }
182 return c;
183 }
184
185 /** @return example long, made of 8 example bytes, unbiased */
186 public static long exampleBigLong()
187 {
188 long l = 0;
189 for (int i = 0; i < 8; i++)
190 { // no bias
191 l <<= 8;
192 l |= exampleByte() & 0xFF;
193 }
194 return l ;
195 }
196
197 /** @return byte array with len example bytes in it, never null */
198 public static byte[] data(int len)
199 {
200 byte[] b = new byte[len];
201
202 for (int i = len - 1; i >=0; i--)
203 {
204 b[i] = exampleByte();
205 }
206 return b ;
207 }
208
209 /** @return unprintable byte array from 0 to 32 bytes long, never null */
210 public static byte[] data()
211 {
212 int len = exampleByte() & 0x1F;
213 return data(len);
214 }
215
216 /** @return unprintable byte array from 0 to 16 bytes long, may be null */
217 public static byte[] dataWithNull()
218 {
219 int b = exampleByte();
220 if ((b & 0xF0) == 0)
221 return null;
222 int len = b & 0x0F;
223 return data(len);
224 }
225
226 /** @return unprintable byte array from min to max bytes long */
227 public static byte[] data(int min, int max)
228 {
229 int len = exampleInt(min, max);
230 return data(len);
231 }
232
233
234
235 /** @return printable string with some chars made into funny characters */
236 public static void dumpUTF(String s)
237 {
238 try {
239 byte[] bytes = s.getBytes("UTF-8");
240 System.err.print(" " + s + " ");
241 System.err.write(bytes, 0, bytes.length);
242 } catch (Exception ex) {
243 throw new Error("UTFF");
244 }
245 }
246
247 /** @return printable string with some chars made into funny characters */
248 public static String makeUTF(String s)
249 {
250 char[] chars = s.toCharArray();
251 int len = chars.length;
252 for (int i = 0; i < len; i++)
253 {
254 if ((exampleByte() & 0x03) == 0)
255 chars[i] = exampleChar();
256 }
257 String s2 = new String(chars);
258 // dumpUTF(s2);
259 return s2;
260 }
261
262 /** @return printable string len bytes long, never null */
263 public static String string(int len)
264 {
265 byte[] data = data(len);
266 return Hex.data2hex(data);
267 }
268
269 /** @return printable string from min to max bytes long */
270 public static String string(int min, int max)
271 {
272 int len = exampleInt(min, max);
273 return string(len);
274 }
275
276 /** @return valid Identifier for the Resources */
277 public static String identifier()
278 {
279 int len = exampleInt(1, 7);
280 return string(len);
281 }
282
283 /** @return printable string from 0 to 32 bytes long, never null */
284 public static String string()
285 {
286 int len = exampleByte() & 0x1F;
287 return string(len);
288 }
289
290 /** @return printable string from 0 to 8 words long, never null */
291 public static String words()
292 {
293 int b = exampleByte() & 0x07;
294 String s = "";
295 for (int i = 0; i < b; i++)
296 {
297 if (!s.equals("") || exampleBool())
298 s += whitespace();
299 s += string(1, 4);
300 }
301 if (exampleBool())
302 s += whitespace();
303 return s;
304 }
305
306 /** @return printable string from 0 to 3 lines of words(), never null */
307 public static String lines()
308 {
309 int b = exampleByte() & 0x03;
310 String s = "";
311 for (int i = 0; i < b; i++)
312 {
313 if (!s.equals("") || (exampleByte() & 0x03) == 0x03)
314 s += "\n";
315 s += words();
316 }
317 if ((exampleByte() & 0x03) == 0x03)
318 s += "\n";
319 return s;
320 }
321
322
323 /**
324 * 0, 1, 2 chars (weighted to 1) of spaces (common) and tabs (rare)
325 * @return some optional white-space
326 */
327 public static String whitespace()
328 {
329 int b = exampleByte();
330 int len = b & 0x03;
331 if (len == 0x03)
332 len = 1;
333 b >>= 2;
334 String s = "";
335 while (len-- > 0)
336 {
337 if ((b & 0x03) == 0x03)
338 s += " "; // tab
339 else
340 s += " ";
341 b >>= 2;
342 }
343 return s;
344 }
345
346
347
348 /**
349 * @return a BigInteger that is positive and made of len junk bytes
350 * @param len bytes, where len >= 1
351 */
352 public static BigInteger examplePosBigInt(int len)
353 {
354 byte[] data = data(len);
355 data[0] &= 0x7F; // so always positive
356 return new BigInteger(data);
357 }
358
359 /**
360 * @return something from 8 bytes to 16 bytes worth of big int.
361 */
362 public static BigInteger examplePosBigInt()
363 {
364 int len = exampleByte() & 0x07;
365 len |= 0x08;
366 return examplePosBigInt(len);
367 }
368
369
370
371 /****************************************************
372 *
373 * These methods are used in conjunction with
374 * above example code to construct encode-decode
375 * tests. They may be better off in another class.
376 *
377 */
378
379 /**
380 * Return the object decoded from the byte stream,
381 * which came from an encode of the same object.
382 *
383 * The class named must follow the WireObject convention
384 * by including an InputStream constructor.
385 *
386 * @throws RuntimeException if the method could not be called
387 * @return an example of the named class.
388 */
389 public static Object decodeFromBytes(String fullclassname, byte[] contents)
390 {
391 Class clazz = getKnownClass(fullclassname);
392 ByteArrayInputStream bais = new ByteArrayInputStream(contents);
393
394 return decodeFromBytes(clazz, bais);
395 }
396
397 /**
398 * Return the object decoded from the byte stream,
399 * which came from an encode of the same object.
400 *
401 * The class supplied must follow the WireObject convention
402 * by including an InputStream constructor.
403 *
404 * @throws RuntimeException if the method could not be called
405 * @return an example of the named class.
406 */
407 public static Object decodeFromBytes(Class clazz, byte[] contents)
408 {
409 ByteArrayInputStream bais = new ByteArrayInputStream(contents);
410
411 return decodeFromBytes(clazz, bais);
412 }
413
414 /**
415 * Return the object decoded from the byte stream,
416 * which came from an encode of the same object.
417 *
418 * The class supplied must follow the WireObject convention
419 * by including an InputStream constructor.
420 *
421 * @throws RuntimeException if the method could not be called
422 * @return an example of the named class.
423 */
424 public static Object decodeFromBytes(Class clazz, InputStream is)
425 {
426 // InputStream now being replaced by WireInputStream
427 Class[] arguments = new Class[1];
428 Class inputStream = getKnownClass("java.io.InputStream");
429 arguments[0] = inputStream;
430 String name = clazz.getName();
431
432 // there should be a way to get the byte[] constructor
433 // based on the Byte.TYPE class, but the javadoc doesn't
434 // say how to make an array class....
435
436 Constructor con;
437 try {
438 con = clazz.getConstructor(arguments);
439 } catch (NoSuchMethodException e) {
440 throw new RuntimeException("no contructor(InputStream) in " + name);
441 }
442
443 Object[] initArgs = new Object[1];
444 initArgs[0] = (Object)is;
445 Object obj;
446 try {
447 obj = con.newInstance(initArgs);
448 } catch (InstantiationException e) {
449 e.printStackTrace();
450 throw new RuntimeException("bad constructor(IS) in "+name+": "+e);
451 } catch (InvocationTargetException e) {
452 e.printStackTrace();
453 throw new RuntimeException("bad constructor(IS) in "+name+": "+e);
454 } catch (IllegalAccessException e) {
455 e.printStackTrace();
456 throw new RuntimeException("bad constructor(IS) in "+name+": "+e);
457 }
458
459 return obj;
460 }
461
462 /**
463 * The class named must follow the WebFunds testing convention
464 * by including the static example() method.
465 *
466 * @throws RuntimeException if the method could not be called
467 * @return an example of the named class.
468 */
469 public static Object getExample(String fullclassname)
470 {
471 Class clazz = getKnownClass(fullclassname);
472 Method meth;
473 try {
474 meth = clazz.getMethod("example", new Class[]{}); // zero args
475 } catch (NoSuchMethodException e) {
476 throw new RuntimeException("no example() in " + fullclassname);
477 }
478
479 Object obj;
480 try {
481 obj = meth.invoke(null, new Object[]{}); // zero args
482 } catch (InvocationTargetException e) {
483 e.printStackTrace();
484 throw new RuntimeException("bad example() "+fullclassname+":\n"+e);
485 } catch (IllegalAccessException e) {
486 throw new RuntimeException("bad example() "+fullclassname+":\n"+e);
487 } catch (Exception e) { // reflection throws lots of rubbish
488 e.printStackTrace();
489 throw new RuntimeException("bad example() "+fullclassname+":\n"+e);
490 }
491
492 if (obj == null)
493 throw new RuntimeException("null example() from " + fullclassname +
494 ": " + clazz);
495
496 return obj;
497 }
498
499 /**
500 * This method just hides the exception.
501 * @throws RuntimeException if the class doesn't exist
502 * @return the Class for this name
503 */
504 public static Class getKnownClass(String fullclassname)
505 {
506 Class byname;
507 try
508 {
509 byname = Class.forName(fullclassname);
510 }
511 catch (ClassNotFoundException e)
512 {
513 throw new RuntimeException("No class for " + fullclassname + "\n" +
514 "check CLASSPATH or name or source.");
515 }
516 return byname;
517 }
518
519
520
521 /****************************************************
522 *
523 * Quick Test Method.
524 */
525
526 public static void main(String[] arg)
527 {
528 System.out.println("string(): " + string());
529 System.out.println("words(): " + words());
530 System.out.println("lines(): -----\n" + lines() + "------");
531 }
532 }