@@ -53,9 +53,11 @@ private String[] runReplWithCommands(String... commands) throws Exception {
5353 @ Test
5454 public void repl_quitAndExit () throws Exception {
5555 String [] output1 = runReplWithCommands (":quit" );
56+
5657 assertThat (output1 [0 ]).contains ("Goodbye!" );
5758
5859 String [] output2 = runReplWithCommands (":exit" );
60+
5961 assertThat (output2 [0 ]).contains ("Goodbye!" );
6062 }
6163
@@ -73,6 +75,7 @@ public void repl_helpCommands() throws Exception {
7375 ":help equiv" ,
7476 ":help non_existent_topic" ,
7577 ":quit" );
78+
7679 assertThat (output [0 ]).contains ("REPL Commands:" );
7780 assertThat (output [0 ]).contains ("Command: :var <name> <type>" );
7881 assertThat (output [0 ]).contains ("Command: :unknown <identifier>" );
@@ -81,6 +84,9 @@ public void repl_helpCommands() throws Exception {
8184 assertThat (output [0 ]).contains ("Query: sat <expression>" );
8285 assertThat (output [0 ]).contains ("Query: valid <expression>" );
8386 assertThat (output [0 ]).contains ("Query: equiv <expression1> <=> <expression2>" );
87+ assertThat (output [0 ]).contains ("Well-known types: timestamp, duration" );
88+ assertThat (output [0 ]).contains ("Optional types: optional<T>" );
89+ assertThat (output [0 ]).contains ("Protobuf types: coming soon" );
8490 }
8591
8692 @ Test
@@ -91,19 +97,27 @@ public void repl_varDeclarations() throws Exception {
9197 ":var port int" ,
9298 ":var scores map<string,int>" ,
9399 ":var tags list<string>" ,
100+ ":var created_at timestamp" ,
101+ ":var timeout duration" ,
102+ ":var opt_user optional<string>" ,
94103 ":vars" ,
95104 ":quit" );
105+
96106 assertThat (output [0 ]).contains ("Variable declared: role : string" );
97107 assertThat (output [0 ]).contains ("Variable declared: port : int" );
98108 assertThat (output [0 ]).contains ("Variable declared: scores : map(string, int)" );
99109 assertThat (output [0 ]).contains ("Variable declared: tags : list(string)" );
100- assertThat (output [0 ]).contains ("Variables (4):" );
110+ assertThat (output [0 ]).contains ("Variable declared: created_at : google.protobuf.Timestamp" );
111+ assertThat (output [0 ]).contains ("Variable declared: timeout : google.protobuf.Duration" );
112+ assertThat (output [0 ]).contains ("Variable declared: opt_user : optional_type(string)" );
113+ assertThat (output [0 ]).contains ("Variables (7):" );
101114 }
102115
103116 @ Test
104117 public void repl_unknownIdentifiers () throws Exception {
105118 String [] output =
106119 runReplWithCommands (":unknown request.headers" , ":unknown request.auth" , ":vars" , ":quit" );
120+
107121 assertThat (output [0 ]).contains ("Added unknown identifier: 'request.headers'" );
108122 assertThat (output [0 ]).contains ("Added unknown identifier: 'request.auth'" );
109123 assertThat (output [0 ]).contains ("Unknowns: [request.headers, request.auth]" );
@@ -114,6 +128,7 @@ public void repl_timeoutConfiguration() throws Exception {
114128 String [] output =
115129 runReplWithCommands (
116130 ":timeout 15" , ":vars" , ":timeout -5" , ":timeout abc" , ":timeout" , ":quit" );
131+
117132 assertThat (output [0 ]).contains ("Timeout set to 15s." );
118133 assertThat (output [0 ]).contains ("Timeout: 15s" );
119134 assertThat (output [1 ]).contains ("Timeout must be a positive integer." );
@@ -125,6 +140,7 @@ public void repl_timeoutConfiguration() throws Exception {
125140 public void repl_unrollConfiguration () throws Exception {
126141 String [] output =
127142 runReplWithCommands (":unroll 10" , ":vars" , ":unroll -1" , ":unroll xyz" , ":unroll" , ":quit" );
143+
128144 assertThat (output [0 ]).contains ("Comprehension unroll limit set to 10." );
129145 assertThat (output [0 ]).contains ("Unroll limit: 10" );
130146 assertThat (output [1 ]).contains ("Unroll limit must be non-negative." );
@@ -137,6 +153,7 @@ public void repl_sessionStateAndClear() throws Exception {
137153 String [] output =
138154 runReplWithCommands (
139155 ":var role string" , ":unknown req.headers" , ":vars" , ":clear" , ":vars" , ":quit" );
156+
140157 assertThat (output [0 ]).contains ("Variables (1):" );
141158 assertThat (output [0 ]).contains ("Session state reset." );
142159 assertThat (output [0 ]).contains ("Variables (0):" );
@@ -147,6 +164,7 @@ public void repl_sessionStateAndClear() throws Exception {
147164 public void repl_satQueries () throws Exception {
148165 String [] output =
149166 runReplWithCommands (":var port int" , "sat port > 1024" , "port > 1024" , "sat" , ":quit" );
167+
150168 assertThat (output [0 ]).contains ("[VERIFIED]" );
151169 assertThat (output [1 ]).contains ("Usage: sat <expression>" );
152170 }
@@ -155,6 +173,7 @@ public void repl_satQueries() throws Exception {
155173 public void repl_validQueries () throws Exception {
156174 String [] output =
157175 runReplWithCommands (":var x int" , "valid x > 0 || x <= 0" , "valid x > 0" , "valid" , ":quit" );
176+
158177 assertThat (output [0 ]).contains ("[VERIFIED]" );
159178 assertThat (output [0 ]).contains ("[VIOLATED]" );
160179 assertThat (output [1 ]).contains ("Usage: valid <expression>" );
@@ -164,13 +183,15 @@ public void repl_validQueries() throws Exception {
164183 public void repl_equivQueries () throws Exception {
165184 String [] output =
166185 runReplWithCommands (":var x int" , "equiv x > 10 <=> 10 < x" , "equiv x > 10" , ":quit" );
186+
167187 assertThat (output [0 ]).contains ("[VERIFIED]" );
168188 assertThat (output [1 ]).contains ("Equivalence query format: equiv <expr1> <=> <expr2>" );
169189 }
170190
171191 @ Test
172192 public void repl_equivDoubleNegation () throws Exception {
173193 String [] output = runReplWithCommands (":var x int" , "equiv !!(x == 10) <=> (x == 10)" , ":quit" );
194+
174195 assertThat (output [0 ]).contains ("[VERIFIED]" );
175196 }
176197
@@ -184,6 +205,45 @@ public void repl_equivCanonicalization() throws Exception {
184205 + " v, v == 1 && k == 'foo')" ,
185206 "equiv int_list.all(e, e > 0) <=> int_list.all(elem, elem > 0)" ,
186207 ":quit" );
208+
209+ assertThat (output [0 ]).contains ("[VERIFIED]" );
210+ assertThat (output [1 ]).isEmpty ();
211+ }
212+
213+ @ Test
214+ public void repl_timestampAndDurationQueries () throws Exception {
215+ String [] output =
216+ runReplWithCommands (
217+ ":var t timestamp" ,
218+ ":var d duration" ,
219+ "sat t > timestamp(1000)" ,
220+ "sat d > duration('60s')" ,
221+ "sat t + d > timestamp(2000)" ,
222+ ":quit" );
223+
224+ assertThat (output [0 ]).contains ("[VERIFIED]" );
225+ assertThat (output [1 ]).isEmpty ();
226+ }
227+
228+ @ Test
229+ public void repl_durationSatisfyingInputFormat () throws Exception {
230+ String [] output =
231+ runReplWithCommands (":var dur duration" , "timestamp(100) - timestamp(50) == dur" , ":quit" );
232+
233+ assertThat (output [0 ]).contains ("[VERIFIED]" );
234+ assertThat (output [0 ]).contains ("dur = duration('50s')" );
235+ assertThat (output [1 ]).isEmpty ();
236+ }
237+
238+ @ Test
239+ public void repl_optionalQueries () throws Exception {
240+ String [] output =
241+ runReplWithCommands (
242+ ":var opt_val optional<int>" ,
243+ "sat opt_val.hasValue() && opt_val.value() > 100" ,
244+ "sat !opt_val.hasValue()" ,
245+ ":quit" );
246+
187247 assertThat (output [0 ]).contains ("[VERIFIED]" );
188248 assertThat (output [1 ]).isEmpty ();
189249 }
@@ -199,6 +259,7 @@ public void repl_unknownCommandsAndErrors() throws Exception {
199259 ":unknown" ,
200260 "invalid + + syntax" ,
201261 ":quit" );
262+
202263 assertThat (output [1 ]).contains ("Unknown command: :unknowncommand" );
203264 assertThat (output [1 ]).contains ("Usage: :var <name> <type>" );
204265 assertThat (output [1 ]).contains ("Unsupported type" );
0 commit comments