testing

package
v1.7.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 12, 2026 License: AGPL-3.0 Imports: 6 Imported by: 0

README

GoSQLX Testing Helpers

A comprehensive testing helper package for writing SQL parsing tests with GoSQLX. This package provides assertion and requirement functions that integrate seamlessly with Go's standard testing package.

Features

  • Validation Helpers: Assert or require SQL validity
  • Formatting Assertions: Test SQL formatting output
  • Metadata Extraction: Assert tables and columns referenced in SQL
  • Statement Type Checking: Verify parsed AST statement types
  • Error Testing: Assert specific error conditions
  • Clear Error Messages: Descriptive failures with SQL context
  • T.Helper() Support: Proper test failure reporting at the call site

Installation

This package is part of GoSQLX. Import it in your tests:

import (
    "testing"
    gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
)

Quick Start

func TestUserQueries(t *testing.T) {
    // Assert SQL is valid
    gosqlxtesting.AssertValidSQL(t, "SELECT * FROM users WHERE active = true")

    // Verify tables referenced
    gosqlxtesting.AssertTables(t,
        "SELECT * FROM users u JOIN orders o ON u.id = o.user_id",
        []string{"users", "orders"})

    // Verify columns selected
    gosqlxtesting.AssertColumns(t,
        "SELECT id, name, email FROM users",
        []string{"id", "name", "email"})

    // Verify statement type
    gosqlxtesting.AssertParsesTo(t,
        "INSERT INTO users (name) VALUES ('John')",
        &ast.InsertStatement{})
}

API Reference

Validation Functions
AssertValidSQL
func AssertValidSQL(t TestingT, sql string) bool

Asserts that SQL is syntactically valid. Test continues on failure.

Example:

gosqlxtesting.AssertValidSQL(t, "SELECT * FROM users")
AssertInvalidSQL
func AssertInvalidSQL(t TestingT, sql string) bool

Asserts that SQL is syntactically invalid. Test continues on failure.

Example:

gosqlxtesting.AssertInvalidSQL(t, "SELECT FROM WHERE")
RequireValidSQL
func RequireValidSQL(t TestingT, sql string)

Requires SQL to be valid. Test stops immediately on failure.

Example:

gosqlxtesting.RequireValidSQL(t, "SELECT * FROM users")
// Code below only executes if SQL is valid
RequireInvalidSQL
func RequireInvalidSQL(t TestingT, sql string)

Requires SQL to be invalid. Test stops immediately on failure.

Example:

gosqlxtesting.RequireInvalidSQL(t, "SELECT FROM")
Formatting Functions
AssertFormattedSQL
func AssertFormattedSQL(t TestingT, sql, expected string) bool

Asserts that SQL formats to match expected output.

Example:

gosqlxtesting.AssertFormattedSQL(t,
    "select * from users",
    "SELECT * FROM users")
Metadata Extraction Functions
AssertTables
func AssertTables(t TestingT, sql string, expectedTables []string) bool

Asserts that SQL references the expected tables (order-independent).

Examples:

// Simple SELECT
gosqlxtesting.AssertTables(t,
    "SELECT * FROM users",
    []string{"users"})

// JOIN query
gosqlxtesting.AssertTables(t,
    "SELECT * FROM users u JOIN orders o ON u.id = o.user_id",
    []string{"users", "orders"})

// Multiple JOINs
gosqlxtesting.AssertTables(t,
    "SELECT * FROM users u LEFT JOIN orders o ON u.id = o.user_id RIGHT JOIN products p",
    []string{"users", "orders", "products"})

// INSERT/UPDATE/DELETE
gosqlxtesting.AssertTables(t, "INSERT INTO users (name) VALUES ('John')", []string{"users"})
gosqlxtesting.AssertTables(t, "UPDATE orders SET status = 'shipped'", []string{"orders"})
gosqlxtesting.AssertTables(t, "DELETE FROM old_records", []string{"old_records"})
AssertColumns
func AssertColumns(t TestingT, sql string, expectedColumns []string) bool

Asserts that SELECT statement selects the expected columns (order-independent).

Examples:

// Simple column list
gosqlxtesting.AssertColumns(t,
    "SELECT id, name, email FROM users",
    []string{"id", "name", "email"})

// Order doesn't matter
gosqlxtesting.AssertColumns(t,
    "SELECT name, id, email FROM users",
    []string{"email", "id", "name"}) // Still passes

// With WHERE clause (only SELECT columns are extracted)
gosqlxtesting.AssertColumns(t,
    "SELECT id, name FROM users WHERE active = true",
    []string{"id", "name"})
Statement Type Functions
AssertParsesTo
func AssertParsesTo(t TestingT, sql string, expectedType interface{}) bool

Asserts that SQL parses to a specific AST statement type.

Examples:

gosqlxtesting.AssertParsesTo(t, "SELECT * FROM users", &ast.SelectStatement{})
gosqlxtesting.AssertParsesTo(t, "INSERT INTO users (name) VALUES ('John')", &ast.InsertStatement{})
gosqlxtesting.AssertParsesTo(t, "UPDATE users SET active = false", &ast.UpdateStatement{})
gosqlxtesting.AssertParsesTo(t, "DELETE FROM users", &ast.DeleteStatement{})
Error Testing Functions
AssertErrorContains
func AssertErrorContains(t TestingT, sql, expectedSubstring string) bool

Asserts that parsing SQL produces an error containing the expected substring.

Examples:

gosqlxtesting.AssertErrorContains(t, "SELECT FROM WHERE", "parsing")
gosqlxtesting.AssertErrorContains(t, "INVALID SQL", "tokenization")
Advanced Functions
RequireParse
func RequireParse(t TestingT, sql string) *ast.AST

Requires SQL to parse successfully and returns the AST. Test stops on failure.

Example:

astNode := gosqlxtesting.RequireParse(t, "SELECT id, name FROM users")

// Make custom assertions on the AST
if selectStmt, ok := astNode.Statements[0].(*ast.SelectStatement); ok {
    if len(selectStmt.Columns) != 2 {
        t.Errorf("Expected 2 columns, got %d", len(selectStmt.Columns))
    }
}

Comprehensive Test Example

func TestUserManagement(t *testing.T) {
    // Test valid user queries
    userQuery := "SELECT id, name, email FROM users WHERE active = true"

    // Validate syntax
    gosqlxtesting.RequireValidSQL(t, userQuery)

    // Verify metadata
    gosqlxtesting.AssertTables(t, userQuery, []string{"users"})
    gosqlxtesting.AssertColumns(t, userQuery, []string{"id", "name", "email"})

    // Verify statement type
    gosqlxtesting.AssertParsesTo(t, userQuery, &ast.SelectStatement{})

    // Test invalid variations
    gosqlxtesting.AssertInvalidSQL(t, "SELECT FROM users WHERE")
    gosqlxtesting.AssertErrorContains(t, "SELECT * FROM", "parsing")
}

Testing Different SQL Features

Window Functions
func TestWindowFunctions(t *testing.T) {
    windowQuery := `
        SELECT
            name,
            salary,
            ROW_NUMBER() OVER (ORDER BY salary DESC) as rank
        FROM employees
    `

    gosqlxtesting.RequireValidSQL(t, windowQuery)
    gosqlxtesting.AssertTables(t, windowQuery, []string{"employees"})
    gosqlxtesting.AssertColumns(t, windowQuery, []string{"name", "salary"})
}
Common Table Expressions (CTEs)
func TestCTEs(t *testing.T) {
    cteQuery := `
        WITH active_users AS (
            SELECT id, name FROM users WHERE active = true
        )
        SELECT name FROM active_users
    `

    gosqlxtesting.RequireValidSQL(t, cteQuery)
    gosqlxtesting.AssertTables(t, cteQuery, []string{"users"})
}
JOIN Queries
func TestJoins(t *testing.T) {
    testCases := []struct {
        name   string
        query  string
        tables []string
    }{
        {
            name:   "INNER JOIN",
            query:  "SELECT * FROM users u INNER JOIN orders o ON u.id = o.user_id",
            tables: []string{"users", "orders"},
        },
        {
            name:   "Multiple JOINs",
            query:  "SELECT * FROM users u JOIN orders o ON u.id = o.user_id JOIN products p ON o.product_id = p.id",
            tables: []string{"users", "orders", "products"},
        },
    }

    for _, tc := range testCases {
        t.Run(tc.name, func(t *testing.T) {
            gosqlxtesting.RequireValidSQL(t, tc.query)
            gosqlxtesting.AssertTables(t, tc.query, tc.tables)
        })
    }
}

Design Decisions

TestingT Interface

The package uses a TestingT interface instead of *testing.T directly. This allows:

  • Easy mocking in the package's own tests
  • Compatibility with testing frameworks that wrap *testing.T
  • Future extensibility
Order-Independent Comparisons

AssertTables and AssertColumns compare slices in an order-independent way, as SQL doesn't guarantee order for these metadata elements.

Synthetic Table Filtering

The table extraction automatically filters out synthetic table names that the parser may generate internally (e.g., tables with parentheses or _with_ patterns).

Clear Error Messages

All assertion functions provide:

  • The SQL that was being tested (truncated to 100 chars if needed)
  • Expected vs actual values
  • Contextual information about the failure
T.Helper() Support

All functions call t.Helper() to ensure test failures are reported at the call site, not inside the helper functions.

Coverage

The testing package achieves 95.0% test coverage, ensuring reliability for your test suites.

Contributing

When adding new helper functions:

  1. Follow the naming convention: Assert* for soft assertions, Require* for hard requirements
  2. Always call t.Helper() as the first line
  3. Provide clear, descriptive error messages
  4. Add comprehensive tests
  5. Add godoc examples in example_test.go

License

Part of the GoSQLX project. See the main project LICENSE for details.

Documentation

Overview

Package testing provides comprehensive test helpers for SQL parsing validation.

This package offers convenient assertion and requirement functions for testing SQL parsing, formatting, and metadata extraction in Go test suites. It integrates seamlessly with Go's standard testing package and follows patterns similar to testify/assert and testify/require.

Overview

The testing package simplifies writing tests for SQL parsing by providing:

  • Clear, descriptive error messages with SQL context
  • Proper test failure reporting with t.Helper() for accurate stack traces
  • Both assertion (test continues) and requirement (test stops) styles
  • Metadata extraction helpers for validating tables and columns
  • SQL validity checking for positive and negative test cases

Quick Start

Basic SQL validation:

import (
    "testing"
    sqltest "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
)

func TestBasicSQL(t *testing.T) {
    // Assert SQL is valid
    sqltest.AssertValidSQL(t, "SELECT * FROM users")

    // Assert SQL is invalid
    sqltest.AssertInvalidSQL(t, "SELECT FROM WHERE")

    // Require SQL to parse (stops test on failure)
    ast := sqltest.RequireParse(t, "SELECT id, name FROM users")
    // Continue working with ast
}

Assertion vs Requirement Functions

The package provides two styles of test helpers:

Assert functions (AssertValidSQL, AssertInvalidSQL, etc.):

  • Report failures with t.Errorf()
  • Test continues after failure
  • Use for non-critical checks or when testing multiple conditions
  • Return bool indicating success (true) or failure (false)

Require functions (RequireValidSQL, RequireParse, etc.):

  • Report failures with t.Fatalf()
  • Test stops immediately on failure
  • Use for critical preconditions that must pass
  • Do not return values (test terminates on failure)

Metadata Validation

Test that SQL queries reference the expected tables and columns:

func TestQueryMetadata(t *testing.T) {
    sql := "SELECT u.name, o.total FROM users u JOIN orders o ON u.id = o.user_id"

    // Verify table references
    sqltest.AssertTables(t, sql, []string{"users", "orders"})

    // Verify column references
    sqltest.AssertColumns(t, sql, []string{"name", "total", "id", "user_id"})
}

AST Type Verification

Verify that SQL parses to the expected statement type:

func TestStatementTypes(t *testing.T) {
    sqltest.AssertParsesTo(t, "SELECT * FROM users", &ast.SelectStatement{})
    sqltest.AssertParsesTo(t, "INSERT INTO users VALUES (1, 'John')", &ast.InsertStatement{})
    sqltest.AssertParsesTo(t, "UPDATE users SET name = 'Jane'", &ast.UpdateStatement{})
    sqltest.AssertParsesTo(t, "DELETE FROM users", &ast.DeleteStatement{})
}

Error Message Testing

Test that parsing produces specific error messages:

func TestParsingErrors(t *testing.T) {
    // Verify error contains expected substring
    sqltest.AssertErrorContains(t, "SELECT FROM WHERE", "unexpected token")

    // Verify SQL is invalid without checking specific message
    sqltest.AssertInvalidSQL(t, "INVALID SQL SYNTAX HERE")
}

Formatting Validation

Test SQL formatting (note: full formatting support coming in future release):

func TestFormatting(t *testing.T) {
    input := "select * from users"
    expected := "SELECT * FROM users;"
    sqltest.AssertFormattedSQL(t, input, expected)
}

Table-Driven Tests

Use the helpers in table-driven tests for comprehensive coverage:

func TestSQLQueries(t *testing.T) {
    tests := []struct {
        name   string
        sql    string
        valid  bool
        tables []string
    }{
        {
            name:   "simple select",
            sql:    "SELECT * FROM users",
            valid:  true,
            tables: []string{"users"},
        },
        {
            name:   "join query",
            sql:    "SELECT * FROM users u JOIN orders o ON u.id = o.user_id",
            valid:  true,
            tables: []string{"users", "orders"},
        },
        {
            name:  "invalid syntax",
            sql:   "SELECT FROM WHERE",
            valid: false,
        },
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            if tt.valid {
                sqltest.AssertValidSQL(t, tt.sql)
                if tt.tables != nil {
                    sqltest.AssertTables(t, tt.sql, tt.tables)
                }
            } else {
                sqltest.AssertInvalidSQL(t, tt.sql)
            }
        })
    }
}

PostgreSQL v1.6.0 Features

Test PostgreSQL-specific features supported in GoSQLX v1.6.0:

func TestPostgreSQLFeatures(t *testing.T) {
    // JSON operators
    sqltest.AssertValidSQL(t, "SELECT data->>'name' FROM users")
    sqltest.AssertValidSQL(t, "SELECT * FROM users WHERE data @> '{\"status\":\"active\"}'")

    // LATERAL JOIN
    sqltest.AssertValidSQL(t, `
        SELECT u.name, o.order_date
        FROM users u,
        LATERAL (SELECT * FROM orders WHERE user_id = u.id LIMIT 3) o
    `)

    // FILTER clause
    sqltest.AssertValidSQL(t, `
        SELECT COUNT(*) FILTER (WHERE status = 'active') FROM users
    `)

    // RETURNING clause
    sqltest.AssertValidSQL(t, `
        INSERT INTO users (name) VALUES ('John') RETURNING id, created_at
    `)

    // DISTINCT ON
    sqltest.AssertValidSQL(t, `
        SELECT DISTINCT ON (dept_id) dept_id, name
        FROM employees ORDER BY dept_id, salary DESC
    `)
}

Advanced SQL Features

Test SQL-99 and SQL:2003 features:

func TestAdvancedFeatures(t *testing.T) {
    // Window functions
    sqltest.AssertValidSQL(t, `
        SELECT name, salary,
            RANK() OVER (PARTITION BY dept ORDER BY salary DESC)
        FROM employees
    `)

    // CTEs with RECURSIVE
    sqltest.AssertValidSQL(t, `
        WITH RECURSIVE org_chart AS (
            SELECT id, name, manager_id FROM employees WHERE manager_id IS NULL
            UNION ALL
            SELECT e.id, e.name, e.manager_id
            FROM employees e JOIN org_chart o ON e.manager_id = o.id
        )
        SELECT * FROM org_chart
    `)

    // GROUPING SETS
    sqltest.AssertValidSQL(t, `
        SELECT region, product, SUM(sales)
        FROM orders
        GROUP BY GROUPING SETS ((region), (product), (region, product))
    `)

    // MERGE statement
    sqltest.AssertValidSQL(t, `
        MERGE INTO target t
        USING source s ON t.id = s.id
        WHEN MATCHED THEN UPDATE SET t.value = s.value
        WHEN NOT MATCHED THEN INSERT (id, value) VALUES (s.id, s.value)
    `)
}

Best Practices

  1. Use t.Helper() pattern: All functions call t.Helper() to report failures at the correct line in your test code, not in the helper function.

2. Choose assertion vs requirement appropriately:

  • Use Assert* for multiple checks in one test

  • Use Require* when failure makes subsequent checks meaningless

    3. Truncated error messages: Long SQL strings are automatically truncated in error messages (max 100 characters) for readability.

    4. Order independence: Table and column assertions compare sets, not ordered lists. ["users", "orders"] matches ["orders", "users"].

    5. Test both positive and negative cases: Always test that valid SQL passes and invalid SQL fails to ensure comprehensive coverage.

Thread Safety

All test helper functions are safe to call concurrently from different goroutines running parallel tests (t.Parallel()). Each test gets its own testing.T instance, so there are no shared resources.

Performance

The test helpers parse SQL using the full GoSQLX parser, which is optimized for performance:

  • Parsing: <1ms for typical queries
  • Metadata extraction: <100μs for complex queries
  • Object pooling: Automatic memory reuse across test cases

For test suites with hundreds or thousands of SQL test cases, the helpers provide excellent performance with minimal overhead.

Error Message Format

All assertion failures include formatted error messages with context:

Expected valid SQL, but got error:
  SQL: SELECT * FROM users WHERE id = ?
  Error: parsing failed: unexpected token at line 1, column 35

SQL table references do not match expected:
  SQL: SELECT * FROM users u JOIN orders o ON u.id = o.user_id
  Expected: [orders users]
  Got: [orders posts users]

Integration with Test Frameworks

While designed for Go's standard testing package, the helpers work with any framework that provides a compatible testing.T interface:

type TestingT interface {
    Helper()
    Errorf(format string, args ...interface{})
    Fatalf(format string, args ...interface{})
}

This allows integration with frameworks like Ginkgo, testify, or custom test runners.

Example Test Suite

Complete example of a comprehensive SQL test suite:

package myapp_test

import (
    "testing"
    sqltest "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
    "github.com/ajitpratap0/GoSQLX/pkg/sql/ast"
)

func TestUserQueries(t *testing.T) {
    t.Run("list all users", func(t *testing.T) {
        sql := "SELECT id, name, email FROM users WHERE active = true"
        sqltest.AssertValidSQL(t, sql)
        sqltest.AssertTables(t, sql, []string{"users"})
        sqltest.AssertColumns(t, sql, []string{"id", "name", "email", "active"})
        sqltest.AssertParsesTo(t, sql, &ast.SelectStatement{})
    })

    t.Run("user with orders", func(t *testing.T) {
        sql := `
            SELECT u.name, COUNT(o.id) as order_count
            FROM users u
            LEFT JOIN orders o ON u.id = o.user_id
            GROUP BY u.name
        `
        sqltest.AssertValidSQL(t, sql)
        sqltest.AssertTables(t, sql, []string{"users", "orders"})
    })

    t.Run("invalid query", func(t *testing.T) {
        sqltest.AssertInvalidSQL(t, "SELECT FROM users WHERE")
        sqltest.AssertErrorContains(t, "SELECT FROM WHERE", "unexpected")
    })
}

See Also

  • gosqlx package: Main high-level API for SQL parsing
  • gosqlx.Parse: Core parsing function used by these helpers
  • gosqlx.ExtractTables, ExtractColumns: Metadata extraction
  • ast package: AST node type definitions

Version

Package testing is part of GoSQLX v1.6.0+.

For the latest documentation and examples, visit: https://github.com/ajitpratap0/GoSQLX

Package testing provides helper functions for testing SQL parsing in Go tests.

This package offers convenient assertion and requirement functions for validating SQL parsing, formatting, and metadata extraction in your test suites. It integrates seamlessly with Go's standard testing package and follows similar patterns to testify/assert.

Example usage:

func TestMySQL(t *testing.T) {
    testing.AssertValidSQL(t, "SELECT * FROM users")
    testing.AssertInvalidSQL(t, "SELECT FROM")
    testing.AssertTables(t, "SELECT * FROM users u JOIN orders o", []string{"users", "orders"})
}

Key features:

  • Clear, descriptive error messages with SQL context
  • Proper test failure reporting with t.Helper()
  • Support for both assertion (test continues) and requirement (test stops) styles
  • Metadata extraction helpers (tables, columns)
Example (ComprehensiveTest)

Example_comprehensiveTest shows a complete test using multiple helpers.

package main

import (
	"testing"

	gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
	"github.com/ajitpratap0/GoSQLX/pkg/sql/ast"
)

func main() {
	t := &testing.T{}

	// Test a user query feature
	userQuery := "SELECT id, name, email FROM users WHERE active = true"

	// Validate it's syntactically correct
	gosqlxtesting.RequireValidSQL(t, userQuery)

	// Verify the tables referenced
	gosqlxtesting.AssertTables(t, userQuery, []string{"users"})

	// Verify the columns selected
	gosqlxtesting.AssertColumns(t, userQuery, []string{"id", "name", "email"})

	// Verify it's a SELECT statement
	gosqlxtesting.AssertParsesTo(t, userQuery, &ast.SelectStatement{})

	// Test invalid query variations
	gosqlxtesting.AssertInvalidSQL(t, "SELECT FROM users WHERE")
	gosqlxtesting.AssertErrorContains(t, "SELECT * FROM", "parsing")
}
Example (CteQueries)

Example_cteQueries demonstrates testing Common Table Expression queries.

package main

import (
	"testing"

	gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
)

func main() {
	t := &testing.T{}

	// CTE query
	cteQuery := `
		WITH active_users AS (
			SELECT id, name FROM users WHERE active = true
		)
		SELECT name FROM active_users
	`

	// Validate CTE syntax
	gosqlxtesting.RequireValidSQL(t, cteQuery)

	// Verify table reference (only actual tables, not CTEs)
	gosqlxtesting.AssertTables(t, cteQuery, []string{"users"})
}
Example (DmlStatements)

Example_dmlStatements demonstrates testing DML operations.

package main

import (
	"testing"

	gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
	"github.com/ajitpratap0/GoSQLX/pkg/sql/ast"
)

func main() {
	t := &testing.T{}

	// INSERT statement
	insertSQL := "INSERT INTO users (id, name, email) VALUES (1, 'John', 'john@example.com')"
	gosqlxtesting.RequireValidSQL(t, insertSQL)
	gosqlxtesting.AssertTables(t, insertSQL, []string{"users"})
	gosqlxtesting.AssertParsesTo(t, insertSQL, &ast.InsertStatement{})

	// UPDATE statement
	updateSQL := "UPDATE users SET name = 'Jane' WHERE id = 1"
	gosqlxtesting.RequireValidSQL(t, updateSQL)
	gosqlxtesting.AssertTables(t, updateSQL, []string{"users"})
	gosqlxtesting.AssertParsesTo(t, updateSQL, &ast.UpdateStatement{})

	// DELETE statement
	deleteSQL := "DELETE FROM users WHERE inactive = true"
	gosqlxtesting.RequireValidSQL(t, deleteSQL)
	gosqlxtesting.AssertTables(t, deleteSQL, []string{"users"})
	gosqlxtesting.AssertParsesTo(t, deleteSQL, &ast.DeleteStatement{})
}
Example (JoinQueries)

Example_joinQueries demonstrates testing various JOIN types.

package main

import (
	"testing"

	gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
)

func main() {
	t := &testing.T{}

	testCases := []struct {
		name   string
		query  string
		tables []string
	}{
		{
			name:   "INNER JOIN",
			query:  "SELECT * FROM users u INNER JOIN orders o ON u.id = o.user_id",
			tables: []string{"users", "orders"},
		},
		{
			name:   "LEFT JOIN",
			query:  "SELECT * FROM users u LEFT JOIN orders o ON u.id = o.user_id",
			tables: []string{"users", "orders"},
		},
		{
			name:   "RIGHT JOIN",
			query:  "SELECT * FROM users u RIGHT JOIN orders o ON u.id = o.user_id",
			tables: []string{"users", "orders"},
		},
		{
			name: "Multiple JOINs",
			query: `SELECT * FROM users u
					JOIN orders o ON u.id = o.user_id
					JOIN products p ON o.product_id = p.id`,
			tables: []string{"users", "orders", "products"},
		},
	}

	for _, tc := range testCases {
		// Validate each query type
		gosqlxtesting.RequireValidSQL(t, tc.query)
		gosqlxtesting.AssertTables(t, tc.query, tc.tables)
	}
}
Example (WindowFunctions)

Example_windowFunctions demonstrates testing window function queries.

package main

import (
	"testing"

	gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
)

func main() {
	t := &testing.T{}

	// Window function query
	windowQuery := `
		SELECT
			name,
			salary,
			ROW_NUMBER() OVER (ORDER BY salary DESC) as rank
		FROM employees
	`

	// Validate complex window function syntax
	gosqlxtesting.RequireValidSQL(t, windowQuery)

	// Verify table reference
	gosqlxtesting.AssertTables(t, windowQuery, []string{"employees"})

	// Verify columns (note: window functions are not extracted as columns)
	gosqlxtesting.AssertColumns(t, windowQuery, []string{"name", "salary"})
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func AssertColumns

func AssertColumns(t TestingT, sql string, expectedColumns []string) bool

AssertColumns asserts that the SQL selects the expected columns. This extracts column names from SELECT statements and compares them (order-independent).

Example:

testing.AssertColumns(t,
    "SELECT id, name, email FROM users",
    []string{"id", "name", "email"})
Example

ExampleAssertColumns demonstrates extracting and validating column references.

package main

import (
	"testing"

	gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
)

func main() {
	t := &testing.T{}

	// Simple column selection
	gosqlxtesting.AssertColumns(t,
		"SELECT id, name, email FROM users",
		[]string{"id", "name", "email"})

	// With WHERE clause (only SELECT columns are extracted)
	gosqlxtesting.AssertColumns(t,
		"SELECT id, name FROM users WHERE active = true",
		[]string{"id", "name"})

	// Order doesn't matter - both assertions pass
	gosqlxtesting.AssertColumns(t,
		"SELECT name, id, email FROM users",
		[]string{"email", "id", "name"})
}

func AssertErrorContains

func AssertErrorContains(t TestingT, sql, expectedSubstring string) bool

AssertErrorContains asserts that parsing the SQL produces an error containing the expected substring. This is useful for testing specific error conditions.

Example:

testing.AssertErrorContains(t, "SELECT FROM WHERE", "unexpected token")
Example

ExampleAssertErrorContains demonstrates testing specific error conditions.

package main

import (
	"testing"

	gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
)

func main() {
	t := &testing.T{}

	// Test that specific error messages are produced
	gosqlxtesting.AssertErrorContains(t,
		"SELECT FROM WHERE",
		"parsing")

	// Test for tokenization errors
	gosqlxtesting.AssertErrorContains(t,
		"SELECT * FROM users WHERE name = 'unterminated",
		"tokenization")
}

func AssertFormattedSQL

func AssertFormattedSQL(t TestingT, sql, expected string) bool

AssertFormattedSQL asserts that the SQL formats to match the expected output. This validates both that the SQL is valid and that it formats correctly.

Example:

testing.AssertFormattedSQL(t,
    "select * from users",
    "SELECT * FROM users;")
Example

ExampleAssertFormattedSQL demonstrates testing SQL formatting.

package main

import (
	"testing"

	gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
)

func main() {
	t := &testing.T{}

	// Test that SQL formats as expected
	sql := "SELECT * FROM users"
	expected := "SELECT * FROM users"

	gosqlxtesting.AssertFormattedSQL(t, sql, expected)
}

func AssertInvalidSQL

func AssertInvalidSQL(t TestingT, sql string) bool

AssertInvalidSQL asserts that the given SQL is syntactically invalid. If the SQL is valid, the test continues but is marked as failed.

Example:

testing.AssertInvalidSQL(t, "SELECT FROM WHERE")
Example

ExampleAssertInvalidSQL demonstrates testing that SQL is invalid.

package main

import (
	"testing"

	gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
)

func main() {
	t := &testing.T{}

	// Assert that malformed SQL is detected
	gosqlxtesting.AssertInvalidSQL(t, "SELECT FROM WHERE")
	gosqlxtesting.AssertInvalidSQL(t, "INSERT INTO")
	gosqlxtesting.AssertInvalidSQL(t, "UPDATE SET name = 'test'")
}

func AssertParsesTo

func AssertParsesTo(t TestingT, sql string, expectedType interface{}) bool

AssertParsesTo asserts that SQL parses to a specific AST statement type. This is useful for verifying that SQL is interpreted as the expected statement type.

Example:

testing.AssertParsesTo(t, "SELECT * FROM users", &ast.SelectStatement{})
Example

ExampleAssertParsesTo demonstrates validating statement types.

package main

import (
	"testing"

	gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
	"github.com/ajitpratap0/GoSQLX/pkg/sql/ast"
)

func main() {
	t := &testing.T{}

	// Verify SQL parses as SELECT statement
	gosqlxtesting.AssertParsesTo(t,
		"SELECT * FROM users",
		&ast.SelectStatement{})

	// Verify SQL parses as INSERT statement
	gosqlxtesting.AssertParsesTo(t,
		"INSERT INTO users (name) VALUES ('John')",
		&ast.InsertStatement{})

	// Verify SQL parses as UPDATE statement
	gosqlxtesting.AssertParsesTo(t,
		"UPDATE users SET active = false",
		&ast.UpdateStatement{})

	// Verify SQL parses as DELETE statement
	gosqlxtesting.AssertParsesTo(t,
		"DELETE FROM users WHERE id = 1",
		&ast.DeleteStatement{})
}

func AssertTables

func AssertTables(t TestingT, sql string, expectedTables []string) bool

AssertTables asserts that the SQL contains references to the expected tables. This extracts table names from the AST and compares them (order-independent).

Example:

testing.AssertTables(t,
    "SELECT * FROM users u JOIN orders o ON u.id = o.user_id",
    []string{"users", "orders"})
Example

ExampleAssertTables demonstrates extracting and validating table references.

package main

import (
	"testing"

	gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
)

func main() {
	t := &testing.T{}

	// Simple SELECT from single table
	gosqlxtesting.AssertTables(t,
		"SELECT * FROM users",
		[]string{"users"})

	// JOIN query with multiple tables
	gosqlxtesting.AssertTables(t,
		"SELECT * FROM users u JOIN orders o ON u.id = o.user_id",
		[]string{"users", "orders"})

	// Complex query with multiple JOINs
	gosqlxtesting.AssertTables(t,
		`SELECT u.name, o.total, p.name
		FROM users u
		LEFT JOIN orders o ON u.id = o.user_id
		RIGHT JOIN products p ON o.product_id = p.id`,
		[]string{"users", "orders", "products"})

	// INSERT statement
	gosqlxtesting.AssertTables(t,
		"INSERT INTO users (name) VALUES ('John')",
		[]string{"users"})

	// UPDATE statement
	gosqlxtesting.AssertTables(t,
		"UPDATE orders SET status = 'shipped' WHERE id = 1",
		[]string{"orders"})

	// DELETE statement
	gosqlxtesting.AssertTables(t,
		"DELETE FROM old_records WHERE created_at < '2020-01-01'",
		[]string{"old_records"})
}

func AssertValidSQL

func AssertValidSQL(t TestingT, sql string) bool

AssertValidSQL asserts that the given SQL is syntactically valid. If the SQL is invalid, the test continues but is marked as failed.

Example:

testing.AssertValidSQL(t, "SELECT * FROM users WHERE active = true")
Example

ExampleAssertValidSQL demonstrates validating SQL syntax in tests.

package main

import (
	"testing"

	gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
)

func main() {
	// In a real test function
	t := &testing.T{} // This would be passed from the test framework

	// Assert that SQL is valid
	gosqlxtesting.AssertValidSQL(t, "SELECT * FROM users WHERE active = true")

	// Multiple validations
	gosqlxtesting.AssertValidSQL(t, "SELECT id, name FROM users")
	gosqlxtesting.AssertValidSQL(t, "INSERT INTO users (name) VALUES ('John')")
	gosqlxtesting.AssertValidSQL(t, "UPDATE users SET active = false WHERE id = 1")
}

func RequireInvalidSQL

func RequireInvalidSQL(t TestingT, sql string)

RequireInvalidSQL requires that the given SQL is syntactically invalid. If the SQL is valid, the test stops immediately.

Example:

testing.RequireInvalidSQL(t, "SELECT FROM WHERE")

func RequireParse

func RequireParse(t TestingT, sql string) *ast.AST

RequireParse requires that the SQL parses successfully and returns the AST. If parsing fails, the test stops immediately.

Example:

ast := testing.RequireParse(t, "SELECT * FROM users")
// Use ast for further assertions
Example

ExampleRequireParse demonstrates getting the AST for further testing.

package main

import (
	"testing"

	gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
	"github.com/ajitpratap0/GoSQLX/pkg/sql/ast"
)

func main() {
	t := &testing.T{}

	// Parse SQL and get AST for custom assertions
	astNode := gosqlxtesting.RequireParse(t, "SELECT id, name FROM users")

	// Now you can make custom assertions on the AST
	if len(astNode.Statements) == 0 {
		t.Error("Expected at least one statement")
	}

	// Type assert to specific statement type
	if selectStmt, ok := astNode.Statements[0].(*ast.SelectStatement); ok {
		if len(selectStmt.Columns) != 2 {
			t.Errorf("Expected 2 columns, got %d", len(selectStmt.Columns))
		}
	}
}

func RequireValidSQL

func RequireValidSQL(t TestingT, sql string)

RequireValidSQL requires that the given SQL is syntactically valid. If the SQL is invalid, the test stops immediately.

Example:

testing.RequireValidSQL(t, "SELECT * FROM users")
// Test continues only if SQL is valid
Example

ExampleRequireValidSQL demonstrates stopping tests on invalid SQL.

package main

import (
	"testing"

	gosqlxtesting "github.com/ajitpratap0/GoSQLX/pkg/gosqlx/testing"
)

func main() {
	t := &testing.T{}

	// Require valid SQL - test stops if invalid
	gosqlxtesting.RequireValidSQL(t, "SELECT * FROM users")

	// This line only executes if SQL is valid
	// ... rest of test code
}

Types

type TestingT

type TestingT interface {
	Helper()
	Errorf(format string, args ...interface{})
	Fatalf(format string, args ...interface{})
}

TestingT is an interface wrapper around *testing.T to allow for mocking in tests. It includes the methods used by the helper functions.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL