Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

adding all the tests

  • Loading branch information...
commit f46f6996640df1a4912b06b2e059a2fb8e0cde75 1 parent a741f4e
@michaelficarra authored
View
2  README.md
@@ -80,7 +80,7 @@ Appends the given string to the string being scanned.
ss.concat(" ghi789") // #<StringScanner 0/20 @ "abc12..."
ss.checkUntil(/h/) // "abc123 def456 gh"
-### eos / endOfstring
+### eos / endOfString
Returns `true` if the scan pointer is at the end of the string being scanned,
`false` otherwise.
View
16 lib/StringScanner.js
@@ -3,6 +3,7 @@
StringScanner = (function() {
function StringScanner(str) {
this.str = str != null ? str : '';
+ this.str = '' + this.str;
this.pos = 0;
this.lastMatch = {
reset: function() {
@@ -35,17 +36,22 @@
patternPos = this.str.substr(this.pos).search(pattern);
if (patternPos < 0) {
this.lastMatch.reset();
- null;
+ return null;
}
matches = this.str.substr(this.pos + patternPos).match(pattern);
this.lastMatch.captures = matches.slice(1);
return this.lastMatch.str = this.str.substr(this.pos, patternPos) + matches[0];
};
StringScanner.prototype.clone = function() {
- var clone;
+ var clone, prop, value, _ref;
clone = new this.constructor(this.str);
clone.pos = this.pos;
- clone.lastMatch = this.lastMatch;
+ clone.lastMatch = {};
+ _ref = this.lastMatch;
+ for (prop in _ref) {
+ value = _ref[prop];
+ clone.lastMatch[prop] = value;
+ }
return clone;
};
StringScanner.prototype.concat = function(str) {
@@ -114,7 +120,7 @@
StringScanner.prototype.scan = function(pattern) {
var chk;
chk = this.check(pattern);
- if (chk == null) {
+ if (chk != null) {
this.pos += chk.length;
}
return chk;
@@ -122,7 +128,7 @@
StringScanner.prototype.scanUntil = function(pattern) {
var chk;
chk = this.checkUntil(pattern);
- if (chk == null) {
+ if (chk != null) {
this.pos += chk.length;
}
return chk;
View
10 src/StringScanner.coffee
@@ -1,6 +1,7 @@
class StringScanner
constructor: (@str = '') ->
+ @str = '' + @str
@pos = 0
@lastMatch = {
reset: ->
@@ -27,7 +28,7 @@ class StringScanner
patternPos = @str.substr(@pos).search pattern
if patternPos < 0
@lastMatch.reset()
- null
+ return null
matches = @str.substr(@pos+patternPos).match pattern
@lastMatch.captures = matches.slice 1
@lastMatch.str = @str.substr(@pos,patternPos) + matches[0]
@@ -35,7 +36,8 @@ class StringScanner
clone: ->
clone = new @constructor(@str)
clone.pos = @pos
- clone.lastMatch = @lastMatch
+ clone.lastMatch = {}
+ clone.lastMatch[prop] = value for prop, value of @lastMatch
clone
concat: (str) ->
@@ -88,12 +90,12 @@ class StringScanner
scan: (pattern) ->
chk = @check pattern
- this.pos += chk.length unless chk?
+ this.pos += chk.length if chk?
chk
scanUntil: (pattern) ->
chk = @checkUntil pattern
- this.pos += chk.length unless chk?
+ this.pos += chk.length if chk?
chk
skip: (pattern) ->
View
278 test/test.coffee
@@ -0,0 +1,278 @@
+StringScanner = require '../lib/StringScanner'
+assert = require 'assert'
+[eq, ok] = [assert.strictEqual, assert.ok]
+
+arrayEqual = (a, b) ->
+ if a is b
+ # 0 isnt -0
+ a isnt 0 or 1/a is 1/b
+ else if a instanceof Array and b instanceof Array
+ return no unless a.length is b.length
+ return no for el, idx in a when not arrayEqual el, b[idx]
+ yes
+ else
+ # NaN is NaN
+ a isnt a and b isnt b
+
+arrayEq = (a, b, msg) -> ok arrayEqual(a, b), msg
+
+test = (feature, fn) -> fn new StringScanner 'abc123 def456'
+
+console.log '\033[0m(' + new Date().toLocaleTimeString() + ') Running tests...\033[0;31m'
+
+
+test 'StringScanner::bol and StringScanner::beginningOfLine', (ss) ->
+ # beginning of string
+ eq true , ss.bol()
+ eq true , ss.beginningOfLine()
+ # neither
+ ss.getch()
+ eq false, ss.bol()
+ eq false, ss.beginningOfLine()
+ # beginning of string after returning false
+ ss.reset()
+ eq true , ss.bol()
+ eq true , ss.beginningOfLine()
+ # beginning of line
+ ss = new StringScanner 'abc\ndef'
+ ss.scan /\w{3}\n/
+ eq true , ss.bol()
+ eq true , ss.beginningOfLine()
+
+test 'StringScanner::captures', (ss) ->
+ # reports multiple captures correctly
+ ss.scan /([a-z]+)\d+(\s*)/
+ arrayEq ['abc', ' '], ss.captures()
+ # a successful match with no capturing groups produces `[]`
+ ss.scan /[a-z]+\d+/
+ arrayEq [], ss.captures()
+ # unsuccessful match produces `[]`
+ eq null, ss.check /(\s+)/
+ arrayEq [], ss.captures()
+ # captures work as expected after a reset
+ ss.reset()
+ ss.check /.*(..) (..)/
+ arrayEq ['23', 'de'], ss.captures()
+
+test 'StringScanner::check', (ss) ->
+ eq 'abc' , ss.check /[a-z]+/i
+ eq 'abc' , ss.check /[a-z]+/i
+ eq 'abc' , ss.scan /[a-z]+/i
+ eq null , ss.check /[a-z]+/i
+ eq '123 ', ss.check /[\d\s]+/
+
+test 'StringScanner::checkUntil', (ss) ->
+ eq 'abc123 ', ss.checkUntil /\s/
+ # does not advance pointer
+ eq 'abc123 ', ss.checkUntil /\s/
+ # produces `null` on unsuccessful match
+ eq null , ss.checkUntil /r/
+ # only looks from pointer position
+ ss.scanUntil /e/
+ eq null , ss.checkUntil /\s/
+
+test 'StringScanner::clone', (ss) ->
+ ss.scan /([a-z])[a-z]+/
+ eq 'abc', ss.match()
+ arrayEq ['a'], ss.captures()
+ clone0 = ss.clone()
+ eq 'abc', clone0.match()
+ arrayEq ['a'], clone0.captures()
+ ss.scan /\d+(\d)/
+ eq '123', ss.match()
+ arrayEq ['3'], ss.captures()
+ eq 'abc', clone0.match()
+ arrayEq ['a'], clone0.captures()
+ clone1 = ss.clone()
+ clone1.scan /\s+/
+ eq '123', ss.match()
+ arrayEq ['3'], ss.captures()
+ eq 'abc', clone0.match()
+ arrayEq ['a'], clone0.captures()
+ eq ' ', clone1.match()
+ arrayEq [], clone1.captures()
+
+test 'StringScanner::concat', (ss) ->
+ eq null, ss.checkUntil /h/
+ ss.concat ' ghi789'
+ eq 'abc123 def456 ghi789', ss.string()
+
+test 'StringScanner::eos and StringScanner::endOfString', (ss) ->
+ eq ss.eos, ss.endOfString
+ eq false, ss.eos()
+ ss.scan /.*/
+ eq true , ss.eos()
+ ss.reset()
+ eq false, ss.eos()
+
+test 'StringScanner::exists and StringScanner::exist', (ss) ->
+ eq ss.exists, ss.exist
+ eq 2 , ss.exists /c/
+ eq 'c' , ss.match()
+ eq true , ss.matched()
+ eq 0 , ss.exists /a/
+ eq 'a' , ss.match()
+ eq true , ss.matched()
+ eq 0 , ss.exists /b*/
+ eq '' , ss.match()
+ eq true , ss.matched()
+ eq null , ss.exists /m/
+ eq null , ss.match()
+ eq false, ss.matched()
+
+test 'StringScanner::getch and StringScanner::getChar', (ss) ->
+ eq ss.getch, ss.getChar
+ eq 'a' , ss.getch()
+ eq 'b' , ss.getch()
+ ss.scan /.*/
+ eq null, ss.getch()
+ ss.reset()
+ eq 'a' , ss.getch()
+
+test 'StringScanner::match', (ss) ->
+ eq null , ss.match()
+ ss.scan /[a-z]+/i
+ eq 'abc', ss.match()
+ ss.scan /[a-z]+/i
+ eq null , ss.match()
+
+test 'StringScanner::matches', (ss) ->
+ eq 3 , ss.matches /[a-z]+/i
+ eq 3 , ss.matches /[a-z]+/i
+ ss.scan /[a-z]+/i
+ eq null, ss.matches /[a-z]+/i
+ eq 4 , ss.matches /\d+\s*/i
+
+test 'StringScanner::matched', (ss) ->
+ eq false, ss.matched()
+ ss.scan /\w+/
+ eq true , ss.matched()
+ ss.scan /\w+/
+ eq false, ss.matched()
+
+test 'StringScanner::matchSize', (ss) ->
+ eq null, ss.matchSize()
+ ss.scan /\w+/
+ eq 6, ss.matchSize()
+ ss.check /\w*/
+ eq 0, ss.matchSize()
+ ss.check /\w+/
+ eq null, ss.matchSize()
+
+test 'StringScanner::peek', (ss) ->
+ eq 'ab', ss.peek 2
+ eq '', ss.peek 0
+ eq '', ss.peek -3
+ eq ss.string(), ss.peek()
+ ss.scan /.*d/
+ eq 'ef4', ss.peek 3
+ eq 'ef456', ss.peek()
+ eq 'ef456', ss.peek 9001
+ eq '', ss.peek 0
+ eq '', ss.peek -1
+
+test 'StringScanner::pointer and StringScanner::position', (ss) ->
+ eq ss.pointer, ss.position
+ eq 0, ss.pointer()
+ ss.scan /\w+\d+\s+/i
+ eq 7, ss.pointer()
+ ss.scan /[a-z]+/i
+ eq 10, ss.pointer()
+ ss.reset()
+ eq 0, ss.pointer()
+
+test 'StringScanner::setPointer', (ss) ->
+ eq 0 , ss.pointer()
+ eq 4 , ss.setPointer 4
+ eq 4 , ss.pointer()
+ ss.getch()
+ eq 5 , ss.pointer()
+ eq 0 , ss.setPointer -3
+ eq 0 , ss.pointer()
+ eq 13, ss.setPointer 9001
+ eq 13, ss.pointer()
+
+test 'StringScanner::reset', (ss) ->
+ ss.scan /\w+/
+ eq 'abc123', ss.match()
+ eq true , ss.matched()
+ eq 6 , ss.matchSize()
+ eq 6 , ss.pointer()
+ ss.reset()
+ eq null , ss.match()
+ eq false , ss.matched()
+ eq null , ss.matchSize()
+ eq 0 , ss.pointer()
+ ok ss.check /\w+/
+
+test 'StringScanner::rest', (ss) ->
+ eq ss.string(), ss.rest()
+ ss.scanUntil /\s/
+ eq 'def456' , ss.rest()
+ ss.reset()
+ eq ss.string(), ss.rest()
+ ss.setPointer 12
+ eq '6' , ss.rest()
+
+test 'StringScanner::scan', (ss) ->
+ eq 'abc' , ss.scan /[a-z]+/
+ eq null , ss.scan /[a-z]+/
+ eq '' , ss.scan /[a-z]*/
+ eq '123' , ss.scan /[0-9]+/
+ ss.check /\s+/
+ eq ' ' , ss.scan /\s+/
+ eq 'def456', ss.scan /.*/
+ eq '' , ss.scan /.*/
+ eq null , ss.scan /./
+
+test 'StringScanner::scanUntil', (ss) ->
+ eq 'abc1' , ss.scanUntil /\d/
+ eq 4 , ss.position()
+ eq '23 ' , ss.scanUntil /\s/
+ eq 7 , ss.position()
+ eq null , ss.scanUntil /z/
+ eq '' , ss.scanUntil /(?:)/
+ eq '' , ss.scanUntil()
+ eq 7 , ss.position()
+ eq 'def456', ss.scanUntil /$/
+ ok ss.eos()
+
+test 'StringScanner::skip', (ss) ->
+ eq 3 , ss.skip /[a-z]+/
+ eq 0 , ss.skip /[a-z]*/
+ eq null, ss.skip /[a-z]+/
+ eq 3 , ss.position()
+ eq 4 , ss.skip /(\d|\s)+/
+ eq 7 , ss.position()
+ eq 6 , ss.skip /.*/
+ ok ss.eos()
+
+test 'StringScanner::skipUntil', (ss) ->
+ eq 0 , ss.position()
+ eq 7 , ss.skipUntil /\s/
+ eq 7 , ss.position()
+ eq 3 , ss.skipUntil /f/
+ eq null, ss.skipUntil /f/
+ eq 3 , ss.skipUntil /$/
+ ok ss.eos()
+
+test 'StringScanner::string', (ss) ->
+ eq 'abc123 def456', ss.string()
+ eq '', (new StringScanner '').string()
+ eq 'abc', (new StringScanner 'abc').string()
+ eq '', (new StringScanner null).string()
+ eq '', (new StringScanner undefined).string()
+ eq '0', (new StringScanner 0).string()
+
+test 'StringScanner::terminate and StringScanner::clear', (ss) ->
+ eq ss.terminate, ss.clear
+ eq 0, ss.pointer()
+ ss.terminate()
+ ok ss.eos()
+ ss.reset()
+ eq 0, ss.pointer()
+ ss.terminate()
+ ok ss.eos()
+
+
+console.log '\033[0;32mall tests passed\033[0m'
Please sign in to comment.
Something went wrong with that request. Please try again.