// Copyright 2012 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.collide.client.code.autocomplete.codemirror;
import com.google.collide.client.code.autocomplete.AutocompleteResult;
import com.google.collide.client.code.autocomplete.DefaultAutocompleteResult;
import com.google.collide.client.code.autocomplete.LanguageSpecificAutocompleter.ExplicitAction;
import com.google.collide.client.code.autocomplete.LanguageSpecificAutocompleter.ExplicitActionType;
import com.google.collide.client.code.autocomplete.MockAutocompleterEnvironment;
import com.google.collide.client.code.autocomplete.SignalEventEssence;
import com.google.collide.client.documentparser.DocumentParser;
import com.google.collide.client.testutil.TestSchedulerImpl;
import com.google.collide.client.util.PathUtil;
import com.google.collide.client.workspace.outline.CssOutlineParser;
import com.google.collide.client.workspace.outline.OutlineConsumer;
import com.google.collide.client.workspace.outline.OutlineNode;
import com.google.collide.codemirror2.Token;
import com.google.collide.json.shared.JsonArray;
import com.google.collide.json.shared.JsonStringSet;
import com.google.collide.shared.document.Line;
import com.google.collide.shared.util.JsonCollections;
import com.google.collide.shared.util.ListenerManager;
import com.google.gwt.core.client.Scheduler;
import org.waveprotocol.wave.client.common.util.SignalEvent.KeySignalType;
import javax.annotation.Nullable;
/**
* Test for explicit autocompletion cases, when codemirror parser is used.
*
*/
public class CssCodemirrorTest extends
com.google.collide.client.testutil.CodeMirrorTestCase {
private static final String EXPLICIT_BRACES = "{\n \n}";
@Override
public String getModuleName() {
return "com.google.collide.client.TestCode";
}
private void checkExplicit(@Nullable String expected, String prefix) {
SignalEventEssence trigger = new SignalEventEssence('{');
MockAutocompleterEnvironment helper = new MockAutocompleterEnvironment();
helper.setup(new PathUtil("foo.css"), prefix, 0, prefix.length(), true);
ExplicitAction action = helper.autocompleter.cssAutocompleter.getExplicitAction(
helper.editor.getSelection(), trigger, false);
AutocompleteResult commonResult = action.getExplicitAutocompletion();
if (expected == null) {
assertNull("result", commonResult);
assertFalse("action", ExplicitActionType.EXPLICIT_COMPLETE == action.getType());
return;
} else {
assertTrue("action", ExplicitActionType.EXPLICIT_COMPLETE == action.getType());
}
assertTrue("result type", commonResult instanceof DefaultAutocompleteResult);
DefaultAutocompleteResult result = (DefaultAutocompleteResult) commonResult;
assertEquals(expected, result.getAutocompletionText());
}
public void testExplicit() {
checkExplicit(EXPLICIT_BRACES, "");
checkExplicit(EXPLICIT_BRACES, "div.root");
checkExplicit(EXPLICIT_BRACES, "div.root ");
checkExplicit(EXPLICIT_BRACES, "div.root /*foo*/");
checkExplicit(EXPLICIT_BRACES, "div.root /*foo*/ ");
checkExplicit(EXPLICIT_BRACES, ".root ");
checkExplicit(EXPLICIT_BRACES, "@media all");
checkExplicit(EXPLICIT_BRACES, "@media all ");
checkExplicit(EXPLICIT_BRACES, "@media all { td");
checkExplicit(EXPLICIT_BRACES, "@media all /*foo*/");
checkExplicit(EXPLICIT_BRACES, "@media all /*foo*/ ");
checkExplicit(null, "{");
checkExplicit(null, "{ ");
checkExplicit(null, "{ {");
checkExplicit(null, "{ /*");
checkExplicit(null, "{ /* ");
checkExplicit(null, "{ /*foo*/");
checkExplicit(null, "{ /*foo*/ ");
checkExplicit(null, "/*");
checkExplicit(null, "/* ");
checkExplicit(null, ".root /*");
checkExplicit(null, ".root {/*foo*/");
checkExplicit(null, "@media all { td {");
}
public void testOutlineWithMedia() {
JsonStringSet tags = JsonCollections.createStringSet("td");
checkOutlineParser("@media screen { td{}}", tags);
checkOutlineParser("@media screen {td {}}", tags);
}
public void testOutline() {
String text = ""
+ " td,\tp.dark-green, a:hover, [title~=hello]"
// ^^ ^^^^^^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^
+ " {\tborder: 3px solid #55AAEE; font: message-box; background-color: #EEEEEE;}"
//
+ " a.bad:visited {background-image:url('gradient2.png');}"
// ^^^^^^^^^^^^^
+ "b/*comment*/.sparse, #para, div#main { -custom:'img {';}"
// ^-----------^^^^^^^ ^^^^^ ^^^^^^^^
+ " .marked p, p > i:first-child {}"
// ^^^^^^^^^ ^^-^-^^^^^^^^^^^^^^
+ " q:lang(no) {quotes: \"~\" \"~\";}\n"
// ^^^^^^^^^^
;
JsonStringSet tags = JsonCollections.createStringSet("td", "p.dark-green", "a:hover",
"[title~=hello]", "a.bad:visited", "b.sparse", "#para", "div#main", ".marked p",
"p > i:first-child", "q:lang(no)");
checkOutlineParser(text, tags);
}
private void checkOutlineParser(String text, JsonStringSet expectedNodes) {
MockAutocompleterEnvironment helper = new MockAutocompleterEnvironment();
helper.setup(new PathUtil("foo.css"), text, 0, 0, true);
ListenerManager<DocumentParser.Listener> registrar = ListenerManager.create();
final JsonArray<OutlineNode> output = JsonCollections.createArray();
OutlineConsumer consumer = new OutlineConsumer() {
@Override
public void onOutlineParsed(JsonArray<OutlineNode> nodes) {
output.clear();
output.addAll(nodes);
}
};
Line line = helper.editor.getDocument().getFirstLine();
JsonArray<Token> tokens = helper.parser
.parseLineSync(line);
CssOutlineParser cssOutlineParser = new CssOutlineParser(registrar, consumer);
cssOutlineParser.onIterationStart(0);
cssOutlineParser.onDocumentLineParsed(line, 0, tokens);
cssOutlineParser.onIterationFinish();
final int outputSize = output.size();
assertEquals("number of nodes", expectedNodes.getKeys().size(), outputSize);
for (int i = 0; i < outputSize; i++) {
OutlineNode node = output.get(i);
String nodeName = node.getName();
assertTrue("unexpected item: [" + nodeName + "]", expectedNodes.contains(nodeName));
}
cssOutlineParser.cleanup();
}
public void testWorkflow() {
final MockAutocompleterEnvironment helper = new MockAutocompleterEnvironment();
// TODO: vars in the global scope are not registered by CM.
String text = "td { cur";
helper.setup(new PathUtil("foo.css"), text, 0, text.length(), true);
final MockAutocompleterEnvironment.MockAutocompleter autocompleter = helper.autocompleter;
final JsonArray<Scheduler.ScheduledCommand> scheduled = JsonCollections.createArray();
Runnable ctrlSpaceClicker = new Runnable() {
@Override
public void run() {
autocompleter.pressKey(
new SignalEventEssence(' ', true, false, false, false, KeySignalType.INPUT));
}
};
TestSchedulerImpl.AngryScheduler scheduler = new TestSchedulerImpl.AngryScheduler() {
@Override
public void scheduleDeferred(ScheduledCommand scheduledCommand) {
scheduled.add(scheduledCommand);
}
};
TestSchedulerImpl.runWithSpecificScheduler(ctrlSpaceClicker, scheduler);
assertEquals("actual autocompletion is deferred", 1, scheduled.size());
scheduled.get(0).execute();
assertFalse("expect nonempty popup", helper.popup.proposals.isEmpty());
scheduled.clear();
Runnable enterClicker = new Runnable() {
@Override
public void run() {
helper.popup.delegate.onSelect(helper.popup.proposals.select(0));
}
};
TestSchedulerImpl.runWithSpecificScheduler(enterClicker, scheduler);
assertEquals("apply proposal is deferred", 1, scheduled.size());
// We expect not to explode at this moment.
scheduled.get(0).execute();
}
}