Projet

Général

Profil

Paste
Télécharger (21,6 ko) Statistiques
| Branche: | Révision:

root / htmltest / sites / all / modules / feeds / tests / feeds.test @ a5572547

1 85ad3d82 Assos Assos
<?php
2
3
/**
4
 * @file
5
 * Common functionality for all Feeds tests.
6
 */
7
8
/**
9
 * Test basic Data API functionality.
10
 */
11
class FeedsWebTestCase extends DrupalWebTestCase {
12
  protected $profile = 'testing';
13
14
  public function setUp() {
15
    $args = func_get_args();
16
17
    // Build the list of required modules which can be altered by passing in an
18
    // array of module names to setUp().
19
    if (isset($args[0])) {
20
      if (is_array($args[0])) {
21
      $modules = $args[0];
22
    }
23
      else {
24
      $modules = $args;
25
    }
26
    }
27
    else {
28
      $modules = array();
29
    }
30
31
    $modules[] = 'taxonomy';
32
    $modules[] = 'image';
33
    $modules[] = 'file';
34
    $modules[] = 'field';
35
    $modules[] = 'field_ui';
36
    $modules[] = 'feeds';
37
    $modules[] = 'feeds_ui';
38
    $modules[] = 'feeds_tests';
39
    $modules[] = 'ctools';
40
    $modules[] = 'job_scheduler';
41
    $modules = array_unique($modules);
42
    parent::setUp($modules);
43
44
    // Add text formats Directly.
45
    $filtered_html_format = array(
46
      'format' => 'filtered_html',
47
      'name' => 'Filtered HTML',
48
      'weight' => 0,
49
      'filters' => array(
50
        // URL filter.
51
        'filter_url' => array(
52
          'weight' => 0,
53
          'status' => 1,
54
        ),
55
        // HTML filter.
56
        'filter_html' => array(
57
          'weight' => 1,
58
          'status' => 1,
59
        ),
60
        // Line break filter.
61
        'filter_autop' => array(
62
          'weight' => 2,
63
          'status' => 1,
64
        ),
65
        // HTML corrector filter.
66
        'filter_htmlcorrector' => array(
67
          'weight' => 10,
68
          'status' => 1,
69
        ),
70
      ),
71
    );
72
    $filtered_html_format = (object) $filtered_html_format;
73
    filter_format_save($filtered_html_format);
74
75
    // Build the list of required administration permissions. Additional
76
    // permissions can be passed as an array into setUp()'s second parameter.
77
    if (isset($args[1]) && is_array($args[1])) {
78
      $permissions = $args[1];
79
    }
80
    else {
81
      $permissions = array();
82
    }
83
84
    $permissions[] = 'access content';
85
    $permissions[] = 'administer site configuration';
86
    $permissions[] = 'administer content types';
87
    $permissions[] = 'administer nodes';
88
    $permissions[] = 'bypass node access';
89
    $permissions[] = 'administer taxonomy';
90
    $permissions[] = 'administer users';
91
    $permissions[] = 'administer feeds';
92
93
    // Create an admin user and log in.
94
    $this->admin_user = $this->drupalCreateUser($permissions);
95
    $this->drupalLogin($this->admin_user);
96
97
    $types = array(
98
      array(
99
        'type' => 'page',
100
        'name' => 'Basic page',
101
        'node_options[status]' => 1,
102
        'node_options[promote]' => 0,
103
      ),
104
      array(
105
        'type' => 'article',
106
        'name' => 'Article',
107
        'node_options[status]' => 1,
108
        'node_options[promote]' => 1,
109
      ),
110
    );
111
    foreach ($types as $type) {
112
      $this->drupalPost('admin/structure/types/add', $type, 'Save content type');
113
      $this->assertText("The content type " . $type['name'] . " has been added.");
114
    }
115
  }
116
117
  /**
118
   * Absolute path to Drupal root.
119
   */
120
  public function absolute() {
121
    return realpath(getcwd());
122
  }
123
124
  /**
125
   * Get the absolute directory path of the feeds module.
126
   */
127
  public function absolutePath() {
128
    return  $this->absolute() . '/' . drupal_get_path('module', 'feeds');
129
  }
130
131
  /**
132
   * Generate an OPML test feed.
133
   *
134
   * The purpose of this function is to create a dynamic OPML feed that points
135
   * to feeds included in this test.
136
   */
137
  public function generateOPML() {
138
    $path = $GLOBALS['base_url'] . '/' . drupal_get_path('module', 'feeds') . '/tests/feeds/';
139
140
  $output =
141
'<?xml version="1.0" encoding="utf-8"?>
142
<opml version="1.1">
143
<head>
144
    <title>Feeds test OPML</title>
145
    <dateCreated>Fri, 16 Oct 2009 02:53:17 GMT</dateCreated>
146
    <ownerName></ownerName>
147
</head>
148
<body>
149
  <outline text="Feeds test group" >
150
    <outline title="Development Seed - Technological Solutions for Progressive Organizations" text="" xmlUrl="' . $path . 'developmentseed.rss2" type="rss" />
151
    <outline title="Magyar Nemzet Online - H\'rek" text="" xmlUrl="' . $path . 'feed_without_guid.rss2" type="rss" />
152
    <outline title="Drupal planet" text="" type="rss" xmlUrl="' . $path . 'drupalplanet.rss2" />
153
  </outline>
154
</body>
155
</opml>';
156
157
    // UTF 8 encode output string and write it to disk
158
    $output = utf8_encode($output);
159
    $filename = file_default_scheme() . '://test-opml-' . $this->randomName() . '.opml';
160
161
    $filename = file_unmanaged_save_data($output, $filename);
162
    return $filename;
163
  }
164
165
  /**
166
   * Create an importer configuration.
167
   *
168
   * @param $name
169
   *   The natural name of the feed.
170
   * @param $id
171
   *   The persistent id of the feed.
172
   * @param $edit
173
   *   Optional array that defines the basic settings for the feed in a format
174
   *   that can be posted to the feed's basic settings form.
175
   */
176
  public function createImporterConfiguration($name = 'Syndication', $id = 'syndication') {
177
    // Create new feed configuration.
178
    $this->drupalGet('admin/structure/feeds');
179
    $this->clickLink('Add importer');
180
    $edit = array(
181
      'name' => $name,
182
      'id' => $id,
183
    );
184
    $this->drupalPost('admin/structure/feeds/create', $edit, 'Create');
185
186
    // Assert message and presence of default plugins.
187
    $this->assertText('Your configuration has been created with default settings.');
188
    $this->assertPlugins($id, 'FeedsHTTPFetcher', 'FeedsSyndicationParser', 'FeedsNodeProcessor');
189
    // Per default attach to page content type.
190
    $this->setSettings($id, NULL, array('content_type' => 'page'));
191
    // Per default attached to article content type.
192
    $this->setSettings($id, 'FeedsNodeProcessor', array('bundle' => 'article'));
193
  }
194
195
  /**
196
   * Choose a plugin for a importer configuration and assert it.
197
   *
198
   * @param $id
199
   *   The importer configuration's id.
200
   * @param $plugin_key
201
   *   The key string of the plugin to choose (one of the keys defined in
202
   *   feeds_feeds_plugins()).
203
   */
204
  public function setPlugin($id, $plugin_key) {
205
    if ($type = FeedsPlugin::typeOf($plugin_key)) {
206
      $edit = array(
207
        'plugin_key' => $plugin_key,
208
      );
209
      $this->drupalPost("admin/structure/feeds/$id/$type", $edit, 'Save');
210
211
      // Assert actual configuration.
212
      $config = unserialize(db_query("SELECT config FROM {feeds_importer} WHERE id = :id", array(':id' => $id))->fetchField());
213
      $this->assertEqual($config[$type]['plugin_key'], $plugin_key, 'Verified correct ' . $type . ' (' . $plugin_key . ').');
214
    }
215
  }
216
217
  /**
218
   * Set importer or plugin settings.
219
   *
220
   * @param $id
221
   *   The importer configuration's id.
222
   * @param $plugin
223
   *   The plugin (class) name, or NULL to set importer's settings
224
   * @param $settings
225
   *   The settings to set.
226
   */
227
  public function setSettings($id, $plugin, $settings) {
228
    $this->drupalPost('admin/structure/feeds/' . $id . '/settings/' . $plugin, $settings, 'Save');
229
    $this->assertText('Your changes have been saved.');
230
  }
231
232
  /**
233
   * Create a test feed node. Test user has to have sufficient permissions:
234
   *
235
   * * create [type] content
236
   * * use feeds
237
   *
238
   * Assumes that page content type has been configured with
239
   * createImporterConfiguration() as a feed content type.
240
   *
241
   * @return
242
   *   The node id of the node created.
243
   */
244
  public function createFeedNode($id = 'syndication', $feed_url = NULL, $title = '', $content_type = NULL) {
245
    if (empty($feed_url)) {
246
      $feed_url = $GLOBALS['base_url'] . '/' . drupal_get_path('module', 'feeds') . '/tests/feeds/developmentseed.rss2';
247
    }
248
249
    // If content type not given, retrieve it.
250
    if (!$content_type) {
251
      $result= db_select('feeds_importer', 'f')
252
        ->condition('f.id', $id, '=')
253
        ->fields('f', array('config'))
254
        ->execute();
255
      $config = unserialize($result->fetchField());
256
      $content_type = $config['content_type'];
257
      $this->assertFalse(empty($content_type), 'Valid content type found: ' . $content_type);
258
    }
259
260
    // Create a feed node.
261
    $edit = array(
262
      'title' => $title,
263
      'feeds[FeedsHTTPFetcher][source]' => $feed_url,
264
    );
265
    $this->drupalPost('node/add/' . str_replace('_', '-', $content_type), $edit, 'Save');
266
    $this->assertText('has been created.');
267
268
    // Get the node id from URL.
269
    $nid = $this->getNid($this->getUrl());
270
271
    // Check whether feed got recorded in feeds_source table.
272
    $query = db_select('feeds_source', 's')
273
      ->condition('s.id', $id, '=')
274
      ->condition('s.feed_nid', $nid, '=');
275
    $query->addExpression("COUNT(*)");
276
    $result = $query->execute()->fetchField();
277
    $this->assertEqual(1, $result);
278
279
    $source = db_select('feeds_source', 's')
280
      ->condition('s.id', $id, '=')
281
      ->condition('s.feed_nid', $nid, '=')
282
      ->fields('s', array('config'))
283
      ->execute()->fetchObject();
284
    $config = unserialize($source->config);
285
    $this->assertEqual($config['FeedsHTTPFetcher']['source'], $feed_url, t('URL in DB correct.'));
286
    return $nid;
287
  }
288
289
  /**
290
   * Edit the configuration of a feed node to test update behavior.
291
   *
292
   * @param $nid
293
   *   The nid to edit.
294
   * @param $feed_url
295
   *   The new (absolute) feed URL to use.
296
   * @param $title
297
   *   Optional parameter to change title of feed node.
298
   */
299
  public function editFeedNode($nid, $feed_url, $title = '') {
300
    $edit = array(
301
      'title' => $title,
302
      'feeds[FeedsHTTPFetcher][source]' => $feed_url,
303
    );
304
    // Check that the update was saved.
305
    $this->drupalPost('node/' . $nid . '/edit', $edit, 'Save');
306
    $this->assertText('has been updated.');
307
308
    // Check that the URL was updated in the feeds_source table.
309
    $source = db_query("SELECT * FROM {feeds_source} WHERE feed_nid = :nid", array(':nid' => $nid))->fetchObject();
310
    $config = unserialize($source->config);
311
    $this->assertEqual($config['FeedsHTTPFetcher']['source'], $feed_url, t('URL in DB correct.'));
312
  }
313
314
  /**
315
   * Batch create a variable amount of feed nodes. All will have the
316
   * same URL configured.
317
   *
318
   * @return
319
   *   An array of node ids of the nodes created.
320
   */
321
  public function createFeedNodes($id = 'syndication', $num = 20, $content_type = NULL) {
322
    $nids = array();
323
    for ($i = 0; $i < $num; $i++) {
324
      $nids[] = $this->createFeedNode($id, NULL, $this->randomName(), $content_type);
325
    }
326
    return $nids;
327
  }
328
329
  /**
330
   * Import a URL through the import form. Assumes FeedsHTTPFetcher in place.
331
   */
332
  public function importURL($id, $feed_url = NULL) {
333
    if (empty($feed_url)) {
334
      $feed_url = $GLOBALS['base_url'] . '/' . drupal_get_path('module', 'feeds') . '/tests/feeds/developmentseed.rss2';
335
    }
336
    $edit = array(
337
      'feeds[FeedsHTTPFetcher][source]' => $feed_url,
338
    );
339
    $nid = $this->drupalPost('import/' . $id, $edit, 'Import');
340
341
    // Check whether feed got recorded in feeds_source table.
342
    $this->assertEqual(1, db_query("SELECT COUNT(*) FROM {feeds_source} WHERE id = :id AND feed_nid = 0", array(':id' => $id))->fetchField());
343
    $source = db_query("SELECT * FROM {feeds_source} WHERE id = :id AND feed_nid = 0",  array(':id' => $id))->fetchObject();
344
    $config = unserialize($source->config);
345
    $this->assertEqual($config['FeedsHTTPFetcher']['source'], $feed_url, t('URL in DB correct.'));
346
347
    // Check whether feed got properly added to scheduler.
348
    $this->assertEqual(1, db_query("SELECT COUNT(*) FROM {job_schedule} WHERE type = :id AND id = 0 AND name = 'feeds_source_import' AND last <> 0 AND scheduled = 0", array(':id' => $id))->fetchField());
349
    // There must be only one entry for callback 'expire' - no matter what the feed_nid is.
350
    $this->assertEqual(0, db_query("SELECT COUNT(*) FROM {job_schedule} WHERE type = :id AND name = 'feeds_importer_expire' AND last <> 0 AND scheduled = 0", array(':id' => $id))->fetchField());
351
  }
352
353
  /**
354
   * Import a file through the import form. Assumes FeedsFileFetcher in place.
355
   */
356
  public function importFile($id, $file) {
357
358
    $this->assertTrue(file_exists($file), 'Source file exists');
359
    $edit = array(
360
      'files[feeds]' => $file,
361
    );
362
    $this->drupalPost('import/' . $id, $edit, 'Import');
363
  }
364
365
  /**
366
   * Assert a feeds configuration's plugins.
367
   *
368
   * @deprecated:
369
   *   Use setPlugin() instead.
370
   *
371
   * @todo Refactor users of assertPlugin() and make them use setPugin() instead.
372
   */
373
  public function assertPlugins($id, $fetcher, $parser, $processor) {
374
    // Assert actual configuration.
375
    $config = unserialize(db_query("SELECT config FROM {feeds_importer} WHERE id = :id", array(':id' => $id))->fetchField());
376
377
    $this->assertEqual($config['fetcher']['plugin_key'], $fetcher, 'Correct fetcher');
378
    $this->assertEqual($config['parser']['plugin_key'], $parser, 'Correct parser');
379
    $this->assertEqual($config['processor']['plugin_key'], $processor, 'Correct processor');
380
  }
381
382
   /**
383
    * Adds mappings to a given configuration.
384
    *
385
    * @param string $id
386
    *   ID of the importer.
387
    * @param array $mappings
388
    *   An array of mapping arrays. Each mapping array must have a source and
389
    *   an target key and can have a unique key.
390
    * @param bool $test_mappings
391
    *   (optional) TRUE to automatically test mapping configs. Defaults to TRUE.
392
    */
393
  public function addMappings($id, $mappings, $test_mappings = TRUE) {
394
395
    $path = "admin/structure/feeds/$id/mapping";
396
397
    // Iterate through all mappings and add the mapping via the form.
398
    foreach ($mappings as $i => $mapping) {
399
400
      if ($test_mappings) {
401
        $current_mapping_key = $this->mappingExists($id, $i, $mapping['source'], $mapping['target']);
402
        $this->assertEqual($current_mapping_key, -1, 'Mapping does not exist before addition.');
403
      }
404
405
      // Get unique flag and unset it. Otherwise, drupalPost will complain that
406
      // Split up config and mapping.
407
      $config = $mapping;
408
      unset($config['source'], $config['target']);
409
      $mapping = array('source' => $mapping['source'], 'target' => $mapping['target']);
410
411
      // Add mapping.
412
      $this->drupalPost($path, $mapping, t('Save'));
413
414
      // If there are other configuration options, set them.
415
      if ($config) {
416
        $this->drupalPostAJAX(NULL, array(), 'mapping_settings_edit_' . $i);
417
418
        // Set some settings.
419
        $edit = array();
420
        foreach ($config as $key => $value) {
421
          $edit["config[$i][settings][$key]"] = $value;
422
        }
423
        $this->drupalPostAJAX(NULL, $edit, 'mapping_settings_update_' . $i);
424
        $this->drupalPost(NULL, array(), t('Save'));
425
      }
426
427
      if ($test_mappings) {
428
        $current_mapping_key = $this->mappingExists($id, $i, $mapping['source'], $mapping['target']);
429
        $this->assertTrue($current_mapping_key >= 0, 'Mapping exists after addition.');
430
      }
431
    }
432
  }
433
434
  /**
435
   * Remove mappings from a given configuration.
436
   *
437
   * @param array $mappings
438
   *   An array of mapping arrays. Each mapping array must have a source and
439
   *   a target key and can have a unique key.
440
   * @param bool $test_mappings
441
   *   (optional) TRUE to automatically test mapping configs. Defaults to TRUE.
442
   */
443
  public function removeMappings($id, $mappings, $test_mappings = TRUE) {
444
    $path = "admin/structure/feeds/$id/mapping";
445
446
    $current_mappings = $this->getCurrentMappings($id);
447
448
    // Iterate through all mappings and remove via the form.
449
    foreach ($mappings as $i => $mapping) {
450
451
      if ($test_mappings) {
452
        $current_mapping_key = $this->mappingExists($id, $i, $mapping['source'], $mapping['target']);
453
        $this->assertEqual($current_mapping_key, $i, 'Mapping exists before removal.');
454
      }
455
456
      $remove_mapping = array("remove_flags[$i]" => 1);
457
458
      $this->drupalPost($path, $remove_mapping, t('Save'));
459
460
      $this->assertText('Your changes have been saved.');
461
462
      if ($test_mappings) {
463
        $current_mapping_key = $this->mappingExists($id, $i, $mapping['source'], $mapping['target']);
464
        $this->assertEqual($current_mapping_key, -1, 'Mapping does not exist after removal.');
465
      }
466
    }
467
  }
468
469
  /**
470
   * Gets an array of current mappings from the feeds_importer config.
471
   *
472
   * @param string $id
473
   *   ID of the importer.
474
   *
475
   * @return bool|array
476
   *   FALSE if the importer has no mappings, or an an array of mappings.
477
   */
478
  public function getCurrentMappings($id) {
479
    $config = db_query("SELECT config FROM {feeds_importer} WHERE id = :id", array(':id' => $id))->fetchField();
480
481
    $config = unserialize($config);
482
483
    // We are very specific here. 'mappings' can either be an array or not
484
    // exist.
485
    if (array_key_exists('mappings', $config['processor']['config'])) {
486
      $this->assertTrue(is_array($config['processor']['config']['mappings']), 'Mappings is an array.');
487
488
      return $config['processor']['config']['mappings'];
489
    }
490
491
    return FALSE;
492
  }
493
494
  /**
495
   * Determines if a mapping exists for a given importer.
496
   *
497
   * @param string $id
498
   *   ID of the importer.
499
   * @param integer $i
500
   *   The key of the mapping.
501
   * @param string $source
502
   *   The source field.
503
   * @param string $target
504
   *   The target field.
505
   *
506
   * @return integer
507
   *   -1 if the mapping doesn't exist, the key of the mapping otherwise.
508
   */
509
  public function mappingExists($id, $i, $source, $target) {
510
511
    $current_mappings = $this->getCurrentMappings($id);
512
513
    if ($current_mappings) {
514
      foreach ($current_mappings as $key => $mapping) {
515
        if ($mapping['source'] == $source && $mapping['target'] == $target && $key == $i) {
516
          return $key;
517
        }
518
      }
519
    }
520
521
    return -1;
522
  }
523
524
  /**
525
   * Helper function, retrieves node id from a URL.
526
   */
527
  public function getNid($url) {
528
    $matches = array();
529
    preg_match('/node\/(\d+?)$/', $url, $matches);
530
    $nid = $matches[1];
531
532
    // Test for actual integerness.
533
    $this->assertTrue($nid === (string) (int) $nid, 'Node id is an integer.');
534
535
    return $nid;
536
  }
537
538
  /**
539
   * Copies a directory.
540
   */
541
  public function copyDir($source, $dest) {
542
    $result = file_prepare_directory($dest, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
543
    foreach (@scandir($source) as $file) {
544
      if (is_file("$source/$file")) {
545
        $file = file_unmanaged_copy("$source/$file", "$dest/$file");
546
      }
547
    }
548
  }
549
550
  /**
551
   * Download and extract SimplePIE.
552
   *
553
   * Sets the 'feeds_simplepie_library_dir' variable to the directory where
554
   * SimplePie is downloaded.
555
   */
556
  function downloadExtractSimplePie($version) {
557
    $url = "http://simplepie.org/downloads/simplepie_$version.mini.php";
558
    $filename = 'simplepie.mini.php';
559
560
    // Avoid downloading the file dozens of times
561
    $library_dir = DRUPAL_ROOT . '/' . $this->originalFileDirectory . '/simpletest/feeds';
562
    $simplepie_library_dir = $library_dir . '/simplepie';
563
564
    if (!file_exists($library_dir)) {
565
      drupal_mkdir($library_dir);
566
    }
567
568
    if (!file_exists($simplepie_library_dir)) {
569
      drupal_mkdir($simplepie_library_dir);
570
    }
571
572
    // Local file name.
573
    $local_file = $simplepie_library_dir . '/' . $filename;
574
575
    // Begin single threaded code.
576
    if (function_exists('sem_get')) {
577
      $semaphore = sem_get(ftok(__FILE__, 1));
578
      sem_acquire($semaphore);
579
    }
580
581
    // Download and extact the archive, but only in one thread.
582
    if (!file_exists($local_file)) {
583
      $local_file = system_retrieve_file($url, $local_file, FALSE, FILE_EXISTS_REPLACE);
584
    }
585
586
    if (function_exists('sem_get')) {
587
      sem_release($semaphore);
588
    }
589
    // End single threaded code.
590
591
    // Verify that files were successfully extracted.
592
    $this->assertTrue(file_exists($local_file), t('@file found.', array('@file' => $local_file)));
593
594
    // Set the simpletest library directory.
595
    variable_set('feeds_library_dir', $library_dir);
596
  }
597
}
598
599
/**
600
 * Provides a wrapper for DrupalUnitTestCase for Feeds unit testing.
601
 */
602
class FeedsUnitTestHelper extends DrupalUnitTestCase {
603
  public function setUp() {
604
    parent::setUp();
605
606
    // Manually include the feeds module.
607
    // @todo Allow an array of modules from the child class.
608
    drupal_load('module', 'feeds');
609
  }
610
}
611
612
class FeedsUnitTestCase extends FeedsUnitTestHelper {
613
  public static function getInfo() {
614
    return array(
615
      'name' => 'Unit tests',
616
      'description' => 'Test basic low-level Feeds module functionality.',
617
      'group' => 'Feeds',
618
    );
619
  }
620
621
  /**
622
   * Test valid absolute urls.
623
   *
624
   * @see ValidUrlTestCase
625
   *
626
   * @todo Remove when http://drupal.org/node/1191252 is fixed.
627
   */
628
  function testFeedsValidURL() {
629
    $url_schemes = array('http', 'https', 'ftp', 'feed', 'webcal');
630
    $valid_absolute_urls = array(
631
      'example.com',
632
      'www.example.com',
633
      'ex-ample.com',
634
      '3xampl3.com',
635
      'example.com/paren(the)sis',
636
      'example.com/index.html#pagetop',
637
      'example.com:8080',
638
      'subdomain.example.com',
639
      'example.com/index.php?q=node',
640
      'example.com/index.php?q=node&param=false',
641
      'user@www.example.com',
642
      'user:pass@www.example.com:8080/login.php?do=login&style=%23#pagetop',
643
      '127.0.0.1',
644
      'example.org?',
645
      'john%20doe:secret:foo@example.org/',
646
      'example.org/~,$\'*;',
647
      'caf%C3%A9.example.org',
648
      '[FEDC:BA98:7654:3210:FEDC:BA98:7654:3210]:80/index.html',
649
      'graph.asfdasdfasdf.com/blarg/feed?access_token=133283760145143|tGew8jbxi1ctfVlYh35CPYij1eE',
650
    );
651
652
    foreach ($url_schemes as $scheme) {
653
      foreach ($valid_absolute_urls as $url) {
654
        $test_url = $scheme . '://' . $url;
655
        $valid_url = feeds_valid_url($test_url, TRUE);
656
        $this->assertTrue($valid_url, t('@url is a valid url.', array('@url' => $test_url)));
657
      }
658
    }
659
660
    $invalid_ablosule_urls = array(
661
      '',
662
      'ex!ample.com',
663
      'ex%ample.com',
664
    );
665
666
    foreach ($url_schemes as $scheme) {
667
      foreach ($invalid_ablosule_urls as $url) {
668
        $test_url = $scheme . '://' . $url;
669
        $valid_url = feeds_valid_url($test_url, TRUE);
670
        $this->assertFalse($valid_url, t('@url is NOT a valid url.', array('@url' => $test_url)));
671
      }
672
    }
673
  }
674
}