summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-30 03:43:04 +0000
committermmenke@chromium.org <mmenke@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-03-30 03:43:04 +0000
commit7bb98c37de669e1e717650eaa20f5633d226ace2 (patch)
tree3d32c295610d27804b027ddf3c70c307b0d047df
parent1d89c16b9905ba786cb2ab691c55071b56ccd44b (diff)
downloadchromium_src-7bb98c37de669e1e717650eaa20f5633d226ace2.zip
chromium_src-7bb98c37de669e1e717650eaa20f5633d226ace2.tar.gz
chromium_src-7bb98c37de669e1e717650eaa20f5633d226ace2.tar.bz2
Extend about:net-internal's filter to treat text separated
by spaces as multiple filters, and "and" the results together. Also add support for quoted strings. BUG=224944 Review URL: https://codereview.chromium.org/13360002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@191492 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/resources/net_internals/events_view.js384
-rw-r--r--chrome/browser/resources/net_internals/log_view_painter.js26
-rw-r--r--chrome/browser/resources/net_internals/source_row.js35
-rw-r--r--chrome/test/data/webui/net_internals/events_view.js67
4 files changed, 277 insertions, 235 deletions
diff --git a/chrome/browser/resources/net_internals/events_view.js b/chrome/browser/resources/net_internals/events_view.js
index 0f70848..7341a90 100644
--- a/chrome/browser/resources/net_internals/events_view.js
+++ b/chrome/browser/resources/net_internals/events_view.js
@@ -174,169 +174,25 @@ var EventsView = (function() {
}
},
- /**
- * Looks for the first occurence of |directive|:parameter in |sourceText|.
- * Parameter can be an empty string.
- *
- * On success, returns an object with two fields:
- * |remainingText| - |sourceText| with |directive|:parameter removed,
- and excess whitespace deleted.
- * |parameter| - the parameter itself.
- *
- * On failure, returns null.
- */
- parseDirective_: function(sourceText, directive) {
- // Adding a leading space allows a single regexp to be used, regardless of
- // whether or not the directive is at the start of the string.
- sourceText = ' ' + sourceText;
- var regExp = new RegExp('\\s+' + directive + ':(\\S*)\\s*', 'i');
- var matchInfo = regExp.exec(sourceText);
- if (matchInfo == null)
- return null;
-
- return {'remainingText': sourceText.replace(regExp, ' ').trim(),
- 'parameter': matchInfo[1]};
- },
-
- /**
- * Just like parseDirective_, except can optionally be a '-' before or
- * the parameter, to negate it. Before is more natural, after
- * allows more convenient toggling.
- *
- * Returned value has the additional field |isNegated|, and a leading
- * '-' will be removed from |parameter|, if present.
- */
- parseNegatableDirective_: function(sourceText, directive) {
- var matchInfo = this.parseDirective_(sourceText, directive);
- if (matchInfo == null)
- return null;
-
- // Remove any leading or trailing '-' from the directive.
- var negationInfo = /^(-?)(\S*?)$/.exec(matchInfo.parameter);
- matchInfo.parameter = negationInfo[2];
- matchInfo.isNegated = (negationInfo[1] == '-');
- return matchInfo;
- },
-
- /**
- * Parse any "sort:" directives, and update |comparisonFunction_| and
- * |doSortBackwards_|as needed. Note only the last valid sort directive
- * is used.
- *
- * Returns |filterText| with all sort directives removed, including
- * invalid ones.
- */
- parseSortDirectives_: function(filterText) {
- this.comparisonFunction_ = compareSourceId;
- this.doSortBackwards_ = false;
-
- while (true) {
- var sortInfo = this.parseNegatableDirective_(filterText, 'sort');
- if (sortInfo == null)
- break;
- var comparisonName = sortInfo.parameter.toLowerCase();
- if (COMPARISON_FUNCTION_TABLE[comparisonName] != null) {
- this.comparisonFunction_ = COMPARISON_FUNCTION_TABLE[comparisonName];
- this.doSortBackwards_ = sortInfo.isNegated;
- }
- filterText = sortInfo.remainingText;
- }
-
- return filterText;
- },
-
- /**
- * Parse any "is:" directives, and update |filter| accordingly.
- *
- * Returns |filterText| with all "is:" directives removed, including
- * invalid ones.
- */
- parseRestrictDirectives_: function(filterText, filter) {
- while (true) {
- var filterInfo = this.parseNegatableDirective_(filterText, 'is');
- if (filterInfo == null)
- break;
- if (filterInfo.parameter == 'active') {
- if (!filterInfo.isNegated) {
- filter.isActive = true;
- } else {
- filter.isInactive = true;
- }
- }
- if (filterInfo.parameter == 'error') {
- if (!filterInfo.isNegated) {
- filter.isError = true;
- } else {
- filter.isNotError = true;
- }
- }
- filterText = filterInfo.remainingText;
- }
- return filterText;
- },
-
- /**
- * Parses all directives that take arbitrary strings as input,
- * and updates |filter| accordingly. Directives of these types
- * are stored as lists.
- *
- * Returns |filterText| with all recognized directives removed.
- */
- parseStringDirectives_: function(filterText, filter) {
- var directives = ['type', 'id'];
- for (var i = 0; i < directives.length; ++i) {
- while (true) {
- var directive = directives[i];
- var filterInfo = this.parseDirective_(filterText, directive);
- if (filterInfo == null)
- break;
-
- // Split parameters around commas and remove empty elements.
- var parameters = filterInfo.parameter.split(',');
- parameters = parameters.filter(function(string) {
- return string.length > 0;
- });
-
- // If there's already a matching filter, take the intersection.
- // This behavior primarily exists for tests. It is not correct
- // when one of the 'type' filters is a partial match.
- if (filter[directive]) {
- parameters = parameters.filter(function(string) {
- return filter[directive].indexOf(string) != -1;
- });
- }
-
- filter[directive] = parameters;
- filterText = filterInfo.remainingText;
- }
- }
- return filterText;
- },
-
- /*
- * Converts |filterText| into an object representing the filter.
- */
- createFilter_: function(filterText) {
- var filter = {};
- filterText = filterText.toLowerCase();
- filterText = this.parseRestrictDirectives_(filterText, filter);
- filterText = this.parseStringDirectives_(filterText, filter);
- filter.text = filterText.trim();
- return filter;
- },
-
setFilter_: function(filterText) {
var lastComparisonFunction = this.comparisonFunction_;
var lastDoSortBackwards = this.doSortBackwards_;
- filterText = this.parseSortDirectives_(filterText);
+ this.pickSortFunction_(filterText);
if (lastComparisonFunction != this.comparisonFunction_ ||
lastDoSortBackwards != this.doSortBackwards_) {
this.sort_();
}
- this.currentFilter_ = this.createFilter_(filterText);
+ var oldFilter = this.currentFilter_;
+ this.currentFilter_ = createFilter_(filterText);
+
+ // No need to filter again if filters match.
+ if (oldFilter &&
+ JSON.stringify(oldFilter) == JSON.stringify(this.currentFilter_)) {
+ return;
+ }
// Iterate through all of the rows and see if they match the filter.
for (var id in this.sourceIdToRowMap_) {
@@ -346,6 +202,25 @@ var EventsView = (function() {
},
/**
+ * Parse any "sort:" directives, and update |comparisonFunction_| and
+ * |doSortBackwards_| as needed. Note only the last valid sort directive
+ * is used.
+ */
+ pickSortFunction_: function(filterText) {
+ this.comparisonFunction_ = compareSourceId_;
+ this.doSortBackwards_ = false;
+
+ var filterList = parseFilter_(filterText);
+ for (var i = 0; i < filterList.length; ++i) {
+ var sort = parseSortDirective_(filterList[i].parsed);
+ if (sort != null) {
+ this.comparisonFunction_ = sort.comparisonFunction;
+ this.doSortBackwards_ = sort.backwards;
+ }
+ }
+ },
+
+ /**
* Repositions |sourceRow|'s in the table using an insertion sort.
* Significantly faster than sorting the entire table again, when only
* one entry has changed.
@@ -529,13 +404,19 @@ var EventsView = (function() {
* removes pre-existing sort parameter before adding the new one.
*/
toggleSortMethod_: function(sortMethod) {
- // Remove old sort directives, if any.
- var filterText = this.parseSortDirectives_(this.getFilterText_());
+ // Get old filter text and remove old sort directives, if any.
+ var filterList = parseFilter_(this.getFilterText_());
+ var filterText = '';
+ for (var i = 0; i < filterList.length; ++i) {
+ if (parseSortDirective_(filterList[i].parsed) == null)
+ filterText += filterList[i].original;
+ }
// If already using specified sortMethod, sort backwards.
if (!this.doSortBackwards_ &&
- COMPARISON_FUNCTION_TABLE[sortMethod] == this.comparisonFunction_)
+ COMPARISON_FUNCTION_TABLE[sortMethod] == this.comparisonFunction_) {
sortMethod = '-' + sortMethod;
+ }
filterText = 'sort:' + sortMethod + ' ' + filterText;
this.setFilterText_(filterText.trim());
@@ -616,14 +497,14 @@ var EventsView = (function() {
var COMPARISON_FUNCTION_TABLE = {
// sort: and sort:- are allowed
- '': compareSourceId,
- 'active': compareActive,
- 'desc': compareDescription,
- 'description': compareDescription,
- 'duration': compareDuration,
- 'id': compareSourceId,
- 'source': compareSourceType,
- 'type': compareSourceType
+ '': compareSourceId_,
+ 'active': compareActive_,
+ 'desc': compareDescription_,
+ 'description': compareDescription_,
+ 'duration': compareDuration_,
+ 'id': compareSourceId_,
+ 'source': compareSourceType_,
+ 'type': compareSourceType_
};
/**
@@ -632,7 +513,7 @@ var EventsView = (function() {
* which puts longer lived events at the top, and behaves better than using
* duration or time of first event.
*/
- function compareActive(source1, source2) {
+ function compareActive_(source1, source2) {
if (!source1.isInactive() && source2.isInactive())
return -1;
if (source1.isInactive() && !source2.isInactive())
@@ -647,25 +528,25 @@ var EventsView = (function() {
// If both ended at the same time, then odds are they were related events,
// started one after another, so sort in the opposite order of their
// source IDs to get a more intuitive ordering.
- return -compareSourceId(source1, source2);
+ return -compareSourceId_(source1, source2);
}
- return compareSourceId(source1, source2);
+ return compareSourceId_(source1, source2);
}
- function compareDescription(source1, source2) {
+ function compareDescription_(source1, source2) {
var source1Text = source1.getDescription().toLowerCase();
var source2Text = source2.getDescription().toLowerCase();
var compareResult = source1Text.localeCompare(source2Text);
if (compareResult != 0)
return compareResult;
- return compareSourceId(source1, source2);
+ return compareSourceId_(source1, source2);
}
- function compareDuration(source1, source2) {
+ function compareDuration_(source1, source2) {
var durationDifference = source2.getDuration() - source1.getDuration();
if (durationDifference)
return durationDifference;
- return compareSourceId(source1, source2);
+ return compareSourceId_(source1, source2);
}
/**
@@ -674,7 +555,7 @@ var EventsView = (function() {
* before the sourceless entry. Any ambiguities are resolved by ordering
* the entries without a source by the order in which they were received.
*/
- function compareSourceId(source1, source2) {
+ function compareSourceId_(source1, source2) {
var sourceId1 = source1.getSourceId();
if (sourceId1 < 0)
sourceId1 = source1.getMaxPreviousEntrySourceId();
@@ -690,13 +571,168 @@ var EventsView = (function() {
return source2.getSourceId() - source1.getSourceId();
}
- function compareSourceType(source1, source2) {
+ function compareSourceType_(source1, source2) {
var source1Text = source1.getSourceTypeString();
var source2Text = source2.getSourceTypeString();
var compareResult = source1Text.localeCompare(source2Text);
if (compareResult != 0)
return compareResult;
- return compareSourceId(source1, source2);
+ return compareSourceId_(source1, source2);
+ }
+
+ /**
+ * Parses a single "sort:" directive, and returns a dictionary containing
+ * the sort function and direction. Returns null on failure, including
+ * the case when no such sort function exists.
+ */
+
+ function parseSortDirective_(filterElement) {
+ var match = /^sort:(-?)(.*)$/.exec(filterElement);
+ if (!match || !COMPARISON_FUNCTION_TABLE[match[2]])
+ return null;
+ return {
+ comparisonFunction: COMPARISON_FUNCTION_TABLE[match[2]],
+ backwards: (match[1] == '-'),
+ };
+ }
+
+ /**
+ * Parses an "is:" directive, and updates |filter| accordingly.
+ *
+ * Returns true on success, and false if |filterElement| is not an "is:"
+ * directive.
+ */
+ function parseRestrictDirective_(filterElement, filter) {
+ var match = /^is:(-?)(.*)$/.exec(filterElement);
+ if (!match)
+ return false;
+ if (match[2] == 'active') {
+ if (match[1] == '-') {
+ filter.isInactive = true;
+ } else {
+ filter.isActive = true;
+ }
+ return true;
+ }
+ if (match[2] == 'error') {
+ if (match[1] == '-') {
+ filter.isNotError = true;
+ } else {
+ filter.isError = true;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Parses all directives that take arbitrary strings as input,
+ * and updates |filter| accordingly. Directives of these types
+ * are stored as lists.
+ *
+ * Returns true on success, and false if |filterElement| is not a
+ * recognized directive.
+ */
+ function parseStringDirective_(filterElement, filter) {
+ var directives = ['type', 'id'];
+ for (var i = 0; i < directives.length; ++i) {
+ var directive = directives[i];
+ var match = RegExp('^' + directive + ':(.*)$').exec(filterElement);
+ if (!match)
+ continue;
+
+ // Split parameters around commas and remove empty elements.
+ var parameters = match[1].split(',');
+ parameters = parameters.filter(function(string) {
+ return string.length > 0;
+ });
+
+ // If there's already a matching filter, take the intersection.
+ // This behavior primarily exists for tests. It is not correct
+ // when one of the 'type' filters is a partial match.
+ if (filter[directive]) {
+ parameters = parameters.filter(function(string) {
+ return filter[directive].indexOf(string) != -1;
+ });
+ }
+
+ filter[directive] = parameters;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Takes in the text of a filter and returns a list of {parsed, original}
+ * pairs that correspond to substrings of the filter before and after
+ * filtering. This function is used both to parse filters and to remove
+ * the sort rule from a filter. Extra whitespace other than a single
+ * character after each element is ignored. Parsed strings are all
+ * lowercase.
+ */
+ function parseFilter_(filterText) {
+ filterText = filterText.toLowerCase();
+
+ // Assemble a list of quoted and unquoted strings in the filter.
+ var filterList = [];
+ var position = 0;
+ while (position < filterText.length) {
+ var inQuote = false;
+ var filterElement = '';
+ var startPosition = position;
+ while (position < filterText.length) {
+ var nextCharacter = filterText[position];
+ ++position;
+ if (nextCharacter == '\\' &&
+ position < filterText.length) {
+ // If there's a backslash, skip the backslash and add the next
+ // character to the element.
+ filterElement += filterText[position];
+ ++position;
+ continue;
+ } else if (nextCharacter == '"') {
+ // If there's an unescaped quote character, toggle |inQuote| without
+ // modifying the element.
+ inQuote = !inQuote;
+ } else if (!inQuote && /\s/.test(nextCharacter)) {
+ // If not in a quote and have a whitespace character, that's the
+ // end of the element.
+ break;
+ } else {
+ // Otherwise, add the next character to the element.
+ filterElement += nextCharacter;
+ }
+ }
+
+ if (filterElement.length > 0) {
+ var filter = {
+ parsed: filterElement,
+ original: filterText.substring(startPosition, position),
+ };
+ filterList.push(filter);
+ }
+ }
+ return filterList;
+ }
+
+ /**
+ * Converts |filterText| into an object representing the filter.
+ */
+ function createFilter_(filterText) {
+ var filter = {};
+ var filterList = parseFilter_(filterText);
+
+ for (var i = 0; i < filterList.length; ++i) {
+ if (parseSortDirective_(filterList[i].parsed) ||
+ parseRestrictDirective_(filterList[i].parsed, filter) ||
+ parseStringDirective_(filterList[i].parsed, filter)) {
+ continue;
+ }
+ if (filter.textFilters == undefined)
+ filter.textFilters = [];
+ filter.textFilters.push(filterList[i].parsed);
+ }
+ return filter;
}
return EventsView;
diff --git a/chrome/browser/resources/net_internals/log_view_painter.js b/chrome/browser/resources/net_internals/log_view_painter.js
index 67b4dd3..1c5b0d0 100644
--- a/chrome/browser/resources/net_internals/log_view_painter.js
+++ b/chrome/browser/resources/net_internals/log_view_painter.js
@@ -5,7 +5,7 @@
// TODO(eroman): put these methods into a namespace.
var printLogEntriesAsText;
-var searchLogEntriesForText;
+var createLogEntryTablePrinter;
var proxySettingsToString;
var stripCookiesAndLoginInfo;
@@ -27,33 +27,17 @@ function canCollapseBeginWithEnd(beginEntry) {
*/
printLogEntriesAsText = function(logEntries, parent, privacyStripping,
logCreationTime) {
- var tablePrinter = createTablePrinter(logEntries, privacyStripping,
- logCreationTime);
+ var tablePrinter = createLogEntryTablePrinter(logEntries, privacyStripping,
+ logCreationTime);
// Format the table for fixed-width text.
tablePrinter.toText(0, parent);
}
-
-/**
- * Searches the table that would be output by printLogEntriesAsText for
- * |searchString|. Returns true if |searchString| would appear entirely within
- * any field in the table. |searchString| must be lowercase.
- *
- * Seperate function from printLogEntriesAsText since TablePrinter.toText
- * modifies the DOM.
- */
-searchLogEntriesForText = function(searchString, logEntries, privacyStripping) {
- var tablePrinter =
- createTablePrinter(logEntries, privacyStripping, undefined);
-
- // Format the table for fixed-width text.
- return tablePrinter.search(searchString);
-}
-
/**
* Creates a TablePrinter for use by the above two functions.
*/
-function createTablePrinter(logEntries, privacyStripping, logCreationTime) {
+createLogEntryTablePrinter = function(logEntries, privacyStripping,
+ logCreationTime) {
var entries = LogGroupEntry.createArrayFrom(logEntries);
var tablePrinter = new TablePrinter();
var parameterOutputter = new ParameterOutputter(tablePrinter);
diff --git a/chrome/browser/resources/net_internals/source_row.js b/chrome/browser/resources/net_internals/source_row.js
index 5bacea6..dcd559e 100644
--- a/chrome/browser/resources/net_internals/source_row.js
+++ b/chrome/browser/resources/net_internals/source_row.js
@@ -193,22 +193,33 @@ var SourceRow = (function() {
return false;
}
- if (filter.text == '')
+ if (!filter.textFilters)
return true;
- // The description is not always contained in one of the log entries.
- if (this.description_.toLowerCase().indexOf(filter.text) != -1)
- return true;
+ // Used for searching for input strings. Lazily initialized.
+ var tablePrinter = null;
- // Allow specifying source types by name.
- var sourceType = this.sourceEntry_.getSourceTypeString();
- if (sourceType.toLowerCase().indexOf(filter.text) != -1)
- return true;
+ for (var i = 0; i < filter.textFilters.length; ++i) {
+ // The description is not always contained in one of the log entries.
+ if (this.description_.toLowerCase().indexOf(
+ filter.textFilters[i]) != -1) {
+ continue;
+ }
+
+ // Allow specifying source types by name.
+ var sourceType = this.sourceEntry_.getSourceTypeString();
+ if (sourceType.toLowerCase().indexOf(filter.textFilters[i]) != -1)
+ continue;
- return searchLogEntriesForText(
- filter.text,
- this.sourceEntry_.getLogEntries(),
- SourceTracker.getInstance().getPrivacyStripping());
+ if (!tablePrinter) {
+ tablePrinter = createLogEntryTablePrinter(
+ this.sourceEntry_.getLogEntries(),
+ SourceTracker.getInstance().getPrivacyStripping());
+ }
+ if (!tablePrinter.search(filter.textFilters[i]))
+ return false;
+ }
+ return true;
},
isSelected: function() {
diff --git a/chrome/test/data/webui/net_internals/events_view.js b/chrome/test/data/webui/net_internals/events_view.js
index 29373ee..56cd8a4 100644
--- a/chrome/test/data/webui/net_internals/events_view.js
+++ b/chrome/test/data/webui/net_internals/events_view.js
@@ -62,7 +62,8 @@ function urlRequestEvents(id) {
'Accept: text/html',
'Accept-Encoding: gzip,deflate,sdch',
'Accept-Language: en-US,en;q=0.8',
- 'Accept-Charset: ISO-8859-1'
+ 'Accept-Charset: ISO-8859-1',
+ 'X-Random-Header-With-Quotes: "Quoted String"""',
],
'line': 'GET / HTTP/1.1\r\n'
},
@@ -147,49 +148,51 @@ TEST_F('NetInternalsTest', 'netInternalsEventsViewFilter', function() {
// |text| is the string to add to the filter.
// |matches| is a 2-element array of booleans indicating which of the two
// requests passes the filter.
- // |textFilter| is true if the filter matches the displayed text of an
- // entry. Two string filter matches are concatenated when used, so
- // will never result in a filter match.
var testFilters = [
- {text: 'http://www.google.com', matches: [true, true], textFilter: true},
- {text: 'MyMagicPony', matches: [false, false], textFilter: true},
- {text: 'type:URL_REQUEST', matches: [true, true], textFilter: false},
- {text: 'type:SOCKET,URL_REQUEST', matches: [true, true], textFilter: false},
- {text: 'type:SOCKET', matches: [false, false], textFilter: false},
- {text: 'id:31,32', matches: [true, false], textFilter: false},
- {text: 'id:32,56,', matches: [false, true], textFilter: false},
- {text: 'is:-active', matches: [true, false], textFilter: false},
- {text: 'is:active', matches: [false, true], textFilter: false},
- {text: 'is:-error', matches: [true, true], textFilter: false},
- {text: 'is:error', matches: [false, false], textFilter: false},
+ {text: 'http://www.google.com', matches: [true, true] },
+ {text: 'MyMagicPony', matches: [false, false] },
+ {text: 'type:URL_REQUEST', matches: [true, true] },
+ {text: 'type:SOCKET,URL_REQUEST', matches: [true, true] },
+ {text: 'type:SOCKET', matches: [false, false] },
+ {text: 'id:31,32', matches: [true, false] },
+ {text: 'id:32,56,', matches: [false, true] },
+ {text: 'is:-active', matches: [true, false] },
+ {text: 'is:active', matches: [false, true] },
+ {text: 'is:-error', matches: [true, true] },
+ {text: 'is:error', matches: [false, false] },
// Partial match of source type.
- {text: 'URL_REQ', matches: [true, true], textFilter: true},
+ {text: 'URL_REQ', matches: [true, true] },
// Partial match of event type type.
- {text: 'SEND_REQUEST', matches: [true, false], textFilter: true},
+ {text: 'SEND_REQUEST', matches: [true, false] },
// Check that ":" works in strings.
- {text: 'Host: www.google.com', matches: [true, false], textFilter: true},
- {text: 'Host: GET', matches: [false, false], textFilter: true},
+ { text: 'Host:', matches: [true, false] },
+ { text: '::', matches: [false, false] },
+ // Test quotes.
+ { text: '"Quoted String"', matches: [true, false] },
+ { text: '"Quoted source"', matches: [false, false] },
+ { text: '"\\"Quoted String\\""', matches: [true, false] },
+ { text: '"\\"\\"Quoted String\\""', matches: [false, false] },
+ { text: '\\"\\"\\"', matches: [true, false] },
+ { text: '\\"\\"\\"\\"', matches: [false, false] },
+ { text: '"Host: www.google.com"', matches: [true, false], },
+ { text: 'Connection:" keep-alive"', matches: [true, false], },
+ { text: '"Host: GET"', matches: [false, false] },
// Make sure sorting has no effect on filters. Sort by ID so order is
// preserved.
- {text: 'sort:id', matches: [true, true], textFilter: false},
+ { text: 'sort:"id"', matches: [true, true] },
+ // Sorting by unrecognized methods should do a text match.
+ { text: 'sort:"shoe size"', matches: [false, false] },
];
for (var filter1 = 0; filter1 < testFilters.length; ++filter1) {
checkFilter(testFilters[filter1].text, testFilters[filter1].matches);
-
// Check |filter1| in combination with all the other filters.
for (var filter2 = 0; filter2 < testFilters.length; ++filter2) {
var matches = [];
for (var i = 0; i < testFilters[filter1].matches.length; ++i) {
- // The merged filter matches an entry if both individual filters do,
- // unless both filters are text filters, since text filters are
- // concatenated.
+ // The merged filter matches an entry if both individual filters do.
matches[i] = testFilters[filter1].matches[i] &&
testFilters[filter2].matches[i];
- if (testFilters[filter1].textFilter &&
- testFilters[filter2].textFilter) {
- matches[i] = false;
- }
}
checkFilter(testFilters[filter1].text + ' ' + testFilters[filter2].text,
@@ -198,6 +201,14 @@ TEST_F('NetInternalsTest', 'netInternalsEventsViewFilter', function() {
}
}
+ // Tests with unmatched quotes. Unlike the strings above, combining them with
+ // other filters is not the same as applying both filters independently.
+ checkFilter('"Quoted String', [true, false]);
+ checkFilter('"Quoted String source', [false, false]);
+ checkFilter('Quoted" String', [true, false]);
+ checkFilter('Quoted" source', [false, false]);
+ checkFilter('Quoted "String', [true, false]);
+
testDone();
});