Runs binary tests sequentially.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Mon, 15 Jun 2015 15:03:59 +0000 (16:03 +0100)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Mon, 15 Jun 2015 15:03:59 +0000 (16:03 +0100)
Prevents all topics from being evaluated at the same time, which
can stress system resources and lead to slower execution.

test/binary-test.js

index 88ab37b..02a2650 100644 (file)
@@ -45,320 +45,382 @@ var deleteFile = function(filename) {
     exec('rm ' + filename);
 };
 
-exports.commandsSuite = vows.describe('binary commands').addBatch({
-  'no options': binaryContext('', {
-    'should output help': function(stdout) {
-      assert.match(stdout, /Usage[:]/);
-    }
-  }),
-  'help': binaryContext('-h', {
-    'should output help': function(error, stdout) {
-      assert.match(stdout, /Usage[:]/);
-    },
-    'should output one file example': function(error, stdout) {
-      assert.include(stdout, 'cleancss -o one-min.css one.css');
-    },
-    'should output multiple files example': function(error, stdout) {
-      assert.include(stdout, 'cat one.css two.css three.css | cleancss -o merged-and-minified.css');
-    },
-    'should output gzipping multiple files example': function(error, stdout) {
-      assert.include(stdout, 'cat one.css two.css three.css | cleancss | gzip -9 -c > merged-minified-and-gzipped.css.gz');
-    }
-  }),
-  'version': binaryContext('-v', {
-    'should output help': function(error, stdout) {
-      var version = JSON.parse(fs.readFileSync('./package.json')).version;
-      assert.equal(stdout, version + '\n');
-    }
-  }),
-  'stdin': pipedContext('a{color: #f00}', '', {
-    'should output data': function(error, stdout) {
-      assert.equal(stdout, 'a{color:red}');
-    }
-  }),
-  'strip all but first comment': pipedContext('/*!1st*//*! 2nd */a{display:block}', '--s1', {
-    'should keep the 2nd comment': function(error, stdout) {
-      assert.equal(stdout, '/*!1st*/a{display:block}');
-    }
-  }),
-  'strip all comments': pipedContext('/*!1st*//*! 2nd */a{display:block}', '--s0', {
-    'should keep the 2nd comment': function(error, stdout) {
-      assert.equal(stdout, 'a{display:block}');
-    }
-  }),
-  'piped with debug info': pipedContext('a{color: #f00;}', '-d', {
-    'should output content to stdout and debug info to stderr': function(error, stdout, stderr) {
-      assert.equal(stdout, 'a{color:red}');
-      assert.notEqual(stderr, '');
-      assert.include(stderr, 'Time spent:');
-      assert.include(stderr, 'Original: 16 bytes');
-      assert.include(stderr, 'Minified: 12 bytes');
-      assert.include(stderr, 'Efficiency: 25%');
-    }
-  }),
-  'piped with debug info on inlining': pipedContext('@import url(test/fixtures/imports-min.css);', '-d', {
-    'should output inlining info': function(error, stdout, stderr) {
-      assert.include(stderr, path.join(process.cwd(), 'test/fixtures/imports-min.css'));
-    }
-  }),
-  'piped with correct debug info on inlining': pipedContext('@import url(test/fixtures/imports.css);', '-d', {
-    'should output correct info': function(error, stdout, stderr) {
-      assert.include(stderr, 'Original: 120 bytes');
-      assert.include(stderr, 'Minified: 86 bytes');
-      assert.include(stderr, 'Efficiency: 28.33%');
-    }
-  }),
-  'to output file with debug info': pipedContext('a{color: #f00;}', '-d -o debug.css', {
-    'should output nothing to stdout and debug info to stderr': function(error, stdout, stderr) {
-      assert.isEmpty(stdout);
-      assert.notEqual(stderr, '');
-      assert.include(stderr, 'Time spent:');
-      assert.include(stderr, 'Original: 16 bytes');
-      assert.include(stderr, 'Minified: 12 bytes');
-      assert.include(stderr, 'Efficiency: 25%');
-    },
-    'should output content to file': function() {
-      var minimized = readFile('debug.css');
-      assert.equal(minimized, 'a{color:red}');
-    },
-    teardown: function() {
-      deleteFile('debug.css');
-    }
-  }),
-  'skip advanced optimizations': pipedContext('a{color:red}p{color:red}', '--skip-advanced', {
-    'should do basic optimizations only': function(error, stdout) {
-      assert.equal(stdout, 'a{color:red}p{color:red}');
-    }
-  }),
-  'skip restructuring optimizations': pipedContext('div{margin-top:0}.one{margin:0}.two{display:block;margin-top:0}', '--skip-restructuring', {
-    'should do basic optimizations only': function(error, stdout) {
-      assert.equal(stdout, 'div{margin-top:0}.one{margin:0}.two{display:block;margin-top:0}');
-    }
-  }),
-  'no relative to path': binaryContext('./test/fixtures/partials-absolute/base.css', {
-    'should not be able to resolve it fully': function(error, stdout, stderr) {
-      assert.isEmpty(stdout);
-      assert.notEqual(error, null);
-      assert.notEqual(stderr, '');
-    }
-  }),
-  'relative to path': binaryContext('-r ./test/fixtures ./test/fixtures/partials-absolute/base.css', {
-    'should be able to resolve it': function(error, stdout) {
-      assert.equal(stdout, '.base2{border-width:0}.sub{padding:0}.base{margin:0}');
-    }
-  }),
-  'from source': binaryContext('./test/fixtures/reset.css', {
-    'should minimize': function(error, stdout) {
-      var minimized = fs.readFileSync('./test/fixtures/reset-min.css', 'utf-8').replace(lineBreakRegExp, '');
-      assert.equal(stdout, minimized);
-    }
-  }),
-  'from multiple sources': binaryContext('./test/fixtures/partials/one.css ./test/fixtures/partials/five.css', {
-    'should minimize all': function(error, stdout) {
-      assert.equal(stdout, '.one{color:red}.five{background:url(data:image/jpeg;base64,/9j/)}');
-    }
-  }),
-  'to file': binaryContext('-o ./reset1-min.css ./test/fixtures/reset.css', {
-    'should give no output': function(error, stdout) {
-      assert.isEmpty(stdout);
-    },
-    'should minimize': function() {
-      var preminified = readFile('./test/fixtures/reset-min.css');
-      var minified = readFile('./reset1-min.css');
-      assert.equal(minified, preminified);
-    },
-    teardown: function() {
-      deleteFile('./reset1-min.css');
-    }
-  }),
-  'disable @import': binaryContext('-s ./test/fixtures/imports.css', {
-    'should disable the import processing': function(error, stdout) {
-      assert.equal(stdout, '@import url(./partials/one.css);@import url(./partials/two.css);.imports{color:#000}');
-    }
-  }),
-  'relative image paths': {
-    'no root & output': binaryContext('./test/fixtures/partials-relative/base.css', {
-      'should leave paths': function(error, stdout) {
-        assert.equal(stdout, 'a{background:url(../partials/extra/down.gif) no-repeat}');
-      }
-    }),
-    'root but no output': binaryContext('-r ./test ./test/fixtures/partials-relative/base.css', {
-      'should rewrite path relative to ./test': function(error, stdout) {
-        assert.equal(stdout, 'a{background:url(/fixtures/partials/extra/down.gif) no-repeat}');
-      }
-    }),
-    'no root but output': binaryContext('-o ./base1-min.css ./test/fixtures/partials-relative/base.css', {
-      'should rewrite path relative to current path': function() {
-        var minimized = readFile('./base1-min.css');
-        assert.equal(minimized, 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}');
+vows.describe('./bin/cleancss')
+  .addBatch({
+    'no options': binaryContext('', {
+      'should output help': function (stdout) {
+        assert.match(stdout, /Usage[:]/);
+      }
+    })
+  })
+  .addBatch({
+    'help': binaryContext('-h', {
+      'should output help': function (error, stdout) {
+        assert.match(stdout, /Usage[:]/);
       },
-      teardown: function() {
-        deleteFile('./base1-min.css');
-      }
-    }),
-    'root and output': binaryContext('-r ./test/fixtures -o ./base2-min.css ./test/fixtures/partials-relative/base.css', {
-      'should rewrite path relative to ./test/fixtures/': function() {
-        var minimized = readFile('./base2-min.css');
-        assert.equal(minimized, 'a{background:url(/partials/extra/down.gif) no-repeat}');
+      'should output one file example': function (error, stdout) {
+        assert.include(stdout, 'cleancss -o one-min.css one.css');
       },
-      teardown: function() {
-        deleteFile('./base2-min.css');
-      }
-    }),
-    'piped with output': pipedContext('a{background:url(test/fixtures/partials/extra/down.gif)}', '-o base3-min.css', {
-      'should keep paths as they are': function() {
-        var minimized = readFile('base3-min.css');
-        assert.equal(minimized, 'a{background:url(test/fixtures/partials/extra/down.gif)}');
+      'should output multiple files example': function (error, stdout) {
+        assert.include(stdout, 'cat one.css two.css three.css | cleancss -o merged-and-minified.css');
       },
-      teardown: function() {
-        deleteFile('base3-min.css');
+      'should output gzipping multiple files example': function (error, stdout) {
+        assert.include(stdout, 'cat one.css two.css three.css | cleancss | gzip -9 -c > merged-minified-and-gzipped.css.gz');
+      }
+    })
+  })
+  .addBatch({
+    'version': binaryContext('-v', {
+      'should output help': function (error, stdout) {
+        var version = JSON.parse(fs.readFileSync('./package.json')).version;
+        assert.equal(stdout, version + '\n');
+      }
+    })
+  })
+  .addBatch({
+    'stdin': pipedContext('a{color: #f00}', '', {
+      'should output data': function (error, stdout) {
+        assert.equal(stdout, 'a{color:red}');
+      }
+    })
+  })
+  .addBatch({
+    'strip all but first comment': pipedContext('/*!1st*//*! 2nd */a{display:block}', '--s1', {
+      'should keep the 2nd comment': function (error, stdout) {
+        assert.equal(stdout, '/*!1st*/a{display:block}');
+      }
+    })
+  })
+  .addBatch({
+    'strip all comments': pipedContext('/*!1st*//*! 2nd */a{display:block}', '--s0', {
+      'should keep the 2nd comment': function (error, stdout) {
+        assert.equal(stdout, 'a{display:block}');
+      }
+    })
+  })
+  .addBatch({
+    'piped with debug info': pipedContext('a{color: #f00;}', '-d', {
+      'should output content to stdout and debug info to stderr': function (error, stdout, stderr) {
+        assert.equal(stdout, 'a{color:red}');
+        assert.notEqual(stderr, '');
+        assert.include(stderr, 'Time spent:');
+        assert.include(stderr, 'Original: 16 bytes');
+        assert.include(stderr, 'Minified: 12 bytes');
+        assert.include(stderr, 'Efficiency: 25%');
+      }
+    })
+  })
+  .addBatch({
+    'piped with debug info on inlining': pipedContext('@import url(test/fixtures/imports-min.css);', '-d', {
+      'should output inlining info': function (error, stdout, stderr) {
+        assert.include(stderr, path.join(process.cwd(), 'test/fixtures/imports-min.css'));
       }
     })
-  },
-  'complex import and url rebasing': {
-    absolute: binaryContext('-r ./test/fixtures/129-assets ./test/fixtures/129-assets/assets/ui.css', {
-      'should rebase urls correctly': function(error, stdout) {
-        assert.isNull(error);
-        assert.include(stdout, 'url(/components/bootstrap/images/glyphs.gif)');
-        assert.include(stdout, 'url(/components/jquery-ui/images/prev.gif)');
-        assert.include(stdout, 'url(/components/jquery-ui/images/next.gif)');
-      }
-    }),
-    relative: binaryContext('-o ui.bundled.css ./test/fixtures/129-assets/assets/ui.css', {
-      'should rebase urls correctly': function() {
-        var minimized = readFile('ui.bundled.css');
-        assert.include(minimized, 'url(test/fixtures/129-assets/components/bootstrap/images/glyphs.gif)');
-        assert.include(minimized, 'url(test/fixtures/129-assets/components/jquery-ui/images/prev.gif)');
-        assert.include(minimized, 'url(test/fixtures/129-assets/components/jquery-ui/images/next.gif)');
+  })
+  .addBatch({
+    'piped with correct debug info on inlining': pipedContext('@import url(test/fixtures/imports.css);', '-d', {
+      'should output correct info': function (error, stdout, stderr) {
+        assert.include(stderr, 'Original: 120 bytes');
+        assert.include(stderr, 'Minified: 86 bytes');
+        assert.include(stderr, 'Efficiency: 28.33%');
+      }
+    })
+  })
+  .addBatch({
+    'to output file with debug info': pipedContext('a{color: #f00;}', '-d -o debug.css', {
+      'should output nothing to stdout and debug info to stderr': function (error, stdout, stderr) {
+        assert.isEmpty(stdout);
+        assert.notEqual(stderr, '');
+        assert.include(stderr, 'Time spent:');
+        assert.include(stderr, 'Original: 16 bytes');
+        assert.include(stderr, 'Minified: 12 bytes');
+        assert.include(stderr, 'Efficiency: 25%');
+      },
+      'should output content to file': function () {
+        var minimized = readFile('debug.css');
+        assert.equal(minimized, 'a{color:red}');
       },
-      teardown: function() {
-        deleteFile('ui.bundled.css');
+      teardown: function () {
+        deleteFile('debug.css');
       }
     })
-  },
-  'complex import and skipped url rebasing': {
-    absolute: binaryContext('-r ./test/fixtures/129-assets --skip-rebase ./test/fixtures/129-assets/assets/ui.css', {
-      'should rebase urls correctly': function(error, stdout) {
-        assert.isNull(error);
-        assert.include(stdout, 'url(../images/glyphs.gif)');
-        assert.include(stdout, 'url(../images/prev.gif)');
-        assert.include(stdout, 'url(../images/next.gif)');
+  })
+  .addBatch({
+    'skip advanced optimizations': pipedContext('a{color:red}p{color:red}', '--skip-advanced', {
+      'should do basic optimizations only': function (error, stdout) {
+        assert.equal(stdout, 'a{color:red}p{color:red}');
       }
     })
-  },
-  'remote import': {
-    topic: function() {
-      this.server = http.createServer(function (req, res) {
-        res.writeHead(200);
-        res.end('p{font-size:13px}');
-      }).listen(31991, '127.0.0.1');
-
-      this.callback(null);
-    },
-    'of a file': binaryContext('http://127.0.0.1:31991/present.css', {
-      succeeds: function(error, stdout) {
-        assert.isNull(error);
-        assert.equal(stdout, 'p{font-size:13px}');
-      }
-    }),
-    teardown: function() {
-      this.server.close();
-    }
-  },
-  'timeout': unixOnlyContext({
-    topic: function() {
-      var self = this;
-      var source = '@import url(http://localhost:24682/timeout.css);';
-
-      this.server = http.createServer(function() {
-        setTimeout(function() {}, 1000);
-      });
-      this.server.listen('24682', function() {
-        exec('echo "' + source + '" | ./bin/cleancss --timeout 0.01', self.callback);
-      });
-    },
-    'should raise warning': function(error, stdout, stderr) {
-      assert.include(stderr, 'Broken @import declaration of "http://localhost:24682/timeout.css" - timeout');
-    },
-    'should output empty response': function(error, stdout) {
-      assert.isEmpty(stdout);
-    },
-    teardown: function() {
-      this.server.close();
+  })
+  .addBatch({
+    'skip restructuring optimizations': pipedContext('div{margin-top:0}.one{margin:0}.two{display:block;margin-top:0}', '--skip-restructuring', {
+      'should do basic optimizations only': function (error, stdout) {
+        assert.equal(stdout, 'div{margin-top:0}.one{margin:0}.two{display:block;margin-top:0}');
+      }
+    })
+  })
+  .addBatch({
+    'no relative to path': binaryContext('./test/fixtures/partials-absolute/base.css', {
+      'should not be able to resolve it fully': function (error, stdout, stderr) {
+        assert.isEmpty(stdout);
+        assert.notEqual(error, null);
+        assert.notEqual(stderr, '');
+      }
+    })
+  })
+  .addBatch({
+    'relative to path': binaryContext('-r ./test/fixtures ./test/fixtures/partials-absolute/base.css', {
+      'should be able to resolve it': function (error, stdout) {
+        assert.equal(stdout, '.base2{border-width:0}.sub{padding:0}.base{margin:0}');
+      }
+    })
+  })
+  .addBatch({
+    'from source': binaryContext('./test/fixtures/reset.css', {
+      'should minimize': function (error, stdout) {
+        var minimized = fs.readFileSync('./test/fixtures/reset-min.css', 'utf-8').replace(lineBreakRegExp, '');
+        assert.equal(stdout, minimized);
+      }
+    })
+  })
+  .addBatch({
+    'from multiple sources': binaryContext('./test/fixtures/partials/one.css ./test/fixtures/partials/five.css', {
+      'should minimize all': function (error, stdout) {
+        assert.equal(stdout, '.one{color:red}.five{background:url(data:image/jpeg;base64,/9j/)}');
+      }
+    })
+  })
+  .addBatch({
+    'to file': binaryContext('-o ./reset1-min.css ./test/fixtures/reset.css', {
+      'should give no output': function (error, stdout) {
+        assert.isEmpty(stdout);
+      },
+      'should minimize': function () {
+        var preminified = readFile('./test/fixtures/reset-min.css');
+        var minified = readFile('./reset1-min.css');
+        assert.equal(minified, preminified);
+      },
+      teardown: function () {
+        deleteFile('./reset1-min.css');
+      }
+    })
+  })
+  .addBatch({
+    'disable @import': binaryContext('-s ./test/fixtures/imports.css', {
+      'should disable the import processing': function (error, stdout) {
+        assert.equal(stdout, '@import url(./partials/one.css);@import url(./partials/two.css);.imports{color:#000}');
+      }
+    })
+  })
+  .addBatch({
+    'relative image paths': {
+      'no root & output': binaryContext('./test/fixtures/partials-relative/base.css', {
+        'should leave paths': function (error, stdout) {
+          assert.equal(stdout, 'a{background:url(../partials/extra/down.gif) no-repeat}');
+        }
+      }),
+      'root but no output': binaryContext('-r ./test ./test/fixtures/partials-relative/base.css', {
+        'should rewrite path relative to ./test': function (error, stdout) {
+          assert.equal(stdout, 'a{background:url(/fixtures/partials/extra/down.gif) no-repeat}');
+        }
+      }),
+      'no root but output': binaryContext('-o ./base1-min.css ./test/fixtures/partials-relative/base.css', {
+        'should rewrite path relative to current path': function () {
+          var minimized = readFile('./base1-min.css');
+          assert.equal(minimized, 'a{background:url(test/fixtures/partials/extra/down.gif) no-repeat}');
+        },
+        teardown: function () {
+          deleteFile('./base1-min.css');
+        }
+      }),
+      'root and output': binaryContext('-r ./test/fixtures -o ./base2-min.css ./test/fixtures/partials-relative/base.css', {
+        'should rewrite path relative to ./test/fixtures/': function () {
+          var minimized = readFile('./base2-min.css');
+          assert.equal(minimized, 'a{background:url(/partials/extra/down.gif) no-repeat}');
+        },
+        teardown: function () {
+          deleteFile('./base2-min.css');
+        }
+      }),
+      'piped with output': pipedContext('a{background:url(test/fixtures/partials/extra/down.gif)}', '-o base3-min.css', {
+        'should keep paths as they are': function () {
+          var minimized = readFile('base3-min.css');
+          assert.equal(minimized, 'a{background:url(test/fixtures/partials/extra/down.gif)}');
+        },
+        teardown: function () {
+          deleteFile('base3-min.css');
+        }
+      })
     }
-  }),
-  'ie7 compatibility': binaryContext('--compatibility ie7 ./test/fixtures/unsupported/selectors-ie7.css', {
-    'should not transform source': function(error, stdout) {
-      assert.equal(stdout, readFile('./test/fixtures/unsupported/selectors-ie7.css'));
+  })
+  .addBatch({
+    'complex import and url rebasing': {
+      'absolute': binaryContext('-r ./test/fixtures/129-assets ./test/fixtures/129-assets/assets/ui.css', {
+        'should rebase urls correctly': function (error, stdout) {
+          assert.isNull(error);
+          assert.include(stdout, 'url(/components/bootstrap/images/glyphs.gif)');
+          assert.include(stdout, 'url(/components/jquery-ui/images/prev.gif)');
+          assert.include(stdout, 'url(/components/jquery-ui/images/next.gif)');
+        }
+      }),
+      'relative': binaryContext('-o ui.bundled.css ./test/fixtures/129-assets/assets/ui.css', {
+        'should rebase urls correctly': function () {
+          var minimized = readFile('ui.bundled.css');
+          assert.include(minimized, 'url(test/fixtures/129-assets/components/bootstrap/images/glyphs.gif)');
+          assert.include(minimized, 'url(test/fixtures/129-assets/components/jquery-ui/images/prev.gif)');
+          assert.include(minimized, 'url(test/fixtures/129-assets/components/jquery-ui/images/next.gif)');
+        },
+        teardown: function () {
+          deleteFile('ui.bundled.css');
+        }
+      })
     }
-  }),
-  'ie8 compatibility': binaryContext('--compatibility ie8 ./test/fixtures/unsupported/selectors-ie8.css', {
-    'should not transform source': function(error, stdout) {
-      assert.equal(stdout, readFile('./test/fixtures/unsupported/selectors-ie8.css'));
+  })
+  .addBatch({
+    'complex import and skipped url rebasing': {
+      'absolute': binaryContext('-r ./test/fixtures/129-assets --skip-rebase ./test/fixtures/129-assets/assets/ui.css', {
+        'should rebase urls correctly': function (error, stdout) {
+          assert.isNull(error);
+          assert.include(stdout, 'url(../images/glyphs.gif)');
+          assert.include(stdout, 'url(../images/prev.gif)');
+          assert.include(stdout, 'url(../images/next.gif)');
+        }
+      })
     }
-  }),
-  'custom compatibility': pipedContext('a{_color:red}', '--compatibility "+properties.iePrefixHack"', {
-    'should not transform source': function(error, stdout) {
-      assert.equal(stdout, 'a{_color:red}');
+  })
+  .addBatch({
+    'remote import': {
+      topic: function () {
+        this.server = http.createServer(function (req, res) {
+          res.writeHead(200);
+          res.end('p{font-size:13px}');
+        }).listen(31991, '127.0.0.1');
+
+        this.callback(null);
+      },
+      'of a file': binaryContext('http://127.0.0.1:31991/present.css', {
+        succeeds: function (error, stdout) {
+          assert.isNull(error);
+          assert.equal(stdout, 'p{font-size:13px}');
+        }
+      }),
+      teardown: function () {
+        this.server.close();
+      }
     }
-  }),
-  'rounding precision': {
-    defaults: pipedContext('div{width:0.10051px}', '', {
-      'should keep 2 decimal places': function(error, stdout) {
-        assert.equal(stdout, 'div{width:.1px}');
-      }
-    }),
-    custom: pipedContext('div{width:0.00051px}', '--rounding-precision 4', {
-      'should keep 4 decimal places': function(error, stdout) {
-        assert.equal(stdout, 'div{width:.0005px}');
-      }
-    }),
-    zero: pipedContext('div{width:1.5051px}', '--rounding-precision 0', {
-      'should keep 0 decimal places': function(error, stdout) {
-        assert.equal(stdout, 'div{width:2px}');
-      }
-    }),
-    disabled: pipedContext('div{width:0.12345px}', '--rounding-precision \\\\-1', {
-      'should keep all decimal places': function(error, stdout) {
-        assert.equal(stdout, 'div{width:.12345px}');
+  })
+  .addBatch({
+    'timeout': unixOnlyContext({
+      topic: function () {
+        var self = this;
+        var source = '@import url(http://localhost:24682/timeout.css);';
+
+        this.server = http.createServer(function () {
+          setTimeout(function () {}, 1000);
+        });
+        this.server.listen('24682', function () {
+          exec('echo "' + source + '" | ./bin/cleancss --timeout 0.01', self.callback);
+        });
+      },
+      'should raise warning': function (error, stdout, stderr) {
+        assert.include(stderr, 'Broken @import declaration of "http://localhost:24682/timeout.css" - timeout');
+      },
+      'should output empty response': function (error, stdout) {
+        assert.isEmpty(stdout);
+      },
+      teardown: function () {
+        this.server.close();
       }
     })
-  },
-  'neighbour merging': {
-    'of (yet) unmergeable properties': pipedContext('a{display:inline-block;color:red;display:-moz-block}', '--skip-aggressive-merging', {
-      'gets right result': function(error, stdout) {
-        assert.equal(stdout, 'a{display:inline-block;color:red;display:-moz-block}');
+  })
+  .addBatch({
+    'ie7 compatibility': binaryContext('--compatibility ie7 ./test/fixtures/unsupported/selectors-ie7.css', {
+      'should not transform source': function (error, stdout) {
+        assert.equal(stdout, readFile('./test/fixtures/unsupported/selectors-ie7.css'));
       }
-    }),
-    'of mergeable properties': pipedContext('a{background:red;display:block;background:white}', '--skip-aggressive-merging', {
-      'gets right result': function(error, stdout) {
-        assert.equal(stdout, 'a{background:#fff;display:block}');
+    })
+  })
+  .addBatch({
+    'ie8 compatibility': binaryContext('--compatibility ie8 ./test/fixtures/unsupported/selectors-ie8.css', {
+      'should not transform source': function (error, stdout) {
+        assert.equal(stdout, readFile('./test/fixtures/unsupported/selectors-ie8.css'));
+      }
+    })
+  })
+  .addBatch({
+    'custom compatibility': pipedContext('a{_color:red}', '--compatibility "+properties.iePrefixHack"', {
+      'should not transform source': function (error, stdout) {
+        assert.equal(stdout, 'a{_color:red}');
       }
     })
-  },
-  '@media merging': pipedContext('@media screen{a{color:red}}@media screen{a{display:block}}', '--skip-media-merging', {
-    'gets right result': function (error, stdout) {
-      assert.equal(stdout, '@media screen{a{color:red}}@media screen{a{display:block}}');
+  })
+  .addBatch({
+    'rounding precision': {
+      defaults: pipedContext('div{width:0.10051px}', '', {
+        'should keep 2 decimal places': function (error, stdout) {
+          assert.equal(stdout, 'div{width:.1px}');
+        }
+      }),
+      custom: pipedContext('div{width:0.00051px}', '--rounding-precision 4', {
+        'should keep 4 decimal places': function (error, stdout) {
+          assert.equal(stdout, 'div{width:.0005px}');
+        }
+      }),
+      zero: pipedContext('div{width:1.5051px}', '--rounding-precision 0', {
+        'should keep 0 decimal places': function (error, stdout) {
+          assert.equal(stdout, 'div{width:2px}');
+        }
+      }),
+      disabled: pipedContext('div{width:0.12345px}', '--rounding-precision \\\\-1', {
+        'should keep all decimal places': function (error, stdout) {
+          assert.equal(stdout, 'div{width:.12345px}');
+        }
+      })
     }
-  }),
-  'shorthand compacting': {
-    'of (yet) unmergeable properties': pipedContext('a{background:url(image.png);background-color:red}', '--skip-shorthand-compacting', {
-      'gets right result': function(error, stdout) {
-        assert.equal(stdout, 'a{background:url(image.png);background-color:red}');
+  })
+  .addBatch({
+    'neighbour merging': {
+      'of (yet) unmergeable properties': pipedContext('a{display:inline-block;color:red;display:-moz-block}', '--skip-aggressive-merging', {
+        'gets right result': function (error, stdout) {
+          assert.equal(stdout, 'a{display:inline-block;color:red;display:-moz-block}');
+        }
+      }),
+      'of mergeable properties': pipedContext('a{background:red;display:block;background:white}', '--skip-aggressive-merging', {
+        'gets right result': function (error, stdout) {
+          assert.equal(stdout, 'a{background:#fff;display:block}');
+        }
+      })
+    }
+  })
+  .addBatch({
+    '@media merging': pipedContext('@media screen{a{color:red}}@media screen{a{display:block}}', '--skip-media-merging', {
+      'gets right result': function (error, stdout) {
+        assert.equal(stdout, '@media screen{a{color:red}}@media screen{a{display:block}}');
       }
     })
-  },
-  'source maps': {
-    'no target file': binaryContext('--source-map ./test/fixtures/reset.css', {
+  })
+  .addBatch({
+    'shorthand compacting': {
+      'of (yet) unmergeable properties': pipedContext('a{background:url(image.png);background-color:red}', '--skip-shorthand-compacting', {
+        'gets right result': function (error, stdout) {
+          assert.equal(stdout, 'a{background:url(image.png);background-color:red}');
+        }
+      })
+    }
+  })
+  .addBatch({
+    'source maps - no target file': binaryContext('--source-map ./test/fixtures/reset.css', {
       'warns about source map not being build': function (error, stdout, stderr) {
         assert.include(stderr, 'Source maps will not be built because you have not specified an output file.');
       },
       'does not include map in stdout': function (error, stdout) {
         assert.notInclude(stdout, '/*# sourceMappingURL');
       }
-    }),
-    'output file': binaryContext('--source-map -o ./reset.min.css ./test/fixtures/reset.css', {
-      'includes map in minified file': function() {
+    })
+  })
+  .addBatch({
+    'source maps - output file': binaryContext('--source-map -o ./reset.min.css ./test/fixtures/reset.css', {
+      'includes map in minified file': function () {
         assert.include(readFile('./reset.min.css'), '/*# sourceMappingURL=reset.min.css.map */');
       },
       'creates a map file': function () {
@@ -380,8 +442,10 @@ exports.commandsSuite = vows.describe('binary commands').addBatch({
         deleteFile('reset.min.css');
         deleteFile('reset.min.css.map');
       }
-    }),
-    'output file in same folder as input': unixOnlyContext({
+    })
+  })
+  .addBatch({
+    'source maps - output file in same folder as input': unixOnlyContext({
       topic: function () {
         var self = this;
 
@@ -405,8 +469,10 @@ exports.commandsSuite = vows.describe('binary commands').addBatch({
         deleteFile('reset.min.css');
         deleteFile('reset.min.css.map');
       }
-    }),
-    'output file with existing map': binaryContext('--source-map -o ./styles.min.css ./test/fixtures/source-maps/styles.css', {
+    })
+  })
+  .addBatch({
+    'source maps - output file with existing map': binaryContext('--source-map -o ./styles.min.css ./test/fixtures/source-maps/styles.css', {
       'includes right content in map file': function () {
         var sourceMap = new SourceMapConsumer(readFile('./styles.min.css.map'));
         assert.deepEqual(
@@ -423,8 +489,10 @@ exports.commandsSuite = vows.describe('binary commands').addBatch({
         deleteFile('styles.min.css');
         deleteFile('styles.min.css.map');
       }
-    }),
-    'output file for existing map in different folder': binaryContext('--source-map -o ./styles-relative.min.css ./test/fixtures/source-maps/relative.css', {
+    })
+  })
+  .addBatch({
+    'source maps - output file for existing map in different folder': binaryContext('--source-map -o ./styles-relative.min.css ./test/fixtures/source-maps/relative.css', {
       'includes right content in map file': function () {
         var sourceMap = new SourceMapConsumer(readFile('./styles-relative.min.css.map'));
         assert.deepEqual(
@@ -441,9 +509,11 @@ exports.commandsSuite = vows.describe('binary commands').addBatch({
         deleteFile('styles-relative.min.css');
         deleteFile('styles-relative.min.css.map');
       }
-    }),
-    'output file with root path': binaryContext('--source-map -o ./reset-root.min.css -r ./test ./test/fixtures/reset.css', {
-      'includes map in minified file': function() {
+    })
+  })
+  .addBatch({
+    'source maps - output file with root path': binaryContext('--source-map -o ./reset-root.min.css -r ./test ./test/fixtures/reset.css', {
+      'includes map in minified file': function () {
         assert.include(readFile('./reset-root.min.css'), '/*# sourceMappingURL=reset-root.min.css.map */');
       },
       'creates a map file': function () {
@@ -465,8 +535,10 @@ exports.commandsSuite = vows.describe('binary commands').addBatch({
         deleteFile('reset-root.min.css');
         deleteFile('reset-root.min.css.map');
       }
-    }),
-    'with input source map': binaryContext('--source-map -o ./import.min.css ./test/fixtures/source-maps/import.css', {
+    })
+  })
+  .addBatch({
+    'source maps - with input source map': binaryContext('--source-map -o ./import.min.css ./test/fixtures/source-maps/import.css', {
       'includes map in minified file': function () {
         assert.include(readFile('./import.min.css'), '/*# sourceMappingURL=import.min.css.map */');
       },
@@ -481,8 +553,10 @@ exports.commandsSuite = vows.describe('binary commands').addBatch({
         deleteFile('import.min.css');
         deleteFile('import.min.css.map');
       }
-    }),
-    'with input source map and source 1inlining': binaryContext('--source-map --source-map-inline-sources -o ./import-inline.min.css ./test/fixtures/source-maps/import.css', {
+    })
+  })
+  .addBatch({
+    'source maps - with input source map and source 1inlining': binaryContext('--source-map --source-map-inline-sources -o ./import-inline.min.css ./test/fixtures/source-maps/import.css', {
       'includes map in minified file': function () {
         assert.include(readFile('./import-inline.min.css'), '/*# sourceMappingURL=import-inline.min.css.map */');
       },
@@ -498,17 +572,19 @@ exports.commandsSuite = vows.describe('binary commands').addBatch({
         deleteFile('import-inline.min.css.map');
       }
     })
-  },
-  'semantic merging': {
-    'disabled': pipedContext('.a{margin:0}.b{margin:10px;padding:0}.c{margin:0}', '', {
-      'should output right data': function(error, stdout) {
-        assert.equal(stdout, '.a{margin:0}.b{margin:10px;padding:0}.c{margin:0}');
-      }
-    }),
-    'enabled': pipedContext('.a{margin:0}.b{margin:10px;padding:0}.c{margin:0}', '--semantic-merging', {
-      'should output right data': function(error, stdout) {
-        assert.equal(stdout, '.a,.c{margin:0}.b{margin:10px;padding:0}');
-      }
-    })
-  }
-});
+  })
+  .addBatch({
+    'semantic merging': {
+      'disabled': pipedContext('.a{margin:0}.b{margin:10px;padding:0}.c{margin:0}', '', {
+        'should output right data': function (error, stdout) {
+          assert.equal(stdout, '.a{margin:0}.b{margin:10px;padding:0}.c{margin:0}');
+        }
+      }),
+      'enabled': pipedContext('.a{margin:0}.b{margin:10px;padding:0}.c{margin:0}', '--semantic-merging', {
+        'should output right data': function (error, stdout) {
+          assert.equal(stdout, '.a,.c{margin:0}.b{margin:10px;padding:0}');
+        }
+      })
+    }
+  })
+  .export(module);