├── .gitignore ├── .travis.yml ├── cli.js ├── LICENSE ├── package.json ├── index.js ├── readme.markdown └── test.ls /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - node 4 | - lts/* 5 | -------------------------------------------------------------------------------- /cli.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var tapMerge = require("./index.js"); 3 | process.stdin 4 | .pipe(tapMerge()) 5 | .pipe(process.stdout); 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, An 2 | 3 | Permission to use, copy, modify, and/or distribute this software for any 4 | purpose with or without fee is hereby granted, provided that the above 5 | copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tap-merge", 3 | "version": "0.3.1", 4 | "description": "Merge multiple TAP streams into one", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "lsc test.ls", 8 | "test-readme": "txm readme.markdown" 9 | }, 10 | "bin": { 11 | "tap-merge": "./cli.js" 12 | }, 13 | "files": [ 14 | "index.js", 15 | "cli.js" 16 | ], 17 | "repository": "anko/tap-merge", 18 | "bugs": "https://github.com/anko/tap-merge/issues", 19 | "keywords": [ 20 | "TAP", 21 | "Test Anything Protocol", 22 | "merge", 23 | "stream" 24 | ], 25 | "author": "Antti Korpi ", 26 | "license": "ISC", 27 | "dependencies": { 28 | "highland": "^2.5.1" 29 | }, 30 | "devDependencies": { 31 | "livescript": "^1.4.0", 32 | "concat-stream": "^1.4.8", 33 | "event-stream": "^3.3.0", 34 | "multistream": "^2.0.2", 35 | "tape": "^4.0.0", 36 | "tests-ex-markdown": "^2.0.0", 37 | "through2": "^2.0.0" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var _ = require("highland"); 4 | 5 | module.exports = function() { 6 | 7 | var plan = { start : 0, end : 0 }; 8 | var previousId = 0; 9 | var seenFirstVersionHeader = false; 10 | 11 | return _.pipeline(_.split(), 12 | _.map(renumber), 13 | _.reject(isNull), 14 | _.consume(addFinalPlan), 15 | _.intersperse("\n"), 16 | _.append("\n")); 17 | 18 | function renumber(line) { 19 | 20 | var match; 21 | 22 | // Matches assert 23 | if (match = line.match(/^((?:not )?ok)(?:\s+(\d+))?\s+(.*)$/)) { 24 | 25 | var okString = match[1]; 26 | var id = parseInt(match[2], 10); 27 | var rest = match[3]; 28 | var nextId = ++previousId; 29 | return okString + " " + nextId + " " + rest; 30 | 31 | // Matches plan 32 | } else if (match = line.match(/^(\d+)..(\d+)$/)) { 33 | 34 | var start = parseInt(match[1], 10); 35 | var end = parseInt(match[2], 10); 36 | plan.start = start; 37 | plan.end += end; 38 | nextId = start; 39 | return null; 40 | 41 | // Matches version header 42 | } else if (line === "TAP version 13") { 43 | 44 | if ( ! seenFirstVersionHeader ) { 45 | seenFirstVersionHeader = true; 46 | return line; 47 | } else return null; 48 | 49 | } else return line; // Everything else: passthrough 50 | } 51 | 52 | function addFinalPlan(err, x, push, next) { 53 | if (err) { 54 | push(err); 55 | next(); 56 | } else if (x === _.nil) { // Ended 57 | push(null, "" + (plan.start || 0) + ".." + plan.end); 58 | push(null, x); 59 | } else { 60 | push(null, x); 61 | next(); 62 | } 63 | } 64 | 65 | function isNull(line) { return line === null } 66 | }; 67 | -------------------------------------------------------------------------------- /readme.markdown: -------------------------------------------------------------------------------- 1 | # tap-merge [![Travis CI status](https://img.shields.io/travis/anko/tap-merge.svg?style=flat-square)][1] [![npm package version](https://img.shields.io/npm/v/tap-merge.svg?style=flat-square)][2] 2 | 3 | Merge [TAP 13][3] streams. 4 | 5 | Re-numbers tests and test plans to remove conflicts. The test plan (e.g. 6 | `1..5`) line is emitted last. Can be used from the command line or as a 7 | module. Streams everything, so it can process concurrently with the TAP 8 | producers. 9 | 10 | Only asserts, plans and the version header lines are parsed. Everything else 11 | is left alone, so extras like YAML blocks or subtests will work. 12 | 13 | ## CLI usage 14 | 15 | cat <(tapProducer1) <(tapProducer2) | tap-merge 16 | 17 | or otherwise concatenate two TAP streams and feed them on `stdin` to 18 | `tap-merge`. 19 | 20 | ## Module usage 21 | 22 | ```js 23 | var tapMerge = require("tap-merge"); 24 | process.stdin // or any readable stream 25 | .pipe(tapMerge()) 26 | .pipe(process.stdout); // or any writable stream 27 | ``` 28 | 29 | If you want to give it multiple streams one after the other, use a module like 30 | [multistream][4]. 31 | 32 | ## Example 33 | 34 | 35 | 36 | Input (two TAP streams, one after the other): 37 | 38 | 39 | 40 | TAP version 13 41 | 1..3 42 | # first test 43 | ok 1 - yep 44 | # second test 45 | ok 2 - yep 46 | # third test 47 | ok 3 - yep 48 | 49 | TAP version 13 50 | 1..2 51 | not ok 1 - fail 52 | ok 2 - just fine 53 | 54 | Output (one TAP stream; conflicts resolved): 55 | 56 | 57 | 58 | TAP version 13 59 | # first test 60 | ok 1 - yep 61 | # second test 62 | ok 2 - yep 63 | # third test 64 | ok 3 - yep 65 | 66 | not ok 4 - fail 67 | ok 5 - just fine 68 | 1..5 69 | 70 | ## Limitations 71 | 72 | Doesn't do validation. Provide valid input. 73 | 74 | ## License 75 | 76 | [ISC][5]. 77 | 78 | [1]: https://travis-ci.org/anko/tap-merge 79 | [2]: https://www.npmjs.com/package/tap-merge 80 | [3]: https://testanything.org/tap-version-13-specification.html 81 | [4]: https://www.npmjs.com/package/multistream 82 | [5]: http://en.wikipedia.org/wiki/ISC_license 83 | -------------------------------------------------------------------------------- /test.ls: -------------------------------------------------------------------------------- 1 | test = require \tape 2 | tap-merge = require \./index.js 3 | through = require \through2 4 | concat = require \concat-stream 5 | es = require \event-stream 6 | multistream = require \multistream 7 | 8 | # Create a dummy stream for given output 9 | test-stream = (output) -> 10 | through! 11 | ..push output 12 | ..push null 13 | 14 | empty-tap = -> test-stream do 15 | """ 16 | TAP version 13 17 | 0..0 18 | """ 19 | tap1 = -> test-stream do 20 | """ 21 | TAP version 13 22 | 1..1 23 | # Hi there 24 | ok 1 - what 25 | """ 26 | tap2 = -> test-stream do 27 | """ 28 | TAP version 13 29 | 1..2 30 | # Hello again 31 | ok 1 - what 32 | # Hello again 33 | ok 2 - what else 34 | """ 35 | tap2-no-descriptions = -> test-stream do 36 | """ 37 | TAP version 13 38 | 1..2 39 | ok 1 - one 40 | ok 2 - two 41 | """ 42 | tap2-fail = -> test-stream do 43 | """ 44 | TAP version 13 45 | 1..2 46 | # Hello again 47 | ok 1 - what 48 | # Hello again 49 | not ok 2 - FAIL 50 | """ 51 | tap2-stuff = -> test-stream do 52 | """ 53 | TAP version 13 54 | 1..2 55 | # Hello again 56 | ok 1 - what 57 | --- 58 | message: "Failed somewhere" 59 | --- 60 | # Hello again 61 | ok 2 - what else 62 | 1..2 63 | ok 1 - yep 64 | ok 2 - yep2 65 | """ 66 | 67 | test "empty stream" (t) -> 68 | t.plan 1 69 | empty-tap! 70 | .pipe tap-merge! 71 | .pipe concat (output) -> 72 | t.equals do 73 | output.to-string!trim! 74 | """ 75 | TAP version 13 76 | 0..0 77 | """ 78 | t.end! 79 | 80 | test "single stream passthrough" (t) -> 81 | t.plan 1 82 | tap1! 83 | .pipe tap-merge! 84 | .pipe concat (output) -> 85 | t.equals do 86 | output.to-string!trim! 87 | """ 88 | TAP version 13 89 | # Hi there 90 | ok 1 - what 91 | 1..1 92 | """ 93 | t.end! 94 | 95 | test "single stream passthrough with yaml and child tests" (t) -> 96 | t.plan 1 97 | tap2-stuff! 98 | .pipe tap-merge! 99 | .pipe concat (output) -> 100 | t.equals do 101 | output.to-string!trim! 102 | """ 103 | TAP version 13 104 | # Hello again 105 | ok 1 - what 106 | --- 107 | message: "Failed somewhere" 108 | --- 109 | # Hello again 110 | ok 2 - what else 111 | 1..2 112 | ok 1 - yep 113 | ok 2 - yep2 114 | 1..2 115 | """ 116 | t.end! 117 | 118 | test "single stream passthrough with no descriptions" (t) -> 119 | t.plan 1 120 | tap2-no-descriptions! 121 | .pipe tap-merge! 122 | .pipe concat (output) -> 123 | t.equals do 124 | output.to-string!trim! 125 | """ 126 | TAP version 13 127 | ok 1 - one 128 | ok 2 - two 129 | 1..2 130 | """ 131 | t.end! 132 | 133 | test "two streams passthrough" (t) -> 134 | t.plan 1 135 | c = multistream [ 136 | tap2! 137 | test-stream "\n" 138 | tap2! 139 | ] 140 | 141 | c 142 | .pipe tap-merge! 143 | .pipe concat (output) -> 144 | t.equals do 145 | output.to-string!trim! 146 | """ 147 | TAP version 13 148 | # Hello again 149 | ok 1 - what 150 | # Hello again 151 | ok 2 - what else 152 | # Hello again 153 | ok 3 - what 154 | # Hello again 155 | ok 4 - what else 156 | 1..4 157 | """ 158 | t.end! 159 | 160 | test "two streams passthrough (first fails one)" (t) -> 161 | t.plan 1 162 | c = multistream [ 163 | tap2-fail! 164 | test-stream "\n" 165 | tap2! 166 | ] 167 | 168 | c 169 | .pipe tap-merge! 170 | .pipe concat (output) -> 171 | t.equals do 172 | output.to-string!trim! 173 | """ 174 | TAP version 13 175 | # Hello again 176 | ok 1 - what 177 | # Hello again 178 | not ok 2 - FAIL 179 | # Hello again 180 | ok 3 - what 181 | # Hello again 182 | ok 4 - what else 183 | 1..4 184 | """ 185 | t.end! 186 | 187 | test "writing to tapMerge using .write and .end works" (t) -> 188 | t.plan 1 189 | tap-merge! 190 | ..pipe concat (output) -> 191 | t.equals do 192 | output.to-string!trim! 193 | """ 194 | TAP version 13 195 | ok 1 - hi 196 | 1..1 197 | """ 198 | t.end! 199 | ..write 'TAP version 13\n' 200 | ..write 'ok 1 - hi\n' 201 | ..write '1..1' 202 | ..end! 203 | --------------------------------------------------------------------------------