001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.shell;
017:
018: import com.google.gwt.core.ext.BadPropertyValueException;
019: import com.google.gwt.core.ext.PropertyOracle;
020: import com.google.gwt.core.ext.TreeLogger;
021: import com.google.gwt.core.ext.UnableToCompleteException;
022: import com.google.gwt.core.ext.typeinfo.TypeOracle;
023: import com.google.gwt.dev.cfg.PublicOracle;
024: import com.google.gwt.dev.jdt.CacheManager;
025: import com.google.gwt.dev.util.Util;
026:
027: import junit.framework.TestCase;
028:
029: import java.io.ByteArrayOutputStream;
030: import java.io.File;
031: import java.io.IOException;
032: import java.io.OutputStream;
033: import java.io.UnsupportedEncodingException;
034: import java.net.MalformedURLException;
035: import java.net.URL;
036: import java.util.ArrayList;
037: import java.util.Arrays;
038: import java.util.List;
039:
040: /**
041: * A wide variety of tests on {@link StandardGeneratorContext}.
042: */
043: public class StandardGeneratorContextTest extends TestCase {
044:
045: private static class MockCacheManager extends CacheManager {
046: }
047:
048: private static class MockPropertyOracle implements PropertyOracle {
049: public String getPropertyValue(TreeLogger logger,
050: String propertyName) throws BadPropertyValueException {
051: return "";
052: }
053: }
054:
055: private static class MockPublicOracle implements PublicOracle {
056:
057: public URL findPublicFile(String partialPath) {
058: if ("onPublicPath.txt".equals(partialPath)) {
059: try {
060: return new File("").toURL();
061: } catch (MalformedURLException e) {
062: throw new RuntimeException(e);
063: }
064: }
065: return null;
066: }
067:
068: public String[] getAllPublicFiles() {
069: return new String[] { "onPublicPath.txt" };
070: }
071:
072: }
073:
074: private static class MockTreeLogger implements TreeLogger {
075:
076: public TreeLogger branch(Type type, String msg, Throwable caught) {
077: return this ;
078: }
079:
080: public boolean isLoggable(Type type) {
081: return false;
082: }
083:
084: public void log(Type type, String msg, Throwable caught) {
085: }
086: }
087:
088: private static class MockTypeOracle extends TypeOracle {
089: }
090:
091: /**
092: * Stores the File objects to delete in the order they were created. Delete
093: * them in reverse order.
094: */
095: private final List<File> toDelete = new ArrayList<File>();
096: private final TypeOracle mockTypeOracle = new MockTypeOracle();
097: private final PropertyOracle mockPropOracle = new MockPropertyOracle();
098: private final PublicOracle mockPublicOracle = new MockPublicOracle();
099: private final File tempGenDir;
100: private final File tempOutDir;
101: private final CacheManager mockCacheManager = new MockCacheManager();
102: private final TreeLogger mockLogger = new MockTreeLogger();
103: private final StandardGeneratorContext genCtx;
104: private int tempFileCounter;
105:
106: public StandardGeneratorContextTest() {
107: tempGenDir = createTempDir("gwt-gen-");
108: tempOutDir = createTempDir("gwt-out-");
109: genCtx = new StandardGeneratorContext(mockTypeOracle,
110: mockPropOracle, mockPublicOracle, tempGenDir,
111: tempOutDir, mockCacheManager);
112: }
113:
114: public void testTryCreateResource_badFileName() {
115: try {
116: genCtx.tryCreateResource(mockLogger, null);
117: fail("The null filename in the previous statement should have caused an exception");
118: } catch (UnableToCompleteException e) {
119: // Success
120: }
121:
122: try {
123: genCtx.tryCreateResource(mockLogger, "");
124: fail("The empty filename in the previous statement should have caused an exception");
125: } catch (UnableToCompleteException e) {
126: // Success
127: }
128:
129: try {
130: genCtx.tryCreateResource(mockLogger, " ");
131: fail("The whitespace-only filename in the previous statement should have caused an exception");
132: } catch (UnableToCompleteException e) {
133: // Success
134: }
135:
136: try {
137: File absFile = new File("stuff.bin");
138: String asbPath = absFile.getAbsolutePath();
139: genCtx.tryCreateResource(mockLogger, asbPath);
140: fail("The absolute path in the previous statement should have caused an exception");
141: } catch (UnableToCompleteException e) {
142: // Success
143: }
144:
145: try {
146: genCtx.tryCreateResource(mockLogger, "asdf\\stuff.bin");
147: fail("The backslash in the path in the previous statement should have caused an exception");
148: } catch (UnableToCompleteException e) {
149: // Success
150: }
151: }
152:
153: /**
154: * Tests that calling commit a second time on the same OutputStream throws an
155: * exception. Note that this behavior should follow the same basic code path
156: * attempting to commit an unknown OutputStream, as in
157: * {@link #testTryCreateResource_commitWithUnknownStream()}.
158: */
159: public void testTryCreateResource_commitCalledTwice()
160: throws UnableToCompleteException, IOException {
161: String path = createTempOutFilename();
162: OutputStream os = genCtx.tryCreateResource(mockLogger, path);
163: os.write("going to call commit twice after this..."
164: .getBytes(Util.DEFAULT_ENCODING));
165: genCtx.commitResource(mockLogger, os);
166: File createdFile = new File(tempOutDir, path);
167: assertTrue(createdFile.exists());
168: rememberToDelete(createdFile);
169: try {
170: genCtx.commitResource(mockLogger, os);
171: fail("Calling commit() again on the same stream object should have caused an exception");
172: } catch (UnableToCompleteException e) {
173: // Success
174: }
175: }
176:
177: public void testTryCreateResource_commitNotCalled()
178: throws UnableToCompleteException, IOException {
179: String path = createTempOutFilename();
180: OutputStream os = genCtx.tryCreateResource(mockLogger, path);
181: byte[] arrayWritten = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
182: os.write(arrayWritten);
183:
184: // Note that we're *not* committing before calling finish().
185: genCtx.finish(mockLogger);
186:
187: File wouldBeCreatedFile = new File(tempOutDir, path);
188: assertFalse(wouldBeCreatedFile.exists());
189: }
190:
191: public void testTryCreateResource_commitWithBadStream() {
192: try {
193: genCtx.commitResource(mockLogger, (OutputStream) null);
194: fail("Calling commit() on a null stream should have caused an exception");
195: } catch (UnableToCompleteException e) {
196: // Success
197: }
198:
199: try {
200: OutputStream os = new ByteArrayOutputStream();
201: genCtx.commitResource(mockLogger, os);
202: fail("Calling commit() on a stream not returned from tryCreateResource() should have caused an exception");
203: } catch (UnableToCompleteException e) {
204: // Success
205: }
206: }
207:
208: /**
209: * Tests that finish() can be called before and after output file creation.
210: *
211: * @throws UnableToCompleteException
212: * @throws IOException
213: *
214: */
215: public void testTryCreateResource_creationWorksBetweenFinishes()
216: throws UnableToCompleteException, IOException {
217: genCtx.finish(mockLogger);
218: testTryCreateResource_normalCompletionWithoutSubDir();
219: genCtx.finish(mockLogger);
220: testTryCreateResource_normalCompletionWithoutSubDir();
221: genCtx.finish(mockLogger);
222: }
223:
224: public void testTryCreateResource_duplicateCreationAttempt()
225: throws UnableToCompleteException {
226: String path = createTempOutFilename();
227: OutputStream os1 = genCtx.tryCreateResource(mockLogger, path);
228: assertNotNull(os1);
229: OutputStream os2 = genCtx.tryCreateResource(mockLogger, path);
230: assertNull(os2);
231: }
232:
233: public void testTryCreateResource_duplicateCreationAfterCommit()
234: throws UnableToCompleteException,
235: UnsupportedEncodingException, IOException {
236: String path = createTempOutFilename();
237: OutputStream os1 = genCtx.tryCreateResource(mockLogger, path);
238: os1.write("going to call commit twice after this..."
239: .getBytes(Util.DEFAULT_ENCODING));
240: genCtx.commitResource(mockLogger, os1);
241: File createdFile = new File(tempOutDir, path);
242: assertTrue(createdFile.exists());
243: rememberToDelete(createdFile);
244:
245: OutputStream os2 = genCtx.tryCreateResource(mockLogger, path);
246: assertNull(os2);
247: }
248:
249: public void testTryCreateResource_finishCalledTwice()
250: throws UnableToCompleteException, IOException {
251: // Borrow impl.
252: testTryCreateResource_commitNotCalled();
253:
254: // Now call finish() again to make sure nothing blows up.
255: try {
256: genCtx.finish(mockLogger);
257: } catch (UnableToCompleteException e) {
258: fail("finish() failed; it should support safely being called any number of times");
259: }
260: }
261:
262: public void testTryCreateResource_normalCompletionWithoutSubDir()
263: throws UnableToCompleteException, IOException {
264: String path = createTempOutFilename();
265: testTryCreateResource_normalCompletion(null, path);
266: }
267:
268: public void testTryCreateResource_normalCompletionWithSubDir()
269: throws UnableToCompleteException, IOException {
270: String subdir = createTempOutFilename();
271: String filename = createTempOutFilename();
272: testTryCreateResource_normalCompletion(subdir, filename);
273: }
274:
275: /**
276: * Tests that tryCreateResource() returns <code>null</code> when the
277: * specified file is already on the public path.
278: *
279: * @throws UnableToCompleteException
280: * @throws IOException
281: */
282: public void testTryCreateResource_outputFileOnPublicPath()
283: throws UnableToCompleteException {
284: OutputStream os = genCtx.tryCreateResource(mockLogger,
285: "onPublicPath.txt");
286: assertNull(
287: "tryCreateResource() should return null when the target file is already on the public path",
288: os);
289: }
290:
291: @Override
292: protected void setUp() throws Exception {
293: mockCacheManager.invalidateVolatileFiles();
294: }
295:
296: protected void tearDown() throws Exception {
297: for (int i = toDelete.size() - 1; i >= 0; --i) {
298: File f = toDelete.get(i);
299: assertTrue(f.delete());
300: }
301: }
302:
303: private File createTempDir(String prefix) {
304: String baseTempPath = System.getProperty("java.io.tmpdir");
305: File newTempDir;
306: do {
307: newTempDir = new File(baseTempPath, prefix
308: + System.currentTimeMillis());
309: } while (!newTempDir.mkdirs());
310: rememberToDelete(newTempDir);
311: return newTempDir;
312: }
313:
314: private String createTempOutFilename() {
315: File tempFile;
316: do {
317: tempFile = new File(tempOutDir, System.currentTimeMillis()
318: + "-" + (++tempFileCounter) + ".gwt.tmp");
319: } while (tempFile.exists());
320: return tempFile.getName();
321: }
322:
323: private void rememberToDelete(File f) {
324: toDelete.add(f);
325: }
326:
327: private void testTryCreateResource_normalCompletion(String subdir,
328: String name) throws UnableToCompleteException, IOException {
329: if (subdir != null) {
330: name = subdir + "/" + name;
331: }
332: OutputStream os = genCtx.tryCreateResource(mockLogger, name);
333: assertNotNull(os);
334: byte[] arrayWritten = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
335: os.write(arrayWritten);
336: genCtx.commitResource(mockLogger, os);
337:
338: if (subdir != null) {
339: File createdDir = new File(tempOutDir, subdir);
340: assertTrue(createdDir.exists());
341: rememberToDelete(createdDir);
342: }
343:
344: File createdFile = new File(tempOutDir, name);
345: assertTrue(createdFile.exists());
346: rememberToDelete(createdFile);
347:
348: // Read the file.
349: byte[] arrayRead = Util.readFileAsBytes(createdFile);
350: assertTrue(Arrays.equals(arrayWritten, arrayRead));
351: }
352:
353: }
|