add --shared
[pylucene.git] / lucene-java-3.4.0 / lucene / backwards / src / test-framework / org / apache / lucene / util / _TestUtil.java
1 package org.apache.lucene.util;
2
3 /**
4  * Licensed to the Apache Software Foundation (ASF) under one or more
5  * contributor license agreements.  See the NOTICE file distributed with
6  * this work for additional information regarding copyright ownership.
7  * The ASF licenses this file to You under the Apache License, Version 2.0
8  * (the "License"); you may not use this file except in compliance with
9  * the License.  You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19
20 import java.io.BufferedOutputStream;
21 import java.io.ByteArrayOutputStream;
22 import java.io.File;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStream;
27 import java.io.PrintStream;
28 import java.lang.reflect.Method;
29 import java.util.Enumeration;
30 import java.util.HashMap;
31 import java.util.Map;
32 import java.util.Random;
33 import java.util.zip.ZipEntry;
34 import java.util.zip.ZipFile;
35
36 import org.junit.Assert;
37
38 import org.apache.lucene.index.CheckIndex;
39 import org.apache.lucene.index.ConcurrentMergeScheduler;
40 import org.apache.lucene.index.IndexWriter;
41 import org.apache.lucene.index.LogMergePolicy;
42 import org.apache.lucene.index.MergePolicy;
43 import org.apache.lucene.index.MergeScheduler;
44 import org.apache.lucene.index.TieredMergePolicy;
45 import org.apache.lucene.search.FieldDoc;
46 import org.apache.lucene.search.ScoreDoc;
47 import org.apache.lucene.search.TopDocs;
48 import org.apache.lucene.store.Directory;
49
50 public class _TestUtil {
51
52   /** Returns temp dir, based on String arg in its name;
53    *  does not create the directory. */
54   public static File getTempDir(String desc) {
55     try {
56       File f = createTempFile(desc, "tmp", LuceneTestCase.TEMP_DIR);
57       f.delete();
58       LuceneTestCase.registerTempFile(f);
59       return f;
60     } catch (IOException e) {
61       throw new RuntimeException(e);
62     }
63   }
64
65   /**
66    * Deletes a directory and everything underneath it.
67    */
68   public static void rmDir(File dir) throws IOException {
69     if (dir.exists()) {
70       for (File f : dir.listFiles()) {
71         if (f.isDirectory()) {
72           rmDir(f);
73         } else {
74           if (!f.delete()) {
75             throw new IOException("could not delete " + f);
76           }
77         }
78       }
79       if (!dir.delete()) {
80         throw new IOException("could not delete " + dir);
81       }
82     }
83   }
84
85   /** 
86    * Convenience method: Unzip zipName + ".zip" under destDir, removing destDir first 
87    */
88   public static void unzip(File zipName, File destDir) throws IOException {
89     
90     ZipFile zipFile = new ZipFile(zipName);
91     
92     Enumeration<? extends ZipEntry> entries = zipFile.entries();
93     
94     rmDir(destDir);
95     
96     destDir.mkdir();
97     LuceneTestCase.registerTempFile(destDir);
98     
99     while (entries.hasMoreElements()) {
100       ZipEntry entry = entries.nextElement();
101       
102       InputStream in = zipFile.getInputStream(entry);
103       File targetFile = new File(destDir, entry.getName());
104       if (entry.isDirectory()) {
105         // allow unzipping with directory structure
106         targetFile.mkdirs();
107       } else {
108         if (targetFile.getParentFile()!=null) {
109           // be on the safe side: do not rely on that directories are always extracted
110           // before their children (although this makes sense, but is it guaranteed?)
111           targetFile.getParentFile().mkdirs();   
112         }
113         OutputStream out = new BufferedOutputStream(new FileOutputStream(targetFile));
114         
115         byte[] buffer = new byte[8192];
116         int len;
117         while((len = in.read(buffer)) >= 0) {
118           out.write(buffer, 0, len);
119         }
120         
121         in.close();
122         out.close();
123       }
124     }
125     
126     zipFile.close();
127   }
128   
129   public static void syncConcurrentMerges(IndexWriter writer) {
130     syncConcurrentMerges(writer.getConfig().getMergeScheduler());
131   }
132
133   public static void syncConcurrentMerges(MergeScheduler ms) {
134     if (ms instanceof ConcurrentMergeScheduler)
135       ((ConcurrentMergeScheduler) ms).sync();
136   }
137
138   /** This runs the CheckIndex tool on the index in.  If any
139    *  issues are hit, a RuntimeException is thrown; else,
140    *  true is returned. */
141   public static CheckIndex.Status checkIndex(Directory dir) throws IOException {
142     ByteArrayOutputStream bos = new ByteArrayOutputStream(1024);
143
144     CheckIndex checker = new CheckIndex(dir);
145     checker.setInfoStream(new PrintStream(bos));
146     CheckIndex.Status indexStatus = checker.checkIndex();
147     if (indexStatus == null || indexStatus.clean == false) {
148       System.out.println("CheckIndex failed");
149       System.out.println(bos.toString());
150       throw new RuntimeException("CheckIndex failed");
151     } else {
152       return indexStatus;
153     }
154   }
155
156   /** Use only for testing.
157    *  @deprecated -- in 3.0 we can use Arrays.toString
158    *  instead */
159   @Deprecated
160   public static String arrayToString(int[] array) {
161     StringBuilder buf = new StringBuilder();
162     buf.append("[");
163     for(int i=0;i<array.length;i++) {
164       if (i > 0) {
165         buf.append(" ");
166       }
167       buf.append(array[i]);
168     }
169     buf.append("]");
170     return buf.toString();
171   }
172
173   /** Use only for testing.
174    *  @deprecated -- in 3.0 we can use Arrays.toString
175    *  instead */
176   @Deprecated
177   public static String arrayToString(Object[] array) {
178     StringBuilder buf = new StringBuilder();
179     buf.append("[");
180     for(int i=0;i<array.length;i++) {
181       if (i > 0) {
182         buf.append(" ");
183       }
184       buf.append(array[i]);
185     }
186     buf.append("]");
187     return buf.toString();
188   }
189
190   public static String randomSimpleString(Random r) {
191     final int end = r.nextInt(10);
192     if (end == 0) {
193       // allow 0 length
194       return "";
195     }
196     final char[] buffer = new char[end];
197     for (int i = 0; i < end; i++) {
198       buffer[i] = (char) _TestUtil.nextInt(r, 97, 102);
199     }
200     return new String(buffer, 0, end);
201   }
202
203   /** Returns random string, including full unicode range. */
204   public static String randomUnicodeString(Random r) {
205     return randomUnicodeString(r, 20);
206   }
207
208   /**
209    * Returns a random string up to a certain length.
210    */
211   public static String randomUnicodeString(Random r, int maxLength) {
212     final int end = r.nextInt(maxLength);
213     if (end == 0) {
214       // allow 0 length
215       return "";
216     }
217     final char[] buffer = new char[end];
218     randomFixedLengthUnicodeString(r, buffer, 0, buffer.length);
219     return new String(buffer, 0, end);
220   }
221
222   /**
223    * Fills provided char[] with valid random unicode code
224    * unit sequence.
225    */
226   public static void randomFixedLengthUnicodeString(Random random, char[] chars, int offset, int length) {
227     int i = offset;
228     final int end = offset + length;
229     while(i < end) {
230       final int t = random.nextInt(5);
231       if (0 == t && i < length - 1) {
232         // Make a surrogate pair
233         // High surrogate
234         chars[i++] = (char) nextInt(random, 0xd800, 0xdbff);
235         // Low surrogate
236         chars[i++] = (char) nextInt(random, 0xdc00, 0xdfff);
237       } else if (t <= 1) {
238         chars[i++] = (char) random.nextInt(0x80);
239       } else if (2 == t) {
240         chars[i++] = (char) nextInt(random, 0x80, 0x800);
241       } else if (3 == t) {
242         chars[i++] = (char) nextInt(random, 0x800, 0xd7ff);
243       } else if (4 == t) {
244         chars[i++] = (char) nextInt(random, 0xe000, 0xfffe);
245       }
246     }
247   }
248
249   private static final int[] blockStarts = {
250     0x0000, 0x0080, 0x0100, 0x0180, 0x0250, 0x02B0, 0x0300, 0x0370, 0x0400, 
251     0x0500, 0x0530, 0x0590, 0x0600, 0x0700, 0x0750, 0x0780, 0x07C0, 0x0800, 
252     0x0900, 0x0980, 0x0A00, 0x0A80, 0x0B00, 0x0B80, 0x0C00, 0x0C80, 0x0D00, 
253     0x0D80, 0x0E00, 0x0E80, 0x0F00, 0x1000, 0x10A0, 0x1100, 0x1200, 0x1380, 
254     0x13A0, 0x1400, 0x1680, 0x16A0, 0x1700, 0x1720, 0x1740, 0x1760, 0x1780, 
255     0x1800, 0x18B0, 0x1900, 0x1950, 0x1980, 0x19E0, 0x1A00, 0x1A20, 0x1B00, 
256     0x1B80, 0x1C00, 0x1C50, 0x1CD0, 0x1D00, 0x1D80, 0x1DC0, 0x1E00, 0x1F00, 
257     0x2000, 0x2070, 0x20A0, 0x20D0, 0x2100, 0x2150, 0x2190, 0x2200, 0x2300, 
258     0x2400, 0x2440, 0x2460, 0x2500, 0x2580, 0x25A0, 0x2600, 0x2700, 0x27C0, 
259     0x27F0, 0x2800, 0x2900, 0x2980, 0x2A00, 0x2B00, 0x2C00, 0x2C60, 0x2C80, 
260     0x2D00, 0x2D30, 0x2D80, 0x2DE0, 0x2E00, 0x2E80, 0x2F00, 0x2FF0, 0x3000, 
261     0x3040, 0x30A0, 0x3100, 0x3130, 0x3190, 0x31A0, 0x31C0, 0x31F0, 0x3200, 
262     0x3300, 0x3400, 0x4DC0, 0x4E00, 0xA000, 0xA490, 0xA4D0, 0xA500, 0xA640, 
263     0xA6A0, 0xA700, 0xA720, 0xA800, 0xA830, 0xA840, 0xA880, 0xA8E0, 0xA900, 
264     0xA930, 0xA960, 0xA980, 0xAA00, 0xAA60, 0xAA80, 0xABC0, 0xAC00, 0xD7B0, 
265     0xE000, 0xF900, 0xFB00, 0xFB50, 0xFE00, 0xFE10, 
266     0xFE20, 0xFE30, 0xFE50, 0xFE70, 0xFF00, 0xFFF0, 
267     0x10000, 0x10080, 0x10100, 0x10140, 0x10190, 0x101D0, 0x10280, 0x102A0, 
268     0x10300, 0x10330, 0x10380, 0x103A0, 0x10400, 0x10450, 0x10480, 0x10800, 
269     0x10840, 0x10900, 0x10920, 0x10A00, 0x10A60, 0x10B00, 0x10B40, 0x10B60, 
270     0x10C00, 0x10E60, 0x11080, 0x12000, 0x12400, 0x13000, 0x1D000, 0x1D100, 
271     0x1D200, 0x1D300, 0x1D360, 0x1D400, 0x1F000, 0x1F030, 0x1F100, 0x1F200, 
272     0x20000, 0x2A700, 0x2F800, 0xE0000, 0xE0100, 0xF0000, 0x100000
273   };
274   
275   private static final int[] blockEnds = {
276     0x007F, 0x00FF, 0x017F, 0x024F, 0x02AF, 0x02FF, 0x036F, 0x03FF, 0x04FF, 
277     0x052F, 0x058F, 0x05FF, 0x06FF, 0x074F, 0x077F, 0x07BF, 0x07FF, 0x083F, 
278     0x097F, 0x09FF, 0x0A7F, 0x0AFF, 0x0B7F, 0x0BFF, 0x0C7F, 0x0CFF, 0x0D7F, 
279     0x0DFF, 0x0E7F, 0x0EFF, 0x0FFF, 0x109F, 0x10FF, 0x11FF, 0x137F, 0x139F, 
280     0x13FF, 0x167F, 0x169F, 0x16FF, 0x171F, 0x173F, 0x175F, 0x177F, 0x17FF, 
281     0x18AF, 0x18FF, 0x194F, 0x197F, 0x19DF, 0x19FF, 0x1A1F, 0x1AAF, 0x1B7F, 
282     0x1BBF, 0x1C4F, 0x1C7F, 0x1CFF, 0x1D7F, 0x1DBF, 0x1DFF, 0x1EFF, 0x1FFF, 
283     0x206F, 0x209F, 0x20CF, 0x20FF, 0x214F, 0x218F, 0x21FF, 0x22FF, 0x23FF, 
284     0x243F, 0x245F, 0x24FF, 0x257F, 0x259F, 0x25FF, 0x26FF, 0x27BF, 0x27EF, 
285     0x27FF, 0x28FF, 0x297F, 0x29FF, 0x2AFF, 0x2BFF, 0x2C5F, 0x2C7F, 0x2CFF, 
286     0x2D2F, 0x2D7F, 0x2DDF, 0x2DFF, 0x2E7F, 0x2EFF, 0x2FDF, 0x2FFF, 0x303F, 
287     0x309F, 0x30FF, 0x312F, 0x318F, 0x319F, 0x31BF, 0x31EF, 0x31FF, 0x32FF, 
288     0x33FF, 0x4DBF, 0x4DFF, 0x9FFF, 0xA48F, 0xA4CF, 0xA4FF, 0xA63F, 0xA69F, 
289     0xA6FF, 0xA71F, 0xA7FF, 0xA82F, 0xA83F, 0xA87F, 0xA8DF, 0xA8FF, 0xA92F, 
290     0xA95F, 0xA97F, 0xA9DF, 0xAA5F, 0xAA7F, 0xAADF, 0xABFF, 0xD7AF, 0xD7FF, 
291     0xF8FF, 0xFAFF, 0xFB4F, 0xFDFF, 0xFE0F, 0xFE1F, 
292     0xFE2F, 0xFE4F, 0xFE6F, 0xFEFF, 0xFFEF, 0xFFFE, /* avoid 0xFFFF on 3.x */
293     0x1007F, 0x100FF, 0x1013F, 0x1018F, 0x101CF, 0x101FF, 0x1029F, 0x102DF, 
294     0x1032F, 0x1034F, 0x1039F, 0x103DF, 0x1044F, 0x1047F, 0x104AF, 0x1083F, 
295     0x1085F, 0x1091F, 0x1093F, 0x10A5F, 0x10A7F, 0x10B3F, 0x10B5F, 0x10B7F, 
296     0x10C4F, 0x10E7F, 0x110CF, 0x123FF, 0x1247F, 0x1342F, 0x1D0FF, 0x1D1FF, 
297     0x1D24F, 0x1D35F, 0x1D37F, 0x1D7FF, 0x1F02F, 0x1F09F, 0x1F1FF, 0x1F2FF, 
298     0x2A6DF, 0x2B73F, 0x2FA1F, 0xE007F, 0xE01EF, 0xFFFFF, 0x10FFFF
299   };
300   
301   /** Returns random string, all codepoints within the same unicode block. */
302   public static String randomRealisticUnicodeString(Random r) {
303     return randomRealisticUnicodeString(r, 20);
304   }
305   
306   /** Returns random string, all codepoints within the same unicode block. */
307   public static String randomRealisticUnicodeString(Random r, int maxLength) {
308     final int end = r.nextInt(maxLength);
309     final int block = r.nextInt(blockStarts.length);
310     StringBuilder sb = new StringBuilder();
311     for (int i = 0; i < end; i++)
312       sb.appendCodePoint(nextInt(r, blockStarts[block], blockEnds[block]));
313     return sb.toString();
314   }
315
316   /** start and end are BOTH inclusive */
317   public static int nextInt(Random r, int start, int end) {
318     return start + r.nextInt(end-start+1);
319   }
320
321   public static boolean anyFilesExceptWriteLock(Directory dir) throws IOException {
322     String[] files = dir.listAll();
323     if (files.length > 1 || (files.length == 1 && !files[0].equals("write.lock"))) {
324       return true;
325     } else {
326       return false;
327     }
328   }
329
330   /** just tries to configure things to keep the open file
331    * count lowish */
332   public static void reduceOpenFiles(IndexWriter w) {
333     // keep number of open files lowish
334     MergePolicy mp = w.getConfig().getMergePolicy();
335     if (mp instanceof LogMergePolicy) {
336       LogMergePolicy lmp = (LogMergePolicy) mp;
337       lmp.setMergeFactor(Math.min(5, lmp.getMergeFactor()));
338     } else if (mp instanceof TieredMergePolicy) {
339       TieredMergePolicy tmp = (TieredMergePolicy) mp;
340       tmp.setMaxMergeAtOnce(Math.min(5, tmp.getMaxMergeAtOnce()));
341       tmp.setSegmentsPerTier(Math.min(5, tmp.getSegmentsPerTier()));
342     }
343
344     MergeScheduler ms = w.getConfig().getMergeScheduler();
345     if (ms instanceof ConcurrentMergeScheduler) {
346       ((ConcurrentMergeScheduler) ms).setMaxThreadCount(2);
347       ((ConcurrentMergeScheduler) ms).setMaxMergeCount(3);
348     }
349   }
350
351   /** Checks some basic behaviour of an AttributeImpl
352    * @param reflectedValues contains a map with "AttributeClass#key" as values
353    */
354   public static <T> void assertAttributeReflection(final AttributeImpl att, Map<String,T> reflectedValues) {
355     final Map<String,Object> map = new HashMap<String,Object>();
356     att.reflectWith(new AttributeReflector() {
357       public void reflect(Class<? extends Attribute> attClass, String key, Object value) {
358         map.put(attClass.getName() + '#' + key, value);
359       }
360     });
361     Assert.assertEquals("Reflection does not produce same map", reflectedValues, map);
362   }
363
364   public static void keepFullyDeletedSegments(IndexWriter w) {
365     try {
366       // Carefully invoke what is a package-private (test
367       // only, internal) method on IndexWriter:
368       Method m = IndexWriter.class.getDeclaredMethod("keepFullyDeletedSegments");
369       m.setAccessible(true);
370       m.invoke(w);
371     } catch (Exception e) {
372       // Should not happen?
373       throw new RuntimeException(e);
374     }
375   }
376   
377   /** 
378    * insecure, fast version of File.createTempFile
379    * uses Random instead of SecureRandom.
380    */
381   public static File createTempFile(String prefix, String suffix, File directory)
382       throws IOException {
383     // Force a prefix null check first
384     if (prefix.length() < 3) {
385       throw new IllegalArgumentException("prefix must be 3");
386     }
387     String newSuffix = suffix == null ? ".tmp" : suffix;
388     File result;
389     do {
390       result = genTempFile(prefix, newSuffix, directory);
391     } while (!result.createNewFile());
392     return result;
393   }
394
395   /* Temp file counter */
396   private static int counter = 0;
397
398   /* identify for differnt VM processes */
399   private static int counterBase = 0;
400
401   private static class TempFileLocker {};
402   private static TempFileLocker tempFileLocker = new TempFileLocker();
403
404   private static File genTempFile(String prefix, String suffix, File directory) {
405     int identify = 0;
406
407     synchronized (tempFileLocker) {
408       if (counter == 0) {
409         int newInt = new Random().nextInt();
410         counter = ((newInt / 65535) & 0xFFFF) + 0x2710;
411         counterBase = counter;
412       }
413       identify = counter++;
414     }
415
416     StringBuilder newName = new StringBuilder();
417     newName.append(prefix);
418     newName.append(counterBase);
419     newName.append(identify);
420     newName.append(suffix);
421     return new File(directory, newName.toString());
422   }
423
424   public static void assertEquals(TopDocs expected, TopDocs actual) {
425     Assert.assertEquals("wrong total hits", expected.totalHits, actual.totalHits);
426     Assert.assertEquals("wrong maxScore", expected.getMaxScore(), actual.getMaxScore(), 0.0);
427     Assert.assertEquals("wrong hit count", expected.scoreDocs.length, actual.scoreDocs.length);
428     for(int hitIDX=0;hitIDX<expected.scoreDocs.length;hitIDX++) {
429       final ScoreDoc expectedSD = expected.scoreDocs[hitIDX];
430       final ScoreDoc actualSD = actual.scoreDocs[hitIDX];
431       Assert.assertEquals("wrong hit docID", expectedSD.doc, actualSD.doc);
432       Assert.assertEquals("wrong hit score", expectedSD.score, actualSD.score, 0.0);
433       if (expectedSD instanceof FieldDoc) {
434         Assert.assertTrue(actualSD instanceof FieldDoc);
435         Assert.assertEquals("wrong sort field values",
436                             ((FieldDoc) expectedSD).fields,
437                             ((FieldDoc) actualSD).fields);
438       } else {
439         Assert.assertFalse(actualSD instanceof FieldDoc);
440       }
441     }
442   }
443 }