packages feed

canontra-0.1.0.0: test/Canontra/DiffSpec.hs

{- |
Module      : Canontra.DiffSpec
Description : Unit test specification for the structural diff diagnostics engine.

Tests declaration diffs, dependency diffs, structural logic diffs,
and call graph topological shift detection.
-}
{-# LANGUAGE OverloadedStrings #-}
module Canontra.DiffSpec (spec) where

import Test.Hspec

import Canontra.Comparison.Diff
import Canontra.Parser.Python (parsePythonSource)
import Canontra.Types

spec :: Spec
spec = do
  describe "Structural Diff Diagnostics" $ do
    it "detects declaration additions and removals" $ do
      let code1 = "def fn_one(): pass\n"
          code2 = "def fn_two(): pass\n"
      case (parsePythonSource "1.py" code1, parsePythonSource "2.py" code2) of
        (Right p1, Right p2) -> do
          let diffRes = diffPrograms p1 p2
          crDeclaration (drComparison diffRes) `shouldBe` Different
          let dDiffs = drDeclarationDiffs diffRes
          any (\d -> ddAction d == "removed" && ddTarget d == "Function: fn_one") dDiffs `shouldBe` True
          any (\d -> ddAction d == "added" && ddTarget d == "Function: fn_two") dDiffs `shouldBe` True
        _ -> expectationFailure "Parse failed"

    it "detects internal function body logic changes while declarations remain identical" $ do
      let code1 = "def calc(a, b):\n    return a + b\n"
          code2 = "def calc(a, b):\n    return a * b\n"
      case (parsePythonSource "1.py" code1, parsePythonSource "2.py" code2) of
        (Right p1, Right p2) -> do
          let diffRes = diffPrograms p1 p2
          crDeclaration (drComparison diffRes) `shouldBe` Identical
          crStructural (drComparison diffRes) `shouldBe` Different
          let sDiffs = drStructuralDiffs diffRes
          length sDiffs `shouldBe` 1
          sdKind (head sDiffs) `shouldBe` "body_logic_modified"
        _ -> expectationFailure "Parse failed"

    it "detects call graph edge additions" $ do
      let code1 = "def helper(): pass\ndef main(): pass\n"
          code2 = "def helper(): pass\ndef main(): helper()\n"
      case (parsePythonSource "1.py" code1, parsePythonSource "2.py" code2) of
        (Right p1, Right p2) -> do
          let diffRes = diffPrograms p1 p2
          crCallGraph (drComparison diffRes) `shouldBe` Different
          let cgDiffs = drCallGraphDiffs diffRes
          any (\d -> cgdAction d == "edge_added" && cgdCaller d == "main" && cgdCallee d == "helper") cgDiffs `shouldBe` True
        _ -> expectationFailure "Parse failed"