Skip to content

Commit 493b4a5

Browse files
committed
Add rules test
1 parent 3ce1404 commit 493b4a5

File tree

4 files changed

+168
-4
lines changed

4 files changed

+168
-4
lines changed

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "test/rules"]
2+
path = test/rules
3+
url = https://github.com/SimpleRegex/Test-Rules

lib/Builder.js

+7-4
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const SyntaxException = require('./Exceptions/Syntax')
44
const BuilderException = require('./Exceptions/Builder')
55
const ImplementationException = require('./Exceptions/Implementation')
66

7-
const NON_LITERAL_CHARACTERS = '[\\^$.|?*+()'
7+
const NON_LITERAL_CHARACTERS = '[\\^$.|?*+()/'
88
const METHOD_TYPE_BEGIN = 0b00001
99
const METHOD_TYPE_CHARACTER = 0b00010
1010
const METHOD_TYPE_GROUP = 0b00100
@@ -247,7 +247,7 @@ class Builder {
247247
ifNotFollowedBy(conditions) {
248248
this._validateAndAddMethodType(METHOD_TYPE_GROUP, METHOD_TYPES_ALLOWED_FOR_CHARACTERS)
249249

250-
return this._addClosure(new Builder()._extends('(?!=%s)'), conditions)
250+
return this._addClosure(new Builder()._extends('(?!%s)'), conditions)
251251
}
252252

253253
/**
@@ -347,12 +347,13 @@ class Builder {
347347
const chars = '+*}?'
348348
const raw = this.getRawRegex()
349349
const last = raw.substr(-1)
350+
const lastMethodType = this._lastMethodType
350351
this._lastMethodType = METHOD_TYPE_QUANTIFIER
351352

352-
353353
if (!chars.includes(last)) {
354354
if (last === ')' && chars.includes(raw.substr(-2, 1))) {
355-
return this.add('?')
355+
const target = lastMethodType === METHOD_TYPE_GROUP ? this._revertLast().slice(0, -1) + '?)' : '?'
356+
return this.add(target)
356357
}
357358

358359
throw new ImplementationException('Cannot apply laziness at this point. Only applicable after quantifier.')
@@ -539,6 +540,8 @@ class Builder {
539540
* @return {Builder}
540541
*/
541542
_addUniqueModifier(modifier) {
543+
this._result = null
544+
542545
if (!this._modifiers.includes(modifier)) {
543546
this._modifiers += modifier
544547
}

test/rules

Submodule rules added at 91a988c

test/rules-test.js

+157
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
'use strict'
2+
3+
const fs = require('fs')
4+
const path = require('path')
5+
const assert = require('assert')
6+
const SRL = require('../')
7+
8+
function testRules() {
9+
const rulesDir = path.resolve(__dirname, './rules')
10+
const files = fs.readdirSync(rulesDir)
11+
12+
files.forEach((file) => {
13+
// Ignore
14+
if (path.extname(file) !== '.rule') {
15+
return
16+
}
17+
18+
const lines = fs.readFileSync(path.join(rulesDir, file), { encoding: 'utf-8' }).split('\n')
19+
runAssertions(buildData(lines))
20+
})
21+
}
22+
23+
function applySpecialChars(target) {
24+
return target.replace('\\n', '\n').replace('\\t', '\t')
25+
}
26+
27+
function getExpression(srl, query) {
28+
return `\n\nSupplied SRL Query: ${srl}\nGenerated Expression: ${query.getRawRegex()}\n\n`
29+
}
30+
31+
function buildData(lines) {
32+
const data = {
33+
srl: null,
34+
matches: [],
35+
no_matches: [],
36+
captures: {}
37+
}
38+
let inCapture = false
39+
let captures = null // Remember captures' name and index.
40+
41+
lines.forEach((line) => {
42+
if (line === '' || line.startsWith('#')) {
43+
return
44+
}
45+
46+
if (inCapture && !line.startsWith('-')) {
47+
inCapture = false
48+
}
49+
50+
if (line.startsWith('srl: ')) {
51+
captures = []
52+
53+
data.srl = line.substr(5).replace(/as\s+"([^"]+)"/g, (s, c) => {
54+
captures.push(c)
55+
return ''
56+
})
57+
} else if (line.startsWith('match: "')) {
58+
data.matches.push(applySpecialChars(line.slice(8, -1)))
59+
} else if (line.startsWith('no match: "')) {
60+
data.no_matches.push(applySpecialChars(line.slice(11, -1)))
61+
} else if (
62+
line.startsWith('capture for "') &&
63+
line.substr(-2, 2) === '":'
64+
) {
65+
inCapture = line.slice(13, -2)
66+
data['captures'][inCapture] = []
67+
} else if (
68+
inCapture &&
69+
line.startsWith('-')
70+
) {
71+
const split = line.substr(1).split(': ')
72+
const index = captures.indexOf(split[1].trim())
73+
let target = data['captures'][inCapture][Number(split[0])]
74+
75+
if (!target) {
76+
target = data['captures'][inCapture][Number(split[0])] = []
77+
}
78+
79+
if (index !== -1) {
80+
target[index] = applySpecialChars(split[2].slice(1, -1))
81+
} else {
82+
target.push(applySpecialChars(split[2].slice(1, -1)))
83+
}
84+
}
85+
})
86+
87+
return data
88+
}
89+
90+
function runAssertions(data) {
91+
assert(data.srl, 'SRL for rule is empty. Invalid rule.')
92+
93+
let query, assertionMade = false
94+
95+
try {
96+
query = new SRL(data.srl)
97+
} catch (e) {
98+
assert(false, `Parser error: ${e.message}\n\nSupplied SRL Query: ${data.srl}\n\n`)
99+
}
100+
101+
data.matches.forEach((match) => {
102+
assert(
103+
query.test(match),
104+
`Failed asserting that this query matches '${match}'.${getExpression(data.srl, query)}`
105+
)
106+
assertionMade = true
107+
})
108+
109+
data.no_matches.forEach((noMatch) => {
110+
assert(
111+
!query.test(noMatch),
112+
`Failed asserting that this query does not match '${noMatch}'.${getExpression(data.srl, query)}`
113+
)
114+
assertionMade = true
115+
})
116+
117+
Object.keys(data.captures).forEach((test) => {
118+
const expected = data.captures[test]
119+
const matches = []
120+
const regex = query.all()
121+
122+
try {
123+
let result = null
124+
while (result = regex.exec(test)) {
125+
matches.push(result.map((item) => item === undefined ? '' : item).slice(1))
126+
127+
if (regex.lastIndex === test.length - 1) {
128+
break
129+
}
130+
}
131+
} catch (e) {
132+
assert(false, `Parser error: ${e.message}${getExpression(data.srl, query)}`)
133+
}
134+
135+
assert.equal(
136+
expected.length,
137+
matches.length,
138+
`Invalid match count for test ${test}.${getExpression(data.srl, query)}`
139+
)
140+
141+
matches.forEach((capture, index) => {
142+
assert.deepEqual(
143+
expected[index],
144+
capture,
145+
`The capture group did not return the expected results for test ${test}.${getExpression(data.srl, query)}`
146+
)
147+
})
148+
149+
assertionMade = true
150+
})
151+
152+
assert(assertionMade, `No assertion. Invalid rule. ${getExpression(data.srl, query)}`)
153+
}
154+
155+
describe('Rules', () => {
156+
testRules()
157+
})

0 commit comments

Comments
 (0)