=== added file 'uc_attribute/uc_attribute.test'
--- uc_attribute/uc_attribute.test	1970-01-01 00:00:00 +0000
+++ uc_attribute/uc_attribute.test	2009-06-15 21:35:17 +0000
@@ -0,0 +1,691 @@
+<?php
+
+class UbercartAttributeTestCase extends DrupalWebTestCase {
+
+  function getInfo() {
+    return array(
+      'name' => 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 = UbercartProductTestCase::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_result(db_query("SELECT aid FROM {uc_product_attributes} WHERE nid = %d", $product->nid)), 
+      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', $product->nid);
+    
+    // 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_result(db_query("SELECT aid FROM {uc_product_attributes} WHERE nid = %d", $product->nid)), 
+      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 = UbercartProductTestCase::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_result(db_query("SELECT aid FROM {uc_class_attributes} WHERE pcid = '%s'", $product_class->pcid)), 
+      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, 'class', $product_class->pcid);
+    
+    // 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_result(db_query("SELECT aid FROM {uc_class_attributes} WHERE pcid = '%s'", $product_class->pcid)), 
+      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_result(db_query("SELECT aid FROM {uc_attributes} WHERE aid = %d", $attribute->aid)), t('Attribute was seriously deleted properly!'), t('Ubercart'));
+    
+    // Test that options were deleted properly.
+    foreach ($options as $option) {
+      $this->assertFalse(db_result(db_query("SELECT oid FROM {uc_attribute_options} WHERE oid = %d", $option->oid)), 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_result(db_query("SELECT COUNT(*) FROM {uc_product_adjustments}")), t('Ubercart'));
+    
+    // Test deletion by aid.
+    uc_attribute_adjustments_delete(array('aid' => 2));
+    $this->assertEqual(5, db_result(db_query("SELECT COUNT(*) FROM {uc_product_adjustments}")), t('Ubercart'));
+
+    // Test deletion by oid.
+    uc_attribute_adjustments_delete(array('oid' => 2));
+    $this->assertEqual(3, db_result(db_query("SELECT COUNT(*) FROM {uc_product_adjustments}")), t('Ubercart'));
+
+    // Test deletion by aid and oid.
+    uc_attribute_adjustments_delete(array('aid' => 1, 'oid' => 3));
+    $this->assertEqual(2, db_result(db_query("SELECT COUNT(*) FROM {uc_product_adjustments}")), 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('<td class="active">'. $edit['name'] .'</td>', t('Verify name field.'), t('Ubercart'));
+    $this->assertRaw('<td>'. $edit['label'] .'</td>', t('Verify label field.'), t('Ubercart'));
+    $this->assertRaw('<td>'. $edit['required'] ? t('Yes') : t('No') .'</td>', t('Verify required field.'), t('Ubercart'));
+    $this->assertRaw('<td align="center">'. $edit['ordering'] .'</td>', t('Verify ordering field.'), t('Ubercart'));
+    $types = _uc_attribute_display_types();
+    $this->assertRaw('<td>'. $types[$edit['display']] .'</td>', 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 = UbercartProductTestCase::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 .'</option>',
+      'adjustment' => $option->name .', +'. $adjust_price .'</option>',
+      'total' => $total_price .'</option>',
+    );
+    
+    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_fetch_object(db_query("SELECT * FROM {uc_attribute_options} WHERE aid = %d", $attribute->aid));
+    
+    $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'));
+  }
+  
+  
+  
+  // Simpletest needs work before we can do this form.
+/*  public function testAttributeUIClassAttributeOverview() {
+    $class = UbercartProductTestCase::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']);
+    $edit['attributes'][$attribute->aid] = $a;
+    $this->showVar($edit);
+    $this->drupalPost('admin/store/products/classes/'. $class->pcid .'/attributes', $edit, t('Save changes'));
+    
+    $attribute = uc_attribute_load($attribute->aid, 'class', $class->pcid);
+    
+    $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 = UbercartProductTestCase::createProductClass();
+    $attribute = self::createAttribute();
+    
+    $this->drupalGet('admin/store/products/classes/'. $class->pcid .'/attributes/add');
+    
+    $this->assertRaw(t('@attribute</option>', array('@option' => $attribute->name)), t('Class attribute add form working.'), t('Ubercart'));
+    
+    $edit['add_attributes'][$attribute->aid] = $attribute->aid;
+    
+    $this->drupalPost('admin/store/products/classes/'. $class->pcid .'/attributes/add', $edit, t('Add atrributes'));
+    
+    $this->assertNoText(t('You must first add attributes to this class.'), t('Class attribute form working.'), t('Ubercart'));
+  }
+  
+  public function testAttributeUIClassAttributeOptionOverview() {
+    $class = UbercartProductTestCase::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('<h2>@attribute</h2>', array('@attribute' => $attribute->name)), t('Class attribute option form working.'), t('Ubercart'));
+    
+    $o = (array) self::createAttribute(array(), FALSE);
+    unset($o['name'], $o['aid']);
+    $edit['attributes'][$attribute->aid]['options'][$option->oid] = $o;
+    $this->showVar($edit);
+    $this->drupalPost('admin/store/products/classes/'. $class->pcid .'/options', $edit, t('Submit'));
+    
+    $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 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_query("INSERT INTO {uc_product_adjustments} (nid, combination, model) VALUES (%d, '%s', '%s')", $data['nid'], $data['combination'], $data['model']);
+  }
+  
+  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('<pre>'. print_r($var, TRUE) .'</pre>');
+  }
+}

