From c896b586d6b1378523c4888b5cc3ad3b5dbfb9b6 Mon Sep 17 00:00:00 2001
From: megachriz <megachriz@654114.no-reply.drupal.org>
Date: Fri, 19 Jun 2015 12:00:02 -0700
Subject: [PATCH] Issue #1107522 by MegaChriz, twistor, ditcheva, nielsonm,
 franz, Niklas Fiekas, cthiebault, Uhkis, gcb, mparker17, guillaumev:
 Framework for expected behavior when importing empty/blank values + text
 field fix

---
 mappers/field.inc                           |  50 +++++
 tests/feeds/content_date.csv                |   3 +
 tests/feeds/content_empty.csv               |   3 +
 tests/feeds/content_link.csv                |   3 +
 tests/feeds/content_non_existent.csv        |   3 +
 tests/feeds/feeds-tests-files-empty.tpl.php |   6 +
 tests/feeds_mapper.test                     |  28 ++-
 tests/feeds_mapper_config.test              |   6 +-
 tests/feeds_mapper_date.test                | 155 +++++++++++++-
 tests/feeds_mapper_date_multiple.test       |   6 +-
 tests/feeds_mapper_field.test               | 149 ++++++++++++-
 tests/feeds_mapper_file.test                | 126 ++++++++++-
 tests/feeds_mapper_format_config.test       |   1 +
 tests/feeds_mapper_hooks.test               |   5 +-
 tests/feeds_mapper_link.test                | 223 ++++++++++++++++++--
 tests/feeds_mapper_path.test                |  10 +-
 tests/feeds_mapper_profile.test             |  11 +-
 tests/feeds_mapper_summary.test             |   5 +-
 tests/feeds_mapper_taxonomy.test            |  95 ++++++++-
 tests/feeds_mapper_unique.test              |   1 +
 tests/feeds_tests.module                    |  53 +++++
 21 files changed, 898 insertions(+), 44 deletions(-)
 create mode 100644 mappers/field.inc
 create mode 100644 tests/feeds/content_date.csv
 create mode 100644 tests/feeds/content_empty.csv
 create mode 100644 tests/feeds/content_link.csv
 create mode 100644 tests/feeds/content_non_existent.csv
 create mode 100644 tests/feeds/feeds-tests-files-empty.tpl.php

diff --git a/mappers/field.inc b/mappers/field.inc
new file mode 100644
index 00000000..91eebe82
--- /dev/null
+++ b/mappers/field.inc
@@ -0,0 +1,50 @@
+<?php
+
+/**
+ * @file
+ * On behalf implementation of Feeds mapping API for field.module.
+ */
+
+/**
+ * Implements hook_feeds_presave().
+ */
+function field_feeds_presave(FeedsSource $source, $entity, $item, $entity_id) {
+  $entity_type = $entity->feeds_item->entity_type;
+
+  // Not a real entity.
+  if (!entity_get_info($entity_type)) {
+    return;
+  }
+
+  // Gather the fields that Feeds is mapping to.
+  $feeds_fields = array();
+  foreach ($source->importer()->processor->getMappings() as $mapping) {
+    list($field) = explode(':', $mapping['target']);
+    $feeds_fields[$field] = TRUE;
+  }
+
+  list(, , $bundle) = entity_extract_ids($entity_type, $entity);
+
+  foreach (field_info_instances($entity_type, $bundle) as $instance) {
+    $field_name = $instance['field_name'];
+
+    // Skip fields that Feeds isn't mapping to, and empty fields.
+    if (!isset($feeds_fields[$field_name]) || empty($entity->$field_name)) {
+      continue;
+    }
+
+    $info = field_info_field($field_name);
+
+    foreach ($entity->$field_name as $language => $values) {
+      // Filter out empty values.
+      $values = _field_filter_items($info, $values);
+
+      // Check that the number of values doesn't exceed the field cardinality.
+      if ($info['cardinality'] != FIELD_CARDINALITY_UNLIMITED && count($values) > $info['cardinality']) {
+        $values = array_slice($values, 0, $info['cardinality']);
+      }
+
+      $entity->{$field_name}[$language] = $values;
+    }
+  }
+}
diff --git a/tests/feeds/content_date.csv b/tests/feeds/content_date.csv
new file mode 100644
index 00000000..68a59cff
--- /dev/null
+++ b/tests/feeds/content_date.csv
@@ -0,0 +1,3 @@
+"guid","title","created","end"
+1,"Lorem ipsum",1251936720,1351936720
+2,"Ut wisi enim ad minim veniam",1251932360,1351932360
diff --git a/tests/feeds/content_empty.csv b/tests/feeds/content_empty.csv
new file mode 100644
index 00000000..5b08023a
--- /dev/null
+++ b/tests/feeds/content_empty.csv
@@ -0,0 +1,3 @@
+"guid","title","created","end","alpha","beta","gamma","delta","body","link_title","url"
+1,"Lorem ipsum",,,,,,,,,
+2,"Ut wisi enim ad minim veniam",0,0,"0",0,0,0,0,0,0
diff --git a/tests/feeds/content_link.csv b/tests/feeds/content_link.csv
new file mode 100644
index 00000000..e2db4a65
--- /dev/null
+++ b/tests/feeds/content_link.csv
@@ -0,0 +1,3 @@
+"guid","title","link_title","url"
+1,"Lorem ipsum","Feeds","https://www.drupal.org/project/feeds"
+2,"Ut wisi enim ad minim veniam","Framework for expected behavior when importing empty/blank values","https://www.drupal.org/node/1107522"
diff --git a/tests/feeds/content_non_existent.csv b/tests/feeds/content_non_existent.csv
new file mode 100644
index 00000000..a614ac3a
--- /dev/null
+++ b/tests/feeds/content_non_existent.csv
@@ -0,0 +1,3 @@
+"guid","title"
+1,"Lorem ipsum"
+2,"Ut wisi enim ad minim veniam"
diff --git a/tests/feeds/feeds-tests-files-empty.tpl.php b/tests/feeds/feeds-tests-files-empty.tpl.php
new file mode 100644
index 00000000..b36606d9
--- /dev/null
+++ b/tests/feeds/feeds-tests-files-empty.tpl.php
@@ -0,0 +1,6 @@
+Title,published,file,GUID,alt,title2
+"Tubing is awesome",205200720,<?php print $files[0]; ?>,0,,
+"Jeff vs Tom",428112720,<?php print $files[1]; ?>,1,,
+"Attersee",1151766000,<?php print $files[2]; ?>,2,,
+"H Street NE",1256326995,<?php print $files[3]; ?>,3,,
+"La Fayette Park",1256326995,<?php print $files[4]; ?>,4,,
diff --git a/tests/feeds_mapper.test b/tests/feeds_mapper.test
index 492af896..0cd0d3d7 100644
--- a/tests/feeds_mapper.test
+++ b/tests/feeds_mapper.test
@@ -2,11 +2,11 @@
 
 /**
  * @file
- * Helper class with auxiliary functions for feeds mapper module tests.
+ * Contains FeedsMapperTestCase.
  */
 
 /**
- * Base class for implementing Feeds Mapper test cases.
+ * Helper class with auxiliary functions for feeds mapper module tests.
  */
 class FeedsMapperTestCase extends FeedsWebTestCase {
 
@@ -55,6 +55,29 @@ class FeedsMapperTestCase extends FeedsWebTestCase {
     }
   }
 
+  /**
+   * Assert that a form field for the given field with the given value
+   * does not exist in the current form.
+   *
+   * @param $field_name
+   *   The name of the field.
+   * @param $value
+   *   The (raw) value of the field.
+   * @param $index
+   *   The index of the field (for q multi-valued field).
+   *
+   * @see FeedsMapperTestCase::getFormFieldsNames()
+   * @see FeedsMapperTestCase::getFormFieldsValues()
+   */
+  protected function assertNoNodeFieldValue($field_name, $value, $index = 0) {
+    $names = $this->getFormFieldsNames($field_name, $index);
+    $values = $this->getFormFieldsValues($field_name, $value);
+    foreach ($names as $k => $name) {
+      $value = $values[$k];
+      $this->assertNoFieldByName($name, $value, t('Did not find form field %name for %field_name with the value %value.', array('%name' => $name, '%field_name' => $field_name, '%value' => $value)));
+    }
+  }
+
   /**
    * Returns the form fields names for a given CCK field. Default implementation
    * provides support for a single form field with the following name pattern
@@ -160,4 +183,5 @@ class FeedsMapperTestCase extends FeedsWebTestCase {
     $field_widgets = FeedsMapperTestCase::$field_widgets;
     return isset($field_widgets[$field_type]) ? $field_widgets[$field_type] : NULL;
   }
+
 }
diff --git a/tests/feeds_mapper_config.test b/tests/feeds_mapper_config.test
index 566bbf96..b22764d1 100644
--- a/tests/feeds_mapper_config.test
+++ b/tests/feeds_mapper_config.test
@@ -2,13 +2,14 @@
 
 /**
  * @file
- * Test cases for Feeds mapping configuration form.
+ * Contains FeedsMapperConfigTestCase.
  */
 
 /**
- * Class for testing basic Feeds ajax mapping configurtaion form behavior.
+ * Test cases for Feeds mapping configuration form.
  */
 class FeedsMapperConfigTestCase extends FeedsMapperTestCase {
+
   public static function getInfo() {
     return array(
       'name' => 'Mapper: Config',
@@ -76,7 +77,6 @@ class FeedsMapperConfigTestCase extends FeedsMapperTestCase {
     $this->assertEqual($settings['select'], 'option4');
     $this->assertEqual($settings['second_value'], $second_callback_value);
 
-
     // Check that form validation works.
     // Click gear to get form.
     $this->drupalPostAJAX(NULL, array(), 'mapping_settings_edit_0');
diff --git a/tests/feeds_mapper_date.test b/tests/feeds_mapper_date.test
index c3cb067f..7dd8cfac 100644
--- a/tests/feeds_mapper_date.test
+++ b/tests/feeds_mapper_date.test
@@ -2,16 +2,17 @@
 
 /**
  * @file
- * Test case for CCK date field mapper mappers/date.inc.
+ * Contains FeedsMapperDateTestCase.
  */
 
 /**
- * Class for testing Feeds <em>content</em> mapper.
+ * Test case for CCK date field mapper mappers/date.inc.
  *
  * @todo: Add test method iCal
  * @todo: Add test method for end date
  */
 class FeedsMapperDateTestCase extends FeedsMapperTestCase {
+
   public static function getInfo() {
     return array(
       'name' => 'Mapper: Date',
@@ -118,4 +119,154 @@ class FeedsMapperDateTestCase extends FeedsMapperTestCase {
       return parent::getFormFieldsNames($field_name, $index);
     }
   }
+
+  /**
+   * Tests if values are cleared out when an empty value is provided.
+   */
+  public function testClearOutValues() {
+    // Create content type.
+    $typename = $this->createContentType(array(), array(
+      'date' => 'date',
+      'datestamp' => 'datestamp',
+      'datetime' => 'datetime',
+    ));
+
+    // Hack to get date fields to not round to every 15 minutes.
+    foreach (array('date', 'datestamp', 'datetime') as $field) {
+      $field = 'field_' . $field;
+      $edit = array(
+        'widget_type' => 'date_select',
+      );
+      $this->drupalPost('admin/structure/types/manage/' . $typename . '/fields/' . $field . '/widget-type', $edit, 'Continue');
+      $edit = array(
+        'instance[widget][settings][increment]' => 1,
+        'field[settings][enddate_get]' => 1,
+      );
+      $this->drupalPost('admin/structure/types/manage/' . $typename . '/fields/' . $field, $edit, 'Save settings');
+      $edit = array(
+        'widget_type' => 'date_text',
+      );
+      $this->drupalPost('admin/structure/types/manage/' . $typename . '/fields/' . $field . '/widget-type', $edit, 'Continue');
+    }
+
+    // Create and configure importer.
+    $this->createImporterConfiguration('Content CSV', 'csv');
+    $this->setSettings('csv', NULL, array(
+      'content_type' => '',
+      'import_period' => FEEDS_SCHEDULE_NEVER,
+    ));
+    $this->setPlugin('csv', 'FeedsFileFetcher');
+    $this->setPlugin('csv', 'FeedsCSVParser');
+    $this->setSettings('csv', 'FeedsNodeProcessor', array(
+      'bundle' => $typename,
+      'update_existing' => 1,
+    ));
+    $this->addMappings('csv', array(
+      0 => array(
+        'source' => 'title',
+        'target' => 'title',
+        'unique' => TRUE,
+      ),
+      1 => array(
+        'source' => 'created',
+        'target' => 'field_date:start',
+      ),
+      2 => array(
+        'source' => 'end',
+        'target' => 'field_date:end',
+      ),
+      3 => array(
+        'source' => 'created',
+        'target' => 'field_datestamp:start',
+      ),
+      4 => array(
+        'source' => 'end',
+        'target' => 'field_datestamp:end',
+      ),
+      5 => array(
+        'source' => 'created',
+        'target' => 'field_datetime:start',
+      ),
+      6 => array(
+        'source' => 'end',
+        'target' => 'field_datetime:end',
+      ),
+    ));
+
+    // Import CSV file.
+    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content_date.csv');
+    $this->assertText('Created 2 nodes');
+
+    // Check the imported nodes.
+    $date_values = array(
+      1 => array(
+        'created' => '09/03/2009 - 00:12',
+        'end' => '11/03/2012 - 09:58',
+      ),
+      2 => array(
+        'created' => '09/02/2009 - 22:59',
+        'end' => '11/03/2012 - 08:46',
+      ),
+    );
+    for ($i = 1; $i <= 2; $i++) {
+      $this->drupalGet("node/$i/edit");
+      $this->assertNodeFieldValue('date', $date_values[$i]['created']);
+      $this->assertFieldByName('field_date[und][0][value2][date]', $date_values[$i]['end']);
+      $this->assertNodeFieldValue('datestamp', $date_values[$i]['created']);
+      $this->assertFieldByName('field_datestamp[und][0][value2][date]', $date_values[$i]['end']);
+      $this->assertNodeFieldValue('datetime', $date_values[$i]['created']);
+      $this->assertFieldByName('field_datetime[und][0][value2][date]', $date_values[$i]['end']);
+    }
+
+    // Import CSV file with empty values.
+    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content_empty.csv');
+    $this->assertText('Updated 2 nodes');
+
+    // Check if all values were cleared out for both nodes.
+    for ($i = 1; $i <= 2; $i++) {
+      $this->drupalGet("node/$i/edit");
+      $this->assertNoNodeFieldValue('date', $date_values[$i]['created']);
+      $this->assertNoFieldByName('field_date[und][0][value2][date]', $date_values[$i]['end']);
+      $this->assertNoNodeFieldValue('datestamp', $date_values[$i]['created']);
+      $this->assertNoFieldByName('field_datestamp[und][0][value2][date]', $date_values[$i]['end']);
+      $this->assertNoNodeFieldValue('datetime', $date_values[$i]['created']);
+      $this->assertNoFieldByName('field_datetime[und][0][value2][date]', $date_values[$i]['end']);
+      $this->drupalGet("node/$i");
+      $this->assertNoText('date_label');
+      $this->assertNoText('datestamp_label');
+      $this->assertNoText('datetime_label');
+    }
+
+    // Re-import the first file again and check if the values returned.
+    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content_date.csv');
+    $this->assertText('Updated 2 nodes');
+    for ($i = 1; $i <= 2; $i++) {
+      $this->drupalGet("node/$i/edit");
+      $this->assertNodeFieldValue('date', $date_values[$i]['created']);
+      $this->assertFieldByName('field_date[und][0][value2][date]', $date_values[$i]['end']);
+      $this->assertNodeFieldValue('datestamp', $date_values[$i]['created']);
+      $this->assertFieldByName('field_datestamp[und][0][value2][date]', $date_values[$i]['end']);
+      $this->assertNodeFieldValue('datetime', $date_values[$i]['created']);
+      $this->assertFieldByName('field_datetime[und][0][value2][date]', $date_values[$i]['end']);
+    }
+
+    // Import CSV file with non-existent values.
+    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content_non_existent.csv');
+    $this->assertText('Updated 2 nodes');
+
+    // Check if all values were cleared out for node 1.
+    $this->drupalGet('node/1/edit');
+    $this->assertNoNodeFieldValue('date', $date_values[1]['created']);
+    $this->assertNoFieldByName('field_date[und][0][value2][date]', $date_values[1]['end']);
+    $this->assertNoNodeFieldValue('datestamp', $date_values[1]['created']);
+    $this->assertNoFieldByName('field_datestamp[und][0][value2][date]', $date_values[1]['end']);
+    $this->assertNoNodeFieldValue('datetime', $date_values[1]['created']);
+    $this->assertNoFieldByName('field_datetime[und][0][value2][date]', $date_values[1]['end']);
+    // Check if labels for fields that should be cleared out are not shown.
+    $this->drupalGet('node/1');
+    $this->assertNoText('date_label');
+    $this->assertNoText('datestamp_label');
+    $this->assertNoText('datetime_label');
+  }
+
 }
diff --git a/tests/feeds_mapper_date_multiple.test b/tests/feeds_mapper_date_multiple.test
index 3886c5a1..18c29919 100644
--- a/tests/feeds_mapper_date_multiple.test
+++ b/tests/feeds_mapper_date_multiple.test
@@ -2,16 +2,17 @@
 
 /**
  * @file
- * Test case for CCK date multi-field mapper mappers/date.inc.
+ * Contains FeedsMapperDateMultipleTestCase.
  */
 
 /**
- * Class for testing Feeds <em>content</em> mapper.
+ * Test case for CCK date multi-field mapper mappers/date.inc.
  *
  * @todo: Add test method iCal
  * @todo: Add test method for end date
  */
 class FeedsMapperDateMultipleTestCase extends FeedsMapperTestCase {
+
   public static function getInfo() {
     return array(
       'name' => 'Mapper: Date, multi value fields',
@@ -115,4 +116,5 @@ class FeedsMapperDateMultipleTestCase extends FeedsMapperTestCase {
       }
     }
   }
+
 }
diff --git a/tests/feeds_mapper_field.test b/tests/feeds_mapper_field.test
index 2506a295..7c9dbd63 100644
--- a/tests/feeds_mapper_field.test
+++ b/tests/feeds_mapper_field.test
@@ -2,13 +2,14 @@
 
 /**
  * @file
- * Test case for simple CCK field mapper mappers/content.inc.
+ * Contains FeedsMapperFieldTestCase.
  */
 
 /**
- * Class for testing Feeds field mapper.
+ * Test case for simple CCK field mapper mappers/content.inc.
  */
 class FeedsMapperFieldTestCase extends FeedsMapperTestCase {
+
   public static function getInfo() {
     return array(
       'name' => 'Mapper: Fields',
@@ -24,7 +25,7 @@ class FeedsMapperFieldTestCase extends FeedsMapperTestCase {
   /**
    * Basic test loading a double entry CSV file.
    */
-  function test() {
+  public function test() {
     // Create content type.
     $typename = $this->createContentType(array(), array(
       'alpha' => 'text',
@@ -87,4 +88,146 @@ class FeedsMapperFieldTestCase extends FeedsMapperTestCase {
     $this->assertNodeFieldValue('gamma', '1.20');
     $this->assertNodeFieldValue('delta', '5.62951');
   }
+
+  /**
+   * Tests if values are cleared out when an empty value is provided.
+   */
+  public function testClearOutValues() {
+    // Create content type.
+    $typename = $this->createContentType(array(), array(
+      'alpha' => 'text',
+      'beta' => 'number_integer',
+      'gamma' => 'number_decimal',
+      'delta' => 'number_float',
+    ));
+
+    // Create and configure importer.
+    $this->createImporterConfiguration('Content CSV', 'csv');
+    $this->setSettings('csv', NULL, array('content_type' => '', 'import_period' => FEEDS_SCHEDULE_NEVER));
+    $this->setPlugin('csv', 'FeedsFileFetcher');
+    $this->setPlugin('csv', 'FeedsCSVParser');
+    $this->setSettings('csv', 'FeedsNodeProcessor', array('bundle' => $typename, 'update_existing' => 1));
+    $this->addMappings('csv', array(
+      array(
+        'source' => 'guid',
+        'target' => 'guid',
+        'unique' => TRUE,
+      ),
+      array(
+        'source' => 'title',
+        'target' => 'title',
+      ),
+      array(
+        'source' => 'created',
+        'target' => 'created',
+      ),
+      array(
+        'source' => 'body',
+        'target' => 'body',
+      ),
+      array(
+        'source' => 'alpha',
+        'target' => 'field_alpha',
+      ),
+      array(
+        'source' => 'beta',
+        'target' => 'field_beta',
+      ),
+      array(
+        'source' => 'gamma',
+        'target' => 'field_gamma',
+      ),
+      array(
+        'source' => 'delta',
+        'target' => 'field_delta',
+      ),
+    ));
+
+    // Import CSV file.
+    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content.csv');
+    $this->assertText('Created 2 nodes');
+
+    // Check the two imported nodes.
+    $this->drupalGet('node/1/edit');
+    $this->assertNodeFieldValue('alpha', 'Lorem');
+    $this->assertNodeFieldValue('beta', '42');
+    $this->assertNodeFieldValue('gamma', '4.20');
+    $this->assertNodeFieldValue('delta', '3.14159');
+    $this->assertFieldByName('body[und][0][value]', 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.');
+    $this->drupalGet('node/2/edit');
+    $this->assertNodeFieldValue('alpha', 'Ut wisi');
+    $this->assertNodeFieldValue('beta', '32');
+    $this->assertNodeFieldValue('gamma', '1.20');
+    $this->assertNodeFieldValue('delta', '5.62951');
+    $this->assertFieldByName('body[und][0][value]', 'Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.');
+
+    // Import CSV file with empty values.
+    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content_empty.csv');
+    $this->assertText('Updated 2 nodes');
+
+    // Check if all values were cleared out for node 1.
+    $this->drupalGet('node/1/edit');
+    $this->assertNoNodeFieldValue('alpha', 'Lorem');
+    $this->assertNoNodeFieldValue('beta', '42');
+    $this->assertNoNodeFieldValue('gamma', '4.20');
+    $this->assertNoNodeFieldValue('delta', '3.14159');
+    $this->assertFieldByName('body[und][0][value]', '');
+    // Check if labels for fields that should be cleared out are not shown.
+    $this->drupalGet('node/1');
+    $this->assertNoText('alpha_text_label');
+    $this->assertNoText('beta_number_integer_label');
+    $this->assertNoText('gamma_number_decimal_label');
+    $this->assertNoText('delta_number_float_label');
+
+    // Check if zero's didn't cleared out values for node 2.
+    $this->drupalGet('node/2/edit');
+    $this->assertNodeFieldValue('alpha', 0);
+    $this->assertNodeFieldValue('beta', 0);
+    $this->assertNodeFieldValue('gamma', 0);
+    $this->assertNodeFieldValue('delta', 0);
+    $this->assertFieldByName('body[und][0][value]', 0);
+    // Check if labels for fields of node 2 are still shown.
+    $this->drupalGet('node/2');
+    $this->assertText('alpha_text_label');
+    $this->assertText('beta_number_integer_label');
+    $this->assertText('gamma_number_decimal_label');
+    $this->assertText('delta_number_float_label');
+
+    // Re-import the first file again.
+    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content.csv');
+    $this->assertText('Updated 2 nodes');
+
+    // Check if the two imported nodes have content again.
+    $this->drupalGet('node/1/edit');
+    $this->assertNodeFieldValue('alpha', 'Lorem');
+    $this->assertNodeFieldValue('beta', '42');
+    $this->assertNodeFieldValue('gamma', '4.20');
+    $this->assertNodeFieldValue('delta', '3.14159');
+    $this->assertFieldByName('body[und][0][value]', 'Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.');
+    $this->drupalGet('node/2/edit');
+    $this->assertNodeFieldValue('alpha', 'Ut wisi');
+    $this->assertNodeFieldValue('beta', '32');
+    $this->assertNodeFieldValue('gamma', '1.20');
+    $this->assertNodeFieldValue('delta', '5.62951');
+    $this->assertFieldByName('body[und][0][value]', 'Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea commodo consequat.');
+
+    // Import CSV file with non-existent values.
+    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content_non_existent.csv');
+    $this->assertText('Updated 2 nodes');
+
+    // Check if all values were cleared out for node 1.
+    $this->drupalGet('node/1/edit');
+    $this->assertNoNodeFieldValue('alpha', 'Lorem');
+    $this->assertNoNodeFieldValue('beta', '42');
+    $this->assertNoNodeFieldValue('gamma', '4.20');
+    $this->assertNoNodeFieldValue('delta', '3.14159');
+    $this->assertFieldByName('body[und][0][value]', '');
+    // Check if labels for fields that should be cleared out are not shown.
+    $this->drupalGet('node/1');
+    $this->assertNoText('alpha_text_label');
+    $this->assertNoText('beta_number_integer_label');
+    $this->assertNoText('gamma_number_decimal_label');
+    $this->assertNoText('delta_number_float_label');
+  }
+
 }
diff --git a/tests/feeds_mapper_file.test b/tests/feeds_mapper_file.test
index 8a7cef58..2cb5acd8 100644
--- a/tests/feeds_mapper_file.test
+++ b/tests/feeds_mapper_file.test
@@ -2,13 +2,14 @@
 
 /**
  * @file
- * Test case for Filefield mapper mappers/filefield.inc.
+ * Contains FeedsMapperFileTestCase.
  */
 
 /**
- * Class for testing Feeds file mapper.
+ * Test case for Filefield mapper mappers/filefield.inc.
  */
 class FeedsMapperFileTestCase extends FeedsMapperTestCase {
+
   public static function getInfo() {
     return array(
       'name' => 'Mapper: File field',
@@ -268,6 +269,127 @@ class FeedsMapperFileTestCase extends FeedsMapperTestCase {
     }
   }
 
+  /**
+   * Tests if values are cleared out when an empty value or no value
+   * is provided.
+   */
+  public function testClearOutValues() {
+    variable_set('feeds_never_use_curl', TRUE);
+
+    $this->createContentType(array(), array('files' => 'file'));
+    $typename = $this->createContentType(array(), array(
+      'images' => 'image',
+    ));
+
+    // Enable title and alt mapping.
+    $edit = array(
+      'instance[settings][alt_field]' => 1,
+      'instance[settings][title_field]' => 1,
+    );
+    $this->drupalPost("admin/structure/types/manage/$typename/fields/field_images", $edit, t('Save settings'));
+
+    // Create and configure importer.
+    $this->createImporterConfiguration('Content CSV', 'csv');
+    $this->setSettings('csv', NULL, array(
+      'content_type' => '',
+      'import_period' => FEEDS_SCHEDULE_NEVER,
+    ));
+    $this->setPlugin('csv', 'FeedsCSVParser');
+    $this->setSettings('csv', 'FeedsNodeProcessor', array(
+      'bundle' => $typename,
+      'update_existing' => 1,
+    ));
+    $this->addMappings('csv', array(
+      0 => array(
+        'source' => 'guid',
+        'target' => 'guid',
+        'unique' => TRUE,
+      ),
+      1 => array(
+        'source' => 'title',
+        'target' => 'title',
+      ),
+      2 => array(
+        'source' => 'file',
+        'target' => 'field_images:uri',
+      ),
+      3 => array(
+        'source' => 'title2',
+        'target' => 'field_images:title',
+      ),
+      4 => array(
+        'source' => 'alt',
+        'target' => 'field_images:alt',
+      ),
+    ));
+
+    // Import.
+    $edit = array(
+      'feeds[FeedsHTTPFetcher][source]' => url('testing/feeds/files-remote.csv', array('absolute' => TRUE)),
+    );
+    $this->drupalPost('import/csv', $edit, 'Import');
+    $this->assertText('Created 5 nodes');
+
+    // Assert files exist.
+    $files = $this->listTestFiles();
+    foreach ($files as $file) {
+      $file_path = drupal_realpath('public://') . '/' . str_replace(' ', '_', $file);
+      $this->assertTrue(file_exists($file_path), format_string('The file %file exists.', array(
+        '%file' => $file_path,
+      )));
+    }
+
+    // Assert files exists with the expected alt/title on node edit form.
+    $entities = db_select('feeds_item')
+      ->fields('feeds_item', array('entity_id'))
+      ->condition('id', 'csv')
+      ->execute()
+      ->fetchAll();
+
+    foreach ($entities as $i => $entity) {
+      $this->drupalGet('node/' . $entity->entity_id . '/edit');
+      $this->assertRaw(str_replace(' ', '_', array_shift($files)));
+      $this->assertRaw("Alt text $i");
+      $this->assertRaw("Title text $i");
+    }
+
+    // Import CSV with empty alt/title fields and check if these are removed.
+    $edit = array(
+      'feeds[FeedsHTTPFetcher][source]' => url('testing/feeds/files-empty-alt-title.csv', array('absolute' => TRUE)),
+    );
+    $this->drupalPost('import/csv', $edit, 'Import');
+    $this->assertText('Updated 5 nodes');
+
+    $files = $this->listTestFiles();
+    foreach ($entities as $i => $entity) {
+      $this->drupalGet('node/' . $entity->entity_id . '/edit');
+      $this->assertRaw(str_replace(' ', '_', array_shift($files)));
+      $this->assertNoRaw("Alt text $i");
+      $this->assertNoRaw("Title text $i");
+    }
+
+    // Import CSV with empty file fields and check if all files are removed.
+    $edit = array(
+      'feeds[FeedsHTTPFetcher][source]' => url('testing/feeds/files-empty.csv', array('absolute' => TRUE)),
+    );
+    $this->drupalPost('import/csv', $edit, 'Import');
+    $this->assertText('Updated 5 nodes');
+
+    // Assert files are removed.
+    $files = $this->listTestFiles();
+    foreach ($files as $file) {
+      $file_path = drupal_realpath('public://') . '/' . str_replace(' ', '_', $file);
+      $this->assertFalse(file_exists($file_path), format_string('The file %file no longer exists.', array(
+        '%file' => $file_path,
+      )));
+    }
+    // Check if the files are removed from the node edit form as well.
+    foreach ($entities as $i => $entity) {
+      $this->drupalGet('node/' . $entity->entity_id . '/edit');
+      $this->assertNoRaw(str_replace(' ', '_', array_shift($files)));
+    }
+  }
+
   /**
    * Lists test files.
    */
diff --git a/tests/feeds_mapper_format_config.test b/tests/feeds_mapper_format_config.test
index 92fa241a..83bfdd6c 100644
--- a/tests/feeds_mapper_format_config.test
+++ b/tests/feeds_mapper_format_config.test
@@ -9,6 +9,7 @@
  * Class for testing "Text format" mapping configuration on text fields.
  */
 class FeedsMapperFormatConfig extends FeedsMapperTestCase {
+
   public static function getInfo() {
     return array(
       'name' => 'Mapper: Text format mapping configuration',
diff --git a/tests/feeds_mapper_hooks.test b/tests/feeds_mapper_hooks.test
index 5d76043a..f99b2d35 100644
--- a/tests/feeds_mapper_hooks.test
+++ b/tests/feeds_mapper_hooks.test
@@ -2,13 +2,14 @@
 
 /**
  * @file
- * Test case for the various callbacks implemented for mappers.
+ * Contains FeedsMapperHookTestCase.
  */
 
 /**
- * Class for testing Feeds field mapper.
+ * Test case for the various callbacks implemented for mappers.
  */
 class FeedsMapperHookTestCase extends FeedsMapperTestCase {
+
   public static function getInfo() {
     return array(
       'name' => 'Mapper: Hooks and callbacks',
diff --git a/tests/feeds_mapper_link.test b/tests/feeds_mapper_link.test
index a64fc944..24f01799 100644
--- a/tests/feeds_mapper_link.test
+++ b/tests/feeds_mapper_link.test
@@ -2,13 +2,28 @@
 
 /**
  * @file
- * Test case for CCK link mapper mappers/date.inc.
+ * Contains FeedsMapperLinkTestCase.
  */
 
 /**
- * Class for testing Feeds <em>link</em> mapper.
+ * Test case for CCK link mapper mappers/date.inc.
  */
 class FeedsMapperLinkTestCase extends FeedsMapperTestCase {
+
+  /**
+   * Title for link fields with a static title.
+   *
+   * @var string
+   */
+  private $staticTitle;
+
+  /**
+   * Name of created content type.
+   *
+   * @var string
+   */
+  private $contentType;
+
   public static function getInfo() {
     return array(
       'name' => 'Mapper: Link',
@@ -20,16 +35,11 @@ class FeedsMapperLinkTestCase extends FeedsMapperTestCase {
 
   public function setUp() {
     parent::setUp(array('link'));
-  }
 
-  /**
-   * Basic test loading a single entry CSV file.
-   */
-  public function test() {
-    $static_title = $this->randomName();
+    $this->staticTitle = $this->randomName();
 
     // Create content type.
-    $typename = $this->createContentType(array(), array(
+    $this->contentType = $this->createContentType(array(), array(
       'alpha' => array(
         'type' => 'link_field',
         'instance_settings' => array(
@@ -52,14 +62,19 @@ class FeedsMapperLinkTestCase extends FeedsMapperTestCase {
       'type' => 'link_field',
         'instance_settings' => array(
           'instance[settings][title]' => 'value',
-          'instance[settings][title_value]' => $static_title,
+          'instance[settings][title_value]' => $this->staticTitle,
         ),
       ),
     ));
+  }
 
+  /**
+   * Basic test loading a single entry CSV file.
+   */
+  public function test() {
     // Create importer configuration.
     $this->createImporterConfiguration(); //Create a default importer configuration
-    $this->setSettings('syndication', 'FeedsNodeProcessor', array('bundle' => $typename)); //Processor settings
+    $this->setSettings('syndication', 'FeedsNodeProcessor', array('bundle' => $this->contentType)); //Processor settings
     $this->addMappings('syndication', array(
       0 => array(
         'source' => 'title',
@@ -112,12 +127,193 @@ class FeedsMapperLinkTestCase extends FeedsMapperTestCase {
     $this->assertNodeFieldValue('alpha', array('url' => $url, 'static' => $title));
     $this->assertNodeFieldValue('beta', array('url' =>  $url));
     $this->assertNodeFieldValue('gamma', array('url' => $url, 'static' => $title));
-    $this->assertNodeFieldValue('omega', array('url' => $url, 'static' => $static_title));
+    $this->assertNodeFieldValue('omega', array('url' => $url, 'static' => $this->staticTitle));
 
     // Test the static title.
     $this->drupalGet('node/2');
-    $this->assertText($static_title, 'Static title link found.');
+    $this->assertText($this->staticTitle, 'Static title link found.');
+  }
+
+  /**
+   * Tests if values are cleared out when an empty value or no value
+   * is provided.
+   */
+  public function testClearOutValues() {
+    // Create and configure importer.
+    $this->createImporterConfiguration('Content CSV', 'csv');
+    $this->setSettings('csv', NULL, array(
+      'content_type' => '',
+      'import_period' => FEEDS_SCHEDULE_NEVER,
+    ));
+    $this->setPlugin('csv', 'FeedsFileFetcher');
+    $this->setPlugin('csv', 'FeedsCSVParser');
+    $this->setSettings('csv', 'FeedsNodeProcessor', array(
+      'bundle' => $this->contentType,
+      'update_existing' => 1,
+    ));
+    $this->addMappings('csv', array(
+      0 => array(
+        'source' => 'guid',
+        'target' => 'guid',
+        'unique' => TRUE,
+      ),
+      1 => array(
+        'source' => 'title',
+        'target' => 'title'
+      ),
+      2 => array(
+        'source' => 'url',
+        'target' => 'field_alpha:url'
+      ),
+      3 => array(
+        'source' => 'link_title',
+        'target' => 'field_alpha:title'
+      ),
+      4 => array(
+        'source' => 'url',
+        'target' => 'field_beta:url'
+      ),
+      5 => array(
+        'source' => 'link_title',
+        'target' => 'field_beta:title'
+      ),
+      6 => array(
+        'source' => 'url',
+        'target' => 'field_gamma:url'
+      ),
+      7 => array(
+        'source' => 'link_title',
+        'target' => 'field_gamma:title'
+      ),
+      8 => array(
+        'source' => 'url',
+        'target' => 'field_omega:url'
+      ),
+      9 => array(
+        'source' => 'link_title',
+        'target' => 'field_omega:title'
+      ),
+    ));
+
+    // Import CSV file.
+    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content_link.csv');
+    $this->assertText('Created 2 nodes');
+
+    // Check the imported nodes.
+    $link_values = array(
+      1 => array(
+        'title' => 'Feeds',
+        'url' => 'https://www.drupal.org/project/feeds',
+      ),
+      2 => array(
+        'title' => 'Framework for expected behavior when importing empty/blank values',
+        'url' => 'https://www.drupal.org/node/1107522',
+      ),
+    );
+
+    for ($i = 1; $i <= 2; $i++) {
+      $this->drupalGet("node/$i/edit");
+      $this->assertNodeFieldValue('alpha', array(
+        'url' => $link_values[$i]['url'],
+        'title' => $link_values[$i]['title'],
+      ));
+      $this->assertNodeFieldValue('beta', array(
+        'url' => $link_values[$i]['url'],
+      ));
+      $this->assertNodeFieldValue('gamma', array(
+        'url' => $link_values[$i]['url'],
+        'title' => $link_values[$i]['title'],
+      ));
+      $this->assertNodeFieldValue('omega', array(
+        'url' => $link_values[$i]['url'],
+      ));
+
+      // Test static title.
+      $this->drupalGet("node/$i");
+      $this->assertText($this->staticTitle, 'Static title link found.');
+    }
+
+    // Import CSV file with empty values.
+    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content_empty.csv');
+    $this->assertText('Updated 2 nodes');
+
+    // Check if all values were cleared out for both nodes.
+    for ($i = 1; $i <= 2; $i++) {
+      $this->drupalGet("node/$i/edit");
+      $this->assertNoNodeFieldValue('alpha', array(
+        'url' => $link_values[$i]['url'],
+        'title' => $link_values[$i]['title'],
+      ));
+      $this->assertNoNodeFieldValue('beta', array(
+        'url' => $link_values[$i]['url'],
+      ));
+      $this->assertNoNodeFieldValue('gamma', array(
+        'url' => $link_values[$i]['url'],
+        'title' => $link_values[$i]['title'],
+      ));
+      $this->assertNoNodeFieldValue('omega', array(
+        'url' => $link_values[$i]['url'],
+      ));
+      // Check labels.
+      $this->drupalGet('node/' . $i);
+      $this->assertNoText('alpha_link_field_label');
+      $this->assertNoText('beta_link_field_label');
+      $this->assertNoText('gamma_link_field_label');
+      $this->assertNoText('omega_link_field_label');
+
+      // Assert that the static title is no longer shown.
+      $this->assertNoText($this->staticTitle, 'Static title link not found.');
+    }
+
+    // Re-import the first file again and check if the values returned.
+    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content_link.csv');
+    $this->assertText('Updated 2 nodes');
+    for ($i = 1; $i <= 2; $i++) {
+      $this->drupalGet("node/$i/edit");
+      $this->assertNodeFieldValue('alpha', array(
+        'url' => $link_values[$i]['url'],
+        'title' => $link_values[$i]['title'],
+      ));
+      $this->assertNodeFieldValue('beta', array(
+        'url' => $link_values[$i]['url'],
+      ));
+      $this->assertNodeFieldValue('gamma', array(
+        'url' => $link_values[$i]['url'],
+        'title' => $link_values[$i]['title'],
+      ));
+      $this->assertNodeFieldValue('omega', array(
+        'url' => $link_values[$i]['url'],
+      ));
+    }
+
+    // Import CSV file with non-existent values.
+    $this->importFile('csv', $this->absolutePath() . '/tests/feeds/content_non_existent.csv');
+    $this->assertText('Updated 2 nodes');
+
+    // Check if all values were cleared out for node 1.
+    $this->drupalGet("node/1/edit");
+    $this->assertNoNodeFieldValue('alpha', array(
+      'url' => $link_values[1]['url'],
+      'title' => $link_values[1]['title'],
+    ));
+    $this->assertNoNodeFieldValue('beta', array(
+      'url' => $link_values[1]['url'],
+    ));
+    $this->assertNoNodeFieldValue('gamma', array(
+      'url' => $link_values[1]['url'],
+      'title' => $link_values[1]['title'],
+    ));
+    $this->assertNoNodeFieldValue('omega', array(
+      'url' => $link_values[1]['url'],
+    ));
+    $this->drupalGet('node/1');
+    $this->assertNoText('alpha_link_field_label');
+    $this->assertNoText('beta_link_field_label');
+    $this->assertNoText('gamma_link_field_label');
+    $this->assertNoText('omega_link_field_label');
 
+    // Assert that the static title is no longer shown.
+    $this->assertNoText($this->staticTitle, 'Static title link not found.');
   }
 
   /**
@@ -154,4 +350,5 @@ class FeedsMapperLinkTestCase extends FeedsMapperTestCase {
       return parent::getFormFieldsValues($field_name, $index);
     }
   }
+
 }
diff --git a/tests/feeds_mapper_path.test b/tests/feeds_mapper_path.test
index bb408dba..b7ccfa32 100644
--- a/tests/feeds_mapper_path.test
+++ b/tests/feeds_mapper_path.test
@@ -2,13 +2,14 @@
 
 /**
  * @file
- * Test case for path alias mapper path.inc.
+ * Contains FeedsMapperPathTestCase.
  */
 
 /**
- * Class for testing Feeds <em>path</em> mapper.
+ * Test case for path alias mapper path.inc.
  */
 class FeedsMapperPathTestCase extends FeedsMapperTestCase {
+
   public static function getInfo() {
     return array(
       'name' => 'Mapper: Path',
@@ -25,7 +26,6 @@ class FeedsMapperPathTestCase extends FeedsMapperTestCase {
    * Basic test loading a single entry CSV file.
    */
   public function testNodeAlias() {
-
     // Create importer configuration.
     $this->createImporterConfiguration($this->randomName(), 'path_test');
     $this->setPlugin('path_test', 'FeedsFileFetcher');
@@ -80,7 +80,6 @@ class FeedsMapperPathTestCase extends FeedsMapperTestCase {
    * Test support for term aliases.
    */
   public function testTermAlias() {
-
     // Create importer configuration.
     $this->createImporterConfiguration($this->randomName(), 'path_test');
     $this->setPlugin('path_test', 'FeedsFileFetcher');
@@ -155,6 +154,7 @@ class FeedsMapperPathTestCase extends FeedsMapperTestCase {
  * Class for testing Feeds <em>path</em> mapper with pathauto.module.
  */
 class FeedsMapperPathPathautoTestCase extends FeedsMapperTestCase {
+
   public static function getInfo() {
     return array(
       'name' => 'Mapper: Path with pathauto',
@@ -172,7 +172,6 @@ class FeedsMapperPathPathautoTestCase extends FeedsMapperTestCase {
    * Basic for allowing pathauto to override the alias.
    */
   public function test() {
-
     // Create importer configuration.
     $this->createImporterConfiguration($this->randomName(), 'path_test');
     $this->setPlugin('path_test', 'FeedsFileFetcher');
@@ -229,4 +228,5 @@ class FeedsMapperPathPathautoTestCase extends FeedsMapperTestCase {
     $in_db = db_query("SELECT * FROM {url_alias} WHERE alias IN (:aliases)", array(':aliases' => $aliases))->fetchAll();
     $this->assertEqual(count($in_db), count($aliases), 'Correct number of aliases in db.');
   }
+
 }
diff --git a/tests/feeds_mapper_profile.test b/tests/feeds_mapper_profile.test
index 9ced5dbd..b0d9efdb 100644
--- a/tests/feeds_mapper_profile.test
+++ b/tests/feeds_mapper_profile.test
@@ -2,13 +2,14 @@
 
 /**
  * @file
- * Test suite for profile mapper mappers/profile.inc.
+ * Contains FeedsMapperProfileTestCase.
  */
 
 /**
- * Class for testing Feeds profile mapper.
+ * Test suite for profile mapper mappers/profile.inc.
  */
 class FeedsMapperProfileTestCase extends FeedsMapperTestCase {
+
   public static function getInfo() {
     return array(
       'name' => 'Mapper: Profile',
@@ -17,7 +18,7 @@ class FeedsMapperProfileTestCase extends FeedsMapperTestCase {
     );
   }
 
-  function setUp() {
+  public function setUp() {
     // Call parent setup with required modules.
     parent::setUp(array('profile'));
   }
@@ -25,8 +26,7 @@ class FeedsMapperProfileTestCase extends FeedsMapperTestCase {
   /**
    * Basic test loading a doulbe entry CSV file.
    */
-  function test() {
-
+  public function test() {
     // Create profile fields.
     $edit = array(
       'category' => 'test',
@@ -99,4 +99,5 @@ class FeedsMapperProfileTestCase extends FeedsMapperTestCase {
     $this->assertEqual($account->profile_textfield_test, 'blue', 'User profile_textfield_test is correct');
     $this->assertEqual($account->profile_select_test, 'beta', 'User profile_select_test is correct');
   }
+
 }
diff --git a/tests/feeds_mapper_summary.test b/tests/feeds_mapper_summary.test
index 88cf9f17..db4c2023 100644
--- a/tests/feeds_mapper_summary.test
+++ b/tests/feeds_mapper_summary.test
@@ -2,13 +2,14 @@
 
 /**
  * @file
- * Test case for mapping to node summary.
+ * Contains FeedsMapperNodeSummaryTestCase.
  */
 
 /**
- * Class for testing Feeds summary mapper.
+ * Test case for mapping to node summary.
  */
 class FeedsMapperNodeSummaryTestCase extends FeedsMapperTestCase {
+
   public static function getInfo() {
     return array(
       'name' => 'Mapper: Text with summary',
diff --git a/tests/feeds_mapper_taxonomy.test b/tests/feeds_mapper_taxonomy.test
index 231235ef..ed557513 100644
--- a/tests/feeds_mapper_taxonomy.test
+++ b/tests/feeds_mapper_taxonomy.test
@@ -2,13 +2,14 @@
 
 /**
  * @file
- * Test case for taxonomy mapper mappers/taxonomy.inc.
+ * Contains FeedsMapperTaxonomyTestCase.
  */
 
 /**
- * Class for testing Feeds <em>content</em> mapper.
+ * Test case for taxonomy mapper mappers/taxonomy.inc.
  */
 class FeedsMapperTaxonomyTestCase extends FeedsMapperTestCase {
+
   public static function getInfo() {
     return array(
       'name' => 'Mapper: Taxonomy',
@@ -115,7 +116,6 @@ class FeedsMapperTaxonomyTestCase extends FeedsMapperTestCase {
    * Tests inheriting taxonomy from the feed node.
    */
   public function testInheritTaxonomy() {
-
     // Adjust importer settings
     $this->setSettings('syndication', NULL, array('import_period' => FEEDS_SCHEDULE_NEVER));
     $this->setSettings('syndication', NULL, array('import_on_create' => FALSE));
@@ -368,6 +368,95 @@ class FeedsMapperTaxonomyTestCase extends FeedsMapperTestCase {
     $this->assertText('Created 10 nodes.');
   }
 
+  /**
+   * Tests if values are cleared out when an empty value or no value
+   * is provided.
+   */
+  public function testClearOutValues() {
+    // Create a CSV importer configuration.
+    $this->createImporterConfiguration('Node import from CSV', 'node');
+    $this->setSettings('node', NULL, array(
+      'content_type' => '',
+    ));
+    $this->setPlugin('node', 'FeedsFileFetcher');
+    $this->setPlugin('node', 'FeedsCSVParser');
+    $this->setSettings('node', 'FeedsNodeProcessor', array(
+      'bundle' => 'article',
+      'update_existing' => 1,
+    ));
+    $this->addMappings('node', array(
+      0 => array(
+        'source' => 'title',
+        'target' => 'title',
+      ),
+      1 => array(
+        'source' => 'alpha',
+        'target' => 'field_tags',
+        'term_search' => 0,
+        'autocreate' => 1,
+      ),
+      2 => array(
+        'source' => 'guid',
+        'target' => 'guid',
+        'unique' => TRUE,
+      ),
+    ));
+
+    $this->importFile('node', $this->absolutePath() . '/tests/feeds/content.csv');
+    $this->assertText('Created 2 nodes');
+
+    // Check the imported nodes.
+    $terms1 = taxonomy_get_term_by_name('Lorem');
+    $term1 = reset($terms1);
+    $terms2 = taxonomy_get_term_by_name('Ut wisi');
+    $term2 = reset($terms2);
+    $taxonomy_values = array(
+      1 => $term1->tid,
+      2 => $term2->tid,
+    );
+    for ($i = 1; $i <= 2; $i++) {
+      $this->drupalGet("node/$i/edit");
+      $this->assertFieldByName('field_tags[und][]', $taxonomy_values[$i]);
+    }
+
+    // Import CSV file with empty values.
+    $this->importFile('node', $this->absolutePath() . '/tests/feeds/content_empty.csv');
+    $this->assertText('Updated 2 nodes');
+
+    // Check if the taxonomy reference field was cleared out for node 1.
+    $this->drupalGet('node/1/edit');
+    $this->assertFieldByName('field_tags[und][]', '_none');
+    $this->drupalGet('node/1');
+    $this->assertNoText('field_tags');
+
+    // Check if zero's didn't cleared out the taxonomy reference field for
+    // node 2.
+    $terms0 = taxonomy_get_term_by_name('0');
+    $term0 = reset($terms0);
+    $this->drupalGet('node/2/edit');
+    $this->assertFieldByName('field_tags[und][]', $term0->tid);
+    $this->drupalGet('node/2');
+    $this->assertText('field_tags');
+
+    // Re-import the first file again and check if the values returned.
+    $this->importFile('node', $this->absolutePath() . '/tests/feeds/content.csv');
+    $this->assertText('Updated 2 nodes');
+    for ($i = 1; $i <= 2; $i++) {
+      $this->drupalGet("node/$i/edit");
+      $this->assertFieldByName('field_tags[und][]', $taxonomy_values[$i]);
+    }
+
+    // Import CSV file with non-existent values.
+    $this->importFile('node', $this->absolutePath() . '/tests/feeds/content_non_existent.csv');
+    $this->assertText('Updated 2 nodes');
+
+    // Check if the taxonomy reference field was cleared out for node 1.
+    $this->drupalGet('node/1/edit');
+    $this->assertFieldByName('field_tags[und][]', '_none');
+    $this->drupalGet('node/1');
+    $this->assertNoText('field_tags');
+  }
+
   /**
    * Finds node style taxonomy term markup in DOM.
    */
diff --git a/tests/feeds_mapper_unique.test b/tests/feeds_mapper_unique.test
index 46b48dd0..bdc6a10a 100644
--- a/tests/feeds_mapper_unique.test
+++ b/tests/feeds_mapper_unique.test
@@ -9,6 +9,7 @@
  * Class for testing Feeds unique callbacks.
  */
 class FeedsMapperUniqueTestCase extends FeedsMapperTestCase {
+
   public static function getInfo() {
     return array(
       'name' => 'Unique target callbacks',
diff --git a/tests/feeds_tests.module b/tests/feeds_tests.module
index 1ddd2a61..fa894622 100644
--- a/tests/feeds_tests.module
+++ b/tests/feeds_tests.module
@@ -24,6 +24,16 @@ function feeds_tests_menu() {
     'access arguments' => array('access content'),
     'type' => MENU_CALLBACK,
   );
+  $items['testing/feeds/files-empty-alt-title.csv'] = array(
+    'page callback' => 'feeds_tests_files_empty_alt_title',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
+  $items['testing/feeds/files-empty.csv'] = array(
+    'page callback' => 'feeds_tests_files_empty',
+    'access arguments' => array('access content'),
+    'type' => MENU_CALLBACK,
+  );
   return $items;
 }
 
@@ -42,6 +52,11 @@ function feeds_tests_theme() {
       'path' => drupal_get_path('module', 'feeds_tests') . '/feeds',
       'template' => 'feeds-tests-files',
     ),
+    'feeds_tests_files_empty' => array(
+      'variables' => array('files' => array()),
+      'path' => drupal_get_path('module', 'feeds_tests') . '/feeds',
+      'template' => 'feeds-tests-files-empty',
+    ),
   );
 }
 
@@ -101,6 +116,44 @@ function feeds_tests_files_remote() {
   print theme('feeds_tests_files', array('files' => $images));
 }
 
+/**
+ * Outputs a CSV file pointing to files without alt/title.
+ *
+ * This is used to test if alt/title attributes are removed on a second import.
+ */
+function feeds_tests_files_empty_alt_title() {
+  $images = array(
+    0 => 'tubing.jpeg',
+    1 => 'foosball.jpeg',
+    2 => 'attersee.jpeg',
+    3 => 'hstreet.jpeg',
+    4 => 'la fayette.jpeg',
+  );
+  $path = drupal_get_path('module', 'feeds_tests') . '/feeds/assets';
+  foreach ($images as &$image) {
+    $image = file_create_url("$path/$image");
+  }
+  drupal_add_http_header('Content-Type', 'text/plain; charset=utf-8');
+  print theme('feeds_tests_files_empty', array('files' => $images));
+}
+
+/**
+ * Outputs a CSV file pointing to no files.
+ *
+ * This is used to test if files are removed on a second import.
+ */
+function feeds_tests_files_empty() {
+  $images = array(
+    0 => '',
+    1 => '',
+    2 => '',
+    3 => '',
+    4 => '',
+  );
+  drupal_add_http_header('Content-Type', 'text/plain; charset=utf-8');
+  print theme('feeds_tests_files_empty', array('files' => $images));
+}
+
 /**
  * Implements hook_feeds_processor_targets().
  */
-- 
GitLab