Index: modules/node/node.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.module,v
retrieving revision 1.1027
diff -u -p -r1.1027 node.module
--- modules/node/node.module	26 Feb 2009 07:30:27 -0000	1.1027
+++ modules/node/node.module	7 Mar 2009 21:52:43 -0000
@@ -1880,6 +1880,7 @@ function node_block_list() {
   $blocks['syndicate']['info'] = t('Syndicate');
   // Not worth caching.
   $blocks['syndicate']['cache'] = BLOCK_NO_CACHE;
+  $blocks['recent']['info'] = t('Recent content');
   return $blocks;
 }
 
@@ -1887,12 +1888,54 @@ function node_block_list() {
  * Implementation of hook_block_view().
  */
 function node_block_view($delta = '') {
-  $block['subject'] = t('Syndicate');
-  $block['content'] = theme('feed_icon', url('rss.xml'), t('Syndicate'));
-
+  $block = array();
+  
+  switch ($delta) {
+    case 'syndicate':
+      $block['subject'] = t('Syndicate');
+      $block['content'] = theme('feed_icon', url('rss.xml'), t('Syndicate'));
+      break;
+    
+    case 'recent':
+      if (user_access('access content')) {
+        $block['subject'] = t('Recent content');
+        $items = array();
+        $select = db_select('node', 'n')
+          ->fields('n', array('created', 'nid', 'title'))
+          ->orderBy('created', 'DESC')
+          ->range(0, variable_get('node_recent_block_count', 10))
+          ->addTag('node_access')
+          ->execute();
+        while ($node = $select->fetch(PDO::FETCH_ASSOC)) {
+          $item = l($node['title'], 'node/' . $node['nid']);
+          $item .= '<br />';
+          $item .= t('@time ago', array('@time' => format_interval(REQUEST_TIME - $node['created'])));
+          $items[] = $item;
+        }
+        if (count($items)) {
+          $block['content'] = theme('item_list', $items);
+        }
+      }
+      break;
+      
+  }
   return $block;
 }
 
+function node_block_configure($delta = '') {
+  $form = array();
+    if ($delta == 'recent') {
+      $form['node_recent_block_count'] = array(
+        '#type' => 'select',
+        '#title' => t('Amount of recent content'),
+        '#default_value' => variable_get('node_recent_block_count', 10),
+        '#options' => drupal_map_assoc(array(2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 30)),
+        '#description' => t('Pieces of content displayed in the <em>Recently posted</em> block.'),
+      );
+    }
+  return $form;
+}
+
 /**
  * A generic function for generating RSS feeds from a set of nodes.
  *
Index: modules/node/node.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/node/node.test,v
retrieving revision 1.16
diff -u -p -r1.16 node.test
--- modules/node/node.test	28 Jan 2009 07:34:30 -0000	1.16
+++ modules/node/node.test	7 Mar 2009 21:52:43 -0000
@@ -18,6 +18,11 @@ class NodeLoadMultipleUnitTest extends D
     parent::setUp();
     $web_user = $this->drupalCreateUser(array('create article content', 'create page content'));
     $this->drupalLogin($web_user);
+    // Disable the "recent content" block, it will mess up our assertions if enabled.
+    db_delete('block')
+      ->condition('module', 'node')
+      ->condition('delta', 'recent')
+      ->execute();
   }
 
   /**
@@ -635,3 +640,101 @@ class NodeRSSContentTestCase extends Dru
     $this->assertText($test_text, t('Extra node content appears in RSS feed.'));
   }
 }
+
+class RecentContentBlockTestCase extends DrupalWebTestCase {
+  protected $nodes;
+
+  /**
+   * Implementation of getInfo().
+   */
+  function getInfo() {
+     return array(
+      'name' => t('Recent content block'),
+      'description' => t('Test to make sure the recent content block works properly; it makes sure that nodes appear there, in the correct order, and the settings work properly.'),
+      'group' => t('Node'),
+    );
+  }
+
+  function setUp() {
+    // Clear the static $nodes cache.
+    $this->nodes = array();
+    parent::setUp();
+  }
+
+  /**
+   * Test the recent content block with a few nodes, less than the maximum.
+   */
+  function testRecentContentBlock() {
+    $this->createTestNodes(3);
+    $this->assertRecentContent();
+  }
+
+  /**
+   * Test the recent content block with a lot of nodes, moer than the maximum.
+   */
+  function testRecentContentBlockOverflow() {
+    $this->createTestNodes(18);
+    $this->assertRecentContent();
+  }
+
+  /**
+   * Test the recent content block with a non-standard maximum number of nodes.
+   */
+  function testRecentContentBlockSettings() {
+    variable_set('node_recent_block_count', 20);
+    $this->createTestNodes(18);
+    $this->assertRecentContent();
+  }
+
+  /**
+   * Test the recent content block with a non-standard maximum number of nodes,
+   * and have more nodes than that custom maximum.
+   */
+  function testRecentContentBlockSettingsOverflow() {
+    variable_set('node_recent_block_count', 5);
+    $this->createTestNodes(18);
+    $this->assertRecentContent();
+  }
+
+  /**
+   * Create a number of nodes, and store them in the protected $nodes array.
+   *
+   * @param $count
+   *   The number of nodes to create.
+   */
+  protected function createTestNodes($count) {
+    $time = REQUEST_TIME - 600;
+    for ($i = 0; $i < $count; $i++) {
+      $this->nodes[($count - $i) - 1] = $this->drupalCreateNode(array('created' => REQUEST_TIME + $i));
+    }
+  }
+
+  /**
+   * Helper assertion that makes sure the nodes appear on the block correctly.
+   */
+  protected function assertRecentContent() {
+    $this->refreshVariables();
+    $count = variable_get('node_recent_block_count', 10);
+    $this->drupalGet('<front>');
+    $results = $this->elements->xpath('//div[@id="block-node-recent"]');
+    $div = $results[0];
+    if (!count($this->nodes)) {
+      $this->assertFalse($div, t('Block does not appear when no nodes exist.'));
+      return;
+    }
+    $this->assertTrue($div, t('Block appears when several nodes exist.'));
+    $title = $div->h2;
+    $this->assertEqual($title, t('Recently posted'), t('Title of the block matches correctly.'));
+    // Under the block div, we have the <div class="content">, and then another
+    // div surrounding the themed item list before we get to the ul.
+    $ul = $div->div->div->ul;
+    $this->assertEqual(count($ul->li), min(count($this->nodes), $count), t('The correct number of nodes are shown.'));
+    for ($i = 0; $i < $count; $i++) {
+      if (isset($this->nodes[$i])) {
+        $list_item = $ul->li[$i];
+        $link = $list_item->a;
+        $this->assertEqual($link, $this->nodes[$i]->title, t('The correct node title is shown.'));
+      }
+    }
+  }
+}
Index: modules/search/search.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/search/search.test,v
retrieving revision 1.15
diff -u -p -r1.15 search.test
--- modules/search/search.test	22 Jan 2009 04:49:58 -0000	1.15
+++ modules/search/search.test	7 Mar 2009 21:52:44 -0000
@@ -252,6 +252,13 @@ class SearchAdvancedSearchForm extends D
     // and searching has to happen in the same request, so running the shutdown
     // function manually is needed to finish the indexing process.
     search_update_totals();
+
+    // Remove the "recent content" block because it will mess up our assertions
+    // later if enabled.
+    db_delete('block')
+      ->condition('module', 'node')
+      ->condition('delta', 'recent')
+      ->execute();
   }
 
   /**
Index: modules/tracker/tracker.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/tracker/tracker.test,v
retrieving revision 1.6
diff -u -p -r1.6 tracker.test
--- modules/tracker/tracker.test	9 Feb 2009 16:27:35 -0000	1.6
+++ modules/tracker/tracker.test	7 Mar 2009 21:52:44 -0000
@@ -20,6 +20,12 @@ class TrackerTest extends DrupalWebTestC
     $permissions = array('access comments', 'post comments', 'post comments without approval');
     $this->user = $this->drupalCreateUser($permissions);
     $this->other_user = $this->drupalCreateUser($permissions);
+    // Remove the "recent content" block because it will mess up our assertions
+    // later on if enabled.
+    db_delete('block')
+      ->condition('module', 'node')
+      ->condition('delta', 'recent')
+      ->execute();
   }
 
   /**
Index: profiles/default/default.profile
===================================================================
RCS file: /cvs/drupal/drupal/profiles/default/default.profile,v
retrieving revision 1.37
diff -u -p -r1.37 default.profile
--- profiles/default/default.profile	3 Feb 2009 12:30:14 -0000	1.37
+++ profiles/default/default.profile	7 Mar 2009 21:52:44 -0000
@@ -91,9 +91,10 @@ function default_profile_task_list() {
  */
 function default_profile_tasks(&$task, $url) {
   
-  // Enable 3 standard blocks.
+  // Enable 4 standard blocks.
   db_query("INSERT INTO {block} (module, delta, theme, status, weight, region, pages, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s', %d)", 'user', 'login', 'garland', 1, 0, 'left', '', -1);
   db_query("INSERT INTO {block} (module, delta, theme, status, weight, region, pages, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s', %d)", 'user', 'navigation', 'garland', 1, 0, 'left', '', -1);
+  db_query("INSERT INTO {block} (module, delta, theme, status, weight, region, pages, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s', %d)", 'node', 'recent', 'garland', 1, 0, 'left', '', -1);
   db_query("INSERT INTO {block} (module, delta, theme, status, weight, region, pages, cache) VALUES ('%s', '%s', '%s', %d, %d, '%s', '%s', %d)", 'system', 'powered-by', 'garland', 1, 10, 'footer', '', -1);
 
   // Insert default user-defined node types into the database. For a complete
