You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@subversion.apache.org by hw...@apache.org on 2010/11/09 17:03:07 UTC

svn commit: r1033047 [2/2] - in /subversion/branches/py-tests-as-modules: ./ subversion/include/ subversion/libsvn_client/ subversion/libsvn_repos/ subversion/libsvn_subr/ subversion/libsvn_wc/ subversion/svn/ subversion/tests/cmdline/ subversion/tests...

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/schedule_tests.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/schedule_tests.py?rev=1033047&r1=1033046&r2=1033047&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/schedule_tests.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/schedule_tests.py Tue Nov  9 16:03:06 2010
@@ -71,7 +71,7 @@ def add_files(sbox):
   svntest.main.file_append(zeta_path, "This is the file 'zeta'.")
   svntest.main.file_append(epsilon_path, "This is the file 'epsilon'.")
 
-  sbox.simple_add(delta_path, zeta_path, epsilon_path)
+  sbox.simple_add('delta', 'A/B/zeta', 'A/D/G/epsilon')
 
   # Make sure the adds show up as such in status
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
@@ -100,7 +100,7 @@ def add_directories(sbox):
   os.mkdir(Y_path)
   os.mkdir(Z_path)
 
-  sbox.simple_add(X_path, Y_path, Z_path)
+  sbox.simple_add('X', 'A/C/Y', 'A/D/H/Z')
 
   # Make sure the adds show up as such in status
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
@@ -150,7 +150,7 @@ def nested_adds(sbox):
   svntest.main.file_append(zeta_path, "This is the file 'zeta'.")
 
   # Finally, let's try adding our new files and directories
-  sbox.simple_add(X_path, Y_path, Z_path)
+  sbox.simple_add('X', 'A/C/Y', 'A/D/H/Z')
 
   # Make sure the adds show up as such in status
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
@@ -177,19 +177,19 @@ def add_executable(sbox):
   sbox.build(read_only = True)
 
   def runTest(wc_dir, fileName, perm, executable):
-    fileName = sbox.ospath(fileName)
+    file_ospath = sbox.ospath(fileName)
     if executable:
       expected_out = ["*\n"]
     else:
       expected_out = []
 
     # create an empty file
-    open(fileName, "w")
+    open(file_ospath, "w")
 
-    os.chmod(fileName, perm)
+    os.chmod(file_ospath, perm)
     sbox.simple_add(fileName)
     svntest.actions.run_and_verify_svn(None, expected_out, [],
-                                       'propget', "svn:executable", fileName)
+                                       'propget', "svn:executable", file_ospath)
 
   test_cases = [
     ("all_exe",   0777, 1),
@@ -210,12 +210,7 @@ def delete_files(sbox):
   wc_dir = sbox.wc_dir
 
   # Schedule some files for deletion
-  iota_path = sbox.ospath('iota')
-  mu_path = sbox.ospath('A/mu')
-  rho_path = sbox.ospath('A/D/G/rho')
-  omega_path = sbox.ospath('A/D/H/omega')
-
-  sbox.simple_rm(iota_path, mu_path, rho_path, omega_path)
+  sbox.simple_rm('iota', 'A/mu', 'A/D/G/rho', 'A/D/H/omega')
 
   # Make sure the deletes show up as such in status
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
@@ -233,17 +228,7 @@ def delete_dirs(sbox):
   wc_dir = sbox.wc_dir
 
   # Schedule some directories for deletion (this is recursive!)
-  E_path = sbox.ospath('A/B/E')
-  F_path = sbox.ospath('A/B/F')
-  H_path = sbox.ospath('A/D/H')
-  alpha_path = sbox.ospath('A/B/E/alpha')
-  beta_path  = sbox.ospath('A/B/E/beta')
-  chi_path   = sbox.ospath('A/D/H/chi')
-  omega_path = sbox.ospath('A/D/H/omega')
-  psi_path   = sbox.ospath('A/D/H/psi')
-
-  # Now, delete (recursively) the directories.
-  sbox.simple_rm(E_path, F_path, H_path)
+  sbox.simple_rm('A/B/E', 'A/B/F', 'A/D/H')
 
   # Make sure the deletes show up as such in status
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
@@ -430,8 +415,8 @@ def unschedule_missing_added(sbox):
 
   svntest.main.file_append(file1_path, "This is the file 'file1'.")
   svntest.main.file_append(file2_path, "This is the file 'file2'.")
-  sbox.simple_add(file1_path, file2_path)
-  sbox.simple_mkdir(dir1_path, dir2_path)
+  sbox.simple_add('file1', 'file2')
+  sbox.simple_mkdir('dir1', 'dir2')
 
   # Make sure the 4 adds show up as such in status
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
@@ -456,8 +441,8 @@ def unschedule_missing_added(sbox):
   svntest.main.run_svn(svntest.verify.AnyOutput, 'rm', file1_path)
   ### actually, the stub does not provide enough information to revert
   ### the addition, so this command will fail. marking as XFail
-  sbox.simple_rm(dir1_path)
-  sbox.simple_revert(file2_path, dir2_path)
+  sbox.simple_rm('dir1')
+  sbox.simple_revert('file2', 'dir2')
 
   # 'svn st' should now show absolutely zero local mods.
   expected_status = svntest.actions.get_virginal_state(wc_dir, 1)
@@ -483,7 +468,7 @@ def delete_missing(sbox):
   svntest.main.safe_rmtree(H_path)
 
   # Now schedule them for deletion anyway, and make sure no error is output.
-  sbox.simple_rm(mu_path, H_path)
+  sbox.simple_rm('A/mu', 'A/D/H')
 
   # Commit the deletions.
   expected_output = svntest.wc.State(wc_dir, {
@@ -511,18 +496,14 @@ def revert_inside_newly_added_dir(sbox):
   "revert inside a newly added dir"
 
   sbox.build(read_only = True)
-  wc_dir = sbox.wc_dir
-
-  os.chdir(wc_dir)
 
   # Schedule a new directory for addition
-  os.mkdir('foo')
-  sbox.simple_add('foo')
+  sbox.simple_mkdir('foo')
 
   # Now change into the newly added directory, revert and make sure
   # no error is output.
-  os.chdir('foo')
-  sbox.simple_revert('.')
+  os.chdir(sbox.ospath('foo'))
+  svntest.main.run_svn(None, 'revert', '.')
 
 #----------------------------------------------------------------------
 # Regression test for issue #1609:
@@ -546,11 +527,11 @@ def status_add_deleted_directory(sbox):
 
   A_path = sbox.ospath('A')
 
-  sbox.simple_rm(A_path)
+  sbox.simple_rm('A')
   svntest.main.safe_rmtree(A_path)
   sbox.simple_commit()
 
-  sbox.simple_mkdir(A_path)
+  sbox.simple_mkdir('A')
 
   expected_status = svntest.actions.get_virginal_state(wc_dir, 2)
   expected_status = svntest.wc.State(wc_dir,

Modified: subversion/branches/py-tests-as-modules/subversion/tests/cmdline/svntest/sandbox.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/cmdline/svntest/sandbox.py?rev=1033047&r1=1033046&r2=1033047&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/cmdline/svntest/sandbox.py (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/cmdline/svntest/sandbox.py Tue Nov  9 16:03:06 2010
@@ -162,10 +162,18 @@ class Sandbox:
     return self._is_built
 
   def ospath(self, relpath, wc_dir=None):
+    """Return RELPATH converted to an OS-style path relative to the WC dir
+       of this sbox, or relative to OS-style path WC_DIR if supplied."""
     if wc_dir is None:
       wc_dir = self.wc_dir
     return os.path.join(wc_dir, svntest.wc.to_ospath(relpath))
 
+  def ospaths(self, relpaths, wc_dir=None):
+    """Return a list of RELPATHS but with each path converted to an OS-style
+       path relative to the WC dir of this sbox, or relative to OS-style
+       path WC_DIR if supplied."""
+    return [self.ospath(rp, wc_dir) for rp in relpaths]
+
   def redirected_root_url(self, temporary=False):
     """If TEMPORARY is set, return the URL which should be configured
        to temporarily redirect to the root of this repository;
@@ -180,47 +188,61 @@ class Sandbox:
                                   parts[1])
     
   def simple_update(self, target=None):
+    """Update the WC or TARGET.
+       TARGET is a relpath relative to the WC."""
     assert not self.read_only
     if target is None:
       target = self.wc_dir
+    else:
+      target = self.ospath(target)
     svntest.main.run_svn(False, 'update', target)
 
   def simple_commit(self, target=None):
+    """Commit the WC or TARGET with a default log message.
+       TARGET is a relpath relative to the WC."""
     assert not self.read_only
     if target is None:
       target = self.wc_dir
+    else:
+      target = self.ospath(target)
     svntest.main.run_svn(False, 'commit',
                          '-m', svntest.main.make_log_msg(),
                          target)
 
   def simple_rm(self, *targets):
+    """TARGET is a relpath relative to the WC."""
     assert len(targets) > 0
-    if len(targets) == 1 and is_url(targets[0]):
-      assert not self.read_only
-      targets = ('-m', svntests.main.make_log_msg(), targets[0])
+    targets = self.ospaths(targets)
     svntest.main.run_svn(False, 'rm', *targets)
 
   def simple_mkdir(self, *targets):
+    """TARGET is a relpath relative to the WC."""
     assert len(targets) > 0
-    if len(targets) == 1 and is_url(targets[0]):
-      assert not self.read_only
-      targets = ('-m', svntests.main.make_log_msg(), targets[0])
+    targets = self.ospaths(targets)
     svntest.main.run_svn(False, 'mkdir', *targets)
 
   def simple_add(self, *targets):
+    """TARGET is a relpath relative to the WC."""
     assert len(targets) > 0
+    targets = self.ospaths(targets)
     svntest.main.run_svn(False, 'add', *targets)
 
   def simple_revert(self, *targets):
+    """TARGET is a relpath relative to the WC."""
     assert len(targets) > 0
+    targets = self.ospaths(targets)
     svntest.main.run_svn(False, 'revert', *targets)
 
   def simple_propset(self, name, value, *targets):
+    """TARGET is a relpath relative to the WC."""
     assert len(targets) > 0
+    targets = self.ospaths(targets)
     svntest.main.run_svn(False, 'propset', name, value, *targets)
 
   def simple_propdel(self, name, *targets):
+    """TARGET is a relpath relative to the WC."""
     assert len(targets) > 0
+    targets = self.ospaths(targets)
     svntest.main.run_svn(False, 'propdel', name, *targets)
 
 

Modified: subversion/branches/py-tests-as-modules/subversion/tests/libsvn_wc/op-depth-test.c
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/subversion/tests/libsvn_wc/op-depth-test.c?rev=1033047&r1=1033046&r2=1033047&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/subversion/tests/libsvn_wc/op-depth-test.c (original)
+++ subversion/branches/py-tests-as-modules/subversion/tests/libsvn_wc/op-depth-test.c Tue Nov  9 16:03:06 2010
@@ -200,6 +200,21 @@ wc_commit(wc_baton_t *b, const char *pat
                             NULL, NULL, NULL, NULL, ctx, b->pool);
 }
 
+static svn_error_t *
+wc_update(wc_baton_t *b, const char *path, svn_revnum_t revnum)
+{
+  svn_client_ctx_t *ctx;
+  apr_array_header_t *result_revs;
+  apr_array_header_t *paths = apr_array_make(b->pool, 1,
+                                             sizeof(const char *));
+  svn_opt_revision_t revision = { svn_opt_revision_number, { revnum } };
+
+  APR_ARRAY_PUSH(paths, const char *) = wc_path(b, path);
+  SVN_ERR(svn_client_create_context(&ctx, b->pool));
+  return svn_client_update3(&result_revs, paths, &revision, svn_depth_infinity,
+                            TRUE, FALSE, FALSE, ctx, b->pool);
+}
+
 /* Create the Greek tree on disk in the WC, and commit it. */
 static svn_error_t *
 add_and_commit_greek_tree(wc_baton_t *b)
@@ -576,15 +591,14 @@ wc_wc_copies(wc_baton_t *b)
 static svn_error_t *
 repo_wc_copies(wc_baton_t *b)
 {
-  const char source_base_file[]   = "A/B/lambda";
-  const char source_base_dir[]    = "A/B/E";
-
   SVN_ERR(add_and_commit_greek_tree(b));
 
   /* Delete some nodes so that we can test copying onto these paths */
 
+  SVN_ERR(wc_delete(b, "A/B/lambda"));
   SVN_ERR(wc_delete(b, "A/D/gamma"));
   SVN_ERR(wc_delete(b, "A/D/G"));
+  SVN_ERR(wc_delete(b, "A/D/H"));
 
   /* Test copying various things */
 
@@ -598,36 +612,56 @@ repo_wc_copies(wc_baton_t *b)
       }
     subtests[] =
       {
-        /* file */
-        { source_base_file, "A/C/copy1", {
-            { 3, "",                "normal",   1, source_base_file }
-          } },
-
-        /* dir */
-        { source_base_dir, "A/C/copy2", {
-            { 3, "",                "normal",   1, source_base_dir },
-            { 3, "alpha",           "normal",   NO_COPY_FROM },
-            { 3, "beta",            "normal",   NO_COPY_FROM }
+        /* file onto nothing */
+        { "iota", "A/C/copy1", {
+            { 3, "",                "normal",       1, "iota" },
+          } },
+
+        /* dir onto nothing */
+        { "A/B/E", "A/C/copy2", {
+            { 3, "",                "normal",       1, "A/B/E" },
+            { 3, "alpha",           "normal",       NO_COPY_FROM },
+            { 3, "beta",            "normal",       NO_COPY_FROM },
+          } },
+
+        /* file onto a schedule-delete file */
+        { "iota", "A/B/lambda", {
+            { 0, "",                "normal",       1, "A/B/lambda" },
+            { 3, "",                "normal",       1, "iota" },
+          } },
+
+        /* dir onto a schedule-delete dir */
+        { "A/B/E", "A/D/G", {
+            { 0, "",                "normal",       1, "A/D/G" },
+            { 0, "pi",              "normal",       1, "A/D/G/pi" },
+            { 0, "rho",             "normal",       1, "A/D/G/rho" },
+            { 0, "tau",             "normal",       1, "A/D/G/tau" },
+            { 3, "",                "normal",       1, "A/B/E" },
+            { 3, "pi",              "base-deleted", NO_COPY_FROM },
+            { 3, "rho",             "base-deleted", NO_COPY_FROM },
+            { 3, "tau",             "base-deleted", NO_COPY_FROM },
+            { 3, "alpha",           "normal",       NO_COPY_FROM },
+            { 3, "beta",            "normal",       NO_COPY_FROM },
           } },
 
         /* dir onto a schedule-delete file */
-        { source_base_dir, "A/D/gamma", {
-            { 0, "",                "normal",   1, "A/D/gamma" },
-            { 3, "",                "normal",   1, source_base_dir },
-            { 3, "alpha",           "normal",   NO_COPY_FROM },
-            { 3, "beta",            "normal",   NO_COPY_FROM }
+        { "A/B/E", "A/D/gamma", {
+            { 0, "",                "normal",       1, "A/D/gamma" },
+            { 3, "",                "normal",       1, "A/B/E" },
+            { 3, "alpha",           "normal",       NO_COPY_FROM },
+            { 3, "beta",            "normal",       NO_COPY_FROM },
           } },
 
         /* file onto a schedule-delete dir */
-        { source_base_file, "A/D/G", {
-            { 0, "",                "normal",   1, "A/D/G" },
-            { 0, "pi",              "normal",   1, "A/D/G/pi" },
-            { 0, "rho",             "normal",   1, "A/D/G/rho" },
-            { 0, "tau",             "normal",   1, "A/D/G/tau" },
-            { 3, "",                "normal",   1, source_base_file },
-            { 3, "pi",              "base-deleted",   NO_COPY_FROM },
-            { 3, "rho",             "base-deleted",   NO_COPY_FROM },
-            { 3, "tau",             "base-deleted",   NO_COPY_FROM }
+        { "iota", "A/D/H", {
+            { 0, "",                "normal",       1, "A/D/H" },
+            { 0, "chi",             "normal",       1, "A/D/H/chi" },
+            { 0, "psi",             "normal",       1, "A/D/H/psi" },
+            { 0, "omega",           "normal",       1, "A/D/H/omega" },
+            { 3, "",                "normal",       1, "iota" },
+            { 3, "chi",             "base-deleted", NO_COPY_FROM },
+            { 3, "psi",             "base-deleted", NO_COPY_FROM },
+            { 3, "omega",           "base-deleted", NO_COPY_FROM },
           } },
 
         { 0 }
@@ -950,12 +984,58 @@ test_repo_wc_copies(const svn_test_opts_
 
   b.pool = pool;
   SVN_ERR(svn_test__create_repos_and_wc(&b.repos_url, &b.wc_abspath,
-                                        "wc_wc_copies", opts, pool));
+                                        "repo_wc_copies", opts, pool));
   SVN_ERR(svn_wc_context_create(&b.wc_ctx, NULL, pool, pool));
 
   return repo_wc_copies(&b);
 }
 
+static svn_error_t *
+test_delete_with_update(const svn_test_opts_t *opts, apr_pool_t *pool)
+{
+  wc_baton_t b;
+
+  b.pool = pool;
+  SVN_ERR(svn_test__create_repos_and_wc(&b.repos_url, &b.wc_abspath,
+                                        "delete_with_update", opts, pool));
+  SVN_ERR(svn_wc_context_create(&b.wc_ctx, NULL, pool, pool));
+  SVN_ERR(wc_mkdir(&b, "A"));
+  SVN_ERR(wc_commit(&b, ""));
+  SVN_ERR(wc_mkdir(&b, "A/B"));
+  SVN_ERR(wc_mkdir(&b, "A/B/C"));
+  SVN_ERR(wc_commit(&b, ""));
+  SVN_ERR(wc_update(&b, "", 1));
+
+  SVN_ERR(wc_delete(&b, "A"));
+  SVN_ERR(wc_mkdir(&b, "A"));
+  SVN_ERR(wc_mkdir(&b, "A/B"));
+  {
+    nodes_row_t rows[] = {
+      { 0, "A",       "normal",        1, "A"},
+      { 1, "A",       "normal",        NO_COPY_FROM},
+      { 2, "A/B",     "normal",        NO_COPY_FROM},
+      { 0 }
+    };
+    SVN_ERR(check_db_rows(&b, "A", rows));
+  }
+  SVN_ERR(wc_update(&b, "", 2));
+  {
+    nodes_row_t rows[] = {
+      { 0, "A",       "normal",        2, "A"},
+      { 0, "A/B",     "normal",        2, "A/B"},
+      { 0, "A/B/C",   "normal",        2, "A/B/C"},
+      { 1, "A",       "normal",        NO_COPY_FROM},
+      { 1, "A/B",     "base-deleted",  NO_COPY_FROM},
+      { 1, "A/B/C",   "base-deleted",  NO_COPY_FROM},
+      { 2, "A/B",     "normal",        NO_COPY_FROM},
+      { 0 }
+    };
+    SVN_ERR(check_db_rows(&b, "A", rows));
+  }
+
+  return SVN_NO_ERROR;
+}
+
 /* ---------------------------------------------------------------------- */
 /* The list of test functions */
 
@@ -963,7 +1043,7 @@ struct svn_test_descriptor_t test_funcs[
   {
     SVN_TEST_NULL,
     SVN_TEST_OPTS_WIMP(test_wc_wc_copies,
-                       "wc_wc_copies",
+                       "test_wc_wc_copies",
                        "needs op_depth"),
     SVN_TEST_OPTS_WIMP(test_reverts,
                        "test_reverts",
@@ -978,10 +1058,13 @@ struct svn_test_descriptor_t test_funcs[
                        "test_delete_with_base",
                        "needs op_depth"),
     SVN_TEST_OPTS_WIMP(test_adds,
-                       "adds",
+                       "test_adds",
                        "needs op_depth"),
     SVN_TEST_OPTS_WIMP(test_repo_wc_copies,
                        "test_repo_wc_copies",
                        "needs op_depth"),
+    SVN_TEST_OPTS_WIMP(test_delete_with_update,
+                       "test_delete_with_update",
+                       "needs op_depth"),
     SVN_TEST_NULL
   };

Modified: subversion/branches/py-tests-as-modules/tools/hook-scripts/mailer/mailer.py
URL: http://svn.apache.org/viewvc/subversion/branches/py-tests-as-modules/tools/hook-scripts/mailer/mailer.py?rev=1033047&r1=1033046&r2=1033047&view=diff
==============================================================================
--- subversion/branches/py-tests-as-modules/tools/hook-scripts/mailer/mailer.py (original)
+++ subversion/branches/py-tests-as-modules/tools/hook-scripts/mailer/mailer.py Tue Nov  9 16:03:06 2010
@@ -866,12 +866,16 @@ class DiffGenerator:
           content = src_fname = dst_fname = None
         else:
           src_fname, dst_fname = diff.get_files()
-          content = DiffContent(self.cfg.get_diff_cmd(self.group, {
-            'label_from' : label1,
-            'label_to' : label2,
-            'from' : src_fname,
-            'to' : dst_fname,
-            }))
+          try:
+            content = DiffContent(self.cfg.get_diff_cmd(self.group, {
+              'label_from' : label1,
+              'label_to' : label2,
+              'from' : src_fname,
+              'to' : dst_fname,
+              }))
+          except OSError:
+            # diff command does not exist, try difflib.unified_diff()
+            content = DifflibDiffContent(label1, label2, src_fname, dst_fname)
 
       # return a data item for this diff
       return _data(
@@ -890,6 +894,33 @@ class DiffGenerator:
         content=content,
         )
 
+def _classify_diff_line(line, seen_change):
+  # classify the type of line.
+  first = line[:1]
+  ltype = ''
+  if first == '@':
+    seen_change = True
+    ltype = 'H'
+  elif first == '-':
+    if seen_change:
+      ltype = 'D'
+    else:
+      ltype = 'F'
+  elif first == '+':
+    if seen_change:
+      ltype = 'A'
+    else:
+      ltype = 'T'
+  elif first == ' ':
+    ltype = 'C'
+  else:
+    ltype = 'U'
+
+  if line[-2] == '\r':
+    line=line[0:-2] + '\n' # remove carriage return
+
+  return line, ltype, seen_change
+
 
 class DiffContent:
   "This is a generator-like object returning annotated lines of a diff."
@@ -917,36 +948,42 @@ class DiffContent:
       self.pipe = None
       raise IndexError
 
-    # classify the type of line.
-    first = line[:1]
-    if first == '@':
-      self.seen_change = True
-      ltype = 'H'
-    elif first == '-':
-      if self.seen_change:
-        ltype = 'D'
-      else:
-        ltype = 'F'
-    elif first == '+':
-      if self.seen_change:
-        ltype = 'A'
-      else:
-        ltype = 'T'
-    elif first == ' ':
-      ltype = 'C'
-    else:
-      ltype = 'U'
+    line, ltype, self.seen_change = _classify_diff_line(line, self.seen_change)
+    return _data(
+      raw=line,
+      text=line[1:-1],  # remove indicator and newline
+      type=ltype,
+      )
 
-    if line[-2] == '\r':
-      line=line[0:-2] + '\n' # remove carriage return
+class DifflibDiffContent():
+  "This is a generator-like object returning annotated lines of a diff."
+
+  def __init__(self, label_from, label_to, from_file, to_file):
+    import difflib
+    self.seen_change = False
+    fromlines = open(from_file, 'U').readlines()
+    tolines = open(to_file, 'U').readlines()
+    self.diff = difflib.unified_diff(fromlines, tolines,
+                                     label_from, label_to)
+    
+  def __nonzero__(self):
+    # we always have some items
+    return True
 
+  def __getitem__(self, idx):
+
+    try:
+      line = self.diff.next()
+    except StopIteration:
+      raise IndexError
+
+    line, ltype, self.seen_change = _classify_diff_line(line, self.seen_change)
     return _data(
       raw=line,
       text=line[1:-1],  # remove indicator and newline
       type=ltype,
       )
 
-
 class TextCommitRenderer:
   "This class will render the commit mail in plain text."