001: package org.tigris.subversion.javahl.tests;
002:
003: /**
004: * @copyright
005: * ====================================================================
006: * Copyright (c) 2003-2004 CollabNet. All rights reserved.
007: *
008: * This software is licensed as described in the file COPYING, which
009: * you should have received as part of this distribution. The terms
010: * are also available at http://subversion.tigris.org/license-1.html.
011: * If newer versions of this license are posted there, you may use a
012: * newer version instead, at your option.
013: *
014: * This software consists of voluntary contributions made by many
015: * individuals. For exact contribution history, see the revision
016: * history and logs, available at http://subversion.tigris.org/.
017: * ====================================================================
018: * @endcopyright
019: */
020:
021: import org.tigris.subversion.javahl.Status;
022: import org.tigris.subversion.javahl.NodeKind;
023: import org.tigris.subversion.javahl.DirEntry;
024:
025: import java.io.*;
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.Map;
029:
030: import junit.framework.Assert;
031:
032: /**
033: * This class describe the expected state of the working copy
034: */
035: public class WC {
036: /**
037: * the map of the items of the working copy. The relative path is the key
038: * for the map
039: */
040: Map items = new HashMap();
041:
042: /**
043: * Generate from the expected state of the working copy a new working copy
044: * @param root the working copy directory
045: * @throws IOException
046: */
047: public void materialize(File root) throws IOException {
048: // generate all directories first
049: Iterator it = items.values().iterator();
050: while (it.hasNext()) {
051: Item item = (Item) it.next();
052: if (item.myContent == null) // is a directory
053: {
054: File dir = new File(root, item.myPath);
055: if (!dir.exists())
056: dir.mkdirs();
057: }
058: }
059: // generate all files with the content in the second run
060: it = items.values().iterator();
061: while (it.hasNext()) {
062: Item item = (Item) it.next();
063: if (item.myContent != null) // is a file
064: {
065: File file = new File(root, item.myPath);
066: PrintWriter pw = new PrintWriter(new FileOutputStream(
067: file));
068: pw.print(item.myContent);
069: pw.close();
070: }
071: }
072: }
073:
074: /**
075: * Add a new item to the working copy
076: * @param path the path of the item
077: * @param content the content of the item. A null content signifies a
078: * directory
079: * @return the new Item object
080: */
081: public Item addItem(String path, String content) {
082: return new Item(path, content);
083: }
084:
085: /**
086: * Returns the item at a path
087: * @param path the path, where the item is searched
088: * @return the found item
089: */
090: public Item getItem(String path) {
091: return (Item) items.get(path);
092: }
093:
094: /**
095: * Remove the item at a path
096: * @param path the path, where the item is removed
097: */
098: public void removeItem(String path) {
099: items.remove(path);
100: }
101:
102: /**
103: * Set text (content) status of the item at a path
104: * @param path the path, where the status is set
105: * @param status the new text status
106: */
107: public void setItemTextStatus(String path, int status) {
108: ((Item) items.get(path)).textStatus = status;
109: }
110:
111: /**
112: * Set property status of the item at a path
113: * @param path the path, where the status is set
114: * @param status the new property status
115: */
116: public void setItemPropStatus(String path, int status) {
117: ((Item) items.get(path)).propStatus = status;
118: }
119:
120: /**
121: * Set the revision number of the item at a path
122: * @param path the path, where the revision number is set
123: * @param revision the new revision number
124: */
125: public void setItemWorkingCopyRevision(String path, long revision) {
126: ((Item) items.get(path)).workingCopyRev = revision;
127: }
128:
129: /**
130: * Returns the file content of the item at a path
131: * @param path the path, where the content is retrieved
132: * @return the content of the file
133: */
134: public String getItemContent(String path) {
135: return ((Item) items.get(path)).myContent;
136: }
137:
138: /**
139: * Set the file content of the item at a path
140: * @param path the path, where the content is set
141: * @param content the new content
142: */
143: public void setItemContent(String path, String content) {
144: // since having no content signals a directory, changes of removing the
145: // content or setting a former not set content is not allowed. That
146: // would change the type of the item.
147: Assert.assertNotNull("cannot unset content", content);
148: Item i = (Item) items.get(path);
149: Assert.assertNotNull("cannot set content on directory",
150: i.myContent);
151: i.myContent = content;
152: }
153:
154: /**
155: * set the flag to check the content of item at a path during next check.
156: * @param path the path, where the flag is set
157: * @param check the flag
158: */
159: public void setItemCheckContent(String path, boolean check) {
160: Item i = (Item) items.get(path);
161: i.checkContent = check;
162: }
163:
164: /**
165: * Set the expected node kind at a path
166: * @param path the path, where the node kind is set
167: * @param nodeKind the expected node kind
168: */
169: public void setItemNodeKind(String path, int nodeKind) {
170: Item i = (Item) items.get(path);
171: i.nodeKind = nodeKind;
172: }
173:
174: /**
175: * Set the expected lock state at a path
176: * @param path the path, where the lock state is set
177: * @param isLocked the flag
178: */
179: public void setItemIsLocked(String path, boolean isLocked) {
180: Item i = (Item) items.get(path);
181: i.isLocked = isLocked;
182: }
183:
184: /**
185: * Set the expected switched flag at a path
186: * @param path the path, where the switch flag is set
187: * @param isSwitched the flag
188: */
189: public void setItemIsSwitched(String path, boolean isSwitched) {
190: Item i = (Item) items.get(path);
191: i.isSwitched = isSwitched;
192: }
193:
194: /**
195: * Copy an expected working copy state
196: * @return the copy of the exiting object
197: */
198: public WC copy() {
199: WC c = new WC();
200: Iterator it = items.values().iterator();
201: while (it.hasNext()) {
202: ((Item) it.next()).copy(c);
203: }
204: return c;
205: }
206:
207: /**
208: * Check the result of a single file SVNClient.list call
209: * @param tested the result array
210: * @param singleFilePath the path to be checked
211: * @throws Exception
212: */
213: void check(DirEntry[] tested, String singleFilePath)
214: throws Exception {
215: Assert.assertEquals("not a single dir entry", 1, tested.length);
216: Item item = (Item) items.get(singleFilePath);
217: Assert.assertNotNull("not found in working copy", item);
218: Assert.assertNotNull("not a file", item.myContent);
219: Assert.assertEquals("state says file, working copy not",
220: tested[0].getNodeKind(),
221: item.nodeKind == -1 ? NodeKind.file : item.nodeKind);
222: }
223:
224: /**
225: * Check the result of a directory SVNClient.list call
226: * @param tested the result array
227: * @param basePath the path of the directory
228: * @param recursive the recursive flag of the call
229: * @throws Exception
230: */
231: void check(DirEntry[] tested, String basePath, boolean recursive)
232: throws Exception {
233: // clear the touched flag of all items
234: Iterator it = items.values().iterator();
235: while (it.hasNext()) {
236: Item item = (Item) it.next();
237: item.touched = false;
238: }
239:
240: // normalize directory path
241: if (basePath != null && basePath.length() > 0) {
242: basePath = basePath + "/";
243: } else {
244: basePath = "";
245: }
246: // check all returned DirEntry's
247: for (int i = 0; i < tested.length; i++) {
248: String name = basePath + tested[i].getPath();
249: Item item = (Item) items.get(name);
250: Assert.assertNotNull("not found in working copy", item);
251: if (item.myContent != null) {
252: Assert.assertEquals(
253: "state says file, working copy not", tested[i]
254: .getNodeKind(),
255: item.nodeKind == -1 ? NodeKind.file
256: : item.nodeKind);
257: } else {
258: Assert.assertEquals("state says dir, working copy not",
259: tested[i].getNodeKind(),
260: item.nodeKind == -1 ? NodeKind.dir
261: : item.nodeKind);
262: }
263: item.touched = true;
264: }
265:
266: // all items should have been in items, should had their touched flag
267: // set
268: it = items.values().iterator();
269: while (it.hasNext()) {
270: Item item = (Item) it.next();
271: if (!item.touched) {
272: if (item.myPath.startsWith(basePath)
273: && !item.myPath.equals(basePath)) {
274: Assert.assertFalse("not found in dir entries",
275: recursive);
276: boolean found = false;
277: for (int i = 0; i < tested.length; i++) {
278: if (tested[i].getNodeKind() == NodeKind.dir) {
279: if (item.myPath.startsWith(basePath
280: + tested[i].getPath())) {
281: found = true;
282: break;
283: }
284: }
285: }
286: Assert
287: .assertTrue("not found in dir entries",
288: found);
289: }
290: }
291: }
292: }
293:
294: /**
295: * Check the result of a SVNClient.status versus the expected state
296: * @param tested the result to be tested
297: * @param workingCopyPath the path of the working copy
298: * @throws Exception
299: */
300: void check(Status[] tested, String workingCopyPath)
301: throws Exception {
302: // clear the touched flag of all items
303: Iterator it = items.values().iterator();
304: while (it.hasNext()) {
305: Item item = (Item) it.next();
306: item.touched = false;
307: }
308:
309: String normalizeWCPath = workingCopyPath.replace(
310: File.separatorChar, '/');
311:
312: // check all result Staus object
313: for (int i = 0; i < tested.length; i++) {
314: String path = tested[i].getPath();
315: Assert.assertTrue(
316: "status path starts not with working copy path",
317: path.startsWith(normalizeWCPath));
318:
319: // we calculate the relative path to the working copy root
320: if (path.length() > workingCopyPath.length() + 1) {
321: Assert.assertEquals("missing '/' in status path", path
322: .charAt(workingCopyPath.length()), '/');
323: path = path.substring(workingCopyPath.length() + 1);
324: } else
325: // this is the working copy root itself
326: path = "";
327:
328: Item item = (Item) items.get(path);
329: Assert.assertNotNull("status not found in working copy",
330: item);
331: Assert.assertEquals("wrong text status in working copy",
332: item.textStatus, tested[i].getTextStatus());
333: if (item.workingCopyRev != -1)
334: Assert.assertEquals(
335: "wrong revision number in working copy",
336: item.workingCopyRev, tested[i]
337: .getRevisionNumber());
338: Assert.assertEquals("lock status wrong", item.isLocked,
339: tested[i].isLocked());
340: Assert.assertEquals("switch status wrong", item.isSwitched,
341: tested[i].isSwitched());
342: Assert.assertEquals("wrong prop status in working copy",
343: item.propStatus, tested[i].getPropStatus());
344: if (item.myContent != null) {
345: Assert.assertEquals(
346: "state says file, working copy not", tested[i]
347: .getNodeKind(),
348: item.nodeKind == -1 ? NodeKind.file
349: : item.nodeKind);
350: if (tested[i].getTextStatus() == Status.Kind.normal
351: || item.checkContent) {
352: File input = new File(workingCopyPath, item.myPath);
353: Reader rd = new InputStreamReader(
354: new FileInputStream(input));
355: StringBuffer buffer = new StringBuffer();
356: int ch;
357: while ((ch = rd.read()) != -1) {
358: buffer.append((char) ch);
359: }
360: rd.close();
361: Assert.assertEquals("content mismatch", buffer
362: .toString(), item.myContent);
363: }
364: } else {
365: Assert.assertEquals("state says dir, working copy not",
366: tested[i].getNodeKind(),
367: item.nodeKind == -1 ? NodeKind.dir
368: : item.nodeKind);
369: }
370: item.touched = true;
371: }
372:
373: // all items which have the touched flag not set, are missing in the
374: // result array
375: it = items.values().iterator();
376: while (it.hasNext()) {
377: Item item = (Item) it.next();
378: Assert.assertTrue(
379: "item in working copy not found in status",
380: item.touched);
381: }
382: }
383:
384: /**
385: * internal class to discribe a single working copy item
386: */
387: public class Item {
388: /**
389: * the content of a file. A directory has a null content
390: */
391: String myContent;
392: /**
393: * the relative path of the item
394: */
395: String myPath;
396: /**
397: * the text (content) status of the item
398: */
399: int textStatus = Status.Kind.normal;
400: /**
401: * the property status of the item.
402: */
403: int propStatus = Status.Kind.none;
404: /**
405: * the expected revision number. -1 means do not check.
406: */
407: long workingCopyRev = -1;
408: /**
409: * flag if item has been touched. To detect missing items.
410: */
411: boolean touched;
412: /**
413: * flag if the content will be checked
414: */
415: boolean checkContent;
416: /**
417: * expected node kind. -1 means do not check.
418: */
419: int nodeKind = -1;
420: /**
421: * expected locked status
422: */
423: boolean isLocked;
424: /**
425: * expected switched status
426: */
427: boolean isSwitched;
428:
429: /**
430: * create a new item
431: * @param path the path of the item.
432: * @param content the content of the item. A null signals a directory.
433: */
434: private Item(String path, String content) {
435: myPath = path;
436: myContent = content;
437: items.put(path, this );
438: }
439:
440: /**
441: * copy constructor
442: * @param source the copy source.
443: * @param owner the WC of the copy
444: */
445: private Item(Item source, WC owner) {
446: myPath = source.myPath;
447: myContent = source.myContent;
448: textStatus = source.textStatus;
449: propStatus = source.propStatus;
450: owner.items.put(myPath, this );
451: }
452:
453: /**
454: * copy this item
455: * @param owner the new WC
456: * @return the copied item
457: */
458: private Item copy(WC owner) {
459: return new Item(this, owner);
460: }
461: }
462: }
|