Index: libraries.api.php
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/libraries/libraries.api.php,v
retrieving revision 1.1
diff -u -p -r1.1 libraries.api.php
--- libraries.api.php	3 Apr 2010 18:55:10 -0000	1.1
+++ libraries.api.php	20 Jul 2010 00:34:10 -0000
@@ -22,7 +22,8 @@
  *     the actual library files in a sub-directory.
  *   - version callback: (optional) The name of a function that detects and
  *     returns the full version string of the library. Defaults to
- *     libraries_get_version().
+ *     libraries_get_version(). The first argument is always $library_path, a
+ *     string containing the library path.
  *   - version arguments: A list of arguments to pass to the version callback.
  *     The default version callback libraries_get_version() expects a single,
  *     single, associative array with named keys:
@@ -30,12 +31,11 @@
  *       path. For example: 'docs/changelog.txt'.
  *     - pattern: A string containing a regular expression (PCRE) to match the
  *       library version. For example: '/@version (\d+)\.(\d+)/'.
- *     - lines: The maximum number of lines to search the pattern in. For
- *       example: 20.
+ *     - lines: (optional) The maximum number of lines to search the pattern in.
+ *       Defaults to 20.
  *     - cols: (optional) The maximum number of characters per line to take into
- *       account. For example: 40. Defaults to unlimited. To be used if the file
- *       containing the library version is minified/compressed, i.e. reading a
- *       single line would read the entire library into memory.
+ *       account. Defaults to 200. In case of minified or compressed files, this
+ *       prevents reading the entire file into memory.
  *   - files: An associative array of library files to load. Supported keys are:
  *     - js: A list of JavaScript files to load, using the same syntax as Drupal
  *       core's hook_library().
@@ -48,7 +48,12 @@
  *     uncompressed/source variant, those can be defined here. Each key should
  *     describe the variant type, e.g. 'minified' or 'source'. Each value is an
  *     associative array of top-level properties that are entirely overridden by
- *     the variant, most often just 'files'. Variants can be version specific.
+ *     the variant, most often just 'files'. Additionally, each variant can
+ *     contain a 'variant callback' and a 'variant arguments' key, which should
+ *     return TRUE or FALSE, depending on whether the variant is available or
+ *     not. The first argument of the variant callback is always $library_path,
+ *     a string containing the library path. If ommitted, the variant is
+ *     expected to always be available. Variants can be version specific.
  *   - versions: (optional) An associative array of supported library versions.
  *     Naturally, external libraries evolve over time and so do their APIs. In
  *     case a library changes between versions, different 'files' may need to be
@@ -62,6 +67,8 @@
  *     the same notion as the top-level 'files' property. Each specified file
  *     should contain the full path to the file.
  *   Additional top-level properties can be registered as needed.
+ *
+ * @see hook_library()
  */
 function hook_libraries_info() {
   // The following is a full explanation of all properties. See below for more
@@ -122,6 +129,10 @@ function hook_libraries_info() {
             'skin/example.css',
           ),
         ),
+        'variant callback' => 'mymodule_check_variant',
+        'variant arguments' => array(
+          'variant' => 'minified',
+        ),
       ),
     ),
     // Optional, but usually required: Override top-level properties for later
@@ -203,9 +214,9 @@ function hook_libraries_info() {
     'download url' => 'http://tinymce.moxiecode.com/download.php',
     'path' => 'jscripts/tiny_mce',
     'version arguments' => array(
-      // It can be easier to parse the first chars of a minified file instead of
-      // doing a multi-line pattern matching in a source file. See 'lines' and
-      // 'cols' below.
+      // It can be easier to parse the first characters of a minified file
+      // instead of doing a multi-line pattern matching in a source file. See
+      // 'lines' and 'cols' below.
       'file' => 'jscripts/tiny_mce/tiny_mce.js',
       // Best practice: Document the actual version strings for later reference.
       // 2.x: this.majorVersion="2";this.minorVersion="1.3"
@@ -278,3 +289,20 @@ function hook_libraries_info() {
   );
   return $libraries;
 }
+
+/**
+ * Alter the library information before detection and caching takes place.
+ *
+ * The library definitions are passed by reference. A common use-case is adding
+ * a module's integration files to the library array, so that the files are
+ * loaded whenever the library is. As noted above, it is important to declare
+ * integration files inside of an array, whose key is the module name.
+ *
+ * @see hook_libraries_info()
+ */
+function hook_libraries_info_alter(&$libraries) {
+  $files = array(
+    'php' => array('example_module.php_spellchecker.inc'),
+  );
+  $libraries['php_spellchecker']['integration files']['example_module'] = $files;
+}
Index: libraries.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/libraries/libraries.module,v
retrieving revision 1.5
diff -u -p -r1.5 libraries.module
--- libraries.module	19 Jul 2010 21:07:22 -0000	1.5
+++ libraries.module	20 Jul 2010 00:34:11 -0000
@@ -210,18 +210,17 @@ function libraries_detect_library(&$libr
   }
   if (!file_exists($library['library path'])) {
     $library['error'] = t('%library could not be found.', array('%library' => $library['title']));
-    continue;
+    return;
   }
 
+  // Add the library path as the first argument of the version callback.
+  $library['version arguments'] = array_merge(array('library_path' => $library['library path']), $library['version arguments']);
+
   // Detect library version.
-  // Special handling for named arguments (single array).
-  if (!isset($library['version arguments'][0])) {
-    $library['version arguments'] = array($library['version arguments']);
-  }
   $library['version'] = call_user_func_array($library['version callback'], $library['version arguments']);
   if (empty($library['version'])) {
     $library['error'] = t('The version of %library could not be detected.', array('%library' => $library['title']));
-    continue;
+    return;
   }
 
   // Determine to which supported version the installed version maps.
@@ -229,13 +228,16 @@ function libraries_detect_library(&$libr
     ksort($library['versions']);
     $version = 0;
     foreach ($library['versions'] as $supported_version => $version_properties) {
-      if (version_compare($library['installed version'], $supported_version, '>=')) {
+      if (version_compare($library['version'], $supported_version, '>=')) {
         $version = $supported_version;
       }
     }
     if (!$version) {
-      $library['error'] = t('The installed version %version of %library is not supported.', array('%version' => $library['installed version'], '%library' => $library['title']));
-      continue;
+      $library['error'] = t('The installed version %version of %library is not supported.', array(
+        '%version' => $library['version'],
+        '%library' => $library['title'],
+      ));
+      return;
     }
 
     // Apply version specific definitions and overrides.
@@ -243,10 +245,147 @@ function libraries_detect_library(&$libr
     unset($library['versions']);
   }
 
+  // Check each variant if it is installed.
+  if (!empty($library['variants'])) {
+    foreach ($library['variants'] as $variant => $info) {
+      // If no variant callback has been set, assume the variant to be
+      // installed.
+      $library['variants'][$variant]['installed'] = TRUE;
+      if (!empty($info['variant callback'])) {
+        // Add the library path as the first argument of the variant callback.
+        $info['variant arguments'] = array_merge(array('library_path' => $library['library path']), $info['variant arguments']);
+        $library['variants'][$variant]['installed'] = call_user_func_array($info['variant callback'], $info['variant arguments']);
+        if (empty($library['variants'][$variant]['installed'])) {
+          $library['variants'][$variant]['error'] = t('The %variant variant of %library could not be found.', array(
+            '%variant' => $variant,
+            '%library' => $library['title'],
+          ));
+        }
+      }
+    }
+  }
+
   // If we end up here, the library should be usable.
   $library['installed'] = TRUE;
-  if (!empty($library['path'])) {
-    $library['library path'] .= '/' . $library['path'];
+}
+
+/**
+ * Loads a library.
+ *
+ * @param $library
+ *   The name of the library to load.
+ * @param $variant
+ *   The name of the variant to load.
+ */
+function libraries_load($library, $variant = NULL) {
+  $library = libraries_info($library);
+  libraries_detect_library($library);
+  libraries_load_files($library, $variant);
+}
+
+/**
+ * Loads a library's files.
+ *
+ * @param $library
+ *   The name of the library to load.
+ * @param $variant
+ *   The name of the variant to load.
+ */
+function libraries_load_files($library, $variant = NULL) {
+  $path = isset($library['path']) ? $library['library path'] . '/' . $library['path'] : $library['library path'];
+
+  // If a variant was specified, override the top-level properties with the
+  // variant properties.
+  if (!empty($variant) && !empty($library['variants'][$variant]['installed'])) {
+    $library = array_merge($library, $library['variants'][$variant]);
+  }
+
+  // Load integration files.
+  if (!empty($library['integration files'])) {
+    foreach ($library['integration files'] as $module => $files) {
+      libraries_load_files(array(
+        'files' => $files,
+        'library path' => drupal_get_path('module', $module),
+      ));
+    }
+  }
+
+  // Load both the JavaScript and the CSS files.
+  // The parameters for drupal_add_js() and drupal_add_css() require special
+  // handling.
+  // @see drupal_process_attached()
+  foreach (array('js', 'css') as $type) {
+    if (!empty($library['files'][$type])) {
+      foreach ($library['files'][$type] as $data => $options) {
+        // If the value is not an array, it's a filename and passed as first
+        // (and only) argument.
+        if (!is_array($options)) {
+          // Prepend the library path to the file name.
+          $data = "$path/$options";
+          $options = NULL;
+        }
+        // In some cases, the first parameter ($data) is an array. Arrays can't be
+        // passed as keys in PHP, so we have to get $data from the value array.
+        if (is_numeric($data)) {
+          $data = $options['data'];
+          unset($options['data']);
+        }
+        // Apply the default weight if the weight isn't explicitly given.
+        if (!isset($options['weight'])) {
+          $options['weight'] = ($type == 'js') ? JS_DEFAULT : CSS_DEFAULT;
+        }
+        call_user_func('drupal_add_' . $type, $data, $options);
+      }
+    }
+  }
+
+
+  // Load PHP files.
+  if (!empty($library['files']['php'])) {
+    foreach ($library['files']['php'] as $file) {
+      $file_path = "$path/$file";
+      if (file_exists($file_path)) {
+        require_once $file_path;
+      }
+    }
+  }
+}
+
+/**
+ * Gets the version information from an arbitrary library.
+ *
+ * @param $file
+ *   The filename to parse for the version, relative to the Drupal root
+ *   directory.
+ * @param $pattern
+ *   A string containing a regular expression (PCRE) to match the library
+ *   version. For example: '/@version (\d+)\.(\d+)/'.
+ * @param $lines
+ *   The maximum number of lines to search the pattern in. For example: 20.
+ * @param $cols
+ *   (optional) The maximum number of characters per line to take into account.
+ *   For example: 40. Defaults to unlimited. To be used if the file containing
+ *   the library version is minified/compressed, i.e. reading a single line
+ *   would read the entire library into memory.
+ *
+ * @return
+ *   A string containing the version of the library.
+ *
+ * @see libraries_get_path()
+ */
+function libraries_get_version($library_path, $file, $pattern, $lines = 20, $cols = 200) {
+  $file = "$library_path/$file";
+  if (!file_exists($file)) {
+    return;
+  }
+  $file = fopen($file, 'r');
+  while ($lines && $line = fgets($file, $cols)) {
+    if (preg_match($pattern, $line, $version)) {
+      fclose($file);
+      return $version[1];
+    }
+    $lines--;
   }
+  fclose($file);
 }
 
Index: tests/libraries.test
===================================================================
RCS file: /cvs/drupal/contributions/modules/libraries/tests/libraries.test,v
retrieving revision 1.2
diff -u -p -r1.2 libraries.test
--- tests/libraries.test	16 Jul 2010 10:53:04 -0000	1.2
+++ tests/libraries.test	20 Jul 2010 00:34:12 -0000
@@ -51,12 +51,27 @@ class LibrariesTestCase extends DrupalWe
     ));
     $this->assertEqual($library['error'], $error, 'Unsupported library version found.');
 
+    // Test supported library version.
+    $library = libraries_info('example_supported_version');
+    libraries_detect_library($library);
+    $this->assertEqual($library['installed'], TRUE, 'Supported library version found.');
+
     // Test libraries_get_version().
-    $library = libraries_info('example_installed');
+    $library = libraries_info('example_default_version_callback');
     libraries_detect_library($library);
     $version = '2';
     $this->assertEqual($library['version'], $version, 'Expected version returned by default version callback.');
 
+    // Test a top-level files property.
+    $library = libraries_info('example_simple');
+    libraries_detect_library($library);
+    $files = array(
+      'js' => array('example_installed_2.js'),
+      'css' => array('example_installed_2.css'),
+      'php' => array('example_installed_2.php'),
+    );
+    $this->assertEqual($library['files'], $files, 'Top-level files property works.');
+
     // Test version-specific library files.
     $files = array(
       'js' => array('example_installed_2.js'),
@@ -64,28 +79,51 @@ class LibrariesTestCase extends DrupalWe
       'php' => array('example_installed_2.php'),
     );
     $this->assertEqual($library['files'], $files, 'Version-specific library files found.');
-    // @todo Ensure that default files are not contained.
 
-    // Test library loading.
-    $this->drupalGet('libraries_test');
+    // Test missing variant.
+    $library = libraries_info('example_variant_missing');
+    libraries_detect_library($library);
+    $error = t('The %variant variant of %library could not be found.', array(
+      '%variant' => key($library['variants']),
+      '%library' => $library['title'],
+    ));
+    $this->assertEqual($library['variants']['example_variant']['error'], $error, 'Missing variant not found.');
+
+    // Test existing variant.
+    $library = libraries_info('example_variant');
+    libraries_detect_library($library);
+    $this->assertEqual($library['variants']['example_variant']['installed'], TRUE, 'Existing variant found.');
 
+    // Test loading of a simple library with a top-level files property.
+    $this->drupalGet('libraries_test/simple');
     $this->assertRaw('example_installed_2.js', 'The JavaScript file is loaded.');
     $this->assertRaw('example_installed_2.css', 'The CSS file is loaded.');
     $this->assertText('example_installed_2.php', 'The PHP file is loaded.');
+
+    // Test loading of integration files.
+    $this->drupalGet('libraries_test/integration_files');
     $this->assertRaw('libraries_test.js', 'The JavaScript integration file is loaded.');
     $this->assertRaw('libraries_test.css', 'The CSS integration file is loaded.');
     $this->assertText('libraries_test.inc', 'The PHP integration file is loaded.');
 
+    // Test version loading.
+    $this->drupalGet('libraries_test/versions');
+    $this->assertNoRaw('example_installed_variant.js', 'The incorrect JavaScript file is not loaded.');
+    $this->assertNoRaw('example_installed_variant.css', 'The incorrect CSS file is not loaded.');
+    $this->assertNoText('example_installed_variant.php', 'The incorrect PHP file is not loaded.');
+    $this->assertRaw('example_installed_2.js', 'The correct JavaScript file is loaded.');
+    $this->assertRaw('example_installed_2.css', 'The correct CSS file is loaded.');
+    $this->assertText('example_installed_2.php', 'The correct PHP file is loaded.');
+
     // Test variant loading.
-    // @todo Move onto libraries_test/variant (maintain namespace).
-    $this->drupalGet('libraries_test_variant');
+    $this->drupalGet('libraries_test/versions_and_variants');
+    $this->assertNoRaw('example_installed_2.js', 'The incorrect JavaScript file is not loaded.');
+    $this->assertNoRaw('example_installed_2.css', 'The incorrect CSS file is not loaded.');
+    $this->assertNoText('example_installed_2.php', 'The incorrect PHP file is not loaded.');
+    $this->assertRaw('example_installed_variant.js', 'The correct JavaScript file is loaded.');
+    $this->assertRaw('example_installed_variant.css', 'The correct CSS file is loaded.');
+    $this->assertText('example_installed_variant.php', 'The correct PHP file is loaded.');
 
-    $this->assertRaw('example_installed_variant.js', 'The JavaScript file is loaded.');
-    $this->assertRaw('example_installed_variant.css', 'The CSS file is loaded.');
-    $this->assertText('example_installed_variant.php', 'The PHP file is loaded.');
-    $this->assertRaw('libraries_test.js', 'The JavaScript integration file is loaded.');
-    $this->assertRaw('libraries_test.css', 'The CSS integration file is loaded.');
-    $this->assertText('libraries_test.inc', 'The PHP integration file is loaded.');
   }
 }
 
Index: tests/libraries_test.module
===================================================================
RCS file: /cvs/drupal/contributions/modules/libraries/tests/libraries_test.module,v
retrieving revision 1.1
diff -u -p -r1.1 libraries_test.module
--- tests/libraries_test.module	16 Jul 2010 10:53:04 -0000	1.1
+++ tests/libraries_test.module	20 Jul 2010 00:34:13 -0000
@@ -16,21 +16,21 @@ function libraries_test_libraries_info()
   // Test library detection.
   $libraries['example_missing'] = array(
     'library path' => drupal_get_path('module', 'libraries') . '/tests/missing',
-    'version callback' => 'libraries_test_get_version',
+    'version callback' => '_libraries_test_get_version',
     'version arguments' => array(
       'version' => '1',
     ),
   );
   $libraries['example_undetected_version'] = array(
     'library path' => drupal_get_path('module', 'libraries') . '/tests',
-    'version callback' => 'libraries_test_get_version',
+    'version callback' => '_libraries_test_get_version',
     'version arguments' => array(
       'version' => 'undetected',
     ),
   );
   $libraries['example_unsupported_version'] = array(
     'library path' => drupal_get_path('module', 'libraries') . '/tests',
-    'version callback' => 'libraries_test_get_version',
+    'version callback' => '_libraries_test_get_version',
     'version arguments' => array(
       'version' => '1',
     ),
@@ -39,9 +39,18 @@ function libraries_test_libraries_info()
     ),
   );
 
-  // Test version- and variant-overloading, default version callback and library
-  // loading.
-  $libraries['example_installed'] = array(
+  $libraries['example_supported_version'] = array(
+    'library path' => drupal_get_path('module', 'libraries') . '/tests',
+    'version callback' => '_libraries_test_get_version',
+    'version arguments' => array(
+      'version' => '2',
+    ),
+    'versions' => array(
+      '2' => array(),
+    ),
+  );
+
+  $libraries['example_default_version_callback'] = array(
     'library path' => drupal_get_path('module', 'libraries') . '/tests/example',
     'version arguments' => array(
       'file' => 'example_installed.txt',
@@ -49,82 +58,231 @@ function libraries_test_libraries_info()
       'pattern' => '/Version (\d+)/',
       'lines' => 5,
     ),
-    // @todo Version-less files, if library declares versions?
-    // @todo These files don't exist. On purpose?
+  );
+
+  // Test a top-level files property.
+  $libraries['example_simple'] = array(
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/example',
+    'version callback' => '_libraries_test_get_version',
+    'version arguments' => array(
+      'version' => '2',
+    ),
     'files' => array(
       'js' => array(
-        'example_installed.js',
+        'example_installed_2.js',
       ),
       'css' => array(
-        'example_installed.css',
+        'example_installed_2.css',
       ),
       'php' => array(
-        'example_installed.php'
+        'example_installed_2.php'
       ),
     ),
   );
 
-  $libraries['example_installed']['versions'] = array(
-    // @todo Files for version 1 do not exist. On purpose?
-    '1' => array(
-      'files' => array(
+  // Test loading of integration files.
+  // Normally added by the corresponding module via hook_libraries_info_alter(),
+  // these files should be automatically loaded when the library is loaded.
+  $libraries['example_integration_files'] = array(
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/example',
+    'version callback' => '_libraries_test_get_version',
+    'version arguments' => array(
+      'version' => '2',
+    ),
+    'integration files' => array(
+      'libraries_test' => array(
         'js' => array(
-          'example_installed_1.js',
+          'libraries_test.js',
         ),
         'css' => array(
-          'example_installed_1.css',
+          'libraries_test.css',
         ),
         'php' => array(
-          'example_installed_1.php',
+          'libraries_test.inc',
         ),
       ),
     ),
-    '2' => array(
-      'files' => array(
-        'js' => array(
-          'example_installed_2.js',
-        ),
-        'css' => array(
-          'example_installed_2.css',
+  );
+
+  // Test version overloading.  
+  $libraries['example_versions'] = array(
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/example',
+    'version callback' => '_libraries_test_get_version',
+    'version arguments' => array(
+      'version' => '2',
+    ),    'library path' => drupal_get_path('module', 'libraries') . '/tests/example',
+    'version callback' => '_libraries_test_get_version',
+    'version arguments' => array(
+      'version' => '2',
+    ),
+    'versions' => array(
+      '1' => array(
+        'files' => array(
+          'js' => array(
+            'example_installed_variant.js',
+          ),
+          'css' => array(
+            'example_installed_variant.css',
+          ),
+          'php' => array(
+            'example_installed_variant.php',
+          ),
         ),
-        'php' => array(
-          'example_installed_2.php',
+      ),
+      '2' => array(
+        'files' => array(
+          'js' => array(
+            'example_installed_2.js',
+          ),
+          'css' => array(
+            'example_installed_2.css',
+          ),
+          'php' => array(
+            'example_installed_2.php',
+          ),
         ),
       ),
     ),
   );
 
-  // @todo Variant callback missing.
-  $libraries['example_installed']['variants'] = array(
-    // @todo Is "variant" the name of a variant?
-    'variant' => array(
-      'files' => array(
-        'js' => array(
-          'example_installed_variant.js',
-        ),
-        'css' => array(
-          'example_installed_variant.css',
+  // Test variant detection.
+  $libraries['example_variant_missing'] = array(
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/example',
+    'version callback' => '_libraries_test_get_version',
+    'version arguments' => array(
+      'version' => '2',
+    ),
+    'variants' => array(
+      'example_variant' => array(
+        'files' => array(
+          'js' => array(
+            'example_installed_variant.js',
+          ),
+          'css' => array(
+            'example_installed_variant.css',
+          ),
+          'php' => array(
+            'example_installed_variant.php',
+          ),
         ),
-        'php' => array(
-          'example_installed_variant.php',
+        'variant callback' => '_libraries_test_detect_variant',
+        'variant arguments' => array(
+          'status' => 'missing'
         ),
       ),
     ),
   );
 
-  // Integration files for example_installed library.
-  // Normally added by the corresponding module via hook_libraries_info_alter(),
-  // these files should be automatically loaded when the library is loaded.
-  $libraries['example_installed']['integration files'] = array(
-    'libraries_test' => array(
-      'js' => array(
-        'libraries_test.js',
+  $libraries['example_variant'] = array(
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/example',
+    'version callback' => '_libraries_test_get_version',
+    'version arguments' => array(
+      'version' => '2',
+    ),
+    'variants' => array(
+      'example_variant' => array(
+        'files' => array(
+          'js' => array(
+            'example_installed_variant.js',
+          ),
+          'css' => array(
+            'example_installed_variant.css',
+          ),
+          'php' => array(
+            'example_installed_variant.php',
+          ),
+        ),
+        'variant callback' => '_libraries_test_detect_variant',
+        'variant arguments' => array(
+          'status' => 'found'
+        ),
       ),
-      'css' => array(
-        'libraries_test.css',
+    ),
+  );
+
+  // Test correct behaviour with multiple versions and multiple variants.
+  $libraries['example_versions_and_variants'] = array(
+    'library path' => drupal_get_path('module', 'libraries') . '/tests/example',
+    'version callback' => '_libraries_test_get_version',
+    'version arguments' => array(
+      'version' => '2',
+    ),
+    'versions' => array(
+      '1' => array(
+        'variants' => array(
+          'example_variant' => array(
+            'files' => array(
+              'js' => array(
+                'example_installed_2.js',
+              ),
+              'css' => array(
+                'example_installed_2.css',
+              ),
+              'php' => array(
+                'example_installed_2.php',
+              ),
+            ),
+            'variant callback' => '_libraries_test_detect_variant',
+            'variant arguments' => array(
+              'status' => 'found'
+            ),
+          ),
+          'example_variant_2' => array(
+            'files' => array(
+              'js' => array(
+                'example_installed_2.js',
+              ),
+              'css' => array(
+                'example_installed_2.css',
+              ),
+              'php' => array(
+                'example_installed_2.php',
+              ),
+            ),
+            'variant callback' => '_libraries_test_detect_variant',
+            'variant arguments' => array(
+              'status' => 'found'
+            ),
+          ),
+        ),
       ),
-      'php' => array(
-        'libraries_test.inc',
+      '2' => array(
+        'variants' => array(
+          'example_variant' => array(
+            'files' => array(
+              'js' => array(
+                'example_installed_variant.js',
+              ),
+              'css' => array(
+                'example_installed_variant.css',
+              ),
+              'php' => array(
+                'example_installed_variant.php',
+              ),
+            ),
+            'variant callback' => '_libraries_test_detect_variant',
+            'variant arguments' => array(
+              'status' => 'found'
+            ),
+          ),
+          'example_variant_2' => array(
+            'files' => array(
+              'js' => array(
+                'example_installed_2.js',
+              ),
+              'css' => array(
+                'example_installed_2.css',
+              ),
+              'php' => array(
+                'example_installed_2.php',
+              ),
+            ),
+            'variant callback' => '_libraries_test_detect_variant',
+            'variant arguments' => array(
+              'status' => 'found'
+            ),
+          ),
+        ),
       ),
     ),
   );
@@ -137,62 +295,79 @@ function libraries_test_libraries_info()
  *
  * Returns exactly the version string entered as the $version parameter, unless
  * you specify 'undetected', in which case it returns nothing.
- *
- * @todo Shouldn't this get some info/arguments passed by Libraries API? (?)
  */
-function libraries_test_get_version($version) {
+function _libraries_test_get_version($library, $version) {
   if ($version !== 'undetected') {
     return $version;
   }
 }
 
 /**
+ * Detects the variant of an example library.
+ *
+ * Returns TRUE or FALSE depending on whether the $status parameter is 'missing'
+ * or 'found'.
+ */
+function _libraries_test_detect_variant($library, $status) {
+  if ($status == 'missing') {
+    return FALSE;
+  }
+  elseif ($status == 'found') {
+    return TRUE;
+  }
+}
+
+/**
  * Implements hook_menu().
  */
 function libraries_test_menu() {
-  $items['libraries_test'] = array(
-    'title' => 'Libraries loading test',
-    'page callback' => 'libraries_test_load',
+  $items['libraries_test/simple'] = array(
+    'title' => 'Test simple library',
+    'page callback' => '_libraries_test_load',
+    'page arguments' => array('example_simple'),
     'access callback' => TRUE,
   );
-  $items['libraries_test_variant'] = array(
-    'title' => 'Libraries variant loading test',
-    'page callback' => 'libraries_test_load_variant',
+  $items['libraries_test/integration_files'] = array(
+    'title' => 'Test integration files',
+    'page callback' => '_libraries_test_load',
+    'page arguments' => array('example_integration_files'),
+    'access callback' => TRUE,
+  );
+  $items['libraries_test/versions'] = array(
+    'title' => 'Test version loading',
+    'page callback' => '_libraries_test_load',
+    'page arguments' => array('example_versions'),
+    'access callback' => TRUE,
+  );
+  $items['libraries_test/variant'] = array(
+    'title' => 'Test variant loading',
+    'page callback' => '_libraries_test_load',
+    'page arguments' => array('example_variant', 'example variant'),
+    'access callback' => TRUE,
+  );
+  $items['libraries_test/versions_and_variants'] = array(
+    'title' => 'Test concurrent version and variant loading',
+    'page callback' => '_libraries_test_load',
+    'page arguments' => array('example_versions_and_variants', 'example_variant'),
     'access callback' => TRUE,
   );
   return $items;
 }
 
 /**
- * Loads the test library.
+ * Loads the test library with multiple versions.
  */
-function libraries_test_load() {
-  libraries_load('example_installed');
+function _libraries_test_load($library, $variant = NULL) {
+  libraries_load($library, $variant);
   // JavaScript and CSS files can be checked directly by SimpleTest, so we only
   // need to manually check for PHP files.
   $output = '';
-  if (function_exists('example_installed_2')) {
-    $output .= 'example_installed_2.php';
-  }
-  // Check for the PHP integration file.
-  if (function_exists('libraries_test_1')) {
-    $output .= 'libraries_test.inc';
-  }
-  return $output;
-}
-
-/**
- * Loads the test variant of the test library.
- */
-function libraries_test_load_variant() {
-  libraries_load('example_installed', 'variant');
-  // JavaScript and CSS files can be checked directly by SimpleTest, so we only
-  // need to manually check for PHP files.
-  $output = '';
-  if (function_exists('example_installed_variant')) {
+  if (function_exists('_libraries_example_installed_variant')) {
     $output .= 'example_installed_variant.php';
   }
-  // Check for the PHP integration file.
+  if (function_exists('_libraries_example_installed_2')) {
+    $output .= 'example_installed_2.php';
+  }
   if (function_exists('libraries_test_1')) {
     $output .= 'libraries_test.inc';
   }
