Skip to content

Commit f89cd9e

Browse files
author
rcartwright
committed
Added LogTest.java, a class that tests Log.java. Corey Shaw wrote the
original code and I revised it. I added a new constructor to Log.java to simplify testing. The constructor accepts a File object for the log file rather than a String name. The other revisions are cosmetic. The following files were modified: M src/edu/rice/cs/drjava/model/definitions/ColoringGlyphPainter.java A src/edu/rice/cs/util/LogTest.java M src/edu/rice/cs/util/Log.java M src/edu/rice/cs/util/Pair.java git-svn-id: file:///tmp/test-svn/trunk@4051 fe72c1cf-3628-48e9-8b72-1c46755d3cff
1 parent f91b092 commit f89cd9e

File tree

4 files changed

+262
-19
lines changed

4 files changed

+262
-19
lines changed

drjava/src/edu/rice/cs/drjava/model/definitions/ColoringGlyphPainter.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -281,14 +281,11 @@ void sync(GlyphView v) {
281281
} else {
282282
kit = Toolkit.getDefaultToolkit();
283283
}
284-
/* Use of the deprecated method here is necessary to get a handle on
285-
* a FontMetrics object. This is required by our dependence on the
286-
* javax.swing.text.Utilities class, which does a lot of Java 1.1-style
287-
* calculation (presumably these methods should be deprecated, too).
288-
* The deprecated use can't be fixed without an in-depth understanding
289-
* of fonts, glyphs, and font rendering. Where _metrics is currently used,
290-
* the Font methods getLineMetrics, getStringBounds, getHeight, getAscent,
291-
* and getDescent will probably be helpful.
284+
/* The deprecated method here is necessary to get a handle on a FontMetrics object. This is required by our
285+
* dependence on the javax.swing.text.Utilities class, which does a lot of Java 1.1-style calculation (presumably
286+
* these methods should be deprecated, too). The deprecated use can't be fixed without an in-depth understanding
287+
* of fonts, glyphs, and font rendering. Where _metrics is currently used, the Font methods getLineMetrics,
288+
* getStringBounds, getHeight, getAscent, and getDescent will probably be helpful.
292289
*/
293290
@SuppressWarnings("deprecation") FontMetrics newMetrics = kit.getFontMetrics(f);
294291
_metrics = newMetrics;

drjava/src/edu/rice/cs/util/Log.java

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,21 +46,27 @@ public class Log {
4646
public static final boolean ENABLE_ALL = false;
4747

4848
/** Whether this particular log is enabled in development mode. */
49-
protected boolean _isEnabled;
49+
protected volatile boolean _isEnabled;
5050

5151
/** The filename of this log. */
52-
protected String _name;
52+
protected volatile String _name;
53+
54+
/** The file object for this log. */
55+
protected volatile File _file;
5356

5457
/** PrintWriter to print messages to a file. */
55-
protected PrintWriter _writer;
58+
protected volatile PrintWriter _writer;
5659

5760
/** Creates a new Log with the given name. If enabled is true, a file is created in the current directory with the
5861
* given name.
5962
* @param name File name for the log
6063
* @param enabled Whether to actively use this log
6164
*/
62-
public Log(String name, boolean isEnabled) {
63-
_name = name;
65+
public Log(String name, boolean isEnabled) { this(new File(name), isEnabled); }
66+
67+
public Log(File f, boolean isEnabled) {
68+
_file = f;
69+
_name = f.getName();
6470
_isEnabled = isEnabled;
6571
_init();
6672
}
@@ -70,8 +76,7 @@ protected void _init() {
7076
if (_writer == null) {
7177
if (_isEnabled || ENABLE_ALL) {
7278
try {
73-
File f = new File(_name);
74-
FileWriter w = new FileWriter(f.getAbsolutePath(), true);
79+
FileWriter w = new FileWriter(_file.getAbsolutePath(), true);
7580
_writer = new PrintWriter(w);
7681

7782
log("Log '" + _name + "' opened: " + (new Date()));
@@ -89,9 +94,7 @@ protected void _init() {
8994
public void setEnabled(boolean isEnabled) { _isEnabled = isEnabled; }
9095

9196
/** Returns whether this log is currently enabled. */
92-
public boolean isEnabled() {
93-
return (_isEnabled || ENABLE_ALL);
94-
}
97+
public boolean isEnabled() { return (_isEnabled || ENABLE_ALL); }
9598

9699
/** Prints a message to the log, if enabled.
97100
* @param message Message to print.
Lines changed: 243 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,243 @@
1+
/*BEGIN_COPYRIGHT_BLOCK
2+
*
3+
* This file is part of DrJava. Download the current version of this project from http://www.drjava.org/
4+
* or http://sourceforge.net/projects/drjava/
5+
*
6+
* DrJava Open Source License
7+
*
8+
* Copyright (C) 2001-2005 JavaPLT group at Rice University (javaplt@rice.edu). All rights reserved.
9+
*
10+
* Developed by: Java Programming Languages Team, Rice University, http://www.cs.rice.edu/~javaplt/
11+
*
12+
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13+
* documentation files (the "Software"), to deal with the Software without restriction, including without limitation
14+
* the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
15+
* to permit persons to whom the Software is furnished to do so, subject to the following conditions:
16+
*
17+
* - Redistributions of source code must retain the above copyright notice, this list of conditions and the
18+
* following disclaimers.
19+
* - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
20+
* following disclaimers in the documentation and/or other materials provided with the distribution.
21+
* - Neither the names of DrJava, the JavaPLT, Rice University, nor the names of its contributors may be used to
22+
* endorse or promote products derived from this Software without specific prior written permission.
23+
* - Products derived from this software may not be called "DrJava" nor use the term "DrJava" as part of their
24+
* names without prior written permission from the JavaPLT group. For permission, write to javaplt@rice.edu.
25+
*
26+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
27+
* THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
28+
* CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29+
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30+
* WITH THE SOFTWARE.
31+
*
32+
*END_COPYRIGHT_BLOCK*/
33+
34+
package edu.rice.cs.util;
35+
36+
import junit.framework.TestCase;
37+
import java.io.FileReader;
38+
import java.io.BufferedReader;
39+
import java.io.IOException;
40+
import java.io.FileWriter;
41+
import java.io.File;
42+
import java.text.ParseException;
43+
import java.util.Date;
44+
import java.util.Random;
45+
46+
import edu.rice.cs.drjava.model.MultiThreadedTestCase;
47+
48+
/** Test cases for {@link Log}.
49+
* @version $Id: FileOpsTest.java 3896 2006-06-26 21:19:25Z rcartwright $
50+
*/
51+
public class LogTest extends MultiThreadedTestCase {
52+
53+
static final String FILENAME_PREFIX = "$#%#$";
54+
static final File FILE1 = new File(FILENAME_PREFIX + "logtest1.txt");
55+
static final File FILE2 = new File(FILENAME_PREFIX + "logtest2.txt");
56+
static final File FILE3 = new File(FILENAME_PREFIX + "logtest3.txt");
57+
58+
static final int SHORT_TIME = 10000; // few seconds in milliseconds
59+
60+
static final int DATE_END = 28; // the ending index of the date field in a log entry
61+
62+
/** A thread class that adds a log message after sleeping a given number of milliseconds */
63+
private class LogTestThread extends Thread {
64+
65+
Log _log;
66+
int _millis;
67+
68+
public LogTestThread(Log log, int millis) {
69+
_log = log;
70+
_millis = millis;
71+
}
72+
73+
public void run() {
74+
try { sleep(_millis); }
75+
catch (InterruptedException e ) {
76+
e.printStackTrace();
77+
fail("testConcurrent failed: sleep interrupted");
78+
}
79+
_log.log( "Test message" );
80+
}
81+
82+
}
83+
84+
public void setUp() throws Exception {
85+
super.setUp();
86+
87+
// Clear log files if they exist, so beginning of files are written by these tests
88+
new FileWriter(FILE1).close();
89+
new FileWriter(FILE2).close();
90+
new FileWriter(FILE3).close();
91+
}
92+
93+
public void tearDown() throws Exception {
94+
// Delete log files
95+
/* Note: this code does not currently delete the files.
96+
* TO DO: Find a way to delete these files so the build directory does not contain more clutter.
97+
*/
98+
FILE1.deleteOnExit();
99+
FILE2.deleteOnExit();
100+
FILE3.deleteOnExit();
101+
102+
super.tearDown();
103+
}
104+
105+
/** Parses a date printed by Date.toString(); returns null if there is a parse error. */
106+
@SuppressWarnings("deprecation")
107+
private static Date parse(String s) {
108+
try { return new Date(Date.parse(s.substring(0, DATE_END))); } // the undeprecated version of parse DOES NOT WORK
109+
catch(RuntimeException e) { return null; } // either IllegalArgument or StringIndexOutOfBounds
110+
}
111+
112+
/** Adds a couple of generic messages to a log, and then tests to make sure they are all correct, in the correct order,
113+
* and their timestamps are within the past few seconds.
114+
*/
115+
public void testLog() throws IOException {
116+
Log log1 = new Log(FILE1, true);
117+
log1.log("Message 1");
118+
log1.log("Message 2");
119+
log1.log("Message 3");
120+
121+
BufferedReader fin = new BufferedReader(new FileReader(FILE1));
122+
Date earlier = new Date(new Date().getTime() - SHORT_TIME);
123+
Date now = new Date();
124+
125+
String s0 = fin.readLine();
126+
// System.err.println("s0 = " + s0);
127+
// System.err.println("s0 converted to millis " + parse(s0));
128+
// System.err.println("Current time in millis is: " + System.currentTimeMillis());
129+
Date time0 = parse(s0);
130+
assertTrue("Log opened within last few seconds", time0.compareTo(earlier) >= 0 && time0.compareTo(now) <= 0);
131+
assertEquals("Log open message", "Log '" + FILE1.getName() + "' opened", s0.substring(30, 60));
132+
133+
String s1 = fin.readLine();
134+
Date time1 = parse(s1);
135+
assertTrue("Date of message 1 within last few seconds", time1.compareTo(earlier) >= 0 && time1.compareTo(now) <= 0);
136+
assertEquals("Log message 1", "Message 1", s1.substring(30));
137+
138+
String s2 = fin.readLine();
139+
Date time2 = parse(s2);
140+
assertTrue("Date of message 2 within last few seconds", time2.compareTo(earlier) >= 0 && time2.compareTo(now) <= 0);
141+
assertEquals("Log message 2", "Message 2", s2.substring(30));
142+
143+
String s3 = fin.readLine();
144+
Date time3 = parse(s3);
145+
assertTrue("Date of message 3 within last few seconds", time3.compareTo(earlier) >= 0 && time3.compareTo(now) <= 0);
146+
assertEquals("Log message 3", "Message 3", s3.substring(30));
147+
148+
fin.close();
149+
}
150+
151+
/** Tests the Exception printing methods in the Log file by throwing two exceptions and using the two types of log
152+
* methods (one with the Throwable itself and the other with the the StackTraceElement[])
153+
*/
154+
public void testExceptionPrinting() throws IOException {
155+
Log log2 = new Log(FILE2, true);
156+
// System.err.println("Starting testExceptionPrinting");
157+
158+
// Throw a couple of exceptions and log them
159+
try { throw new ArrayIndexOutOfBoundsException(); }
160+
catch (ArrayIndexOutOfBoundsException e) {
161+
//e.printStackTrace();
162+
log2.log("Message 1", e);
163+
}
164+
165+
try { throw new NullPointerException(); }
166+
catch (NullPointerException e) {
167+
//e.printStackTrace();
168+
log2.log("Message 2", e.getStackTrace());
169+
}
170+
171+
BufferedReader fin = new BufferedReader(new FileReader(FILE2));
172+
Date earlier = new Date(new Date().getTime() - SHORT_TIME);
173+
Date now = new Date();
174+
175+
String s0 = fin.readLine();
176+
Date time0 = parse(s0);
177+
assertTrue("Log opened within last few seconds", time0.compareTo(earlier) >= 0 && time0.compareTo(now) <= 0);
178+
assertEquals("Log open message", "Log '" + FILE2.getName() + "' opened", s0.substring(30, 60));
179+
180+
String s1 = fin.readLine();
181+
Date time1 = parse(s1);
182+
assertTrue("Date of message 1 within last few seconds", time1.compareTo(earlier) >= 0 && time1.compareTo(now) <= 0);
183+
assertEquals("Log message 1", "Message 1", s1.substring(30));
184+
assertEquals("Log exception 1", "java.lang.ArrayIndexOutOfBoundsException", fin.readLine());
185+
186+
// Since it's difficult to test the rest of the stack trace, just skip over it
187+
String s2;
188+
Date time2;
189+
do {
190+
s2 = fin.readLine();
191+
// System.err.println("traceback line = " + s2);
192+
time2 = parse(s2); // returns null if there is a parse error
193+
}
194+
while (time2 == null);
195+
196+
// System.err.println("Skipped over traceback");
197+
198+
assertTrue("Date of message 2 within last few seconds", time2.compareTo(earlier) >= 0 && time2.compareTo(now) <= 0);
199+
assertEquals("Log message 2", "Message 2", s2.substring(30));
200+
assertEquals("Log exception 2 (trace line 1)",
201+
"edu.rice.cs.util.LogTest.testExceptionPrinting", fin.readLine().substring(0,46));
202+
203+
fin.close();
204+
}
205+
206+
private static final int NUM_THREADS = 50;
207+
private static final int DELAY = 100;
208+
209+
/** Attempts to test Log's behavior when called concurrently from several sources. Spawns NUM_THREADS LogTestThreads
210+
* (see above)that wait a random number between 0 and DELAY milliseconds and then log a message. The function tests
211+
* to make sure that the messages and dates are all intact (if the Log was not handling concurrent requests properly,
212+
* the entries in the log may be corrupted).
213+
*/
214+
public void testConcurrentWrites() throws IOException, InterruptedException {
215+
216+
Log log3 = new Log(FILE3, true);
217+
Random r = new Random();
218+
Thread[] threads = new Thread[NUM_THREADS];
219+
for (int i = 0; i < NUM_THREADS; i++) threads[i] = new LogTestThread(log3, r.nextInt(DELAY));
220+
for (int i = 0; i < NUM_THREADS; i++) threads[i].start();
221+
for (int i = 0; i < NUM_THREADS; i++) threads[i].join();
222+
223+
BufferedReader fin = new BufferedReader(new FileReader(FILE3));
224+
Date earlier = new Date(new Date().getTime() - SHORT_TIME);
225+
Date now = new Date();
226+
227+
String s0 = fin.readLine();
228+
Date time0 = parse(s0);
229+
assertTrue("Log opened within last 10 seconds", time0.compareTo(earlier) >= 0 && time0.compareTo(now) <= 0);
230+
assertEquals("Log open message", "Log '" + FILE3.getName() + "' opened", s0.substring(30, 60));
231+
232+
for (int i = 0; i < NUM_THREADS; i++) {
233+
String s1 = fin.readLine();
234+
Date time1 = parse(s1);
235+
assertTrue("Date of message within last 10 seconds", time1.compareTo(earlier) >= 0 && time1.compareTo(now) <= 0);
236+
assertEquals("Log message", "Test message", s1.substring(30));
237+
}
238+
239+
fin.close();
240+
}
241+
242+
}
243+

drjava/src/edu/rice/cs/util/Pair.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public U getSecond() {
5656
}
5757

5858
public String toString() {
59-
return "("+getFirst().toString()+", "+getSecond().toString()+")";
59+
return "(" + getFirst().toString() + ", " + getSecond().toString() + ")";
6060
}
6161

6262
}

0 commit comments

Comments
 (0)