| 490 | } |
| 491 | |
| 492 | func TestIntegration_BackwardCompatibility(t *testing.T) { |
| 493 | // These programs should parse and run correctly without temporal features |
| 494 | tests := []struct { |
| 495 | name string |
| 496 | program string |
| 497 | }{ |
| 498 | { |
| 499 | name: "simple facts and rules", |
| 500 | program: ` |
| 501 | node(/a). |
| 502 | node(/b). |
| 503 | edge(/a, /b). |
| 504 | path(X, Y) :- edge(X, Y). |
| 505 | path(X, Z) :- edge(X, Y), path(Y, Z). |
| 506 | `, |
| 507 | }, |
| 508 | { |
| 509 | name: "negation", |
| 510 | program: ` |
| 511 | all(/a). |
| 512 | all(/b). |
| 513 | excluded(/a). |
| 514 | included(X) :- all(X), !excluded(X). |
| 515 | `, |
| 516 | }, |
| 517 | { |
| 518 | name: "transforms", |
| 519 | program: ` |
| 520 | item(1). |
| 521 | item(2). |
| 522 | item(3). |
| 523 | total(N) :- item(X) |> do fn:group_by(), let N = fn:count(). |
| 524 | `, |
| 525 | }, |
| 526 | { |
| 527 | name: "comparisons", |
| 528 | program: ` |
| 529 | age(/alice, 30). |
| 530 | age(/bob, 25). |
| 531 | adult(Name) :- age(Name, Age), Age >= 18. |
| 532 | `, |
| 533 | }, |
| 534 | } |
| 535 | |
| 536 | for _, test := range tests { |
| 537 | t.Run(test.name, func(t *testing.T) { |
| 538 | unit, err := parse.Unit(strings.NewReader(test.program)) |
| 539 | if err != nil { |
| 540 | t.Fatalf("Failed to parse program: %v", err) |
| 541 | } |
| 542 | |
| 543 | // Verify no clauses have temporal annotations |
| 544 | for i, clause := range unit.Clauses { |
| 545 | if clause.HeadTime != nil && !clause.HeadTime.IsEternal() { |
| 546 | t.Errorf("Clause %d has unexpected temporal annotation: %v", i, clause.HeadTime) |
| 547 | } |
| 548 | } |
| 549 | }) |