Metastatic.Test.AdapterHelper (Metastatic v0.9.2)

View Source

Testing utilities for language adapters (M1 ↔ M2 transformations).

Provides macros and helper functions to test adapter round-trip fidelity, validate conformance, and measure transformation quality.

M1 ↔ M2 Round-Trip Testing

A round-trip test validates the following pipeline:

Source  M1  M2  M1  Source

Where:

  • Source → M1: adapter.parse/1
  • M1 → M2: adapter.to_meta/1
  • M2 → M1: adapter.from_meta/2
  • M1 → Source: adapter.unparse/1

Fidelity Metrics

  • Exact match: Source output matches input exactly
  • Semantic match: ASTs match even if formatting differs
  • Partial match: Core structure preserved but details lost

Usage

defmodule MyAdapterTest do
  use ExUnit.Case
  import Metastatic.Test.AdapterHelper

  test "round-trip simple arithmetic" do
    source = "x + 5"
    assert_round_trip(MyAdapter, source)
  end

  test "validates M2 conformance" do
    source = "x + 5"
    assert_valid_meta_ast(MyAdapter, source)
  end
end

Summary

Functions

Assert that source code round-trips successfully through the adapter.

Assert that source code produces a valid MetaAST.

Assert that MetaAST can be reified back to source.

Calculate round-trip fidelity score.

Load test fixtures from a directory.

Measure adapter performance.

Functions

assert_round_trip(adapter, source, opts \\ [])

@spec assert_round_trip(module(), String.t(), keyword()) :: :ok

Assert that source code round-trips successfully through the adapter.

Validates: Source → M1 → M2 → M1 → Source

Options

  • :exact - Require exact source match (default: false)
  • :semantic - Allow formatting differences (default: true)

Examples

assert_round_trip(MyAdapter, "x + 5")
assert_round_trip(MyAdapter, "x + 5", exact: true)

assert_valid_meta_ast(adapter, source, opts \\ [])

@spec assert_valid_meta_ast(module(), String.t(), keyword()) ::
  Metastatic.Document.t()

Assert that source code produces a valid MetaAST.

Validates: Source → M1 → M2 and checks M2 conformance.

Options

  • :mode - Validation mode (:strict, :standard, :permissive)
  • :max_depth - Maximum allowed AST depth
  • :max_nodes - Maximum allowed node count

Examples

assert_valid_meta_ast(MyAdapter, "x + 5")
assert_valid_meta_ast(MyAdapter, "x + 5", mode: :strict)

assert_valid_reification(adapter, meta_ast, metadata)

@spec assert_valid_reification(module(), Metastatic.AST.meta_ast(), map()) ::
  String.t()

Assert that MetaAST can be reified back to source.

Validates: M2 → M1 → Source

Examples

ast = {:binary_op, :arithmetic, :+, {:variable, "x"}, {:literal, :integer, 5}}
assert_valid_reification(MyAdapter, ast, %{})

calculate_fidelity(original, result)

@spec calculate_fidelity(String.t(), String.t()) :: float()

Calculate round-trip fidelity score.

Returns a percentage (0.0 to 100.0) representing how closely the round-trip output matches the input.

Examples

fidelity = calculate_fidelity(original, round_trip_result)
# => 95.5

load_fixtures(dir)

@spec load_fixtures(String.t()) :: [{String.t(), String.t(), term() | nil}]

Load test fixtures from a directory.

Expects a directory structure like:

fixtures/
 python/
    simple_arithmetic.py
    list_comprehension.py
    expected/
        simple_arithmetic.exs
        list_comprehension.exs

Returns a list of {source_file, source_code, expected_meta_ast} tuples.

Examples

fixtures = load_fixtures("test/fixtures/python")

measure_performance(adapter, source)

@spec measure_performance(module(), String.t()) :: map()

Measure adapter performance.

Returns timing information for each stage of the transformation pipeline.

Examples

metrics = measure_performance(MyAdapter, source)
# => %{
#   parse_time_us: 150,
#   to_meta_time_us: 200,
#   from_meta_time_us: 180,
#   unparse_time_us: 120,
#   total_time_us: 650
# }