Testing Parsers
The ParserTestBase<TLanguage>
can be used to create tests for a parser of a specific language. It derives from BaseTestWithTextControl
, which means it will create an in-memory ReSharper instance, with a solution and a project loaded. The test will load a specific text file into an in-memory text control, parse it, retrieve any IFile
instances that match TLanguage
, and compare the results against a .gold
file.
The .gold
file will be the IFile
and children, written as an indented text file. Each line will be another node in the tree, with the text being the result of calling ToString()
on the node instance.
For example, given the following CSS file - test01.css
:
Then the test01.css.gold
file would be something like:
Note that the PSI tree includes comments and whitespace.
Also note that the input file contains a {caret}
text. The ParserTestBase<T>
class finds the file to test by looking for the current text caret location, as defined by special strings in the file. Here, it is looking for {caret}
to know which file should be processed. This means that all input files require the {caret}
text to be added to the file. See below for an alternative implementation that doesn't require {caret}
in the input file.
Implementation
Derived classes will need to override RelativeTestDataPath
to declare the path to the data and gold files, relative to test\data
.
Each test method can call one of the following methods, which allows specifying the base name used to create the input and gold file names:
DoNamedTest
orDoNamedTest2
- will use the name of the test method as the file base name. TheDoNamedTest2
method will also strip anyTest
prefix from the method first.DoOneTest
will use the passed in string as the file base name.
These methods will specify the base name of the file to add to the in-memory project, but do not specify the file extension. This is added by the test base classes, by appending the value of the Extension
property. This property will retrieve the extension to use by looking for attributes on either the test method or the test class. The first attribute that implements ITestFileExtensionProvider
is used to get the value. Typically, this is achieved by using the [TestFileExtension]
attribute, and specifying the extension (with dot) in the constructor. This is usually taken as a constant value defined in the project file type.
Customisation
The ParserTestBase<T>
base class does not provide any hooks to customise. However, it is possible to use an alternative implementation, which does not require the {caret}
special text in the input file, and includes extra asserts.
Alternative implementation
The default base class requires the input file to include {caret}
so that it knows which file to test, even if there is only one file added to the in-memory project. As an alternative, a language can implement a different base class that doesn't have this requirement, something like this:
This will create a parser for the single file in the project, retrieve the IFile
, and compare it against the .gold
file. The input file does not require the {caret}
identifier.
Furthermore, this test will also check that the text of the file matches the text recreated by getting the text of each node in the tree, as well as validating the range of each tree node against the length of its text, further ensuring the tree is correct.