/plugins/net.danieldietrich.protectedregions.core/src/test/xtend/net/danieldietrich/protectedregions/ProtectedRegionSupportTest.xtend
Xtend | 264 lines | 214 code | 34 blank | 16 comment | 4 complexity | e92953ced8c6ab92275f08c325ab92f8 MD5 | raw file
1package net.danieldietrich.protectedregions
2
3import static org.junit.Assert.*
4
5import com.google.inject.Guice
6
7import java.io.FileNotFoundException
8import java.nio.charset.Charset
9
10import org.junit.Before
11import org.junit.Test
12
13/**
14 * Note: These test cases access the file system instead of passing
15 * CharSequences to simulate real parsing conditions.
16 */
17class ProtectedRegionSupportTest {
18
19 extension ModelBuilder modelBuilder
20 extension ParserFactory parserFactory
21 extension ProtectedRegionSupport support
22
23 static val BASE_DIR = "src/test/resources"
24 static val CHARSET = Charset::forName("UTF-8")
25
26 @Before
27 def void setup() {
28 val injector = Guice::createInjector
29 modelBuilder = injector.getInstance(typeof(ModelBuilder))
30 parserFactory = injector.getInstance(typeof(ParserFactory))
31 support = injector.getInstance(typeof(ProtectedRegionSupport))
32 }
33
34 @Test
35 def void mergeShouldMatchExpected() {
36 parsingPreviousAndMergingCurrentShouldMatchExpected(javaParser, "protected")
37 }
38
39 @Test
40 def void xmlParserShouldMatchExpected() {
41 parsingPreviousAndMergingCurrentShouldMatchExpected(xmlParser, "xml")
42 }
43
44 @Test
45 def void switchedRegionsParserShouldPreserveEnabledRegionsOnly() {
46 parsingPreviousAndMergingCurrentShouldMatchExpected(javaParser, "switched")
47 }
48
49 @Test
50 def void fillInShouldMatchExpected() {
51
52 val parser = javaParser => [
53 inverse = true
54 resolver = new FillInRegionResolver
55 ]
56
57 parsingPreviousAndMergingCurrentShouldMatchExpected(parser, "fill_in")
58
59 }
60
61 def private parsingPreviousAndMergingCurrentShouldMatchExpected(ProtectedRegionParser parser, String fileNamePrefix) {
62
63 val currentFile = '''src/test/resources/«fileNamePrefix»_current.txt'''.file
64 val previousFile = '''src/test/resources/«fileNamePrefix»_previous.txt'''.file
65 val expectedFile = '''src/test/resources/«fileNamePrefix»_expected.txt'''.file
66
67 // only support files relevant for this test case
68 support.addParser(parser, previousFile.filter)
69
70 // only read previous content
71 support.read(BASE_DIR.file, [CHARSET])
72
73 val generatedContent = currentFile.read
74 val mergedContent = support.merge(previousFile, generatedContent, [CHARSET]) // pass previous to use the correct parser
75 val expectedContent = expectedFile.read
76
77 assertEquals(expectedContent, mergedContent)
78
79 }
80
81 @Test
82 def void nonExistingFilesShouldByHandledGracefully() {
83 support.merge("does_not_exist".file, "", [CHARSET])
84 }
85
86 @Test
87 def void idsShouldBeUniquePerFile() {
88 val file = "src/test/resources/non_unique_ids.txt".file
89 support.addParser(javaParser, file.filter)
90 try {
91 support.read(BASE_DIR.file, [CHARSET])
92 assertTrue("Duplicate marked region with id 'uniqueId' not detected.", false)
93 } catch (IllegalStateException x) {
94 assertEquals("Duplicate marked region with id 'uniqueId' detected", x.getMessage());
95 }
96 }
97
98 @Test
99 def void scalaParserShouldReadNestedComments() {
100
101 val regions = (scalaParser => [
102 resolver = new NestedCommentRegionResolver
103 ]).parse("src/test/resources/nested_comments.txt".file.read)
104
105 // Scala does not recognize nested comment-like id's
106 assertTrue(regions.findFirst[id == "1234"] != null)
107
108 }
109
110 @Test
111 def void javaParserShouldntReadNestedCommentsButDoesWhichIsOkInThisCase() {
112
113 val regions = (javaParser => [
114 resolver = new NestedCommentRegionResolver
115 ]).parse("src/test/resources/nested_comments.txt".file.read)
116
117 // SPECIAL CASE
118 // ------------
119 // xpr reads: /* PROTECTED REGION /*1234*/ ENABLED START */
120 // java reads: /* PROTECTED REGION /*1234*/
121 // -> remaining string invalid java: ENABLED START */
122 //
123 // GOLDEN RULE: xtext-protected-regions reads valid code only
124 // => this case cannot occur
125 // => the following xpr behavior is ok:
126 assertTrue(regions.findFirst[id == "1234"] != null)
127
128 }
129
130 @Test
131 def void alternativeRegionNotationsShouldWorkAsWell() {
132
133 val parser = parser("java")[
134 model[
135 comment("//")
136 comment("/*", "*/")
137 string('"').withEscape("\\")
138 string("'").withEscape("\\")
139 ]
140 ] => [
141 resolver = new SimpleRegionResolver
142 ]
143
144 parsingPreviousAndMergingCurrentShouldMatchExpected(parser, "simple")
145
146 }
147
148 @Test
149 def void xmlCDataShouldBeIgnored() {
150 val regions = xmlParser.parse("src/test/resources/ignore_xml_cdata.txt".file.read)
151 assertTrue(regions.findFirst[id == "no.id"] == null)
152 }
153
154 @Test
155 def void javaStringsShouldBeIgnored() {
156 val regions = javaParser.parse("src/test/resources/ignore_java_strings.txt".file.read)
157 assertTrue(regions.findFirst[id == "no.id"] == null)
158 }
159
160 @Test
161 def void javaStringEscapesShouldBeIdentified() {
162 val regions = javaParser.parse("src/test/resources/ignore_java_string_escapes.txt".file.read)
163 assertTrue(regions.findFirst[id == "no.id"] == null)
164 }
165
166 @Test(expected = typeof(IllegalStateException))
167 def void locallyDuplicatedRegionIdsShouldBeDetected() {
168 support.addParser(javaParser, "src/test/resources/locally_duplicated_id.txt".file.filter)
169 support.read(BASE_DIR.file, [CHARSET])
170 }
171
172 @Test(expected = typeof(IllegalStateException))
173 def void globallyDuplicatedRegionIdsShouldBeDetected() {
174 support.addParser(xmlParser => [
175 resolver = new DefaultGeneratedRegionResolver
176 inverse = true
177 ], "src/test/resources/globally_duplicated_id1.txt".file.filter)
178 support.addParser(javaParser, "src/test/resources/globally_duplicated_id2.txt".file.filter)
179 support.read(BASE_DIR.file, [CHARSET])
180 }
181
182 @Test(expected = typeof(IllegalStateException))
183 def void missingStartMarkerShouldBeDetected() {
184 javaParser.parse("src/test/resources/missing_start_marker.txt".file.read)
185 }
186
187 @Test(expected = typeof(IllegalStateException))
188 def void missingNestedStartMarkerShouldBeDetected() {
189 javaParser.parse("src/test/resources/nested_start_marker.txt".file.read)
190 }
191
192 @Test(expected = typeof(IllegalStateException))
193 def void missingEndMarkerAtEndOfFileShouldBeDetected() {
194 javaParser.parse("src/test/resources/missing_end_marker.txt".file.read)
195 }
196
197 @Test
198 def void issue37ShouldBeSolved() {
199 javaParser.parse("src/test/resources/issue#37.txt".file.read)
200 }
201
202 def private file(CharSequence fileName) {
203 new JavaIoFile(new java.io.File(fileName.toString))
204 }
205
206 def private filter(File file) {
207 new SingleFileFilter(file)
208 }
209
210 def private read(File file) {
211 if (!file.exists) throw new FileNotFoundException("File "+ file +" not found.")
212 file.read(CHARSET)
213 }
214
215}
216
217@Data class SingleFileFilter extends FileFilter {
218 val File file
219 override accept(File file) {
220 _file.equals(file)
221 }
222}
223
224class NestedCommentRegionResolver extends RegionResolver {
225
226 // example: PROTECTED REGION /*1234*/ START
227 static val PR_START = "PROTECTED\\s+REGION\\s+/\\*\\s*([0-9]+)\\s*\\*/\\s+(?:(ENABLED)\\s+)?START"
228 static val PR_END = "PROTECTED\\s+REGION\\s+END"
229
230 new() { super(PR_START, PR_END) }
231
232 override isEnabled(String regionStart) {
233 "ENABLED".equals(getEnabled(regionStart))
234 }
235
236}
237
238class FillInRegionResolver extends RegionResolver {
239
240 // example: GENERATED ID(1234) START
241 static val PR_START = "GENERATED\\s+ID\\s*\\(\\s*([0-9]+)\\s*\\)\\s+(?:(DISABLED)\\s+)?START"
242 static val PR_END = "GENERATED\\s+END"
243
244 new() { super(PR_START, PR_END) }
245
246 override isEnabled(String regionStart) {
247 !"DISABLED".equals(getEnabled(regionStart))
248 }
249
250}
251
252class SimpleRegionResolver extends RegionResolver {
253
254 // $(SomeClass.imports)-{
255 // }-$
256 static val ID = "[\\p{L}\\p{N}\\.:_$]*"
257 static val PR_START = "\\$\\(("+ ID +")\\)-\\{"
258 static val PR_END = "\\}-\\$"
259
260 new() { super(PR_START, PR_END) }
261
262 override isEnabled(String regionStart) { true }
263
264}