/plugins/net.danieldietrich.protectedregions.core/src/test/xtend/net/danieldietrich/protectedregions/ProtectedRegionSupportTest.xtend

https://github.com/danieldietrich/xtext-protected-regions · Xtend · 264 lines · 179 code · 65 blank · 20 comment · 11 complexity · e92953ced8c6ab92275f08c325ab92f8 MD5 · raw file

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