mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
201 lines
4.8 KiB
JavaScript
201 lines
4.8 KiB
JavaScript
// Handles the job of waiting until text is seen that matches a
|
|
// regular expression.
|
|
import { makeFulfillablePromise } from '../utils/fiber-helpers.js';
|
|
import TestFailure from './test-failure.js';
|
|
import { Console } from '../console/console.js';
|
|
|
|
export default class Matcher {
|
|
constructor(run) {
|
|
this.buf = "";
|
|
this.fullBuffer = "";
|
|
this.ended = false;
|
|
this.resetMatch();
|
|
this.run = run; // used only to set a field on exceptions
|
|
this.endPromise = new Promise((resolve) => {
|
|
this.resolveEndPromise = resolve;
|
|
});
|
|
}
|
|
|
|
async write(data) {
|
|
this.buf += data;
|
|
this.fullBuffer += data;
|
|
await this._tryMatch();
|
|
}
|
|
|
|
getFullBuffer() {
|
|
return this.fullBuffer;
|
|
}
|
|
|
|
resetMatch() {
|
|
const mp = this.matchPromise;
|
|
|
|
this.matchPattern = null;
|
|
this.matchPromise = null;
|
|
this.matchStrict = null;
|
|
this.matchFullBuffer = false;
|
|
|
|
return mp;
|
|
}
|
|
|
|
setMatchStrict(strict) {
|
|
this.matchStrict = strict;
|
|
}
|
|
|
|
rejectMatch(error) {
|
|
const mp = this.resetMatch();
|
|
if (mp) {
|
|
mp.reject(error);
|
|
} else {
|
|
// If this.matchPromise was not defined, we should not swallow this
|
|
// error, so we must throw it instead.
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
resolveMatch(value) {
|
|
const mp = this.resetMatch();
|
|
if (mp) {
|
|
mp.resolve(value);
|
|
}
|
|
}
|
|
|
|
match(pattern, timeout, strict) {
|
|
return this.matchAsync(pattern, { timeout, strict });
|
|
}
|
|
|
|
// Like match, but returns a Promise without calling .await().
|
|
async matchAsync(pattern, {
|
|
timeout = null,
|
|
strict = false,
|
|
matchFullBuffer = false,
|
|
}) {
|
|
if (this.matchPromise) {
|
|
return Promise.reject(new Error("already have a match pending?"));
|
|
}
|
|
this.matchPattern = pattern;
|
|
this.matchStrict = strict;
|
|
this.matchFullBuffer = matchFullBuffer;
|
|
const mp = this.matchPromise = makeFulfillablePromise();
|
|
await this._tryMatch(); // could clear this.matchPromise
|
|
|
|
let timer = null;
|
|
if (timeout) {
|
|
const failure = new TestFailure('match-timeout', {
|
|
run: this.run,
|
|
pattern: this.matchPattern,
|
|
});
|
|
|
|
timer = setTimeout(() => {
|
|
this.rejectMatch(failure);
|
|
}, timeout * 1000);
|
|
} else {
|
|
return mp;
|
|
}
|
|
|
|
return mp.then(
|
|
(result) => {
|
|
clearTimeout(timer);
|
|
return result;
|
|
},
|
|
(error) => {
|
|
clearTimeout(timer);
|
|
throw error;
|
|
}
|
|
);
|
|
}
|
|
|
|
matchBeforeEnd(pattern, timeout) {
|
|
return this._beforeEnd(() => this.matchAsync(pattern, {
|
|
timeout: timeout || 15,
|
|
matchFullBuffer: true,
|
|
}));
|
|
}
|
|
|
|
_beforeEnd(promiseCallback) {
|
|
this.endPromise = this.endPromise.then(promiseCallback);
|
|
return this.endPromise;
|
|
}
|
|
|
|
end() {
|
|
return this.endAsync();
|
|
}
|
|
|
|
endAsync() {
|
|
this.resolveEndPromise();
|
|
return this._beforeEnd(async () => {
|
|
this.ended = true;
|
|
this._tryMatch();
|
|
return this.matchPromise;
|
|
});
|
|
}
|
|
|
|
matchEmpty() {
|
|
if (this.buf.length > 0) {
|
|
Console.info("Extra junk is :", this.buf);
|
|
throw new TestFailure('junk-at-end', { run: this.run });
|
|
}
|
|
}
|
|
|
|
async _tryMatch() {
|
|
const mp = this.matchPromise;
|
|
if (! mp) {
|
|
return;
|
|
}
|
|
|
|
let ret = null;
|
|
|
|
if (this.matchFullBuffer) {
|
|
// Note: this.matchStrict is ignored if this.matchFullBuffer truthy.
|
|
if (this.matchPattern instanceof RegExp) {
|
|
ret = this.fullBuffer.match(this.matchPattern);
|
|
} else if (this.fullBuffer.indexOf(this.matchPattern) >= 0) {
|
|
ret = this.matchPattern;
|
|
}
|
|
} else if (this.matchPattern instanceof RegExp) {
|
|
const m = this.buf.match(this.matchPattern);
|
|
if (m) {
|
|
if (this.matchStrict && m.index !== 0) {
|
|
Console.info("Extra junk is: ", this.buf.substr(0, m.index));
|
|
this.rejectMatch(new TestFailure('junk-before', {
|
|
run: this.run,
|
|
pattern: this.matchPattern,
|
|
}));
|
|
return;
|
|
}
|
|
ret = m;
|
|
this.buf = this.buf.slice(m.index + m[0].length);
|
|
}
|
|
} else {
|
|
const i = this.buf.indexOf(this.matchPattern);
|
|
if (i !== -1) {
|
|
if (this.matchStrict && i !== 0) {
|
|
Console.info("Extra junk is: ", this.buf.substr(0, i));
|
|
this.rejectMatch(new TestFailure('junk-before', {
|
|
run: this.run,
|
|
pattern: this.matchPattern,
|
|
}));
|
|
return;
|
|
}
|
|
ret = this.matchPattern;
|
|
this.buf = this.buf.slice(i + this.matchPattern.length);
|
|
}
|
|
}
|
|
|
|
if (ret !== null) {
|
|
this.resolveMatch(ret);
|
|
return;
|
|
}
|
|
|
|
if (this.ended) {
|
|
this.rejectMatch(new TestFailure('no-match', {
|
|
run: this.run,
|
|
pattern: this.matchPattern,
|
|
}));
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
import { markThrowingMethods } from "./test-utils.js";
|
|
markThrowingMethods(Matcher.prototype);
|