Skip to content

Commit

Permalink
added a bunch of unit tests and fixed the bugs found because of that
Browse files Browse the repository at this point in the history
  • Loading branch information
dslmeinte committed Nov 7, 2011
1 parent 1788b94 commit 14a3d66
Show file tree
Hide file tree
Showing 13 changed files with 423 additions and 67 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class SelectorsTests extends AbstractXtextTests {
val cssFile = getModel(^class.classLoader.getResourceAsStream(path))
val issues = diagnostician.validate(cssFile).children
if( issues.size > 0 ) {
// FIXME the following won't output something?!
issues.map [println(it.message)]
Assert::fail
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/*
* This file should be a completely valid (both syntactically and w.r.t. validation)
* CSS file which serves (in the 1st place) as an early warning mechanism w.r.t. the
* implementation of the "Selectors Level 3" part of CSS
* (see: http://www.w3.org/TR/css3-selectors).
*
* Various aspects of parsing and validation should be checked in more detail
* by unit tests, both positive and negative.
*/

/* ¤5. Groups of selectors */

h1 { font-family: sans-serif }
Expand Down Expand Up @@ -52,3 +62,31 @@ p[title*="hello"] {}
[|att] { color: green }
[att] { color: green }

/* ¤6.4. Class selectors */

*.pastoral { color: green } /* all elements with class~=pastoral */
.pastoral { color: green } /* all elements with class~=pastoral */
p.pastoral.marine { color: green }

/* ¤6.5. ID selectors */

h1#chapter1 {}
#chapter1 {}
*#z98y {}

/* ¤6.6.1.1. The link pseudo-classes: :link and :visited */

a.external:visited {}

/* ¤6.6.1.2. The user action pseudo-classes :hover, :active, and :focus */

a:link /* unvisited links */ {}
a:visited /* visited links */ {}
a:hover /* user hovers */ {}
a:active /* active links */ {}

a:focus {}
a:focus:hover {}

/* ¤6.6.2. The target pseudo-class :target */

87 changes: 53 additions & 34 deletions nl.dslmeinte.xtext.css/src/nl/dslmeinte/xtext/css/CSS.xtext
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Import:
;

NamespaceDeclaration:
'@namespace' name=ID? url=URL ';'
'@namespace' name=ID? url=(STRING|URL) ';'
;

RuleSet:
Expand Down Expand Up @@ -80,6 +80,7 @@ SimpleSelectorSequence hidden():
( head=( TypeSelector | UniversalSelector ) simpleSelectors+=TailSimpleSelector* )
| ( simpleSelectors+=TailSimpleSelector+ )
;
// validation: only last element may be a PseudoElementSelector (sub type of PseudoSelector)

TailSimpleSelector returns SimpleSelector: // synthetic type to limit choice for parser, without need for validation
IDSelector | AttributeSelector | ClassSelector | PseudoSelector | NegationSelector
Expand All @@ -100,17 +101,6 @@ CombinatorExpression returns SelectorExpression hidden():
* is re-serializable.
*/

enum NoArgsPseudos:
link | visited
| hover | active | focus
| target
| enabled | disabled | checked | indeterminate
| root
| firstChild='first-child' | lastChild='last-child'
| onlyChild='only-child'
| empty
;

SimpleSelector: // convenience super type, also references by Less grammar
TypeSelector
| UniversalSelector
Expand All @@ -136,15 +126,15 @@ enum HtmlElements:
// TODO generate into this grammar to be able to provide better content assist/code completion

UniversalSelector:
{UniversalSelector}
(namespacePrefix=NamespacePrefix)? '*'
{UniversalSelector} (namespacePrefix=NamespacePrefix)? '*'
;

AttributeSelector hidden(WS):
'['
attribute=Attribute matcher=AttributeSelectorMatchers value=(ID|STRING)
attribute=Attribute ( matcher=AttributeSelectorMatchers value=(ID|STRING) )? // !matcher.eIsSet means: AttributePresenceSelector
']'
;
// TODO try to find a solution which has better hierarchy (e.g., AttributeValueSelector and AttributePresenceSelector)

Attribute hidden():
(namespacePrefix=NamespacePrefix)? name=ID
Expand All @@ -168,27 +158,47 @@ ClassSelector:
;

PseudoSelector:
NoArgsPseudoClassSelector
| PseudoElementSelector
| LanguagePseudoClassSelector
| FunctionalPseudoClassSelector
':'
(
NoArgsPseudoClassSelector
| PseudoElementSelector
| LanguagePseudoClassSelector
| FunctionalPseudoClassSelector
)
;

NoArgsPseudoClassSelector hidden():
':' pseudo=NoArgsPseudos
pseudo=NoArgsPseudos
;

enum NoArgsPseudos:
link | visited
| hover | active | focus
| target
| enabled | disabled | checked | indeterminate
| root
| firstChild='first-child' | lastChild='last-child'
| onlyChild='only-child'
| empty
;

PseudoElementSelector hidden():
':' doubleSemiColon?=':'? pseudo=PseudoElements
doubleSemiColon?=':'? pseudo=PseudoElements
;

enum PseudoElements:
firstLetter='first-letter' | firstLine='first-line'
| before | after
;
// validation: warning if "legacy" pseudo-element is used with only a single semi-colon

LanguagePseudoClassSelector hidden():
'lang(' langugageId=ID ')'
;
// validation: language matches /\w+(-\w+)?/

FunctionalPseudoClassSelector hidden():
':' pseudo=FunctionalPseudoClasses '(' argument=TypeArgument ')'
pseudo=FunctionalPseudoClasses '(' argument=TypeArgument ')'
;

TypeArgument hidden(WS):
Expand Down Expand Up @@ -221,11 +231,6 @@ enum FunctionalPseudoClasses:
| onlyOfType='only-of-type'
;

LanguagePseudoClassSelector hidden():
':lang(' langugageId=ID ')'
;
// validation: language matches /\w+(-\w+)?/

NegationSelector hidden():
':not(' simpleSelector=NegationSimpleSelector ')'
;
Expand All @@ -247,7 +252,7 @@ NegationSimpleSelector returns SimpleSelector: // synthetic type to limit choice
*/

ValueLiteral:
NumberLiteral | StringLiteral | ColorLiteral | BareWordLiteral
NumberLiteral | StringLiteral | ColorLiteral | URLLiteral | BareWordLiteral
;

NumberLiteral hidden():
Expand Down Expand Up @@ -277,12 +282,17 @@ ComponentColorLiteral:
// either all percentages (with correct range), or all dimension-less integers 0-255
// validation on ComponentHSLColor:
// all percentages (with correct range)
// TODO can % be optional for 0 (or 0.0)?

enum ColorNames:
black | white // | ...
;
// TODO generate into this grammar to provide content assist/code completion

URLLiteral:
value=URL
;

// something we don't know about:
BareWordLiteral:
bareWord=ID
Expand Down Expand Up @@ -314,11 +324,12 @@ terminal HASH_ID: '#' PREFIXABLE_ID_START ID_PART* ;
terminal DOT_ID: '.' PREFIXABLE_ID_START ID_PART* ;
// CSSValueConverterService#DOT_ID takes care of removing the '.'

// special terminal for namespace references:
terminal PIPE_ID: '|' PREFIXABLE_ID_START ID_PART* ;

terminal URL: 'url(' -> ')' ;
// CSSValueConverterService#URL takes care of removing the 'url(' WS .. WS ')
/*
* CSSValueConverterService#URL takes care of removing the whitespace so that
* the rule effectively becomes: 'url(' WS? .. WS? ')
*/
// TODO validation on url itself

terminal INT returns ecore::EInt: ('-')? DEC_DIGIT+ ;

Expand All @@ -334,12 +345,20 @@ terminal fragment ID_START: PREFIXABLE_ID_START | '-';

terminal fragment PREFIXABLE_ID_START: ('a'..'z'|'A'..'Z'|'_') ;

terminal STRING :
terminal STRING : // copied from common.Terminals grammar
'"' ( '\\' ('b'|'t'|'n'|'f'|'r'|'u'|'"'|"'"|'\\') | !('\\'|'"') )* '"' |
"'" ( '\\' ('b'|'t'|'n'|'f'|'r'|'u'|'"'|"'"|'\\') | !('\\'|"'") )* "'"
;

terminal ML_COMMENT : '/*' -> '*/' ;
terminal ML_COMMENT : '/*' -> '*/' ; // copied from common.Terminals grammar

terminal WS : (' '|'\t'|'\r'|'\n')+ ; // TODO add '\f' without causing Xtext generation problems


/*
* Roadmap:
*
* 1) W3C compliant lexing
* 2) W3C specification harvesting -> generate into grammar
*/

2 changes: 1 addition & 1 deletion nl.dslmeinte.xtext.less.tests/.classpath
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="src-gen"/>
<classpathentry kind="src" path="xtend-gen"/>
<classpathentry kind="output" path="bin"/>
</classpath>
6 changes: 6 additions & 0 deletions nl.dslmeinte.xtext.less.tests/.project
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,15 @@
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
</natures>
</projectDescription>
4 changes: 3 additions & 1 deletion nl.dslmeinte.xtext.less.tests/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ Require-Bundle: nl.dslmeinte.xtext.less,
org.eclipse.xtext.junit4,
org.eclipse.xtext.ui.junit,
org.junit4,
org.eclipse.ui.workbench;resolution:=optional
org.eclipse.ui.workbench;resolution:=optional,
org.eclipse.xtext.xbase.lib;bundle-version="2.1.0",
org.eclipse.xtext.xtend2.lib;bundle-version="2.1.0"
Import-Package: org.apache.log4j,
org.apache.commons.logging
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
2 changes: 1 addition & 1 deletion nl.dslmeinte.xtext.less.tests/build.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
source.. = src/,\
src-gen/
xtend-gen/
bin.includes = META-INF/,\
.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package nl.dslmeinte.xtext.less.test

import nl.dslmeinte.xtext.less.LessStandaloneSetup
import org.eclipse.emf.ecore.resource.Resource$Diagnostic
import org.eclipse.emf.ecore.util.Diagnostician
import org.eclipse.xtext.junit.AbstractXtextTests
import org.junit.Assert

class ExamplesTest extends AbstractXtextTests {

private Diagnostician diagnostician

override protected setUp() {
super.setUp()
with(typeof(LessStandaloneSetup));
diagnostician = new Diagnostician()
}

def void test_all_examples_at_once() {
val path = ^class.^package.name.replace('.', '/') + "/examples.less"
val cssFile = getModelAndExpect(^class.classLoader.getResourceAsStream(path), Integer::MIN_VALUE) // TODO -> UNKNOWN_EXPECTATION

val resource = cssFile.eResource

for( e : resource.errors ) {
e.print("error")
}
// resource.errors.map [it.print("error")]

for( w : resource.warnings ) {
w.print("warning")
}
// resource.warnings.map [println("warning:\t" + it)]

val issues = diagnostician.validate(cssFile).children
for( i : issues ) {
i.print
}
// issues.map [println("issue:\t" + it)]
if( issues.size > 0 || resource.errors.size > 0 ) {
Assert::fail("there were syntactic errors and/or semantic issues")
}
}

def private print(Diagnostic it, String type) {
println( '''LÇlineÈÇsafeColumnÈ ÇtypeÈ ÇmessageÈ'''.toString )
}

def private print(org.eclipse.emf.common.util.Diagnostic it) {
println( '''ÇseverityÈ ÇmessageÈ'''.toString ) // TODO map severity int -> String
}

def private safeColumn(Diagnostic it) {
try {
"@" + column
} catch( UnsupportedOperationException e ) {
""
}
}

}
Loading

0 comments on commit 14a3d66

Please sign in to comment.