t('Attribute API'), 'description' => t('Test the attribute API.'), 'group' => t('Ubercart'), ); } /** * */ function setUp() { parent::setUp('token', 'uc_store', 'uc_product', 'uc_attribute', 'ca', 'uc_order', 'uc_cart'); $admin_user = $this->drupalCreateUser(array('administer store', 'administer attributes', 'administer products', 'administer product classes')); $this->drupalLogin($admin_user); } /** * */ public function testAttributeAPI() { // Create an attribute. $attribute = self::createAttribute(); // Test retrieval. $loaded_attribute = uc_attribute_load($attribute->aid); // Check the attribute integrity. foreach (self::_attributeFieldsToTest() as $field) { if ($loaded_attribute->$field != $attribute->$field) { $this->fail(t('Attribute integrity check failed.'), t('Ubercart')); break; } } // Add a product. $product = UcProductTestCase::createProduct(); // Attach the attribute to a product. uc_attribute_subject_save($attribute, 'product', $product->nid); // Confirm the database is correct. $this->assertEqual( $attribute->aid, db_query("SELECT aid FROM {uc_product_attributes} WHERE nid = :nid", array(':nid' => $product->nid))->fetchField(), t('Attribute was attached to a product properly.'), t('Ubercart') ); $this->assertTrue(uc_attribute_subject_exists($attribute->aid, 'product', $product->nid)); // Test retrieval. $loaded_attribute = uc_attribute_load($attribute->aid, $product->nid, 'product'); // Check the attribute integrity. foreach (self::_attributeFieldsToTest('product') as $field) { if ($loaded_attribute->$field != $attribute->$field) { $this->fail(t('Attribute integrity check failed.'), t('Ubercart')); break; } } // Delete it. uc_attribute_subject_delete($attribute->aid, 'product', $product->nid); // Confirm again. $this->assertFalse( db_query("SELECT aid FROM {uc_product_attributes} WHERE nid = :nid", array(':nid' => $product->nid))->fetchField(), t('Attribute was detached from a product properly.'), t('Ubercart') ); $this->assertFalse(uc_attribute_subject_exists($attribute->aid, 'product', $product->nid)); // Add a product class. $product_class = UcProductTestCase::createProductClass(); // Attach the attribute to a product class. uc_attribute_subject_save($attribute, 'class', $product_class->pcid); // Confirm the database is correct. $this->assertEqual( $attribute->aid, db_query("SELECT aid FROM {uc_class_attributes} WHERE pcid = :pcid", array(':pcid' => $product_class->pcid))->fetchField(), t('Attribute was attached to a product class properly.'), t('Ubercart') ); $this->assertTrue(uc_attribute_subject_exists($attribute->aid, 'class', $product_class->pcid)); // Test retrieval. $loaded_attribute = uc_attribute_load($attribute->aid, $product_class->pcid, 'class'); // Check the attribute integrity. foreach (self::_attributeFieldsToTest('class') as $field) { if ($loaded_attribute->$field != $attribute->$field) { $this->fail(t('Attribute integrity check failed.'), t('Ubercart')); break; } } // Delete it. uc_attribute_subject_delete($attribute->aid, 'class', $product_class->pcid); // Confirm again. $this->assertFalse( db_query("SELECT aid FROM {uc_class_attributes} WHERE pcid = :pcid", array(':pcid' => $product_class->pcid))->fetchField(), t('Attribute was detached from a product class properly.'), t('Ubercart') ); $this->assertFalse(uc_attribute_subject_exists($attribute->aid, 'class', $product_class->pcid)); // Create a few more. for ($i = 0; $i < 5; $i++) { $a = self::createAttribute(); $attributes[$a->aid] = $a; } // Add some options, organizing them by aid and oid. $attribute_aids = array_keys($attributes); $all_options = array(); foreach ($attribute_aids as $aid) { for ($i = 0; $i < 3; $i++) { $option = self::createAttributeOption(array('aid' => $aid)); $all_options[$option->aid][$option->oid] = $option; } } for ($i = 0; $i < 3; $i++) { $option = self::createAttributeOption(array('aid' => $attribute->aid)); $all_options[$option->aid][$option->oid] = $option; } // Get the options. $attribute = uc_attribute_load($attribute->aid); // Load every attribute we got. $attributes_with_options = uc_attribute_load_multiple(); // Make sure all the new options are on attributes correctly. foreach ($all_options as $aid => $options) { foreach ($options as $oid => $option) { foreach (self::_attributeOptionFieldsToTest() as $field) { if ($option->$field != $attributes_with_options[$aid]->options[$oid]->$field) { $this->fail(t('Option integrity check failed.'), t('Ubercart')); break; } } } } // Pick 5 keys to check at random. $aids = drupal_map_assoc(array_rand($attributes, 3)); // Load the attributes back. $loaded_attributes = uc_attribute_load_multiple($aids); // Make sure we only got the attributes we asked for. No more, no less. $this->assertEqual(count($aids), count($loaded_attributes), t('Verifying attribute result.'), t('Ubercart')); $this->assertEqual(count($aids), count(array_intersect_key($aids, $loaded_attributes)), t('Verifying attribute result.'), t('Ubercart')); // Check the attributes' integrity. foreach ($loaded_attributes as $aid => $loaded_attribute) { foreach (self::_attributeFieldsToTest() as $field) { if ($attributes[$aid]->$field != $loaded_attributes[$aid]->$field) { $this->fail(t('Attribute integrity check failed.'), t('Ubercart')); break; } } } // Add the selected attributes to the product. foreach ($loaded_attributes as $loaded_attribute) { uc_attribute_subject_save($loaded_attribute, 'product', $product->nid, TRUE); } // Test loading all product attributes. (This covers uc_attribute_load_product_attributes(), // as the semantics are the same -cha0s) $loaded_product_attributes = uc_attribute_load_multiple(array(), 'product', $product->nid); // We'll get all in $loaded_attributes above, plus the original. $product_attributes = $loaded_attributes; // Make sure we only got the attributes we asked for. No more, no less. $this->assertEqual(count($loaded_product_attributes), count($product_attributes), t('Verifying attribute result.'), t('Ubercart')); $this->assertEqual(count($loaded_product_attributes), count(array_intersect_key($loaded_product_attributes, $product_attributes)), t('Verifying attribute result.'), t('Ubercart')); // Check the attributes' integrity. foreach ($loaded_product_attributes as $aid => $loaded_product_attribute) { foreach (self::_attributeFieldsToTest('product') as $field) { if ($loaded_product_attributes[$aid]->$field != $product_attributes[$aid]->$field) { $this->fail(t('Attribute integrity check failed.'), t('Ubercart')); break; } } } // Make sure all the options are on attributes correctly. foreach ($all_options as $aid => $options) { foreach ($options as $oid => $option) { if (empty($loaded_product_attributes[$aid]) || empty($loaded_product_attributes[$aid]->options[$oid])) continue; foreach (self::_attributeOptionFieldsToTest() as $field) { if ($option->$field != $loaded_product_attributes[$aid]->options[$oid]->$field) { $this->fail(t('Option integrity check failed.'), t('Ubercart')); break; } } } } // Add the selected attributes to the product. foreach ($loaded_attributes as $loaded_attribute) { uc_attribute_subject_save($loaded_attribute, 'class', $product_class->pcid, TRUE); } // Test loading all product attributes. (This covers uc_attribute_load_product_attributes(), // as the semantics are the same -cha0s) $loaded_class_attributes = uc_attribute_load_multiple(array(), 'class', $product_class->pcid); // We'll get all in $loaded_attributes above, plus the original. $class_attributes = $loaded_attributes; // Make sure we only got the attributes we asked for. No more, no less. $this->assertEqual(count($loaded_class_attributes), count($class_attributes), t('Verifying attribute result.'), t('Ubercart')); $this->assertEqual(count($loaded_class_attributes), count(array_intersect_key($loaded_class_attributes, $class_attributes)), t('Verifying attribute result.'), t('Ubercart')); // Check the attributes' integrity. foreach ($loaded_class_attributes as $aid => $loaded_class_attribute) { foreach (self::_attributeFieldsToTest('class') as $field) { if ($loaded_class_attributes[$aid]->$field != $class_attributes[$aid]->$field) { $this->fail(t('Attribute integrity check failed.'), t('Ubercart')); break; } } } // Make sure all the options are on attributes correctly. foreach ($all_options as $aid => $options) { foreach ($options as $oid => $option) { if (empty($loaded_class_attributes[$aid]) || empty($loaded_class_attributes[$aid]->options[$oid])) continue; foreach (self::_attributeOptionFieldsToTest() as $field) { if ($option->$field != $loaded_class_attributes[$aid]->options[$oid]->$field) { $this->fail(t('Option integrity check failed.'), t('Ubercart')); break; } } } } // Test deletion of base attribute. $aid = $attribute->aid; $options = $attribute->options; uc_attribute_delete($attribute->aid); $this->assertFalse(uc_attribute_load($attribute->aid), t('Attribute was deleted properly.'), t('Ubercart')); // Sanity check! $this->assertFalse(db_query("SELECT aid FROM {uc_attributes} WHERE aid = :aid", array(':aid' => $attribute->aid))->fetchField(), t('Attribute was seriously deleted properly!'), t('Ubercart')); // Test that options were deleted properly. foreach ($options as $option) { $this->assertFalse(db_query("SELECT oid FROM {uc_attribute_options} WHERE oid = :oid", array(':oid' => $option->oid))->fetchField(), t('Make sure options are deleted properly.'), t('Ubercart')); } // Test the deletion applied to products too. $loaded_product_attributes = uc_attribute_load_multiple(array(), 'product', $product->nid); // We'll get all in $loaded_attributes above, without the original. (Which // has been deleted.) $product_attributes = $loaded_attributes; // Make sure we only got the attributes we asked for. No more, no less. $this->assertEqual(count($loaded_product_attributes), count($product_attributes), t('Verifying attribute result.'), t('Ubercart')); $this->assertEqual(count($loaded_product_attributes), count(array_intersect_key($loaded_product_attributes, $product_attributes)), t('Verifying attribute result.'), t('Ubercart')); // Test the deletion applied to classes too. $loaded_class_attributes = uc_attribute_load_multiple(array(), 'class', $product_class->pcid); // We'll get all in $loaded_attributes above, without the original. (Which // has been deleted.) $class_attributes = $loaded_attributes; // Make sure we only got the attributes we asked for. No more, no less. $this->assertEqual(count($loaded_class_attributes), count($class_attributes), t('Verifying attribute result.'), t('Ubercart')); $this->assertEqual(count($loaded_class_attributes), count(array_intersect_key($loaded_class_attributes, $class_attributes)), t('Verifying attribute result.'), t('Ubercart')); // Add some adjustments. self::createProductAdjustment(array('combination' => 'a:1:{i:1;s:1:"1";}', 'nid' => 1)); self::createProductAdjustment(array('combination' => 'a:1:{i:1;s:1:"2";}', 'nid' => 1)); self::createProductAdjustment(array('combination' => 'a:1:{i:1;s:1:"3";}', 'nid' => 1)); self::createProductAdjustment(array('combination' => 'a:1:{i:2;s:1:"1";}', 'nid' => 2)); self::createProductAdjustment(array('combination' => 'a:1:{i:3;s:1:"1";}', 'nid' => 2)); self::createProductAdjustment(array('combination' => 'a:1:{i:1;s:1:"2";}', 'nid' => 3)); self::createProductAdjustment(array('combination' => 'a:1:{i:1;s:1:"3";}', 'nid' => 3)); self::createProductAdjustment(array('combination' => 'a:1:{i:3;s:1:"2";}', 'nid' => 3)); self::createProductAdjustment(array('combination' => 'a:1:{i:3;s:1:"3";}', 'nid' => 4)); // Test deletion by nid. uc_attribute_adjustments_delete(array('nid' => 1)); $this->assertEqual(6, db_query("SELECT COUNT(*) FROM {uc_product_adjustments}")->fetchField(), t('Ubercart')); // Test deletion by aid. uc_attribute_adjustments_delete(array('aid' => 2)); $this->assertEqual(5, db_query("SELECT COUNT(*) FROM {uc_product_adjustments}")->fetchField(), t('Ubercart')); // Test deletion by oid. uc_attribute_adjustments_delete(array('oid' => 2)); $this->assertEqual(3, db_query("SELECT COUNT(*) FROM {uc_product_adjustments}")->fetchField(), t('Ubercart')); // Test deletion by aid and oid. uc_attribute_adjustments_delete(array('aid' => 1, 'oid' => 3)); $this->assertEqual(2, db_query("SELECT COUNT(*) FROM {uc_product_adjustments}")->fetchField(), t('Ubercart')); } /** * */ public function testAttributeUIAddAttribute() { $this->drupalGet('admin/store/attributes/add'); $this->AssertText(t('The name of the attribute used in administrative forms'), t('Attribute add form working.'), t('Ubercart')); $edit = (array) self::createAttribute(array(), FALSE); $this->drupalPost('admin/store/attributes/add', $edit, t('Submit')); $this->assertRaw(''. $edit['name'] .'', t('Verify name field.'), t('Ubercart')); $this->assertRaw(''. $edit['label'] .'', t('Verify label field.'), t('Ubercart')); $this->assertRaw(''. ($edit['required'] ? t('Yes') : t('No')) .'', t('Verify required field.'), t('Ubercart')); $this->assertRaw(''. $edit['ordering'] .'', t('Verify ordering field.'), t('Ubercart')); $types = _uc_attribute_display_types(); $this->assertRaw(''. $types[$edit['display']] .'', t('Verify ordering field.'), t('Ubercart')); $attribute = uc_attribute_load($edit['aid']); $fields_ok = TRUE; foreach ($edit as $field => $value) { if ($attribute->$field != $value) { $this->showVar($attribute); $this->showVar($edit); $fields_ok = FALSE; break; } } } /** * */ public function testAttributeUISettings() { $product = UcProductTestCase::createProduct(); $attribute = self::createAttribute(array( 'display' => 1, )); $option = self::createAttributeOption(array( 'price' => 30, )); $attribute->options[$option->oid] = $option; uc_attribute_subject_save($attribute, 'product', $product->nid, TRUE); $context = array( 'revision' => 'formatted', 'location' => 'product-attribute-form-element', 'subject' => array('attribute' => $attribute), 'extras' => array('option' => $option), ); $qty = $product->default_qty; if (!$qty) { $qty = 1; } $price_info = array( 'price' => $option->price, 'qty' => $qty, ); $adjust_price = uc_price($price_info, $context); $price_info['price'] += $product->sell_price; $total_price = uc_price($price_info, $context); $raw = array( 'none' => $option->name .'', 'adjustment' => $option->name .', +'. $adjust_price .'', 'total' => $total_price .'', ); foreach (array('none', 'adjustment', 'total') as $type) { $edit['uc_attribute_option_price_format'] = $type; $this->drupalPost('admin/store/settings/attributes', $edit, t('Save configuration')); $this->drupalGet('node/'. $product->nid); $this->AssertRaw($raw[$type], t('Attribute option pricing is correct.'), t('Ubercart')); } } /** * */ public function testAttributeUIEditAttribute() { $attribute = self::createAttribute(); $this->drupalGet('admin/store/attributes/'. $attribute->aid .'/edit'); $this->AssertText(t('Edit attribute: @name', array('@name' => $attribute->name)), t('Attribute edit form working.'), t('Ubercart')); $edit = (array) self::createAttribute(array(), FALSE); $this->drupalPost('admin/store/attributes/'. $attribute->aid .'/edit', $edit, t('Submit')); $attribute = uc_attribute_load($attribute->aid); $fields_ok = TRUE; foreach ($edit as $field => $value) { if ($attribute->$field != $value) { $this->showVar($attribute); $this->showVar($edit); $fields_ok = FALSE; break; } } $this->AssertTrue($fields_ok, t('Attribute edited properly.'), t('Ubercart')); } /** * */ public function testAttributeUIDeleteAttribute() { $attribute = self::createAttribute(); $this->drupalGet('admin/store/attributes/'. $attribute->aid .'/delete'); $this->AssertText(t('Are you sure you want to delete the attribute @name?', array('@name' => $attribute->name)), t('Attribute delete form working.'), t('Ubercart')); $edit = (array) self::createAttribute(); unset($edit['aid']); $this->drupalPost('admin/store/attributes/'. $attribute->aid .'/delete', array(), t('Delete')); $this->AssertText(t('Product attribute deleted.'), t('Attribute deleted properly.'), t('Ubercart')); } /** * */ public function testAttributeUIAttributeOptions() { $attribute = self::createAttribute(); $option = self::createAttributeOption(); uc_attribute_option_save($option); $this->drupalGet('admin/store/attributes/'. $attribute->aid .'/options'); $this->AssertText(t('Options for @name', array('@name' => $attribute->name)), t('Attribute options form working.'), t('Ubercart')); } /** * */ public function testAttributeUIAttributeOptionsAdd() { $attribute = self::createAttribute(); $this->drupalGet('admin/store/attributes/'. $attribute->aid .'/options/add'); $this->AssertText(t('Options for @name', array('@name' => $attribute->name)), t('Attribute options add form working.'), t('Ubercart')); $edit = (array) self::createAttributeOption(array(), FALSE); unset($edit['aid']); $this->drupalPost('admin/store/attributes/'. $attribute->aid .'/options/add', $edit, t('Submit')); $option = db_query("SELECT * FROM {uc_attribute_options} WHERE aid = :aid", array(':aid' => $attribute->aid))->fetchObject(); $fields_ok = TRUE; foreach ($edit as $field => $value) { if ($option->$field != $value) { $this->showVar($option); $this->showVar($edit); $fields_ok = FALSE; break; } } $this->assertTrue($fields_ok, t('Attribute option added successfully by form.'), t('Ubercart')); } /** * */ public function testAttributeUIAttributeOptionsEdit() { $attribute = self::createAttribute(); $option = self::createAttributeOption(); uc_attribute_option_save($option); $this->drupalGet('admin/store/attributes/'. $attribute->aid .'/options/'. $option->oid .'/edit'); $this->AssertText(t('Edit option: @name', array('@name' => $option->name)), t('Attribute options edit form working.'), t('Ubercart')); $edit = (array) self::createAttributeOption(array(), FALSE); unset($edit['aid']); $this->drupalPost('admin/store/attributes/'. $attribute->aid .'/options/'. $option->oid .'/edit', $edit, t('Submit')); $option = uc_attribute_option_load($option->oid); $fields_ok = TRUE; foreach ($edit as $field => $value) { if ($option->$field != $value) { $this->showVar($option); $this->showVar($edit); $fields_ok = FALSE; break; } } $this->assertTrue($fields_ok, t('Attribute option edited successfully by form.'), t('Ubercart')); } /** * */ public function testAttributeUIAttributeOptionsDelete() { $attribute = self::createAttribute(); $option = self::createAttributeOption(); uc_attribute_option_save($option); $this->drupalGet('admin/store/attributes/'. $attribute->aid .'/options/'. $option->oid .'/delete'); $this->AssertText(t('Are you sure you want to delete the option @name?', array('@name' => $option->name)), t('Attribute options delete form working.'), t('Ubercart')); $this->drupalPost('admin/store/attributes/'. $attribute->aid .'/options/'. $option->oid .'/delete', array(), t('Delete')); $option = uc_attribute_option_load($option->oid); $this->assertFalse($option, t('Attribute option deleted successfully by form'), t('Ubercart')); } /** * */ public function testAttributeUIClassAttributeOverview() { $class = UcProductTestCase::createProductClass(); $attribute = self::createAttribute(); $this->drupalGet('admin/store/products/classes/'. $class->pcid .'/attributes'); $this->assertText(t('You must first add attributes to this class.'), t('Class attribute form working.'), t('Ubercart')); uc_attribute_subject_save($attribute, 'class', $class->pcid); $this->drupalGet('admin/store/products/classes/'. $class->pcid .'/attributes'); $this->assertNoText(t('You must first add attributes to this class.'), t('Class attribute form working.'), t('Ubercart')); $a = (array) self::createAttribute(array(), FALSE); unset($a['name'], $a['description']); foreach ($a as $field => $value) { $edit["attributes[{$attribute->aid}][$field]"] = $value; } $this->showVar($edit); $this->drupalPost('admin/store/products/classes/'. $class->pcid .'/attributes', $edit, t('Save changes')); $attribute = uc_attribute_load($attribute->aid, $class->pcid, 'class'); $fields_ok = TRUE; foreach ($a as $field => $value) { if ($attribute->$field != $value) { $this->showVar($attribute); $this->showVar($a); $fields_ok = FALSE; break; } } $this->assertTrue($fields_ok, t('Class attribute edited successfully by form.'), t('Ubercart')); $edit = array(); $edit["attributes[{$attribute->aid}][remove]"] = TRUE; $this->drupalPost('admin/store/products/classes/'. $class->pcid .'/attributes', $edit, t('Save changes')); $this->assertText(t('You must first add attributes to this class.'), t('Class attribute form working.'), t('Ubercart')); } /** * */ public function testAttributeUIClassAttributeAdd() { $class = UcProductTestCase::createProductClass(); $attribute = self::createAttribute(); $this->drupalGet('admin/store/products/classes/'. $class->pcid .'/attributes/add'); $this->assertRaw(t('@attribute', array('@attribute' => $attribute->name)), t('Class attribute add form working.'), t('Ubercart')); $edit["add_attributes[]"] = $attribute->aid; $this->drupalPost('admin/store/products/classes/'. $class->pcid .'/attributes/add', $edit, t('Add attributes')); $this->assertNoText(t('You must first add attributes to this class.'), t('Class attribute form working.'), t('Ubercart')); } /** * */ public function testAttributeUIClassAttributeOptionOverview() { $class = UcProductTestCase::createProductClass(); $attribute = self::createAttribute(); $option = self::createAttributeOption(); uc_attribute_subject_save($attribute, 'class', $class->pcid); $this->drupalGet('admin/store/products/classes/'. $class->pcid .'/options'); $this->assertRaw(t(' @option', array('@option' => $option->name)), t('Class attribute option form working.'), t('Ubercart')); $o = (array) self::createAttributeOption(array(), FALSE); unset($o['name'], $o['aid']); $o['select'] = TRUE; foreach ($o as $field => $value) { $edit["attributes[$attribute->aid][options][$option->oid][$field]"] = $value; } unset($o['select']); $edit["attributes[$attribute->aid][default]"] = $option->oid; $this->showVar($edit); $this->drupalPost('admin/store/products/classes/'. $class->pcid .'/options', $edit, t('Submit')); $this->assertText('The product class options have been saved.', t('Class attribute option saved.'), t('Ubercart')); $this->showVar($option); $option = uc_attribute_subject_option_load($option->oid, 'class', $class->pcid); $fields_ok = TRUE; foreach ($o as $field => $value) { if ($option->$field != $value) { $this->showVar($option); $this->showVar($o); $fields_ok = FALSE; break; } } $this->assertTrue($fields_ok, t('Class attribute option edited successfully by form.'), t('Ubercart')); } /** * */ public static function createProductAdjustment($data) { $adjustment = $data + array( 'nid' => rand(1, db_last_insert_id('node', 'nid')), 'model' => self::randomName(8), ); db_insert('uc_product_adjustments') ->fields($data) ->execute(); } /** * */ protected static function _attributeFieldsToTest($type = '') { $fields = array( 'aid', 'name', 'ordering', 'required', 'display', 'description', 'label', ); switch ($type) { case 'product': case 'class': $info = uc_attribute_type_info($type); $fields = array_merge($fields, array($info['id'])); break; } return $fields; } /** * */ protected static function _attributeOptionFieldsToTest($type = '') { $fields = array( 'aid', 'oid', 'name', 'cost', 'price', 'weight', 'ordering', ); switch ($type) { case 'product': case 'class': $info = uc_attribute_type_info($type); $fields = array_merge($fields, array($info['id'])); break; } return $fields; } /** * */ public static function createAttribute($data = array(), $save = TRUE) { $attribute = $data + array( 'name' => DrupalWebTestCase::randomName(8), 'label' => DrupalWebTestCase::randomName(8), 'description' => DrupalWebTestCase::randomName(8), 'required' => rand(0, 1) ? TRUE : FALSE, 'display' => rand(0, 3), 'ordering' => rand(-10, 10), ); $attribute = (object) $attribute; if ($save) { uc_attribute_save($attribute); } return $attribute; } /** * */ public static function createAttributeOption($data = array(), $save = TRUE) { $option = $data + array( 'aid' => rand(1, db_last_insert_id('uc_attributes', 'aid')), 'name' => DrupalWebTestCase::randomName(8), 'cost' => rand(-500, 500), 'price' => rand(-500, 500), 'weight' => rand(-500, 500), 'ordering' => rand(-10, 10), ); $option = (object) $option; if ($save) { uc_attribute_option_save($option); } return $option; } /** * */ function showVar($var) { $this->pass('
'. print_r($var, TRUE) .'
'); } }