Repository: AlecStrong/sql-psi
Pull request #343 (2022-03-24 00:51:44)

Make the fixture tests reusable
 - Split them into their own module.
 - Create a separate test for each dialect
 - Also fix it so every dialect is running the ANSI tests
 
 Scroll bar is deceiving its mostly moved files


Patch:
diff --git a/core/build.gradle b/core/build.gradle
index 3430571..12fe3ea 100644
--- a/core/build.gradle
+++ b/core/build.gradle
@@ -17,10 +17,9 @@ dependencies {
   compileOnly libs.intellijLang
   compileOnly libs.intellijCore
 
-  testImplementation libs.intellijLang
-  testImplementation libs.intellijCore
   testImplementation libs.junit
   testImplementation libs.truth
+  testImplementation project(":test-fixtures")
 }
 
 generateLexer {
diff --git a/core/gradle.properties b/core/gradle.properties
index e2b1fc6..b7abe88 100644
--- a/core/gradle.properties
+++ b/core/gradle.properties
@@ -1,4 +1,4 @@
-POM_ARTIFACT_ID=sqlite-psi-core
-POM_NAME=SQLite-PSI Core
-POM_DESCRIPTION=Implementation of the IntelliJ PSI interface for SQLite
+POM_ARTIFACT_ID=core
+POM_NAME=SQL-PSI Core
+POM_DESCRIPTION=Implementation of the IntelliJ PSI interface for SQL
 POM_PACKAGING=jar
diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/DialectPreset.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/DialectPreset.kt
index 39eeabc..5b4b914 100644
--- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/DialectPreset.kt
+++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/DialectPreset.kt
@@ -5,6 +5,7 @@ import com.alecstrong.sql.psi.core.mysql.MySqlParserUtil
 import com.alecstrong.sql.psi.core.postgresql.PostgreSqlParserUtil
 import com.alecstrong.sql.psi.core.psi.SqlTypes
 import com.alecstrong.sql.psi.core.sqlite_3_18.psi.mixins.StatementValidatorMixin
+import com.alecstrong.sql.psi.core.hsql.psi.mixins.ColumnDefMixin as HSqlColumnDefMixin
 import com.alecstrong.sql.psi.core.mysql.psi.mixins.ColumnDefMixin as MySqlColumnDefMixin
 import com.alecstrong.sql.psi.core.postgresql.psi.mixins.ColumnDefMixin as PostgreSqlColumnDefMixin
 import com.alecstrong.sql.psi.core.sqlite_3_18.SqliteParserUtil as Sqlite_3_18Util
@@ -94,6 +95,14 @@ enum class DialectPreset {
       SqlParserUtil.reset()
       HsqlParserUtil.reset()
       HsqlParserUtil.overrideSqlParser()
+
+      val currentElementCreation = HsqlParserUtil.createElement
+      HsqlParserUtil.createElement = {
+        when (it.elementType) {
+          SqlTypes.COLUMN_DEF -> HSqlColumnDefMixin(it)
+          else -> currentElementCreation(it)
+        }
+      }
     }
   };
 
diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/hsql/hsql.bnf b/core/src/main/kotlin/com/alecstrong/sql/psi/core/hsql/hsql.bnf
index 9b90eaf..11e76e9 100644
--- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/hsql/hsql.bnf
+++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/hsql/hsql.bnf
@@ -103,6 +103,7 @@ insert_stmt ::= [ {with_clause} ] ( INSERT | MERGE ) INTO [ {database_name} '.'
   extends = "com.alecstrong.sql.psi.core.psi.impl.SqlInsertStmtImpl"
   implements = "com.alecstrong.sql.psi.core.psi.SqlInsertStmt"
   override = true
+  pin = 5
 }
 
 merge_key_selector ::= KEY '(' {column_name} ')'
\ No newline at end of file
diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/hsql/psi/mixins/ColumnDefMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/hsql/psi/mixins/ColumnDefMixin.kt
new file mode 100644
index 0000000..01b4597
--- /dev/null
+++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/hsql/psi/mixins/ColumnDefMixin.kt
@@ -0,0 +1,11 @@
+package com.alecstrong.sql.psi.core.hsql.psi.mixins
+
+import com.alecstrong.sql.psi.core.psi.impl.SqlColumnDefImpl
+import com.intellij.lang.ASTNode
+
+internal class ColumnDefMixin(node: ASTNode) : SqlColumnDefImpl(node) {
+
+  override fun hasDefaultValue(): Boolean {
+    return columnConstraintList.any { it.node.text == "AUTO_INCREMENT" } || super.hasDefaultValue()
+  }
+}
diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/postgresql/PostgreSql.bnf b/core/src/main/kotlin/com/alecstrong/sql/psi/core/postgresql/PostgreSql.bnf
index 7b14772..4154ef4 100644
--- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/postgresql/PostgreSql.bnf
+++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/postgresql/PostgreSql.bnf
@@ -126,6 +126,7 @@ with_clause_auxiliary_stmt ::= {compound_select_stmt} | delete_stmt_limited | in
 delete_stmt_limited ::= [ {with_clause} ] DELETE FROM {qualified_table_name} [ WHERE <<expr '-1'>> ] [ [ ORDER BY {ordering_term} ( ',' {ordering_term} ) * ] LIMIT <<expr '-1'>> [ ( OFFSET | ',' ) <<expr '-1'>> ] ] [ returning_clause ] {
   extends = "com.alecstrong.sql.psi.core.psi.impl.SqlDeleteStmtLimitedImpl"
   implements = "com.alecstrong.sql.psi.core.psi.SqlDeleteStmtLimited"
+  pin = 2
   override = true
 }
 
@@ -137,6 +138,7 @@ insert_stmt ::= [ {with_clause} ]
   extends = "com.alecstrong.sql.psi.core.psi.impl.SqlInsertStmtImpl"
   implements = "com.alecstrong.sql.psi.core.psi.SqlInsertStmt"
   override = true
+  pin = 5
 }
 
 
diff --git a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableNameMixin.kt b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableNameMixin.kt
index bca1d95..2b952ed 100644
--- a/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableNameMixin.kt
+++ b/core/src/main/kotlin/com/alecstrong/sql/psi/core/psi/mixins/TableNameMixin.kt
@@ -4,6 +4,7 @@ import com.alecstrong.sql.psi.core.SqlAnnotationHolder
 import com.alecstrong.sql.psi.core.SqlParser
 import com.alecstrong.sql.psi.core.psi.SqlColumnExpr
 import com.alecstrong.sql.psi.core.psi.SqlDropTableStmt
+import com.alecstrong.sql.psi.core.psi.SqlDropViewStmt
 import com.alecstrong.sql.psi.core.psi.SqlForeignTable
 import com.alecstrong.sql.psi.core.psi.SqlNamedElementImpl
 import com.alecstrong.sql.psi.core.psi.SqlNewTableName
@@ -44,7 +45,9 @@ internal abstract class TableNameMixin(
         annotationHolder.createErrorAnnotation(this, "Table already defined with name $name")
       }
     } else if (references == null) {
-      if (parent is SqlDropTableStmt && parent.node.findChildByType(SqlTypes.EXISTS) != null) return
+      if ((parent is SqlDropTableStmt || parent is SqlDropViewStmt) &&
+        parent.node.findChildByType(SqlTypes.EXISTS) != null
+      ) return
       annotationHolder.createErrorAnnotation(this, "No table found with name $name")
     }
     super.annotate(annotationHolder)
diff --git a/gradle.properties b/gradle.properties
index 689b405..a55fd41 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,10 +1,10 @@
-GROUP=com.alecstrong
+GROUP=com.alecstrong.sql.psi
 VERSION_NAME=0.4.0-SNAPSHOT
 
-POM_URL=https://github.com/alecstrong/sqlite-psi/
-POM_SCM_URL=https://github.com/alecstrong/sqlite-psi/
-POM_SCM_CONNECTION=scm:git:git://github.com/alecstrong/sqlite-psi.git
-POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/alecstrong/sqlite-psi.git
+POM_URL=https://github.com/alecstrong/sql-psi/
+POM_SCM_URL=https://github.com/alecstrong/sql-psi/
+POM_SCM_CONNECTION=scm:git:git://github.com/alecstrong/sql-psi.git
+POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/alecstrong/sql-psi.git
 
 POM_LICENCE_NAME=The Apache Software License, Version 2.0
 POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
diff --git a/settings.gradle b/settings.gradle
index 5f86294..f53dad9 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -6,6 +6,7 @@ pluginManagement {
 }
 
 include ':core'
+include ':test-fixtures'
 include ':sample-core'
 include ':sample-headless'
 include ':sample-plugin'


Test patch:
diff --git a/core/src/test/fixtures/foreign-key-error/failure.txt b/core/src/test/fixtures/foreign-key-error/failure.txt
deleted file mode 100644
index 20765a3..0000000
--- a/core/src/test/fixtures/foreign-key-error/failure.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Player.s line 4:12 - Table team does not have a unique index on column name
-Player.s line 4:28 - No column found with name name
-Team.s line 3:51 - '(', ')', ',', <column constraint real>, DEFERRABLE, MATCH, NOT or ON expected, got '.'
\ No newline at end of file
diff --git a/core/src/test/fixtures/insert-or-replace/Test.s b/core/src/test/fixtures_sqlite_3_18/insert-or-replace/Test.s
similarity index 100%
rename from core/src/test/fixtures/insert-or-replace/Test.s
rename to core/src/test/fixtures_sqlite_3_18/insert-or-replace/Test.s
diff --git a/core/src/test/fixtures/insert-without-columns/Test.s b/core/src/test/fixtures_sqlite_3_18/insert-without-columns/Test.s
similarity index 100%
rename from core/src/test/fixtures/insert-without-columns/Test.s
rename to core/src/test/fixtures_sqlite_3_18/insert-without-columns/Test.s
diff --git a/core/src/test/fixtures/no-insert-rowid/Test.s b/core/src/test/fixtures_sqlite_3_18/no-insert-rowid/Test.s
similarity index 100%
rename from core/src/test/fixtures/no-insert-rowid/Test.s
rename to core/src/test/fixtures_sqlite_3_18/no-insert-rowid/Test.s
diff --git a/core/src/test/fixtures/recursive-common-table/Querys.s b/core/src/test/fixtures_sqlite_3_18/recursive-common-table/Querys.s
similarity index 100%
rename from core/src/test/fixtures/recursive-common-table/Querys.s
rename to core/src/test/fixtures_sqlite_3_18/recursive-common-table/Querys.s
diff --git a/core/src/test/fixtures/recursive-common-table/failure.txt b/core/src/test/fixtures_sqlite_3_18/recursive-common-table/failure.txt
similarity index 100%
rename from core/src/test/fixtures/recursive-common-table/failure.txt
rename to core/src/test/fixtures_sqlite_3_18/recursive-common-table/failure.txt
diff --git a/core/src/test/fixtures/rowid/Test.s b/core/src/test/fixtures_sqlite_3_18/rowid/Test.s
similarity index 100%
rename from core/src/test/fixtures/rowid/Test.s
rename to core/src/test/fixtures_sqlite_3_18/rowid/Test.s
diff --git a/core/src/test/fixtures/rowid/failure.txt b/core/src/test/fixtures_sqlite_3_18/rowid/failure.txt
similarity index 100%
rename from core/src/test/fixtures/rowid/failure.txt
rename to core/src/test/fixtures_sqlite_3_18/rowid/failure.txt
diff --git a/core/src/test/fixtures/sdk-search-fts/Item.s b/core/src/test/fixtures_sqlite_3_18/sdk-search-fts/Item.s
similarity index 100%
rename from core/src/test/fixtures/sdk-search-fts/Item.s
rename to core/src/test/fixtures_sqlite_3_18/sdk-search-fts/Item.s
diff --git a/core/src/test/fixtures/sdk-search/Item.s b/core/src/test/fixtures_sqlite_3_18/sdk-search/Item.s
similarity index 100%
rename from core/src/test/fixtures/sdk-search/Item.s
rename to core/src/test/fixtures_sqlite_3_18/sdk-search/Item.s
diff --git a/core/src/test/fixtures_sqlite_3_18/syntax-error/Table.s b/core/src/test/fixtures_sqlite_3_18/syntax-error/Table.s
index 453d5f7..9468b2b 100644
--- a/core/src/test/fixtures_sqlite_3_18/syntax-error/Table.s
+++ b/core/src/test/fixtures_sqlite_3_18/syntax-error/Table.s
@@ -1,2 +1,1 @@
-SELECT *
-FRM chair;
+DELETE FRM chair;
diff --git a/core/src/test/fixtures_sqlite_3_18/syntax-error/failure.txt b/core/src/test/fixtures_sqlite_3_18/syntax-error/failure.txt
index f06cba0..af0d205 100644
--- a/core/src/test/fixtures_sqlite_3_18/syntax-error/failure.txt
+++ b/core/src/test/fixtures_sqlite_3_18/syntax-error/failure.txt
@@ -1,1 +1,1 @@
-Table.s line 2:0 - ',', <compound operator real>, FROM, GROUP, LIMIT, ORDER or WHERE expected, got 'FRM'
+Table.s line 1:6 - FROM expected, got 'FRM'
diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/FixtureCompiler.kt b/core/src/test/kotlin/com/alecstrong/sql/psi/core/FixtureCompiler.kt
index 3ec0a98..4938418 100644
--- a/core/src/test/kotlin/com/alecstrong/sql/psi/core/FixtureCompiler.kt
+++ b/core/src/test/kotlin/com/alecstrong/sql/psi/core/FixtureCompiler.kt
@@ -1,5 +1,6 @@
 package com.alecstrong.sql.psi.core
 
+import com.alecstrong.sql.psi.test.fixtures.TestHeadlessParser
 import com.intellij.psi.PsiElement
 import java.io.File
 
diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/HSqlFixturesTest.kt b/core/src/test/kotlin/com/alecstrong/sql/psi/core/HSqlFixturesTest.kt
new file mode 100644
index 0000000..cbe32a5
--- /dev/null
+++ b/core/src/test/kotlin/com/alecstrong/sql/psi/core/HSqlFixturesTest.kt
@@ -0,0 +1,33 @@
+package com.alecstrong.sql.psi.core
+
+import com.alecstrong.sql.psi.test.fixtures.FixturesTest
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+import java.io.File
+
+@RunWith(Parameterized::class)
+class HSqlFixturesTest(name: String, fixtureRoot: File) : FixturesTest(name, fixtureRoot) {
+  override val replaceRules = arrayOf(
+    "TEXT" to "VARCHAR(8)",
+    "AUTOINCREMENT" to "AUTO_INCREMENT",
+    "?1" to ":one",
+    "?2" to ":two"
+  )
+
+  override fun setupDialect() {
+    DialectPreset.HSQL.setup()
+  }
+
+  companion object {
+    private val fixtures = arrayOf("src/test/fixtures_hsql")
+
+    @Suppress("unused") // Used by Parameterized JUnit runner reflectively.
+    @Parameters(name = "{0}")
+    @JvmStatic fun parameters() = fixtures.flatMap { fixtureFolder ->
+      File(fixtureFolder).listFiles()!!
+        .filter { it.isDirectory }
+        .map { arrayOf(it.name, it) }
+    } + ansiFixtures
+  }
+}
diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/MySqlFixturesTest.kt b/core/src/test/kotlin/com/alecstrong/sql/psi/core/MySqlFixturesTest.kt
new file mode 100644
index 0000000..777bb3e
--- /dev/null
+++ b/core/src/test/kotlin/com/alecstrong/sql/psi/core/MySqlFixturesTest.kt
@@ -0,0 +1,33 @@
+package com.alecstrong.sql.psi.core
+
+import com.alecstrong.sql.psi.test.fixtures.FixturesTest
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+import java.io.File
+
+@RunWith(Parameterized::class)
+class MySqlFixturesTest(name: String, fixtureRoot: File) : FixturesTest(name, fixtureRoot) {
+  override val replaceRules = arrayOf(
+    "TEXT" to "VARCHAR(8)",
+    "AUTOINCREMENT" to "AUTO_INCREMENT",
+    "?1" to ":one",
+    "?2" to ":two"
+  )
+
+  override fun setupDialect() {
+    DialectPreset.MYSQL.setup()
+  }
+
+  companion object {
+    private val fixtures = arrayOf("src/test/fixtures_mysql")
+
+    @Suppress("unused") // Used by Parameterized JUnit runner reflectively.
+    @Parameters(name = "{0}")
+    @JvmStatic fun parameters() = fixtures.flatMap { fixtureFolder ->
+      File(fixtureFolder).listFiles()!!
+        .filter { it.isDirectory }
+        .map { arrayOf(it.name, it) }
+    } + ansiFixtures
+  }
+}
diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/PostgreSqlFixturesTest.kt b/core/src/test/kotlin/com/alecstrong/sql/psi/core/PostgreSqlFixturesTest.kt
new file mode 100644
index 0000000..35bf435
--- /dev/null
+++ b/core/src/test/kotlin/com/alecstrong/sql/psi/core/PostgreSqlFixturesTest.kt
@@ -0,0 +1,34 @@
+package com.alecstrong.sql.psi.core
+
+import com.alecstrong.sql.psi.test.fixtures.FixturesTest
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+import java.io.File
+
+@RunWith(Parameterized::class)
+class PostgreSqlFixturesTest(name: String, fixtureRoot: File) : FixturesTest(name, fixtureRoot) {
+  override val replaceRules = arrayOf(
+    "INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT" to "SERIAL NOT NULL PRIMARY KEY",
+    "AUTOINCREMENT" to "",
+    "?1" to "?",
+    "?2" to "?",
+    "BLOB" to "TEXT",
+  )
+
+  override fun setupDialect() {
+    DialectPreset.POSTGRESQL.setup()
+  }
+
+  companion object {
+    private val fixtures = arrayOf("src/test/fixtures_postgresql")
+
+    @Suppress("unused") // Used by Parameterized JUnit runner reflectively.
+    @Parameters(name = "{0}")
+    @JvmStatic fun parameters() = fixtures.flatMap { fixtureFolder ->
+      File(fixtureFolder).listFiles()!!
+        .filter { it.isDirectory }
+        .map { arrayOf(it.name, it) }
+    } + ansiFixtures
+  }
+}
diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite318FixturesTest.kt b/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite318FixturesTest.kt
new file mode 100644
index 0000000..486b0ae
--- /dev/null
+++ b/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite318FixturesTest.kt
@@ -0,0 +1,26 @@
+package com.alecstrong.sql.psi.core
+
+import com.alecstrong.sql.psi.test.fixtures.FixturesTest
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+import java.io.File
+
+@RunWith(Parameterized::class)
+class Sqlite318FixturesTest(name: String, fixtureRoot: File) : FixturesTest(name, fixtureRoot) {
+  override fun setupDialect() {
+    DialectPreset.SQLITE_3_18.setup()
+  }
+
+  companion object {
+    private val fixtures = arrayOf("src/test/fixtures_upsert_not_supported", "src/test/fixtures_sqlite_3_18")
+
+    @Suppress("unused") // Used by Parameterized JUnit runner reflectively.
+    @Parameters(name = "{0}")
+    @JvmStatic fun parameters() = fixtures.flatMap { fixtureFolder ->
+      File(fixtureFolder).listFiles()!!
+        .filter { it.isDirectory }
+        .map { arrayOf(it.name, it) }
+    } + ansiFixtures
+  }
+}
diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite324FixturesTest.kt b/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite324FixturesTest.kt
new file mode 100644
index 0000000..fcd443d
--- /dev/null
+++ b/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite324FixturesTest.kt
@@ -0,0 +1,30 @@
+package com.alecstrong.sql.psi.core
+
+import com.alecstrong.sql.psi.test.fixtures.FixturesTest
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+import java.io.File
+
+@RunWith(Parameterized::class)
+class Sqlite324FixturesTest(name: String, fixtureRoot: File) : FixturesTest(name, fixtureRoot) {
+  override val replaceRules = arrayOf(
+    "ORDER or WHERE expected" to "ORDER, WHERE or WINDOW expected"
+  )
+
+  override fun setupDialect() {
+    DialectPreset.SQLITE_3_24.setup()
+  }
+
+  companion object {
+    private val fixtures = arrayOf("src/test/fixtures_sqlite_3_18", "src/test/fixtures_sqlite_3_24")
+
+    @Suppress("unused") // Used by Parameterized JUnit runner reflectively.
+    @Parameters(name = "{0}")
+    @JvmStatic fun parameters() = fixtures.flatMap { fixtureFolder ->
+      File(fixtureFolder).listFiles()!!
+        .filter { it.isDirectory }
+        .map { arrayOf(it.name, it) }
+    } + ansiFixtures
+  }
+}
diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite325FixturesTest.kt b/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite325FixturesTest.kt
new file mode 100644
index 0000000..9073b1f
--- /dev/null
+++ b/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite325FixturesTest.kt
@@ -0,0 +1,30 @@
+package com.alecstrong.sql.psi.core
+
+import com.alecstrong.sql.psi.test.fixtures.FixturesTest
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+import java.io.File
+
+@RunWith(Parameterized::class)
+class Sqlite325FixturesTest(name: String, fixtureRoot: File) : FixturesTest(name, fixtureRoot) {
+  override val replaceRules = arrayOf(
+    "ORDER or WHERE expected" to "ORDER, WHERE or WINDOW expected"
+  )
+
+  override fun setupDialect() {
+    DialectPreset.SQLITE_3_25.setup()
+  }
+
+  companion object {
+    private val fixtures = arrayOf("src/test/fixtures_sqlite_3_18", "src/test/fixtures_sqlite_3_24", "src/test/fixtures_sqlite_3_25")
+
+    @Suppress("unused") // Used by Parameterized JUnit runner reflectively.
+    @Parameters(name = "{0}")
+    @JvmStatic fun parameters() = fixtures.flatMap { fixtureFolder ->
+      File(fixtureFolder).listFiles()!!
+        .filter { it.isDirectory }
+        .map { arrayOf(it.name, it) }
+    } + ansiFixtures
+  }
+}
diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite330FixturesTest.kt b/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite330FixturesTest.kt
new file mode 100644
index 0000000..2cfcc6c
--- /dev/null
+++ b/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite330FixturesTest.kt
@@ -0,0 +1,30 @@
+package com.alecstrong.sql.psi.core
+
+import com.alecstrong.sql.psi.test.fixtures.FixturesTest
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+import java.io.File
+
+@RunWith(Parameterized::class)
+class Sqlite330FixturesTest(name: String, fixtureRoot: File) : FixturesTest(name, fixtureRoot) {
+  override val replaceRules = arrayOf(
+    "ORDER or WHERE expected" to "ORDER, WHERE or WINDOW expected"
+  )
+
+  override fun setupDialect() {
+    DialectPreset.SQLITE_3_30.setup()
+  }
+
+  companion object {
+    private val fixtures = arrayOf("src/test/fixtures_sqlite_3_18", "src/test/fixtures_sqlite_3_24", "src/test/fixtures_sqlite_3_25", "src/test/fixtures_sqlite_3_30")
+
+    @Suppress("unused") // Used by Parameterized JUnit runner reflectively.
+    @Parameters(name = "{0}")
+    @JvmStatic fun parameters() = fixtures.flatMap { fixtureFolder ->
+      File(fixtureFolder).listFiles()!!
+        .filter { it.isDirectory }
+        .map { arrayOf(it.name, it) }
+    } + ansiFixtures
+  }
+}
diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite335FixturesTest.kt b/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite335FixturesTest.kt
new file mode 100644
index 0000000..2bafb8f
--- /dev/null
+++ b/core/src/test/kotlin/com/alecstrong/sql/psi/core/Sqlite335FixturesTest.kt
@@ -0,0 +1,30 @@
+package com.alecstrong.sql.psi.core
+
+import com.alecstrong.sql.psi.test.fixtures.FixturesTest
+import org.junit.runner.RunWith
+import org.junit.runners.Parameterized
+import org.junit.runners.Parameterized.Parameters
+import java.io.File
+
+@RunWith(Parameterized::class)
+class Sqlite335FixturesTest(name: String, fixtureRoot: File) : FixturesTest(name, fixtureRoot) {
+  override val replaceRules = arrayOf(
+    "ORDER or WHERE expected" to "ORDER, WHERE or WINDOW expected"
+  )
+
+  override fun setupDialect() {
+    DialectPreset.SQLITE_3_35.setup()
+  }
+
+  companion object {
+    private val fixtures = arrayOf("src/test/fixtures_sqlite_3_18", "src/test/fixtures_sqlite_3_24", "src/test/fixtures_sqlite_3_25", "src/test/fixtures_sqlite_3_30", "src/test/fixtures_sqlite_3_35")
+
+    @Suppress("unused") // Used by Parameterized JUnit runner reflectively.
+    @Parameters(name = "{0}")
+    @JvmStatic fun parameters() = fixtures.flatMap { fixtureFolder ->
+      File(fixtureFolder).listFiles()!!
+        .filter { it.isDirectory }
+        .map { arrayOf(it.name, it) }
+    } + ansiFixtures
+  }
+}
diff --git a/test-fixtures/build.gradle b/test-fixtures/build.gradle
new file mode 100644
index 0000000..c7f1c73
--- /dev/null
+++ b/test-fixtures/build.gradle
@@ -0,0 +1,10 @@
+plugins {
+  alias(libs.plugins.kotlinJvm)
+}
+
+dependencies {
+  api project(":core")
+  api libs.junit
+  api libs.intellijLang
+  api libs.intellijCore
+}
\ No newline at end of file
diff --git a/test-fixtures/gradle.properties b/test-fixtures/gradle.properties
new file mode 100644
index 0000000..c1638fa
--- /dev/null
+++ b/test-fixtures/gradle.properties
@@ -0,0 +1,4 @@
+POM_ARTIFACT_ID=test-fixtures
+POM_NAME=Test Fixtures
+POM_DESCRIPTION=A fixture for testing extensions of SQL PSI.
+POM_PACKAGING=jar
diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/FixturesTest.kt b/test-fixtures/src/main/kotlin/com/alecstrong/sql/psi/test/fixtures/FixturesTest.kt
similarity index 62%
rename from core/src/test/kotlin/com/alecstrong/sql/psi/core/FixturesTest.kt
rename to test-fixtures/src/main/kotlin/com/alecstrong/sql/psi/test/fixtures/FixturesTest.kt
index 685b29f..06745d1 100644
--- a/core/src/test/kotlin/com/alecstrong/sql/psi/core/FixturesTest.kt
+++ b/test-fixtures/src/main/kotlin/com/alecstrong/sql/psi/test/fixtures/FixturesTest.kt
@@ -1,21 +1,33 @@
-package com.alecstrong.sql.psi.core
+package com.alecstrong.sql.psi.test.fixtures
 
+import com.alecstrong.sql.psi.core.SqlAnnotationHolder
 import com.intellij.psi.PsiDocumentManager
 import com.intellij.psi.PsiElement
 import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.Parameterized
-import org.junit.runners.Parameterized.Parameters
 import java.io.File
+import java.util.Enumeration
+import java.util.jar.JarEntry
+import java.util.jar.JarFile
+
+abstract class FixturesTest(val name: String, val fixtureRoot: File) {
+  protected open val replaceRules: Array<Pair<String, String>> = emptyArray()
+
+  abstract fun setupDialect()
 
-@RunWith(Parameterized::class)
-class FixturesTest(val dialect: DialectPreset, val name: String, val fixtureRoot: File) {
   @Test fun execute() {
-    dialect.setup()
+    setupDialect()
+
     val parser = TestHeadlessParser()
     val errors = ArrayList<String>()
+
+    val newRoot = File("build/fixtureCopies/${fixtureRoot.name}Copy")
+    fixtureRoot.copyRecursively(newRoot, overwrite = true)
+    if (name in ansiFixtures.map { it.first() }) {
+      newRoot.replaceKeywords()
+    }
+
     val environment = parser.build(
-      fixtureRoot.path,
+      newRoot.path,
       object : SqlAnnotationHolder {
         override fun createErrorAnnotation(element: PsiElement, s: String) {
           val documentManager = PsiDocumentManager.getInstance(element.project)
@@ -40,7 +52,7 @@ class FixturesTest(val dialect: DialectPreset, val name: String, val fixtureRoot
     println(sourceFiles)
 
     val expectedFailures = ArrayList<String>()
-    val expectedFailuresFile = File(fixtureRoot, "failure.txt")
+    val expectedFailuresFile = File(newRoot, "failure.txt")
     if (expectedFailuresFile.exists()) {
       expectedFailures += expectedFailuresFile.readText().splitLines().filter { it.isNotEmpty() }
     }
@@ -77,37 +89,65 @@ class FixturesTest(val dialect: DialectPreset, val name: String, val fixtureRoot
         throw AssertionError("Test failed because the compile output unexpectedly has $extrasStr. $assertionMsgEnd")
       }
     }
+
+    newRoot.deleteRecursively()
   }
 
-  fun PsiElement.printTree(printer: (String) -> Unit) {
+  private fun PsiElement.printTree(printer: (String) -> Unit) {
     printer("$this\n")
     children.forEach { child ->
       child.printTree { printer("  $it") }
     }
   }
 
+  private fun File.replaceKeywords() {
+    if (isDirectory) {
+      listFiles()?.forEach { it.replaceKeywords() }
+      return
+    }
+    replaceRules.forEach { (from, to) ->
+      writeText(readText().replace(from, to))
+    }
+  }
+
   companion object {
-    private val dialects = mapOf(
-      DialectPreset.SQLITE_3_18 to arrayOf("src/test/fixtures", "src/test/fixtures_upsert_not_supported", "src/test/fixtures_sqlite_3_18"),
-      DialectPreset.SQLITE_3_24 to arrayOf("src/test/fixtures", "src/test/fixtures_sqlite_3_24"),
-      DialectPreset.SQLITE_3_25 to arrayOf("src/test/fixtures", "src/test/fixtures_sqlite_3_24", "src/test/fixtures_sqlite_3_25"),
-      DialectPreset.SQLITE_3_30 to arrayOf("src/test/fixtures", "src/test/fixtures_sqlite_3_24", "src/test/fixtures_sqlite_3_25", "src/test/fixtures_sqlite_3_30"),
-      DialectPreset.SQLITE_3_35 to arrayOf("src/test/fixtures", "src/test/fixtures_sqlite_3_24", "src/test/fixtures_sqlite_3_25", "src/test/fixtures_sqlite_3_30", "src/test/fixtures_sqlite_3_35"),
-      DialectPreset.MYSQL to arrayOf("src/test/fixtures_mysql"),
-      DialectPreset.HSQL to arrayOf("src/test/fixtures_hsql"),
-      DialectPreset.POSTGRESQL to arrayOf("src/test/fixtures_postgresql")
-    )
+    init {
+      loadFolderFromResources("fixtures")
+    }
 
-    @Suppress("unused") // Used by Parameterized JUnit runner reflectively.
-    @Parameters(name = "{0}: {1}")
-    @JvmStatic fun parameters() = dialects.flatMap { (dialect, fixtureFolders) ->
-      fixtureFolders.flatMap { fixtureFolder ->
-        File(fixtureFolder).listFiles()
-          .filter { it.isDirectory }
-          .map { arrayOf(dialect, it.name, it) }
+    @JvmStatic
+    protected val ansiFixtures = File("build/fixtures").listFiles()
+      .filter { it.isDirectory }
+      .map { arrayOf(it.name, it) }
+  }
+}
+
+private fun Any.loadFolderFromResources(path: String) {
+  val jarFile = File(javaClass.protectionDomain.codeSource.location.path)
+  val parentFile = File("build")
+  File(parentFile, path).apply { if (exists()) deleteRecursively() }
+
+  assert(jarFile.isFile)
+
+  val jar = JarFile(jarFile)
+  val entries: Enumeration<JarEntry> = jar.entries() // gives ALL entries in jar
+  while (entries.hasMoreElements()) {
+    val entry = entries.nextElement()
+    val name: String = entry.name
+    if (name.startsWith("$path/")) { // filter according to the path
+      if (entry.isDirectory) {
+        File(parentFile, entry.name).mkdir()
+      } else {
+        File(parentFile, entry.name).apply {
+          createNewFile()
+          jar.getInputStream(entry).use {
+            it.copyTo(outputStream())
+          }
+        }
       }
     }
   }
+  jar.close()
 }
 
 private fun formatErrorList(errors: List<String>): String {
diff --git a/core/src/test/kotlin/com/alecstrong/sql/psi/core/TestHeadlessParser.kt b/test-fixtures/src/main/kotlin/com/alecstrong/sql/psi/test/fixtures/TestHeadlessParser.kt
similarity index 85%
rename from core/src/test/kotlin/com/alecstrong/sql/psi/core/TestHeadlessParser.kt
rename to test-fixtures/src/main/kotlin/com/alecstrong/sql/psi/test/fixtures/TestHeadlessParser.kt
index 66747c8..4313391 100644
--- a/core/src/test/kotlin/com/alecstrong/sql/psi/core/TestHeadlessParser.kt
+++ b/test-fixtures/src/main/kotlin/com/alecstrong/sql/psi/test/fixtures/TestHeadlessParser.kt
@@ -1,5 +1,9 @@
-package com.alecstrong.sql.psi.core
+package com.alecstrong.sql.psi.test.fixtures
 
+import com.alecstrong.sql.psi.core.SqlAnnotationHolder
+import com.alecstrong.sql.psi.core.SqlCoreEnvironment
+import com.alecstrong.sql.psi.core.SqlFileBase
+import com.alecstrong.sql.psi.core.SqlParserDefinition
 import com.intellij.icons.AllIcons
 import com.intellij.lang.Language
 import com.intellij.openapi.fileTypes.LanguageFileType
@@ -7,7 +11,7 @@ import com.intellij.psi.FileViewProvider
 import com.intellij.psi.tree.IFileElementType
 import java.io.File
 
-internal class TestHeadlessParser {
+class TestHeadlessParser {
   private val parserDefinition = TestParserDefinition()
 
   fun build(root: String, annotator: SqlAnnotationHolder): SqlCoreEnvironment {
diff --git a/core/src/test/fixtures/alias-in-subquery/Test.s b/test-fixtures/src/main/resources/fixtures/alias-in-subquery/Test.s
similarity index 100%
rename from core/src/test/fixtures/alias-in-subquery/Test.s
rename to test-fixtures/src/main/resources/fixtures/alias-in-subquery/Test.s
diff --git a/core/src/test/fixtures/alter-in-unordered/Test.s b/test-fixtures/src/main/resources/fixtures/alter-in-unordered/Test.s
similarity index 100%
rename from core/src/test/fixtures/alter-in-unordered/Test.s
rename to test-fixtures/src/main/resources/fixtures/alter-in-unordered/Test.s
diff --git a/core/src/test/fixtures/alter-table-multiple/1.s b/test-fixtures/src/main/resources/fixtures/alter-table-multiple/1.s
similarity index 100%
rename from core/src/test/fixtures/alter-table-multiple/1.s
rename to test-fixtures/src/main/resources/fixtures/alter-table-multiple/1.s
diff --git a/core/src/test/fixtures/bind-failures/Test.s b/test-fixtures/src/main/resources/fixtures/bind-failures/Test.s
similarity index 100%
rename from core/src/test/fixtures/bind-failures/Test.s
rename to test-fixtures/src/main/resources/fixtures/bind-failures/Test.s
diff --git a/core/src/test/fixtures/bind-failures/failure.txt b/test-fixtures/src/main/resources/fixtures/bind-failures/failure.txt
similarity index 100%
rename from core/src/test/fixtures/bind-failures/failure.txt
rename to test-fixtures/src/main/resources/fixtures/bind-failures/failure.txt
diff --git a/core/src/test/fixtures/bind-parameters-valid/Test.s b/test-fixtures/src/main/resources/fixtures/bind-parameters-valid/Test.s
similarity index 100%
rename from core/src/test/fixtures/bind-parameters-valid/Test.s
rename to test-fixtures/src/main/resources/fixtures/bind-parameters-valid/Test.s
diff --git a/core/src/test/fixtures/bitwise-operator/Test.s b/test-fixtures/src/main/resources/fixtures/bitwise-operator/Test.s
similarity index 100%
rename from core/src/test/fixtures/bitwise-operator/Test.s
rename to test-fixtures/src/main/resources/fixtures/bitwise-operator/Test.s
diff --git a/core/src/test/fixtures/collate-nocase/Test.s b/test-fixtures/src/main/resources/fixtures/collate-nocase/Test.s
similarity index 100%
rename from core/src/test/fixtures/collate-nocase/Test.s
rename to test-fixtures/src/main/resources/fixtures/collate-nocase/Test.s
diff --git a/core/src/test/fixtures/column-through-join-alias/Test.s b/test-fixtures/src/main/resources/fixtures/column-through-join-alias/Test.s
similarity index 100%
rename from core/src/test/fixtures/column-through-join-alias/Test.s
rename to test-fixtures/src/main/resources/fixtures/column-through-join-alias/Test.s
diff --git a/core/src/test/fixtures/create-if-not-exists/1.s b/test-fixtures/src/main/resources/fixtures/create-if-not-exists/1.s
similarity index 100%
rename from core/src/test/fixtures/create-if-not-exists/1.s
rename to test-fixtures/src/main/resources/fixtures/create-if-not-exists/1.s
diff --git a/core/src/test/fixtures/create-index-collision/Test.s b/test-fixtures/src/main/resources/fixtures/create-index-collision/Test.s
similarity index 100%
rename from core/src/test/fixtures/create-index-collision/Test.s
rename to test-fixtures/src/main/resources/fixtures/create-index-collision/Test.s
diff --git a/core/src/test/fixtures/create-index-collision/failure.txt b/test-fixtures/src/main/resources/fixtures/create-index-collision/failure.txt
similarity index 100%
rename from core/src/test/fixtures/create-index-collision/failure.txt
rename to test-fixtures/src/main/resources/fixtures/create-index-collision/failure.txt
diff --git a/core/src/test/fixtures/create-index-validation-failures/Test.s b/test-fixtures/src/main/resources/fixtures/create-index-validation-failures/Test.s
similarity index 100%
rename from core/src/test/fixtures/create-index-validation-failures/Test.s
rename to test-fixtures/src/main/resources/fixtures/create-index-validation-failures/Test.s
diff --git a/core/src/test/fixtures/create-index-validation-failures/failure.txt b/test-fixtures/src/main/resources/fixtures/create-index-validation-failures/failure.txt
similarity index 100%
rename from core/src/test/fixtures/create-index-validation-failures/failure.txt
rename to test-fixtures/src/main/resources/fixtures/create-index-validation-failures/failure.txt
diff --git a/core/src/test/fixtures/create-table-validation-failures/Child1.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child1.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Child1.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child1.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Child10.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child10.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Child10.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child10.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Child11.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child11.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Child11.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child11.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Child2.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child2.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Child2.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child2.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Child3.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child3.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Child3.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child3.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Child4.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child4.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Child4.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child4.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Child5.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child5.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Child5.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child5.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Child6.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child6.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Child6.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child6.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Child7.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child7.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Child7.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child7.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Child8.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child8.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Child8.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child8.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Child9.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child9.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Child9.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Child9.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Parent.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Parent.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Parent.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Parent.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Parent2.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Parent2.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Parent2.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Parent2.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Test.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Test.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Test.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Test.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Test2.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Test2.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Test2.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Test2.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Test3.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Test3.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Test3.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Test3.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Test4.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Test4.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Test4.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Test4.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Test5.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Test5.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Test5.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Test5.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/Test6.s b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Test6.s
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/Test6.s
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/Test6.s
diff --git a/core/src/test/fixtures/create-table-validation-failures/failure.txt b/test-fixtures/src/main/resources/fixtures/create-table-validation-failures/failure.txt
similarity index 100%
rename from core/src/test/fixtures/create-table-validation-failures/failure.txt
rename to test-fixtures/src/main/resources/fixtures/create-table-validation-failures/failure.txt
diff --git a/core/src/test/fixtures/create-trigger-collision/Test.s b/test-fixtures/src/main/resources/fixtures/create-trigger-collision/Test.s
similarity index 100%
rename from core/src/test/fixtures/create-trigger-collision/Test.s
rename to test-fixtures/src/main/resources/fixtures/create-trigger-collision/Test.s
diff --git a/core/src/test/fixtures/create-trigger-collision/failure.txt b/test-fixtures/src/main/resources/fixtures/create-trigger-collision/failure.txt
similarity index 100%
rename from core/src/test/fixtures/create-trigger-collision/failure.txt
rename to test-fixtures/src/main/resources/fixtures/create-trigger-collision/failure.txt
diff --git a/core/src/test/fixtures/create-trigger-docid/Test.s b/test-fixtures/src/main/resources/fixtures/create-trigger-docid/Test.s
similarity index 100%
rename from core/src/test/fixtures/create-trigger-docid/Test.s
rename to test-fixtures/src/main/resources/fixtures/create-trigger-docid/Test.s
diff --git a/core/src/test/fixtures/create-trigger-raise/Test.s b/test-fixtures/src/main/resources/fixtures/create-trigger-raise/Test.s
similarity index 100%
rename from core/src/test/fixtures/create-trigger-raise/Test.s
rename to test-fixtures/src/main/resources/fixtures/create-trigger-raise/Test.s
diff --git a/core/src/test/fixtures/create-trigger-success/Test.s b/test-fixtures/src/main/resources/fixtures/create-trigger-success/Test.s
similarity index 100%
rename from core/src/test/fixtures/create-trigger-success/Test.s
rename to test-fixtures/src/main/resources/fixtures/create-trigger-success/Test.s
diff --git a/core/src/test/fixtures/create-trigger-validation-failures/Test.s b/test-fixtures/src/main/resources/fixtures/create-trigger-validation-failures/Test.s
similarity index 100%
rename from core/src/test/fixtures/create-trigger-validation-failures/Test.s
rename to test-fixtures/src/main/resources/fixtures/create-trigger-validation-failures/Test.s
diff --git a/core/src/test/fixtures/create-trigger-validation-failures/failure.txt b/test-fixtures/src/main/resources/fixtures/create-trigger-validation-failures/failure.txt
similarity index 100%
rename from core/src/test/fixtures/create-trigger-validation-failures/failure.txt
rename to test-fixtures/src/main/resources/fixtures/create-trigger-validation-failures/failure.txt
diff --git a/core/src/test/fixtures/delete-error/Test.s b/test-fixtures/src/main/resources/fixtures/delete-error/Test.s
similarity index 100%
rename from core/src/test/fixtures/delete-error/Test.s
rename to test-fixtures/src/main/resources/fixtures/delete-error/Test.s
diff --git a/core/src/test/fixtures/delete-validation-failures/Test.s b/test-fixtures/src/main/resources/fixtures/delete-validation-failures/Test.s
similarity index 100%
rename from core/src/test/fixtures/delete-validation-failures/Test.s
rename to test-fixtures/src/main/resources/fixtures/delete-validation-failures/Test.s
diff --git a/core/src/test/fixtures/delete-validation-failures/failure.txt b/test-fixtures/src/main/resources/fixtures/delete-validation-failures/failure.txt
similarity index 100%
rename from core/src/test/fixtures/delete-validation-failures/failure.txt
rename to test-fixtures/src/main/resources/fixtures/delete-validation-failures/failure.txt
diff --git a/core/src/test/fixtures/double-error/Test.s b/test-fixtures/src/main/resources/fixtures/double-error/Test.s
similarity index 100%
rename from core/src/test/fixtures/double-error/Test.s
rename to test-fixtures/src/main/resources/fixtures/double-error/Test.s
diff --git a/core/src/test/fixtures/double-error/failure.txt b/test-fixtures/src/main/resources/fixtures/double-error/failure.txt
similarity index 100%
rename from core/src/test/fixtures/double-error/failure.txt
rename to test-fixtures/src/main/resources/fixtures/double-error/failure.txt
diff --git a/core/src/test/fixtures/duplicate-column-name/IdentifierTable.s b/test-fixtures/src/main/resources/fixtures/duplicate-column-name/IdentifierTable.s
similarity index 100%
rename from core/src/test/fixtures/duplicate-column-name/IdentifierTable.s
rename to test-fixtures/src/main/resources/fixtures/duplicate-column-name/IdentifierTable.s
diff --git a/core/src/test/fixtures/duplicate-column-name/Table.s b/test-fixtures/src/main/resources/fixtures/duplicate-column-name/Table.s
similarity index 100%
rename from core/src/test/fixtures/duplicate-column-name/Table.s
rename to test-fixtures/src/main/resources/fixtures/duplicate-column-name/Table.s
diff --git a/core/src/test/fixtures/duplicate-column-name/failure.txt b/test-fixtures/src/main/resources/fixtures/duplicate-column-name/failure.txt
similarity index 100%
rename from core/src/test/fixtures/duplicate-column-name/failure.txt
rename to test-fixtures/src/main/resources/fixtures/duplicate-column-name/failure.txt
diff --git a/core/src/test/fixtures/duplicate-table-name/Table.s b/test-fixtures/src/main/resources/fixtures/duplicate-table-name/Table.s
similarity index 100%
rename from core/src/test/fixtures/duplicate-table-name/Table.s
rename to test-fixtures/src/main/resources/fixtures/duplicate-table-name/Table.s
diff --git a/core/src/test/fixtures/duplicate-table-name/Table2.s b/test-fixtures/src/main/resources/fixtures/duplicate-table-name/Table2.s
similarity index 100%
rename from core/src/test/fixtures/duplicate-table-name/Table2.s
rename to test-fixtures/src/main/resources/fixtures/duplicate-table-name/Table2.s
diff --git a/core/src/test/fixtures/duplicate-table-name/failure.txt b/test-fixtures/src/main/resources/fixtures/duplicate-table-name/failure.txt
similarity index 100%
rename from core/src/test/fixtures/duplicate-table-name/failure.txt
rename to test-fixtures/src/main/resources/fixtures/duplicate-table-name/failure.txt
diff --git a/core/src/test/fixtures/exists-clause/Test.s b/test-fixtures/src/main/resources/fixtures/exists-clause/Test.s
similarity index 100%
rename from core/src/test/fixtures/exists-clause/Test.s
rename to test-fixtures/src/main/resources/fixtures/exists-clause/Test.s
diff --git a/core/src/test/fixtures/expression-failures/Test.s b/test-fixtures/src/main/resources/fixtures/expression-failures/Test.s
similarity index 83%
rename from core/src/test/fixtures/expression-failures/Test.s
rename to test-fixtures/src/main/resources/fixtures/expression-failures/Test.s
index 505ddf6..4c9f6e6 100644
--- a/core/src/test/fixtures/expression-failures/Test.s
+++ b/test-fixtures/src/main/resources/fixtures/expression-failures/Test.s
@@ -1,5 +1,5 @@
 CREATE TABLE test (
-  _id INTEGER NOT NULL PRIMARY KEY,
+  _id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
   other_column INTEGER NOT NULL
 );
 
diff --git a/core/src/test/fixtures/expression-failures/failure.txt b/test-fixtures/src/main/resources/fixtures/expression-failures/failure.txt
similarity index 100%
rename from core/src/test/fixtures/expression-failures/failure.txt
rename to test-fixtures/src/main/resources/fixtures/expression-failures/failure.txt
diff --git a/core/src/test/fixtures/foreign-key-error/Player.s b/test-fixtures/src/main/resources/fixtures/foreign-key-error/Player.s
similarity index 70%
rename from core/src/test/fixtures/foreign-key-error/Player.s
rename to test-fixtures/src/main/resources/fixtures/foreign-key-error/Player.s
index 0f0e1d9..07df554 100644
--- a/core/src/test/fixtures/foreign-key-error/Player.s
+++ b/test-fixtures/src/main/resources/fixtures/foreign-key-error/Player.s
@@ -1,6 +1,7 @@
 CREATE TABLE player (
   name TEXT NOT NULL,
   number INTEGER NOT NULL,
-  team TEXT REFERENCES team(name),
+  team TEXT
+    REFERENCES team(name),
   PRIMARY KEY (team, number)
 );
\ No newline at end of file
diff --git a/core/src/test/fixtures/foreign-key-error/Team.s b/test-fixtures/src/main/resources/fixtures/foreign-key-error/Team.s
similarity index 100%
rename from core/src/test/fixtures/foreign-key-error/Team.s
rename to test-fixtures/src/main/resources/fixtures/foreign-key-error/Team.s
diff --git a/test-fixtures/src/main/resources/fixtures/foreign-key-error/failure.txt b/test-fixtures/src/main/resources/fixtures/foreign-key-error/failure.txt
new file mode 100644
index 0000000..12e20aa
--- /dev/null
+++ b/test-fixtures/src/main/resources/fixtures/foreign-key-error/failure.txt
@@ -0,0 +1,3 @@
+Player.s line 5:4 - Table team does not have a unique index on column name
+Player.s line 5:20 - No column found with name name
+Team.s line 3:51 - '(', ')', ',', <column constraint real>, DEFERRABLE, MATCH, NOT or ON expected, got '.'
\ No newline at end of file