001// Copyright 2007 The Apache Software Foundation
002//
003// Licensed under the Apache License, Version 2.0 (the "License");
004// you may not use this file except in compliance with the License.
005// You may obtain a copy of the License at
006//
007//     http://www.apache.org/licenses/LICENSE-2.0
008//
009// Unless required by applicable law or agreed to in writing, software
010// distributed under the License is distributed on an "AS IS" BASIS,
011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012// See the License for the specific language governing permissions and
013// limitations under the License.
014
015package org.apache.tapestry5.test;
016
017import java.io.*;
018import static java.lang.String.format;
019import java.util.ArrayList;
020import java.util.List;
021import java.util.Random;
022
023/**
024 * Provides access to random data that can be used when populating a test database with "reasonable" data. The majority
025 * of this is access to random words from an american english dictionary, which can be strung together to form names,
026 * sentences and paragraphs.
027 */
028public final class RandomDataSource
029{
030    private final Random random = new Random(System.currentTimeMillis());
031
032    private final List<String> words = new ArrayList<String>();
033
034    public RandomDataSource()
035    {
036        for (int i = 0; i < 4; i++)
037            readWords("english." + i);
038
039        for (int i = 0; i < 3; i++)
040            readWords("american." + i);
041
042        System.out.printf("Dictionary contains %d words\n", words.size());
043    }
044
045    private void readWords(String name)
046    {
047        System.out.println("Reading " + name + " ...");
048
049        int count = 0;
050
051        InputStream is = getClass().getResourceAsStream(name);
052
053        if (is == null) throw new RuntimeException(format("File '%s' not found.", name));
054
055        try
056        {
057            BufferedInputStream bis = new BufferedInputStream(is);
058            InputStreamReader isr = new InputStreamReader(bis);
059            LineNumberReader r = new LineNumberReader(isr);
060
061            while (true)
062            {
063                String word = r.readLine();
064
065                if (word == null) break;
066
067                count++;
068                words.add(word);
069            }
070
071            r.close();
072        }
073        catch (IOException ex)
074        {
075            throw new RuntimeException(format("Error reading '%s': %s", name + ex.getMessage()), ex);
076        }
077
078        System.out.printf("... %d words\n", count);
079    }
080
081    public boolean maybe(int percent)
082    {
083        assert percent > 0 && percent <= 100;
084
085        return random.nextInt(100) < percent;
086    }
087
088    public int random(int min, int max)
089    {
090        assert min <= max;
091
092        return random.nextInt(max - min + 1) + min;
093    }
094
095    /**
096     * Returns a random word frm the dictionary. These words are usually all lowercase.
097     */
098    public String word()
099    {
100        int index = random.nextInt(words.size());
101
102        return words.get(index);
103    }
104
105    /**
106     * Returns a random word, capitalized. Useful when create random names.
107     */
108    public String capitalizedWord()
109    {
110        String word = word();
111
112        char[] chars = word.toCharArray();
113
114        chars[0] = Character.toUpperCase(chars[0]);
115
116        return new String(chars);
117    }
118
119    /**
120     * Returns a word that is "safe" for use in an email address.
121     */
122    public String safeWord()
123    {
124        String word = word();
125
126        int x = word.indexOf('\'');
127
128        return x < 0 ? word : word.substring(0, x);
129    }
130
131    /**
132     * Returns a random value from the list of values supplied.
133     */
134    public <T> T oneOf(T... values)
135    {
136        assert values.length > 0;
137
138        int index = random.nextInt(values.length);
139
140        return values[index];
141    }
142
143    /**
144     * Returns a random enum value, given the enum type.
145     */
146    public <T extends Enum> T oneOf(Class<T> enumClass)
147    {
148        return oneOf(enumClass.getEnumConstants());
149    }
150
151    /**
152     * Creates a space-separated list of random words. If in sentence form, then the first word is capitalized, and a
153     * period is appended.
154     *
155     * @param minWords   minimun number of words in the list
156     * @param maxWords   maximum number of words in the list
157     * @param asSentence if true, the output is "dressed up" as a non-sensical sentence
158     * @return the word list / sentence
159     */
160    public String wordList(int minWords, int maxWords, boolean asSentence)
161    {
162        assert minWords <= maxWords;
163        assert minWords > 0;
164
165        StringBuilder builder = new StringBuilder();
166
167        int count = random(minWords, maxWords);
168
169        for (int i = 0; i < count; i++)
170        {
171
172            if (i > 0) builder.append(' ');
173
174            if (i == 0 && asSentence)
175                builder.append(capitalizedWord());
176            else
177                builder.append(word());
178        }
179
180        if (asSentence) builder.append('.');
181
182        return builder.toString();
183    }
184
185    /**
186     * Strings together a random number of word lists (in sentence form) to create something that looks like a
187     * paragraph.
188     *
189     * @param minSentences per paragraph
190     * @param maxSentences per paragraph
191     * @param minWords     per sentence
192     * @param maxWords     per sentence
193     * @return the random paragraph
194     */
195    public String paragraph(int minSentences, int maxSentences, int minWords, int maxWords)
196    {
197        assert minSentences < maxSentences;
198        assert minSentences > 0;
199
200        int count = random(minSentences, maxSentences);
201
202        StringBuilder builder = new StringBuilder();
203
204        for (int i = 0; i < count; i++)
205        {
206            if (i > 0) builder.append(' ');
207
208            builder.append(wordList(minWords, maxWords, true));
209        }
210
211        return builder.toString();
212    }
213}