Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

henon entered the plan. i will "fast forward" the development speed

* Gitty.Core is now a "real" standalone project (git-sharp) and got its own solution.
* added testgui that can execute the unit tests. cool for debugging!!!
* ported a lot of unit tests and a lot of code to get them working
* fixed some errors in the existing ported code
* ... and had a lot of fun ;)

Signed-off-by: henon <meinrad.recheis@gmail.com>
  • Loading branch information...
commit 92300d82e3c10f3a7a35652d9a770c487795a64a 1 parent f42efb8
@henon authored
Showing with 7,604 additions and 99 deletions.
  1. +1 −0  .gitignore
  2. +5 −3 AnyObjectId.cs
  3. +51 −29 Commit.cs
  4. +411 −0 Constants.cs
  5. +27 −13 FileMode.cs
  6. +6 −2 Gitty.Core.csproj
  7. +10 −0 LockFile.cs
  8. +387 −0 ObjectChecker.cs
  9. +5 −4 PersonIdent.cs
  10. +46 −39 RepositoryConfig.cs
  11. +8 −0 TestGUI/App.xaml
  12. +16 −0 TestGUI/App.xaml.cs
  13. +66 −0 TestGUI/Browser.xaml
  14. +53 −0 TestGUI/Browser.xaml.cs
  15. +55 −0 TestGUI/Properties/AssemblyInfo.cs
  16. +71 −0 TestGUI/Properties/Resources.Designer.cs
  17. +117 −0 TestGUI/Properties/Resources.resx
  18. +30 −0 TestGUI/Properties/Settings.Designer.cs
  19. +7 −0 TestGUI/Properties/Settings.settings
  20. +66 −0 TestGUI/TestFixtureView.cs
  21. +123 −0 TestGUI/TestGUI.csproj
  22. +32 −0 TestGUI/TestRunner.xaml
  23. +336 −0 TestGUI/TestRunner.xaml.cs
  24. +92 −0 TestGUI/TestcaseView.cs
  25. BIN  TestGUI/screenshot01.png
  26. BIN  Tests/Dependencies/nunit.framework.dll
  27. +78 −8 Tests/Gitty.Core.Tests.csproj
  28. +1,626 −0 Tests/ObjectCheckerTests.cs
  29. +111 −1 Tests/ObjectIdTests.cs
  30. +123 −0 Tests/PersonIdentTests.cs
  31. +328 −0 Tests/RepositoryTestCase.cs
  32. +96 −0 Tests/Resources/all_packed_objects.txt
  33. +155 −0 Tests/Resources/create-second-pack
  34. BIN  Tests/Resources/gitgit.index
  35. +1,437 −0 Tests/Resources/gitgit.lsfiles
  36. +331 −0 Tests/Resources/gitgit.lstree
  37. BIN  Tests/Resources/pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12.idx
  38. BIN  Tests/Resources/pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12.pack
  39. BIN  Tests/Resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idx
  40. BIN  Tests/Resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idxV2
  41. BIN  Tests/Resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.pack
  42. BIN  Tests/Resources/pack-546ff360fe3488adb20860ce3436a2d6373d2796.idx
  43. BIN  Tests/Resources/pack-546ff360fe3488adb20860ce3436a2d6373d2796.pack
  44. BIN  Tests/Resources/pack-9fb5b411fe6dfa89cc2e6b89d2bd8e5de02b5745.idx
  45. BIN  Tests/Resources/pack-9fb5b411fe6dfa89cc2e6b89d2bd8e5de02b5745.pack
  46. BIN  Tests/Resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.idx
  47. BIN  Tests/Resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.idxV2
  48. BIN  Tests/Resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.pack
  49. BIN  Tests/Resources/pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa.idx
  50. BIN  Tests/Resources/pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa.pack
  51. BIN  Tests/Resources/pack-huge.idx
  52. +33 −0 Tests/Resources/packed-refs
  53. +13 −0 Tests/TestUtils.cs
  54. +317 −0 Tests/TreeTests.cs
  55. +73 −0 Util/ISystemReader.cs
  56. +54 −0 Util/MutableInteger.cs
  57. +32 −0 Util/Numbers.cs
  58. +729 −0 Util/RawParseUtils.cs
  59. +15 −0 Util/String.cs
  60. +32 −0 git-sharp.sln
View
1  .gitignore
@@ -7,3 +7,4 @@ bin
obj
*.user
*.suo
+*.bak
View
8 AnyObjectId.cs
@@ -1,6 +1,7 @@
/*
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2008, Kevin Thompson <kevin.thompson@theautomaters.com>
+ * Copyright (C) 2009, Henon <meinrad.recheis@gmail.com>
*
* All rights reserved.
*
@@ -59,7 +60,7 @@ internal class Constants
public static readonly int StringLength = ObjectIdLength * 2;
}
-
+
public static bool operator ==(AnyObjectId a, AnyObjectId b)
{
if ((object)a == null)
@@ -81,7 +82,7 @@ internal class Constants
public virtual bool Equals(AnyObjectId obj)
{
- return (obj != null) ? Equals(this, obj) : false;
+ return (obj != null) ? this == obj : false;
}
public override bool Equals(object obj)
@@ -231,7 +232,8 @@ public override string ToString()
return new string(ToHexCharArray());
}
- public ObjectId Copy() {
+ public ObjectId Copy()
+ {
if (this.GetType() == typeof(ObjectId))
return (ObjectId)this;
return new ObjectId(this);
View
80 Commit.cs
@@ -3,6 +3,7 @@
* Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2007, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2008, Kevin Thompson <kevin.thompson@theautomaters.com>
+ * Copyright (C) 2009, Henon <meinrad.recheis@gmail.com>
*
* All rights reserved.
*
@@ -139,38 +140,38 @@ public Commit(Repository db, ObjectId id, byte[] raw)
private ObjectId treeId;
public ObjectId TreeId
- {
- get
- {
- return treeId;
- }
- set
- {
- if (treeId == null || !treeId.Equals(value))
- {
- treeEntry = null;
- }
- treeId = value;
+ {
+ get
+ {
+ return treeId;
}
- }
-
+ set
+ {
+ if (treeId == null || !treeId.Equals(value))
+ {
+ treeEntry = null;
+ }
+ treeId = value;
+ }
+ }
+
private Tree treeEntry;
public Tree TreeEntry
- {
- get
- {
- if (treeEntry == null)
- {
- treeEntry = Repository.MapTree(this.TreeId);
- if (treeEntry == null)
- throw new MissingObjectException(this.TreeId, ObjectType.Tree);
- }
- return treeEntry;
- }
- set
- {
- treeId = value.TreeId;
- treeEntry = value;
+ {
+ get
+ {
+ if (treeEntry == null)
+ {
+ treeEntry = Repository.MapTree(this.TreeId);
+ if (treeEntry == null)
+ throw new MissingObjectException(this.TreeId, ObjectType.Tree);
+ }
+ return treeEntry;
+ }
+ set
+ {
+ treeId = value.TreeId;
+ treeEntry = value;
}
}
@@ -181,6 +182,27 @@ public Tree TreeEntry
public Encoding Encoding { get; set; }
public Repository Repository { get; protected set; }
+ // Returns all ancestor-commits of this commit
+ public IEnumerable<Commit> Ancestors
+ {
+ get
+ {
+ var ancestors = new Dictionary<ObjectId, Commit>();
+ CollectAncestorIdsRecursive(this, ancestors);
+ return ancestors.Values.ToArray();
+ }
+ }
+
+ private static void CollectAncestorIdsRecursive(Commit commit, Dictionary<ObjectId,Commit> ancestors)
+ {
+ foreach (var parent in commit.ParentIds.Where(id => !ancestors.ContainsKey(id)).Select(id => commit.Repository.OpenCommit(id)))
+ {
+ var parent_commit = parent as Commit;
+ ancestors[parent_commit.CommitId] = parent_commit;
+ CollectAncestorIdsRecursive(parent_commit, ancestors);
+ }
+ }
+
private string message;
public string Message
{
View
411 Constants.cs
@@ -2,7 +2,9 @@
* Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2008, Google Inc.
* Copyright (C) 2008, Kevin Thompson <kevin.thompson@theautomaters.com>
+ * Copyright (C) 2009, Henon <meinrad.recheis@gmail.com>
*
* All rights reserved.
*
@@ -113,5 +115,414 @@ public static class ObjectTypes
public static readonly string RefsRemotes = Refs + "remotes/";
public static readonly string[] RefSearchPaths = { "", Refs, RefsTags, RefsHeads, RefsRemotes };
+
+ /** Hash function used natively by Git for all objects. */
+ private static string HASH_FUNCTION = "SHA-1";
+
+ /** Length of an object hash. */
+ public static int OBJECT_ID_LENGTH = 20;
+
+ /** Special name for the "HEAD" symbolic-ref. */
+ public static string HEAD = "HEAD";
+
+ /**
+ * Text string that identifies an object as a commit.
+ * <p>
+ * Commits connect trees into a string of project histories, where each
+ * commit is an assertion that the best way to continue is to use this other
+ * tree (set of files).
+ */
+ public static string TYPE_COMMIT = "commit";
+
+ /**
+ * Text string that identifies an object as a blob.
+ * <p>
+ * Blobs store whole file revisions. They are used for any user file, as
+ * well as for symlinks. Blobs form the bulk of any project's storage space.
+ */
+ public static string TYPE_BLOB = "blob";
+
+ /**
+ * Text string that identifies an object as a tree.
+ * <p>
+ * Trees attach object ids (hashes) to names and file modes. The normal use
+ * for a tree is to store a version of a directory and its contents.
+ */
+ public static string TYPE_TREE = "tree";
+
+ /**
+ * Text string that identifies an object as an annotated tag.
+ * <p>
+ * Annotated tags store a pointer to any other object, and an additional
+ * message. It is most commonly used to record a stable release of the
+ * project.
+ */
+ public static string TYPE_TAG = "tag";
+
+
+ private static byte[] ENCODED_TYPE_COMMIT = encodeASCII(TYPE_COMMIT);
+
+ private static byte[] ENCODED_TYPE_BLOB = encodeASCII(TYPE_BLOB);
+
+ private static byte[] ENCODED_TYPE_TREE = encodeASCII(TYPE_TREE);
+
+ private static byte[] ENCODED_TYPE_TAG = encodeASCII(TYPE_TAG);
+
+ /** An unknown or invalid object type code. */
+ public const int OBJ_BAD = -1;
+
+ /**
+ * In-pack object type: extended types.
+ * <p>
+ * This header code is reserved for future expansion. It is currently
+ * undefined/unsupported.
+ */
+ public const int OBJ_EXT = 0;
+
+ /**
+ * In-pack object type: commit.
+ * <p>
+ * Indicates the associated object is a commit.
+ * <p>
+ * <b>This constant is fixed and is defined by the Git packfile format.</b>
+ *
+ * @see #TYPE_COMMIT
+ */
+ public const int OBJ_COMMIT = 1;
+
+ /**
+ * In-pack object type: tree.
+ * <p>
+ * Indicates the associated object is a tree.
+ * <p>
+ * <b>This constant is fixed and is defined by the Git packfile format.</b>
+ *
+ * @see #TYPE_BLOB
+ */
+ public const int OBJ_TREE = 2;
+
+ /**
+ * In-pack object type: blob.
+ * <p>
+ * Indicates the associated object is a blob.
+ * <p>
+ * <b>This constant is fixed and is defined by the Git packfile format.</b>
+ *
+ * @see #TYPE_BLOB
+ */
+ public const int OBJ_BLOB = 3;
+
+ /**
+ * In-pack object type: annotated tag.
+ * <p>
+ * Indicates the associated object is an annotated tag.
+ * <p>
+ * <b>This constant is fixed and is defined by the Git packfile format.</b>
+ *
+ * @see #TYPE_TAG
+ */
+ public const int OBJ_TAG = 4;
+
+ /** In-pack object type: reserved for future use. */
+ public const int OBJ_TYPE_5 = 5;
+
+ /**
+ * In-pack object type: offset delta
+ * <p>
+ * Objects stored with this type actually have a different type which must
+ * be obtained from their delta base object. Delta objects store only the
+ * changes needed to apply to the base object in order to recover the
+ * original object.
+ * <p>
+ * An offset delta uses a negative offset from the start of this object to
+ * refer to its delta base. The base object must exist in this packfile
+ * (even in the case of a thin pack).
+ * <p>
+ * <b>This constant is fixed and is defined by the Git packfile format.</b>
+ */
+ public const int OBJ_OFS_DELTA = 6;
+
+ /**
+ * In-pack object type: reference delta
+ * <p>
+ * Objects stored with this type actually have a different type which must
+ * be obtained from their delta base object. Delta objects store only the
+ * changes needed to apply to the base object in order to recover the
+ * original object.
+ * <p>
+ * A reference delta uses a full object id (hash) to reference the delta
+ * base. The base object is allowed to be omitted from the packfile, but
+ * only in the case of a thin pack being transferred over the network.
+ * <p>
+ * <b>This constant is fixed and is defined by the Git packfile format.</b>
+ */
+ public const int OBJ_REF_DELTA = 7;
+
+ /**
+ * Pack file signature that occurs at file header - identifies file as Git
+ * packfile formatted.
+ * <p>
+ * <b>This constant is fixed and is defined by the Git packfile format.</b>
+ */
+ public static byte[] PACK_SIGNATURE = { (byte)'P', (byte)'A', (byte)'C', (byte)'K' };
+
+ /** Native character encoding for commit messages, file names... */
+ public static string CHARACTER_ENCODING = "UTF-8";
+
+ /** Native character encoding for commit messages, file names... */
+ //public static Charset CHARSET; // [henon] TODO replace by Encoding?
+
+
+ /** Default main branch name */
+ public static string MASTER = "master";
+
+ /** Prefix for branch refs */
+ public static string R_HEADS = "refs/heads/";
+
+ /** Prefix for remotes refs */
+ public static string R_REMOTES = "refs/remotes/";
+
+ /** Prefix for tag refs */
+ public static string R_TAGS = "refs/tags/";
+
+ /** Prefix for any ref */
+ public static string R_REFS = "refs/";
+
+ /** Logs folder name */
+ public static string LOGS = "logs";
+
+ /** Info refs folder */
+ public static string INFO_REFS = "info/refs";
+
+ /** Packed refs file */
+ public static string PACKED_REFS = "packed-refs";
+
+ /** The environment variable that contains the system user name */
+ public static string OS_USER_NAME_KEY = "user.name";
+
+ /** The environment variable that contains the author's name */
+ public static string GIT_AUTHOR_NAME_KEY = "GIT_AUTHOR_NAME";
+
+ /** The environment variable that contains the author's email */
+ public static string GIT_AUTHOR_EMAIL_KEY = "GIT_AUTHOR_EMAIL";
+
+ /** The environment variable that contains the commiter's name */
+ public static string GIT_COMMITTER_NAME_KEY = "GIT_COMMITTER_NAME";
+
+ /** The environment variable that contains the commiter's email */
+ public static string GIT_COMMITTER_EMAIL_KEY = "GIT_COMMITTER_EMAIL";
+
+ /** Default value for the user name if no other information is available */
+ public static string UNKNOWN_USER_DEFAULT = "unknown-user";
+
+ /** Beginning of the common "Signed-off-by: " commit message line */
+ public static string SIGNED_OFF_BY_TAG = "Signed-off-by: ";
+
+#if false
+ /**
+ * Create a new digest function for objects.
+ *
+ * @return a new digest object.
+ * @throws RuntimeException
+ * this Java virtual machine does not support the required hash
+ * function. Very unlikely given that JGit uses a hash function
+ * that is in the Java reference specification.
+ */
+ public static MessageDigest newMessageDigest() {
+ try {
+ return MessageDigest.getInstance(HASH_FUNCTION);
+ } catch (NoSuchAlgorithmException nsae) {
+ throw new RuntimeException("Required hash function "
+ + HASH_FUNCTION + " not available.", nsae);
+ }
+ }
+
+ /**
+ * Convert an OBJ_* type constant to a TYPE_* type constant.
+ *
+ * @param typeCode the type code, from a pack representation.
+ * @return the canonical string name of this type.
+ */
+ public static string typeString( int typeCode) {
+ switch (typeCode) {
+ case OBJ_COMMIT:
+ return TYPE_COMMIT;
+ case OBJ_TREE:
+ return TYPE_TREE;
+ case OBJ_BLOB:
+ return TYPE_BLOB;
+ case OBJ_TAG:
+ return TYPE_TAG;
+ default:
+ throw new IllegalArgumentException("Bad object type: " + typeCode);
+ }
+ }
+
+ /**
+ * Convert an OBJ_* type constant to an ASCII encoded string constant.
+ * <p>
+ * The ASCII encoded string is often the canonical representation of
+ * the type within a loose object header, or within a tag header.
+ *
+ * @param typeCode the type code, from a pack representation.
+ * @return the canonical ASCII encoded name of this type.
+ */
+ public static byte[] encodedTypeString( int typeCode) {
+ switch (typeCode) {
+ case OBJ_COMMIT:
+ return ENCODED_TYPE_COMMIT;
+ case OBJ_TREE:
+ return ENCODED_TYPE_TREE;
+ case OBJ_BLOB:
+ return ENCODED_TYPE_BLOB;
+ case OBJ_TAG:
+ return ENCODED_TYPE_TAG;
+ default:
+ throw new IllegalArgumentException("Bad object type: " + typeCode);
+ }
+ }
+
+ /**
+ * Parse an encoded type string into a type constant.
+ *
+ * @param id
+ * object id this type string came from; may be null if that is
+ * not known at the time the parse is occurring.
+ * @param typeString
+ * string version of the type code.
+ * @param endMark
+ * character immediately following the type string. Usually ' '
+ * (space) or '\n' (line feed).
+ * @param offset
+ * position within <code>typeString</code> where the parse
+ * should start. Updated with the new position (just past
+ * <code>endMark</code> when the parse is successful.
+ * @return a type code constant (one of {@link #OBJ_BLOB},
+ * {@link #OBJ_COMMIT}, {@link #OBJ_TAG}, {@link #OBJ_TREE}.
+ * @throws CorruptObjectException
+ * there is no valid type identified by <code>typeString</code>.
+ */
+ public static int decodeTypeString( AnyObjectId id,
+ byte[] typeString, byte endMark,
+ MutableInteger offset) throws CorruptObjectException {
+ try {
+ int position = offset.value;
+ switch (typeString[position]) {
+ case 'b':
+ if (typeString[position + 1] != 'l'
+ || typeString[position + 2] != 'o'
+ || typeString[position + 3] != 'b'
+ || typeString[position + 4] != endMark)
+ throw new CorruptObjectException(id, "invalid type");
+ offset.value = position + 5;
+ return Constants.OBJ_BLOB;
+
+ case 'c':
+ if (typeString[position + 1] != 'o'
+ || typeString[position + 2] != 'm'
+ || typeString[position + 3] != 'm'
+ || typeString[position + 4] != 'i'
+ || typeString[position + 5] != 't'
+ || typeString[position + 6] != endMark)
+ throw new CorruptObjectException(id, "invalid type");
+ offset.value = position + 7;
+ return Constants.OBJ_COMMIT;
+
+ case 't':
+ switch (typeString[position + 1]) {
+ case 'a':
+ if (typeString[position + 2] != 'g'
+ || typeString[position + 3] != endMark)
+ throw new CorruptObjectException(id, "invalid type");
+ offset.value = position + 4;
+ return Constants.OBJ_TAG;
+
+ case 'r':
+ if (typeString[position + 2] != 'e'
+ || typeString[position + 3] != 'e'
+ || typeString[position + 4] != endMark)
+ throw new CorruptObjectException(id, "invalid type");
+ offset.value = position + 5;
+ return Constants.OBJ_TREE;
+
+ default:
+ throw new CorruptObjectException(id, "invalid type");
+ }
+
+ default:
+ throw new CorruptObjectException(id, "invalid type");
+ }
+ } catch (ArrayIndexOutOfBoundsException bad) {
+ throw new CorruptObjectException(id, "invalid type");
+ }
+ }
+
+ /**
+ * Convert an integer into its decimal representation.
+ *
+ * @param s
+ * the integer to convert.
+ * @return a decimal representation of the input integer. The returned array
+ * is the smallest array that will hold the value.
+ */
+ public static byte[] encodeASCII( long s) {
+ return encodeASCII(Long.toString(s));
+ }
+#endif
+
+ /**
+ * Convert a string to US-ASCII encoding.
+ *
+ * @param s
+ * the string to convert. Must not contain any characters over
+ * 127 (outside of 7-bit ASCII).
+ * @return a byte array of the same length as the input string, holding the
+ * same characters, in the same order.
+ * @throws IllegalArgumentException
+ * the input string contains one or more characters outside of
+ * the 7-bit ASCII character space.
+ */
+ public static byte[] encodeASCII( string s) {
+ byte[] r = new byte[s.Length];
+ for (int k = r.Length - 1; k >= 0; k--) {
+ char c = s[k];
+ if (c > 127)
+ throw new ArgumentException("Not ASCII string: " + s);
+ r[k] = (byte) c;
+ }
+ return r;
+ }
+
+#if false
+ /**
+ * Convert a string to a byte array in the standard character encoding.
+ *
+ * @param str
+ * the string to convert. May contain any Unicode characters.
+ * @return a byte array representing the requested string, encoded using the
+ * default character encoding (UTF-8).
+ * @see #CHARACTER_ENCODING
+ */
+ public static byte[] encode( string str) {
+ ByteBuffer bb = Constants.CHARSET.encode(str);
+ int len = bb.limit();
+ if (bb.hasArray() && bb.arrayOffset() == 0) {
+ byte[] arr = bb.array();
+ if (arr.length == len)
+ return arr;
+ }
+
+ byte[] arr = new byte[len];
+ bb.get(arr);
+ return arr;
+ }
+
+ static {
+ if (OBJECT_ID_LENGTH != newMessageDigest().getDigestLength())
+ throw new LinkageError("Incorrect OBJECT_ID_LENGTH.");
+ CHARSET = Charset.forName(CHARACTER_ENCODING);
+ }
+#endif
+
}
}
View
40 FileMode.cs
@@ -2,6 +2,7 @@
* Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2008, Kevin Thompson <kevin.thompson@theautomaters.com>
+ * Copyright (C) 2009, Henon <meinrad.recheis@gmail.com>
*
* All rights reserved.
*
@@ -49,17 +50,30 @@ namespace Gitty.Core
public class FileMode
{
- public static readonly FileMode Tree = new FileMode(0040000, ObjectType.Tree, modeBits => (modeBits & 0170000) == 0040000);
+ // [henon] c# does not support octal literals, so every number starting with 0 has to be converted to decimal!
+ // frequently used octal literals and their decimal counterparts:
+ // decimal ... octal
+ // 33188 ... 0100644
+ // 33261 ... 0100755
+ // 61440 ... 0170000
+ // 16384 ... 0040000
+ // 32768 ... 0100000
+ // 40960 ... 0120000
+ // 57344 ... 0160000
+ // 73 ... 0111
- public static readonly FileMode Symlink = new FileMode(0120000, ObjectType.Blob, modeBits => (modeBits & 0170000) == 0120000);
+ public static readonly FileMode Tree = new FileMode(16384, ObjectType.Tree, modeBits => (modeBits & 61440) == 16384);
- public static readonly FileMode RegularFile = new FileMode(0100644, ObjectType.Blob, modeBits => (modeBits & 0170000) == 0100000 && (modeBits & 0111) == 0);
+ public static readonly FileMode Symlink = new FileMode(40960, ObjectType.Blob, modeBits => (modeBits & 61440) == 40960);
- public static readonly FileMode ExecutableFile = new FileMode(0100755, ObjectType.Blob, modeBits => (modeBits & 0170000) == 0100000 && (modeBits & 0111) != 0);
+ public static readonly FileMode RegularFile = new FileMode(33188, ObjectType.Blob, modeBits => (modeBits & 61440) == 32768 && (modeBits & 73) == 0);
- public static readonly FileMode GitLink = new FileMode(0160000, ObjectType.Commit, modeBits => (modeBits & 0170000) == 0160000);
+ public static readonly FileMode ExecutableFile = new FileMode(33261, ObjectType.Blob, modeBits => (modeBits & 61440) == 32768 && (modeBits & 73) != 0);
+
+ public static readonly FileMode GitLink = new FileMode(57344, ObjectType.Commit, modeBits => (modeBits & 61440) == 57344);
+
+ public static readonly FileMode Missing = new FileMode(0, ObjectType.Bad, modeBits => modeBits == 0);
- public static readonly FileMode Missing = new FileMode(0000000, ObjectType.Bad, modeBits => modeBits == 0);
private byte[] _octalBytes;
@@ -105,21 +119,21 @@ private FileMode(int mode, ObjectType type, EqualsDelegate equals)
public static FileMode FromBits(int bits)
{
- switch (bits & 0170000)
+ switch (bits & 61440) // octal 0170000
{
- case 0000000:
+ case 0:
if (bits == 0)
return Missing;
break;
- case 0040000:
+ case 16384: // octal 0040000
return Tree;
- case 0100000:
- if ((bits & 0111) != 0)
+ case 32768: // octal 0100000
+ if ((bits & 73) != 0) // octal 0111
return ExecutableFile;
return RegularFile;
- case 0120000:
+ case 40960: // octal 0120000
return Symlink;
- case 0160000:
+ case 57344: // octal 0160000
return GitLink;
}
View
8 Gitty.Core.csproj
@@ -1,9 +1,9 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="3.5">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>9.0.30729</ProductVersion>
+ <ProductVersion>9.0.21022</ProductVersion>
<SchemaVersion>2.0</SchemaVersion>
<ProjectGuid>{C46EDD61-C202-465A-93F1-ADE20A83BB59}</ProjectGuid>
<OutputType>Library</OutputType>
@@ -75,6 +75,7 @@
<Compile Include="LockFile.cs" />
<Compile Include="MutableObjectId.cs" />
<Compile Include="NullProgressMonitor.cs" />
+ <Compile Include="ObjectChecker.cs" />
<Compile Include="ObjectId.cs" />
<Compile Include="ObjectIdMap.cs" />
<Compile Include="ObjectLoader.cs" />
@@ -110,6 +111,9 @@
<Compile Include="TreeVisitor.cs" />
<Compile Include="TreeVisitorWithCurrentDirectory.cs" />
<Compile Include="UnpackedObjectLoader.cs" />
+ <Compile Include="Util\ISystemReader.cs" />
+ <Compile Include="Util\MutableInteger.cs" />
+ <Compile Include="Util\String.cs" />
<Compile Include="Util\CheckedOutputStream.cs" />
<Compile Include="Util\CRC32.cs" />
<Compile Include="Util\MessageDigest.cs" />
View
10 LockFile.cs
@@ -2,6 +2,7 @@
* Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
* Copyright (C) 2008, Kevin Thompson <kevin.thompson@theautomaters.com>
+ * Copyright (C) 2009, Henon <meinrad.recheis@gmail.com>
*
* All rights reserved.
*
@@ -308,7 +309,16 @@ public void Dispose()
public void Release()
{
+ if (this.Locked == false)
+ return;
+ try
+ {
this.FileStream.Unlock(0, this.FileStream.Length);
+ }
+ catch (IOException)
+ {
+ // unlocking went wrong
+ }
this.Locked = false;
}
View
387 ObjectChecker.cs
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2008, Google Inc.
+ * Copyright (C) 2009, Henon <meinrad.recheis@gmail.com>
+ *
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Gitty.Core.Exceptions;
+using Gitty.Core.Util;
+
+namespace Gitty.Core
+{
+
+ /**
+ * Verifies that an object is formatted correctly.
+ * <p>
+ * Verifications made by this class only check that the fields of an object are
+ * formatted correctly. The ObjectId checksum of the object is not verified, and
+ * connectivity links between objects are also not verified. Its assumed that
+ * the caller can provide both of these validations on its own.
+ * <p>
+ * Instances of this class are not thread safe, but they may be reused to
+ * perform multiple object validations.
+ */
+ public class ObjectChecker
+ {
+ /** Header "tree " */
+ public static char[] tree = "tree ".ToCharArray();
+
+ /** Header "parent " */
+ public static char[] parent = "parent ".ToCharArray();
+
+ /** Header "author " */
+ public static char[] author = "author ".ToCharArray();
+
+ /** Header "committer " */
+ public static char[] committer = "committer ".ToCharArray();
+
+ /** Header "encoding " */
+ public static char[] encoding = "encoding ".ToCharArray();
+
+ /** Header "object " */
+ public static char[] @object = "object ".ToCharArray();
+
+ /** Header "type " */
+ public static char[] type = "type ".ToCharArray();
+
+ /** Header "tag " */
+ public static char[] tag = "tag ".ToCharArray();
+
+ /** Header "tagger " */
+ public static char[] tagger = "tagger ".ToCharArray();
+
+ private MutableObjectId tempId = new MutableObjectId();
+
+ private MutableInteger ptrout = new MutableInteger();
+
+ /**
+ * Check an object for parsing errors.
+ *
+ * @param objType
+ * type of the object. Must be a valid object type code in
+ * {@link Constants}.
+ * @param raw
+ * the raw data which comprises the object. This should be in the
+ * canonical format (that is the format used to generate the
+ * ObjectId of the object). The array is never modified.
+ * @throws CorruptObjectException
+ * if an error is identified.
+ */
+ public void check(int objType, char[] raw)
+ {
+ switch (objType)
+ {
+ case Constants.OBJ_COMMIT:
+ checkCommit(raw);
+ break;
+ case Constants.OBJ_TAG:
+ checkTag(raw);
+ break;
+ case Constants.OBJ_TREE:
+ checkTree(raw);
+ break;
+ case Constants.OBJ_BLOB:
+ checkBlob(raw);
+ break;
+ default:
+ throw new CorruptObjectException("Invalid object type: " + objType);
+ }
+ }
+
+ private int id(char[] raw, int ptr)
+ {
+ try
+ {
+ tempId.FromString(Encoding.ASCII.GetBytes(raw), ptr);
+ return ptr + AnyObjectId.Constants.StringLength;
+ }
+ catch (ArgumentException e) // [henon] replaced IllegalArgumentException
+ {
+ return -1;
+ }
+ }
+
+ private int personIdent(char[] raw, int ptr)
+ {
+ int emailB = RawParseUtils.nextLF(raw, ptr, '<');
+ if (emailB == ptr || raw[emailB - 1] != '<')
+ return -1;
+
+ int emailE = RawParseUtils.nextLF(raw, emailB, '>');
+ if (emailE == emailB || raw[emailE - 1] != '>')
+ return -1;
+ if (emailE == raw.Length || raw[emailE] != ' ')
+ return -1;
+
+ RawParseUtils.parseBase10(raw, emailE + 1, ptrout); // when
+ ptr = ptrout.value;
+ if (emailE + 1 == ptr)
+ return -1;
+ if (ptr == raw.Length || raw[ptr] != ' ')
+ return -1;
+
+ RawParseUtils.parseBase10(raw, ptr + 1, ptrout); // tz offset
+ if (ptr + 1 == ptrout.value)
+ return -1;
+ return ptrout.value;
+ }
+
+ /**
+ * Check a commit for errors.
+ *
+ * @param raw
+ * the commit data. The array is never modified.
+ * @throws CorruptObjectException
+ * if any error was detected.
+ */
+ public void checkCommit(char[] raw)
+ {
+ int ptr = 0;
+
+ if ((ptr = RawParseUtils.match(raw, ptr, tree)) < 0)
+ throw new CorruptObjectException("no tree header");
+ if ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\n')
+ throw new CorruptObjectException("invalid tree");
+
+ while (RawParseUtils.match(raw, ptr, parent) >= 0)
+ {
+ ptr += parent.Length;
+ if ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\n')
+ throw new CorruptObjectException("invalid parent");
+ }
+
+ if ((ptr = RawParseUtils.match(raw, ptr, author)) < 0)
+ throw new CorruptObjectException("no author");
+ if ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
+ throw new CorruptObjectException("invalid author");
+
+ if ((ptr = RawParseUtils.match(raw, ptr, committer)) < 0)
+ throw new CorruptObjectException("no committer");
+ if ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
+ throw new CorruptObjectException("invalid committer");
+ }
+
+ /**
+ * Check an annotated tag for errors.
+ *
+ * @param raw
+ * the tag data. The array is never modified.
+ * @throws CorruptObjectException
+ * if any error was detected.
+ */
+ public void checkTag(char[] raw)
+ {
+ int ptr = 0;
+
+ if ((ptr = RawParseUtils.match(raw, ptr, @object)) < 0)
+ throw new CorruptObjectException("no object header");
+ if ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\n')
+ throw new CorruptObjectException("invalid object");
+
+ if ((ptr = RawParseUtils.match(raw, ptr, type)) < 0)
+ throw new CorruptObjectException("no type header");
+ ptr = RawParseUtils.nextLF(raw, ptr);
+
+ if ((ptr = RawParseUtils.match(raw, ptr, tag)) < 0)
+ throw new CorruptObjectException("no tag header");
+ ptr = RawParseUtils.nextLF(raw, ptr);
+
+ if ((ptr = RawParseUtils.match(raw, ptr, tagger)) < 0)
+ throw new CorruptObjectException("no tagger header");
+ if ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
+ throw new CorruptObjectException("invalid tagger");
+ }
+
+ private static int lastPathChar(int mode)
+ {
+ return (int)(FileMode.Tree.Equals(mode) ? '/' : '\0');
+ }
+
+ private static int pathCompare(char[] raw, int aPos, int aEnd, int aMode, int bPos, int bEnd, int bMode)
+ {
+ while (aPos < aEnd && bPos < bEnd)
+ {
+ int cmp = (((byte)raw[aPos++]) & 0xff) - (((byte)raw[bPos++]) & 0xff);
+ if (cmp != 0)
+ return cmp;
+ }
+
+ if (aPos < aEnd)
+ return (((byte)raw[aPos]) & 0xff) - lastPathChar(bMode);
+ if (bPos < bEnd)
+ return lastPathChar(aMode) - (((byte)raw[bPos]) & 0xff);
+ return 0;
+ }
+
+ private static bool duplicateName(char[] raw, int thisNamePos, int thisNameEnd)
+ {
+ int sz = raw.Length;
+ int nextPtr = thisNameEnd + 1 + Constants.OBJECT_ID_LENGTH;
+ for (; ; )
+ {
+ int nextMode = 0;
+ for (; ; )
+ {
+ if (nextPtr >= sz)
+ return false;
+ char c = raw[nextPtr++];
+ if (' ' == c)
+ break;
+ nextMode <<= 3;
+ nextMode += ((byte)c - (byte)'0');
+ }
+
+ int nextNamePos = nextPtr;
+ for (; ; )
+ {
+ if (nextPtr == sz)
+ return false;
+ char c = raw[nextPtr++];
+ if (c == '\0')
+ break;
+ }
+ if (nextNamePos + 1 == nextPtr)
+ return false;
+
+ int cmp = pathCompare(raw, thisNamePos, thisNameEnd, FileMode.Tree.Bits, nextNamePos, nextPtr - 1, nextMode);
+ if (cmp < 0)
+ return false;
+ else if (cmp == 0)
+ return true;
+
+ nextPtr += Constants.OBJECT_ID_LENGTH;
+ }
+ }
+
+ /**
+ * Check a canonical formatted tree for errors.
+ *
+ * @param raw
+ * the raw tree data. The array is never modified.
+ * @throws CorruptObjectException
+ * if any error was detected.
+ */
+ public void checkTree(char[] raw)
+ {
+ int sz = raw.Length;
+ int ptr = 0;
+ int lastNameB = 0, lastNameE = 0, lastMode = 0;
+
+ while (ptr < sz)
+ {
+ int thisMode = 0;
+ for (; ; )
+ {
+ if (ptr == sz)
+ throw new CorruptObjectException("truncated in mode");
+ char c = raw[ptr++];
+ if (' ' == c)
+ break;
+ if (c < '0' || c > '7')
+ throw new CorruptObjectException("invalid mode character");
+ if (thisMode == 0 && c == '0')
+ throw new CorruptObjectException("mode starts with '0'");
+ thisMode <<= 3;
+ thisMode += ((byte)c - (byte)'0');
+ }
+
+ if (FileMode.FromBits(thisMode).ObjectType == ObjectType.Bad)
+ throw new CorruptObjectException("invalid mode " + NB.DecimalToBase(thisMode, 8));
+
+ int thisNameB = ptr;
+ for (; ; )
+ {
+ if (ptr == sz)
+ throw new CorruptObjectException("truncated in name");
+ char c = raw[ptr++];
+ if (c == '\0')
+ break;
+ if (c == '/')
+ throw new CorruptObjectException("name contains '/'");
+ }
+ if (thisNameB + 1 == ptr)
+ throw new CorruptObjectException("zero length name");
+ if (raw[thisNameB] == '.')
+ {
+ int nameLen = (ptr - 1) - thisNameB;
+ if (nameLen == 1)
+ throw new CorruptObjectException("invalid name '.'");
+ if (nameLen == 2 && raw[thisNameB + 1] == '.')
+ throw new CorruptObjectException("invalid name '..'");
+ }
+ if (duplicateName(raw, thisNameB, ptr - 1))
+ throw new CorruptObjectException("duplicate entry names");
+
+ if (lastNameB != 0)
+ {
+ int cmp = pathCompare(raw, lastNameB, lastNameE,
+ lastMode, thisNameB, ptr - 1, thisMode);
+ if (cmp > 0)
+ throw new CorruptObjectException("incorrectly sorted");
+ }
+
+ lastNameB = thisNameB;
+ lastNameE = ptr - 1;
+ lastMode = thisMode;
+
+ ptr += Constants.OBJECT_ID_LENGTH;
+ if (ptr > sz)
+ throw new CorruptObjectException("truncated in object id");
+ }
+ }
+
+ /**
+ * Check a blob for errors.
+ *
+ * @param raw
+ * the blob data. The array is never modified.
+ * @throws CorruptObjectException
+ * if any error was detected.
+ */
+ public void checkBlob(char[] raw)
+ {
+ // We can always assume the blob is valid.
+ }
+ }
+
+}
View
9 PersonIdent.cs
@@ -41,6 +41,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Text;
+using Gitty.Core.Util;
namespace Gitty.Core
{
@@ -158,7 +159,7 @@ public PersonIdent(string str)
}
else
{
- String tzHoursStr = str.Substring(sp + 1, sp + 4).Trim();
+ String tzHoursStr = str.Slice(sp + 1, sp + 4).Trim();
int tzHours;
if (tzHoursStr[0] == '+')
{
@@ -169,12 +170,12 @@ public PersonIdent(string str)
tzHours = int.Parse(tzHoursStr);
}
int tzMins = int.Parse(str.Substring(sp + 4).Trim());
- _whenTicks = long.Parse(str.Substring(gt + 1, sp).Trim()) * 1000;
+ _whenTicks = long.Parse(str.Slice(gt + 1, sp).Trim()) * 1000;
_tzOffset = TimeSpan.FromMinutes(tzHours * 60 + tzMins);
}
- this.Name = str.Substring(0, lt).Trim ();
- this.EmailAddress = str.Substring(lt + 1, gt).Trim ();
+ this.Name = str.Slice(0, lt).Trim ();
+ this.EmailAddress = str.Slice(lt + 1, gt).Trim ();
}
public override int GetHashCode()
View
85 RepositoryConfig.cs
@@ -1,42 +1,42 @@
-/*
- * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
- * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
- * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
- * Copyright (C) 2008, Thad Hughes <thadh@thad.corp.google.com>
- * Copyright (C) 2008, Kevin Thompson <kevin.thompson@theautomaters.com>
- *
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * - Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * - Neither the name of the Git Development Community nor the
- * names of its contributors may be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/*
+ * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * Copyright (C) 2008, Thad Hughes <thadh@thad.corp.google.com>
+ * Copyright (C) 2008, Kevin Thompson <kevin.thompson@theautomaters.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
@@ -89,6 +89,13 @@ public RepositoryConfig(RepositoryConfig baseConfig, FileInfo configFile)
public Repository Repository { get; private set; }
public FileInfo ConfigFile { get; private set; }
+ /**
+ * Overrides the default system reader by a custom one.
+ * @param newSystemReader new system reader
+ * [henon] Needed by test suite
+ */
+ public static ISystemReader SystemReader { set; get; }
+
#endregion
View
8 TestGUI/App.xaml
@@ -0,0 +1,8 @@
+<Application x:Class="TestGUI.App"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ StartupUri="Browser.xaml">
+ <Application.Resources>
+
+ </Application.Resources>
+</Application>
View
16 TestGUI/App.xaml.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Windows;
+
+namespace TestGUI
+{
+ /// <summary>
+ /// Interaction logic for App.xaml
+ /// </summary>
+ public partial class App : Application
+ {
+ }
+}
View
66 TestGUI/Browser.xaml
@@ -0,0 +1,66 @@
+<Window x:Class="TestGUI.Browser"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:core="clr-namespace:Gitty.Core;assembly=Gitty.Core"
+ xmlns:testgui="clr-namespace:TestGUI"
+ Title="Test GUI" MinHeight="423" MinWidth="568">
+ <Window.Resources>
+ <HierarchicalDataTemplate DataType="{x:Type core:Tree}" ItemsSource="{Binding Path=Children}">
+ <TextBlock Text="{Binding Name}" TextTrimming="CharacterEllipsis"/>
+ </HierarchicalDataTemplate>
+ <DataTemplate DataType="{x:Type core:FileTreeEntry}">
+ <TextBlock Text="{Binding Name}" TextTrimming="CharacterEllipsis" Foreground="CornflowerBlue"/>
+ </DataTemplate>
+ </Window.Resources>
+ <TabControl>
+ <TabItem Header="Unit tests" Name="m_unit_tests">
+
+ </TabItem>
+ <TabItem Header="Browser">
+ <DockPanel>
+ <!--<Label DockPanel.Dock="Top">Repository Browser</Label>-->
+ <StackPanel DockPanel.Dock="Top" Orientation="Horizontal" Margin="0,0,0,5">
+ <Label>Repository Url:</Label>
+ <TextBox Name="m_url_textbox">..\..\..\</TextBox>
+ <Button Click="Button_Click" Margin="5,0,0,0">Load</Button>
+ </StackPanel>
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="2*"/>
+ <ColumnDefinition Width="2"/>
+ <ColumnDefinition Width="1*"/>
+ </Grid.ColumnDefinitions>
+
+ <!--commits-->
+ <DockPanel>
+ <TextBlock DockPanel.Dock="Top" Background="Silver">Commits</TextBlock>
+ <ListView Name="m_list" DockPanel.Dock="Top">
+ <ListView.View>
+ <GridView>
+ <GridView.Columns>
+ <GridViewColumn Header="SHA" DisplayMemberBinding="{Binding Path=SHA}" />
+ <GridViewColumn Header="Message" DisplayMemberBinding="{Binding Path=Message}"/>
+ <GridViewColumn Header="Committer" DisplayMemberBinding="{Binding Path=Committer}"/>
+ <GridViewColumn Header="CommitedDate" DisplayMemberBinding="{Binding Path=CommittedDate}"/>
+ <GridViewColumn Header="Author" DisplayMemberBinding="{Binding Path=Author}"/>
+ <GridViewColumn Header="AuthoredDate" DisplayMemberBinding="{Binding Path=AuthoredDate}"/>
+ <GridViewColumn Header="Size" DisplayMemberBinding="{Binding Path=Size}" />
+ </GridView.Columns>
+ </GridView>
+ </ListView.View>
+ </ListView>
+ </DockPanel>
+ <GridSplitter Width="2" Grid.Column="1" ResizeBehavior="PreviousAndNext"/>
+
+ <!--tree-->
+ <DockPanel Grid.Column="2">
+ <TextBlock DockPanel.Dock="Top" Background="Silver">Repository</TextBlock>
+ <TreeView Name="m_tree">
+
+ </TreeView>
+ </DockPanel>
+ </Grid>
+ </DockPanel>
+ </TabItem>
+ </TabControl>
+</Window>
View
53 TestGUI/Browser.xaml.cs
@@ -0,0 +1,53 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using Gitty.Core;
+using Gitty.Core.Tests;
+using System.Collections.ObjectModel;
+using System.Reflection;
+
+namespace TestGUI
+{
+
+ public partial class Browser : Window
+ {
+ public Browser()
+ {
+ InitializeComponent();
+ var testrunner = new TestRunner();
+ m_unit_tests.Content = testrunner;
+ testrunner.AddAssembly(Assembly.Load("Gitty.Core.Tests"));
+
+ m_list.SelectionChanged += (o, args) => SelectCommit(m_list.SelectedItem as Commit);
+ }
+
+ private void SelectCommit(Commit commit)
+ {
+ //m_tree.ItemsSource = commit.Tree.Children;
+ //(m_tree.ItemContainerGenerator.ContainerFromIndex(0) as TreeViewItem).IsExpanded = true;
+ }
+
+ // load
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ var url = m_url_textbox.Text;
+ Repository repo = Repository.Open(url);
+ var head = repo.OpenCommit(repo.Head.ObjectId) as Commit;
+ var list = head.Ancestors.ToList();
+ list.Insert(0, head);
+ m_list.ItemsSource = list;
+ m_list.SelectedIndex = 0;
+ }
+
+ }
+}
View
55 TestGUI/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("TestGUI")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("eqqon")]
+[assembly: AssemblyProduct("TestGUI")]
+[assembly: AssemblyCopyright("Copyright © eqqon 2009")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+//In order to begin building localizable applications, set
+//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
+//inside a <PropertyGroup>. For example, if you are using US english
+//in your source files, set the <UICulture> to en-US. Then uncomment
+//the NeutralResourceLanguage attribute below. Update the "en-US" in
+//the line below to match the UICulture setting in the project file.
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
+
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
View
71 TestGUI/Properties/Resources.Designer.cs
@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.1433
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace TestGUI.Properties
+{
+
+
+ /// <summary>
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ /// </summary>
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "2.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources
+ {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources()
+ {
+ }
+
+ /// <summary>
+ /// Returns the cached ResourceManager instance used by this class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager
+ {
+ get
+ {
+ if ((resourceMan == null))
+ {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("TestGUI.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ /// <summary>
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ /// </summary>
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture
+ {
+ get
+ {
+ return resourceCulture;
+ }
+ set
+ {
+ resourceCulture = value;
+ }
+ }
+ }
+}
View
117 TestGUI/Properties/Resources.resx
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+ <!--
+ Microsoft ResX Schema
+
+ Version 2.0
+
+ The primary goals of this format is to allow a simple XML format
+ that is mostly human readable. The generation and parsing of the
+ various data types are done through the TypeConverter classes
+ associated with the data types.
+
+ Example:
+
+ ... ado.net/XML headers & schema ...
+ <resheader name="resmimetype">text/microsoft-resx</resheader>
+ <resheader name="version">2.0</resheader>
+ <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+ <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+ <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+ <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+ <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+ <value>[base64 mime encoded serialized .NET Framework object]</value>
+ </data>
+ <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+ <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+ <comment>This is a comment</comment>
+ </data>
+
+ There are any number of "resheader" rows that contain simple
+ name/value pairs.
+
+ Each data row contains a name, and value. The row also contains a
+ type or mimetype. Type corresponds to a .NET class that support
+ text/value conversion through the TypeConverter architecture.
+ Classes that don't support this are serialized and stored with the
+ mimetype set.
+
+ The mimetype is used for serialized objects, and tells the
+ ResXResourceReader how to depersist the object. This is currently not
+ extensible. For a given mimetype the value must be set accordingly:
+
+ Note - application/x-microsoft.net.object.binary.base64 is the format
+ that the ResXResourceWriter will generate, however the reader can
+ read any of the formats listed below.
+
+ mimetype: application/x-microsoft.net.object.binary.base64
+ value : The object must be serialized with
+ : System.Serialization.Formatters.Binary.BinaryFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.soap.base64
+ value : The object must be serialized with
+ : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+ : and then encoded with base64 encoding.
+
+ mimetype: application/x-microsoft.net.object.bytearray.base64
+ value : The object must be serialized into a byte array
+ : using a System.ComponentModel.TypeConverter
+ : and then encoded with base64 encoding.
+ -->
+ <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+ <xsd:element name="root" msdata:IsDataSet="true">
+ <xsd:complexType>
+ <xsd:choice maxOccurs="unbounded">
+ <xsd:element name="metadata">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" />
+ <xsd:attribute name="type" type="xsd:string" />
+ <xsd:attribute name="mimetype" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="assembly">
+ <xsd:complexType>
+ <xsd:attribute name="alias" type="xsd:string" />
+ <xsd:attribute name="name" type="xsd:string" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="data">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+ <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+ <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+ </xsd:complexType>
+ </xsd:element>
+ <xsd:element name="resheader">
+ <xsd:complexType>
+ <xsd:sequence>
+ <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+ </xsd:sequence>
+ <xsd:attribute name="name" type="xsd:string" use="required" />
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:choice>
+ </xsd:complexType>
+ </xsd:element>
+ </xsd:schema>
+ <resheader name="resmimetype">
+ <value>text/microsoft-resx</value>
+ </resheader>
+ <resheader name="version">
+ <value>2.0</value>
+ </resheader>
+ <resheader name="reader">
+ <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+ <resheader name="writer">
+ <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+ </resheader>
+</root>
View
30 TestGUI/Properties/Settings.Designer.cs
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+// This code was generated by a tool.
+// Runtime Version:2.0.50727.1433
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace TestGUI.Properties
+{
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "9.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+ {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default
+ {
+ get
+ {
+ return defaultInstance;
+ }
+ }
+ }
+}
View
7 TestGUI/Properties/Settings.settings
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
+ <Profiles>
+ <Profile Name="(Default)" />
+ </Profiles>
+ <Settings />
+</SettingsFile>
View
66 TestGUI/TestFixtureView.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Reflection;
+using System.Diagnostics;
+
+namespace TestGUI
+{
+ internal class TestFixtureView
+ {
+ public TestFixtureView(string name, Type fixture)
+ {
+ Name = name;
+ FixtureType = fixture;
+ Tests = new List<TestcaseView>();
+ }
+
+ public string Name { get; set; }
+ public Type FixtureType { get; set; }
+ public MethodInfo SetupMethod { get; set; }
+ public MethodInfo TeardownMethod { get; set; }
+ public List<TestcaseView> Tests { get; private set; }
+
+ internal void AddTest(TestcaseView testcase)
+ {
+ testcase.Fixture = this;
+ Tests.Add(testcase);
+ }
+
+ private object m_instance;
+ public object Instance
+ {
+ get
+ {
+ if (m_instance == null)
+ {
+ m_instance = CreateInstance(FixtureType, new object[0]);
+ }
+ return m_instance;
+ }
+ }
+
+ public static object CreateInstance(Type type, params object[] args)
+ {
+ Debug.Assert(type != null, "type cannot be null!!!!");
+ try
+ {
+ return type.InvokeMember(
+ null,
+ BindingFlags.Public |
+ BindingFlags.NonPublic |
+ BindingFlags.CreateInstance |
+ BindingFlags.Instance,
+ null,
+ null,
+ args);
+ }
+ catch (TargetInvocationException e)
+ {
+ Console.WriteLine(e.PrettyPrint());
+ throw e;
+ }
+ }
+ }
+}
View
123 TestGUI/TestGUI.csproj
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>9.0.21022</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{4B53BA11-1ADE-44E7-AC0F-7748D5701C25}</ProjectGuid>
+ <OutputType>WinExe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>TestGUI</RootNamespace>
+ <AssemblyName>TestGUI</AssemblyName>
+ <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="nunit.framework, Version=2.5.0.8258, Culture=neutral, PublicKeyToken=96d09a1eb7f44a77, processorArchitecture=MSIL">
+ <SpecificVersion>False</SpecificVersion>
+ <HintPath>..\Tests\Dependencies\nunit.framework.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Core">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Xml.Linq">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data.DataSetExtensions">
+ <RequiredTargetFramework>3.5</RequiredTargetFramework>
+ </Reference>
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ <Reference Include="WindowsBase" />
+ <Reference Include="PresentationCore" />
+ <Reference Include="PresentationFramework" />
+ </ItemGroup>
+ <ItemGroup>
+ <ApplicationDefinition Include="App.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </ApplicationDefinition>
+ <Page Include="Browser.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Page Include="TestRunner.xaml">
+ <Generator>MSBuild:Compile</Generator>
+ <SubType>Designer</SubType>
+ </Page>
+ <Compile Include="App.xaml.cs">
+ <DependentUpon>App.xaml</DependentUpon>
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Browser.xaml.cs">
+ <DependentUpon>Browser.xaml</DependentUpon>
+ <SubType>Code</SubType>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Properties\AssemblyInfo.cs">
+ <SubType>Code</SubType>
+ </Compile>
+ <Compile Include="Properties\Resources.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DesignTime>True</DesignTime>
+ <DependentUpon>Resources.resx</DependentUpon>
+ </Compile>
+ <Compile Include="Properties\Settings.Designer.cs">
+ <AutoGen>True</AutoGen>
+ <DependentUpon>Settings.settings</DependentUpon>
+ <DesignTimeSharedInput>True</DesignTimeSharedInput>
+ </Compile>
+ <Compile Include="TestcaseView.cs" />
+ <Compile Include="TestFixtureView.cs" />
+ <Compile Include="TestRunner.xaml.cs" />
+ <EmbeddedResource Include="Properties\Resources.resx">
+ <Generator>ResXFileCodeGenerator</Generator>
+ <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+ </EmbeddedResource>
+ <None Include="Properties\Settings.settings">
+ <Generator>SettingsSingleFileGenerator</Generator>
+ <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+ </None>
+ <AppDesigner Include="Properties\" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="..\Gitty.Core.csproj">
+ <Project>{C46EDD61-C202-465A-93F1-ADE20A83BB59}</Project>
+ <Name>Gitty.Core</Name>
+ </ProjectReference>
+ <ProjectReference Include="..\Tests\Gitty.Core.Tests.csproj">
+ <Project>{37052DA4-F6A9-47D0-94AA-96F4A7E0462C}</Project>
+ <Name>Gitty.Core.Tests</Name>
+ </ProjectReference>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
View
32 TestGUI/TestRunner.xaml
@@ -0,0 +1,32 @@
+<UserControl x:Class="TestGUI.TestRunner"
+ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ MinHeight="500" MinWidth="700">
+ <Grid>
+ <Grid.ColumnDefinitions>
+ <ColumnDefinition Width="3*" />
+ <ColumnDefinition Width="7*" />
+ </Grid.ColumnDefinitions>
+ <TreeView Name="m_treeview" Grid.Column="0" >
+ <TreeViewItem Header="All assemblies" IsExpanded="True"></TreeViewItem>
+ </TreeView>
+ <GridSplitter Width="5" BorderThickness="1" BorderBrush="DarkGray" />
+
+ <Grid Grid.Column="1">
+ <Grid.RowDefinitions>
+ <RowDefinition Height="*"></RowDefinition>
+ <RowDefinition Height="5"></RowDefinition>
+ <RowDefinition Height="*"></RowDefinition>
+ </Grid.RowDefinitions>
+ <DockPanel Grid.Row="0">
+ <DockPanel DockPanel.Dock="Top">
+ <Button Name="m_button_run" Width="50">Run</Button>
+ <ProgressBar Name="m_progressbar"></ProgressBar>
+ </DockPanel>
+ <TextBox Name="m_textbox1" DockPanel.Dock="Bottom">Status</TextBox>
+ </DockPanel>
+ <GridSplitter Grid.Row="1" BorderThickness="1" BorderBrush="DarkGray" HorizontalAlignment="Stretch" ResizeDirection="Rows" ShowsPreview="False" ResizeBehavior="PreviousAndNext"/>
+ <TextBox Name="m_textbox2" Grid.Row="2" >Backtrace</TextBox>
+ </Grid>
+ </Grid>
+</UserControl>
View
336 TestGUI/TestRunner.xaml.cs
@@ -0,0 +1,336 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.Reflection;
+using NUnit.Framework;
+using System.IO;
+
+namespace TestGUI
+{
+ /// <summary>
+ /// Interaction logic for Frontend.xaml
+ /// </summary>
+ public partial class TestRunner : UserControl
+ {
+ public TestRunner()
+ {
+ InitializeComponent();
+ m_button_run.Click += (o, args) =>
+ {
+ var item = m_treeview.SelectedItem as TreeViewItem;
+ if (item == null)
+ return;
+ RunAll(item);
+ PresentSummary(item);
+ };
+ Init();
+ }
+ //ImageSource red_icon = new BitmapImage().FromFile(Directory.GetCurrentDirectory() + @"./Resources/offline.png");
+ //ImageSource green_icon = new BitmapImage().FromFile(Directory.GetCurrentDirectory() + @"./Resources/online.png");
+
+ public void Init()
+ {
+ var item = m_treeview.Items[0] as TreeViewItem;
+ {
+
+ item.PreviewMouseDown += (o, args) => PresentSummary(item);
+ item.ContextMenu = InitContextMenu(item);
+ }
+
+ List<Assembly> assemblies = new List<Assembly>();
+ assemblies.Add(Assembly.GetEntryAssembly());
+ foreach (AssemblyName name in Assembly.GetEntryAssembly().GetReferencedAssemblies())
+ assemblies.Add(Assembly.Load(name));
+ foreach (Assembly assembly in assemblies)
+ Analyze(assembly, item.Items);
+ }
+
+ public void AddAssembly(Assembly assembly)
+ {
+ Analyze(assembly, (m_treeview.Items[0] as TreeViewItem).Items);
+ }
+
+ private void Analyze(Assembly assembly, ItemCollection collection)
+ {
+ var item = new TreeViewItem();
+ {
+ item.Header = assembly.GetName().Name;
+ item.Tag = assembly;
+ collection.Add(item);
+ item.PreviewMouseDown += (o, args) => PresentSummary(item);
+ }
+ foreach (Type type in assembly.GetExportedTypes())
+ Analyze(type, item.Items);
+
+ if (item.Items.Count == 0)
+ {
+ collection.Remove(item); // pruning assemblies without testcases
+ return;
+ }
+ item.ContextMenu = InitContextMenu(item);
+ }
+
+ private void Analyze(Type type, ItemCollection collection)
+ {
+ object[] attrs = Attribute.GetCustomAttributes(type);
+ //if ( attrs.Contains(NUnit.Framework.TestAttribute);
+ if (type.GetCustomAttributes(typeof(TestFixtureAttribute), false).Count() == 0)
+ return;
+ var fixture = new TestFixtureView(type.Name, type);
+ var item = new TreeViewItem();
+ {
+ item.Header = type.Name;
+ item.Tag = fixture;
+ collection.Add(item);
+ item.PreviewMouseDown += (o, args) => PresentSummary(item);
+ }
+
+ foreach (MethodInfo method in type.GetMethods(BindingFlags.Public | BindingFlags.Instance))
+ Analyze(type, method, item.Items, fixture);
+
+ }
+
+ private void Analyze(Type type, MethodInfo method, ItemCollection collection, TestFixtureView fixture)
+ {
+ if (method.GetCustomAttributes(typeof(TestAttribute), false).Count() > 0)
+ {
+
+ var testcase = new TestcaseView(type, method);
+ collection.Add(CreateItem(testcase));
+ fixture.AddTest(testcase);
+ }
+ else if (method.GetCustomAttributes(typeof(SetUpAttribute), false).Count() > 0)
+ {
+ fixture.SetupMethod = method;
+ }
+ else if (method.GetCustomAttributes(typeof(TearDownAttribute), false).Count() > 0)
+ {
+ fixture.TeardownMethod = method;
+ }
+ }
+
+ private TreeViewItem CreateItem(TestcaseView testcase)
+ {
+
+ var item = new TreeViewItem();
+ item.Header = testcase.TestMethod.Name;
+ item.FontWeight = FontWeights.Bold;
+ item.Tag = testcase;
+ item.ContextMenu = InitContextMenu(item);
+ item.PreviewMouseDown += (o, args) => PresentSummary(item);
+#if false
+ ImageSource iconSource=red_icon;
+ TextBlock textBlock;
+ Image icon;
+
+ StackPanel stack = new StackPanel();
+ stack.Orientation = Orientation.Horizontal;
+ item.Header = stack;
+ //Uncomment this code If you want to add an Image after the Node-HeaderText
+ //textBlock = new TextBlock();
+ //textBlock.VerticalAlignment = VerticalAlignment.Center;
+ //stack.Children.Add(textBlock);
+ icon = new Image();
+ icon.VerticalAlignment = VerticalAlignment.Center;
+ icon.Margin = new Thickness(0, 0, 4, 0);
+ icon.Source = iconSource;
+ stack.Children.Add(icon);
+ //Add the HeaderText After Adding the icon
+ textBlock = new TextBlock();
+ textBlock.VerticalAlignment = VerticalAlignment.Center;
+ stack.Children.Add(textBlock);
+#endif
+ return item;
+ }
+
+ private void PresentSummary(TreeViewItem item)
+ {
+ m_textbox2.Text = "";
+ var testcase = item.Tag as TestcaseView;
+ if (testcase == null) // present summary
+ {
+
+ StringBuilder s = new StringBuilder("Summary for " + item.Header.ToString() + ":\n\n");
+ foreach (var i in item.IterateDown())
+ {
+ var treeitem = i as TreeViewItem;
+ if (treeitem.Tag is TestcaseView)
+ s.AppendLine(StatusMessage(treeitem.Tag as TestcaseView));
+ }
+ m_textbox1.Text = s.ToString();
+ return;
+ }
+ m_textbox1.Text = StatusMessage(testcase);
+ if (testcase.Failed)
+ {
+ item.ExpandUpRecursive();
+ //((item.Header as StackPanel).Children[0] as Image).Source = red_icon;
+ //(item.Header as TextBlock).
+ item.Foreground = Brushes.Red;
+ //m_textbox1.Text = testcase.ToString() + " --> FAILED:\n\n" + testcase.Exception.Message;
+ string s = testcase.Exception.PrettyPrint();
+ m_textbox2.Text = s;
+ Console.WriteLine(s);
+ }
+ }
+
+ private string StatusMessage(TestcaseView testcase)
+ {
+ if (testcase.IsExecuted == false)
+ return testcase.ToString() + " ... not yet run.";
+ if (testcase.Failed)
+ return "*** " + testcase.ToString() + " --> FAILED:\n\n" + testcase.Exception.Message;
+ else
+ return testcase.ToString() + " --> OK";
+ }
+
+ private ContextMenu InitContextMenu(TreeViewItem item)
+ {
+ var menu = new ContextMenu();
+ var item1 = new MenuItem();
+ {
+ menu.Items.Add(item1);
+ item1.Header = "Run";
+ item1.Click += (o, args) =>
+ {
+ RunAll(item);
+ PresentSummary(item);
+ };
+ }
+ var item2 = new MenuItem();
+ {
+ menu.Items.Add(item2);
+ item2.Header = "Expand all";
+ item2.Click += (o, args) => item.ExpandDownRecursive();
+ } return menu;
+ }
+
+ private void RunAll(TreeViewItem item)
+ {
+ if (item == null)
+ return;
+ if (item.Tag is TestcaseView)
+ Run(item.Tag as TestcaseView, item);
+ else
+ foreach (var child in item.Items)
+ RunAll(child as TreeViewItem);
+ }
+
+ private void Run(TestcaseView testcase, TreeViewItem item)
+ {
+ item.Foreground = Brushes.Black; // Colors.Black;
+ m_textbox1.Text = "Running ... " + testcase.ToString();
+ m_textbox2.Text = "";
+ testcase.Run();
+
+ PresentSummary(item);
+ }
+
+ }
+
+
+ public static class ExceptionExtension
+ {
+ public static string PrettyPrint(this Exception exception)
+ {
+ m_string_builder = new StringBuilder();
+ PrintRecursive(exception, "");
+ return m_string_builder.ToString();
+ }
+
+ private static StringBuilder m_string_builder;
+
+ private static void PrintRecursive(Exception exception, string indent)
+ {
+ string stars = new string('*', 80);
+ m_string_builder.AppendLine(indent + stars);
+ m_string_builder.AppendFormat(indent + "{0}: \"{1}\"\n", exception.GetType().Name, exception.Message);
+ m_string_builder.AppendLine(indent + new string('-', 80));
+ if (exception.InnerException != null)
+ {
+ m_string_builder.AppendLine(indent + "InnerException:");
+ PrintRecursive(exception.InnerException, indent + " ");
+ }
+ foreach (string line in exception.StackTrace.Split(new string[] { " at " }, StringSplitOptions.RemoveEmptyEntries))
+ {
+ if (string.IsNullOrEmpty(line.Trim())) continue;
+ string[] parts;
+ parts = line.Trim().Split(new string[] { " in " }, StringSplitOptions.RemoveEmptyEntries);
+ string class_info = parts[0];
+ if (parts.Length == 2)
+ {
+ parts = parts[1].Trim().Split(new string[] { "line" }, StringSplitOptions.RemoveEmptyEntries);
+ if (parts.Length == 2)
+ {
+ string src_file = parts[0];
+ int line_nr = int.Parse(parts[1]);
+ m_string_builder.AppendFormat(indent + " {0}({1},1): {2}\n", src_file.TrimEnd(':'), line_nr, class_info);
+ }
+ else
+ m_string_builder.AppendLine(indent + " " + class_info);
+ }
+ else
+ m_string_builder.AppendLine(indent + " " + class_info);
+ }
+ m_string_builder.AppendLine(indent + stars);
+ }
+
+ }
+
+ public static class TreeViewItemExtension
+ {
+ public static void Expand(this TreeViewItem item)
+ {
+ item.IsExpanded = true;
+ }
+
+ public static void Collapse(this TreeViewItem item)
+ {
+ item.IsExpanded = false;
+ }
+
+ public static void ExpandUpRecursive(this TreeViewItem item)
+ {
+ var parent = item.Parent as TreeViewItem;
+ if (parent == null)
+ return;
+ parent.Expand();
+ parent.ExpandUpRecursive();
+ }
+
+ public static void ExpandDownRecursive(this TreeViewItem item)
+ {
+ item.Expand();
+ foreach (var child in item.Items)
+ (child as TreeViewItem).ExpandDownRecursive();
+ }
+
+ public static IEnumerable<object> IterateDown(this TreeViewItem item)
+ {
+ var list = new List<object>();
+ IterateDown(item, list);
+ return list;
+ }
+
+ private static void IterateDown(TreeViewItem item, List<object> list)
+ {
+ foreach (var child in item.Items)
+ {
+ //var child = i as TreeViewItem;
+ list.Add(child);
+ if (child is TreeViewItem)
+ IterateDown(child as TreeViewItem, list);
+ }
+ }
+ }
+}
View
92 TestGUI/TestcaseView.cs
@@ -0,0 +1,92 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Reflection;
+using System.Diagnostics;
+
+namespace TestGUI
+{
+ internal class TestcaseView
+ {
+ public TestcaseView(Type t, MethodInfo m)
+ {
+ Type = t;
+ TestMethod = m;
+ }
+
+ public Type Type
+ {
+ get;
+ set;
+ }
+
+ public MethodInfo TestMethod
+ {
+ get;
+ set;
+ }
+
+
+ public TestFixtureView Fixture { get; set; }
+
+ public void Setup()
+ {
+ if (Fixture.SetupMethod == null)
+ return;
+ Fixture.SetupMethod.Invoke(Fixture.Instance, new object[0]);
+ }
+
+ public void Teardown()
+ {
+ if (Fixture.TeardownMethod == null)
+ return;
+ try
+ {
+ Fixture.TeardownMethod.Invoke(Fixture.Instance, new object[0]);
+ }