| 136 | } |
| 137 | |
| 138 | func TestIntegration_TemporalOperators(t *testing.T) { |
| 139 | tests := []struct { |
| 140 | name string |
| 141 | program string |
| 142 | wantOpType ast.TemporalOperatorType |
| 143 | }{ |
| 144 | { |
| 145 | name: "diamond minus operator", |
| 146 | program: "recently_active(X) :- <-[0s, 168h] active(X).", |
| 147 | wantOpType: ast.DiamondMinus, |
| 148 | }, |
| 149 | { |
| 150 | name: "box minus operator", |
| 151 | program: "stable(X) :- [-[0s, 720h] employed(X).", |
| 152 | wantOpType: ast.BoxMinus, |
| 153 | }, |
| 154 | } |
| 155 | |
| 156 | for _, test := range tests { |
| 157 | t.Run(test.name, func(t *testing.T) { |
| 158 | unit, err := parse.Unit(strings.NewReader(test.program)) |
| 159 | if err != nil { |
| 160 | t.Fatalf("Failed to parse program: %v", err) |
| 161 | } |
| 162 | |
| 163 | if len(unit.Clauses) != 1 { |
| 164 | t.Fatalf("Expected 1 clause, got %d", len(unit.Clauses)) |
| 165 | } |
| 166 | |
| 167 | clause := unit.Clauses[0] |
| 168 | if len(clause.Premises) != 1 { |
| 169 | t.Fatalf("Expected 1 premise, got %d", len(clause.Premises)) |
| 170 | } |
| 171 | |
| 172 | tempLit, ok := clause.Premises[0].(ast.TemporalLiteral) |
| 173 | if !ok { |
| 174 | t.Fatalf("Premise is %T, want TemporalLiteral", clause.Premises[0]) |
| 175 | } |
| 176 | |
| 177 | if tempLit.Operator == nil { |
| 178 | t.Fatal("TemporalLiteral.Operator is nil") |
| 179 | } |
| 180 | |
| 181 | if tempLit.Operator.Type != test.wantOpType { |
| 182 | t.Errorf("Operator.Type = %v, want %v", tempLit.Operator.Type, test.wantOpType) |
| 183 | } |
| 184 | }) |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | func TestIntegration_TemporalStoreAndQuery(t *testing.T) { |
| 189 | // Create a temporal store |