@@ -251,3 +251,173 @@ impl Database {
251251 }
252252
253253}
254+
255+ #[ cfg( test) ]
256+ mod tests {
257+ use super :: * ;
258+ use crate :: parser:: Symbol ;
259+ use tempfile:: TempDir ;
260+
261+ fn make_symbol ( id : & str , file : & str , name : & str , kind : & str ) -> Symbol {
262+ Symbol {
263+ id : id. to_string ( ) ,
264+ file : file. to_string ( ) ,
265+ name : name. to_string ( ) ,
266+ kind : kind. to_string ( ) ,
267+ start_line : 1 ,
268+ end_line : 10 ,
269+ hash : "abc123" . to_string ( ) ,
270+ }
271+ }
272+
273+ fn setup_db ( ) -> ( TempDir , Database ) {
274+ let tmp = TempDir :: new ( ) . unwrap ( ) ;
275+ let db_path = tmp. path ( ) . join ( "test.db" ) ;
276+ let db = Database :: open ( & db_path) . unwrap ( ) ;
277+ db. init_schema ( ) . unwrap ( ) ;
278+ ( tmp, db)
279+ }
280+
281+ #[ test]
282+ fn test_open_and_init_schema ( ) {
283+ let tmp = TempDir :: new ( ) . unwrap ( ) ;
284+ let db_path = tmp. path ( ) . join ( "test.db" ) ;
285+ let db = Database :: open ( & db_path) . unwrap ( ) ;
286+ assert ! ( db. init_schema( ) . is_ok( ) ) ;
287+ }
288+
289+ #[ test]
290+ fn test_upsert_and_count_symbols ( ) {
291+ let ( _tmp, db) = setup_db ( ) ;
292+ let symbols: Vec < Symbol > = ( 0 ..5 )
293+ . map ( |i| make_symbol ( & format ! ( "file.rs::fn{}" , i) , "file.rs" , & format ! ( "fn{}" , i) , "function" ) )
294+ . collect ( ) ;
295+ db. upsert_symbols ( & symbols) . unwrap ( ) ;
296+ assert_eq ! ( db. count_symbols( ) . unwrap( ) , 5 ) ;
297+ }
298+
299+ #[ test]
300+ fn test_upsert_updates_existing ( ) {
301+ let ( _tmp, db) = setup_db ( ) ;
302+ let sym = make_symbol ( "file.rs::foo" , "file.rs" , "foo" , "function" ) ;
303+ db. upsert_symbols ( & [ sym] ) . unwrap ( ) ;
304+ assert_eq ! ( db. count_symbols( ) . unwrap( ) , 1 ) ;
305+
306+ // Update same symbol with different hash
307+ let updated = Symbol {
308+ id : "file.rs::foo" . to_string ( ) ,
309+ file : "file.rs" . to_string ( ) ,
310+ name : "foo" . to_string ( ) ,
311+ kind : "function" . to_string ( ) ,
312+ start_line : 5 ,
313+ end_line : 20 ,
314+ hash : "new_hash" . to_string ( ) ,
315+ } ;
316+ db. upsert_symbols ( & [ updated] ) . unwrap ( ) ;
317+ assert_eq ! ( db. count_symbols( ) . unwrap( ) , 1 ) ;
318+ }
319+
320+ #[ test]
321+ fn test_list_symbols_no_filter ( ) {
322+ let ( _tmp, db) = setup_db ( ) ;
323+ let symbols = vec ! [
324+ make_symbol( "a.rs::fn1" , "a.rs" , "fn1" , "function" ) ,
325+ make_symbol( "a.rs::fn2" , "a.rs" , "fn2" , "function" ) ,
326+ make_symbol( "b.rs::fn3" , "b.rs" , "fn3" , "function" ) ,
327+ ] ;
328+ db. upsert_symbols ( & symbols) . unwrap ( ) ;
329+ let all = db. list_symbols ( None ) . unwrap ( ) ;
330+ assert_eq ! ( all. len( ) , 3 ) ;
331+ }
332+
333+ #[ test]
334+ fn test_list_symbols_with_filter ( ) {
335+ let ( _tmp, db) = setup_db ( ) ;
336+ let symbols = vec ! [
337+ make_symbol( "src/a.rs::fn1" , "src/a.rs" , "fn1" , "function" ) ,
338+ make_symbol( "src/a.rs::fn2" , "src/a.rs" , "fn2" , "function" ) ,
339+ make_symbol( "src/b.rs::fn3" , "src/b.rs" , "fn3" , "function" ) ,
340+ ] ;
341+ db. upsert_symbols ( & symbols) . unwrap ( ) ;
342+ let filtered = db. list_symbols ( Some ( "a.rs" ) ) . unwrap ( ) ;
343+ assert_eq ! ( filtered. len( ) , 2 ) ;
344+ for row in & filtered {
345+ assert ! ( row. 1 . contains( "a.rs" ) ) ;
346+ }
347+ }
348+
349+ #[ test]
350+ fn test_search_symbols ( ) {
351+ let ( _tmp, db) = setup_db ( ) ;
352+ let symbols = vec ! [
353+ make_symbol( "src/auth.rs::login" , "src/auth.rs" , "login" , "function" ) ,
354+ make_symbol( "src/auth.rs::logout" , "src/auth.rs" , "logout" , "function" ) ,
355+ make_symbol( "src/db.rs::connect" , "src/db.rs" , "connect" , "function" ) ,
356+ ] ;
357+ db. upsert_symbols ( & symbols) . unwrap ( ) ;
358+ let results = db. search_symbols ( & [ "login" ] ) . unwrap ( ) ;
359+ assert_eq ! ( results. len( ) , 1 ) ;
360+ assert_eq ! ( results[ 0 ] . 2 , "login" ) ;
361+ }
362+
363+ #[ test]
364+ fn test_available_symbols_in_files ( ) {
365+ let ( _tmp, db) = setup_db ( ) ;
366+ let symbols = vec ! [
367+ make_symbol( "f.rs::a" , "f.rs" , "a" , "function" ) ,
368+ make_symbol( "f.rs::b" , "f.rs" , "b" , "function" ) ,
369+ make_symbol( "f.rs::c" , "f.rs" , "c" , "function" ) ,
370+ ] ;
371+ db. upsert_symbols ( & symbols) . unwrap ( ) ;
372+
373+ // Lock symbol "f.rs::b"
374+ db. conn . execute (
375+ "INSERT INTO locks (symbol_id, agent_id, intent) VALUES (?1, ?2, ?3)" ,
376+ params ! [ "f.rs::b" , "agent-1" , "editing" ] ,
377+ ) . unwrap ( ) ;
378+
379+ let available = db. available_symbols_in_files ( & [ "f.rs" ] ) . unwrap ( ) ;
380+ assert_eq ! ( available. len( ) , 2 ) ;
381+ assert ! ( available. contains( & "f.rs::a" . to_string( ) ) ) ;
382+ assert ! ( available. contains( & "f.rs::c" . to_string( ) ) ) ;
383+ assert ! ( !available. contains( & "f.rs::b" . to_string( ) ) ) ;
384+ }
385+
386+ #[ test]
387+ fn test_session_lifecycle ( ) {
388+ let ( _tmp, db) = setup_db ( ) ;
389+ db. create_session ( "sess1" , "feature/x" , "main" ) . unwrap ( ) ;
390+
391+ let active = db. get_active_session ( ) . unwrap ( ) ;
392+ assert ! ( active. is_some( ) ) ;
393+ let ( name, branch, base) = active. unwrap ( ) ;
394+ assert_eq ! ( name, "sess1" ) ;
395+ assert_eq ! ( branch, "feature/x" ) ;
396+ assert_eq ! ( base, "main" ) ;
397+
398+ db. close_session ( "sess1" ) . unwrap ( ) ;
399+ let active = db. get_active_session ( ) . unwrap ( ) ;
400+ assert ! ( active. is_none( ) ) ;
401+ }
402+
403+ #[ test]
404+ fn test_no_active_session ( ) {
405+ let ( _tmp, db) = setup_db ( ) ;
406+ let active = db. get_active_session ( ) . unwrap ( ) ;
407+ assert ! ( active. is_none( ) ) ;
408+ }
409+
410+ #[ test]
411+ fn test_integrity_check_on_open ( ) {
412+ let tmp = TempDir :: new ( ) . unwrap ( ) ;
413+ let db_path = tmp. path ( ) . join ( "test.db" ) ;
414+ // First open creates the file
415+ {
416+ let db = Database :: open ( & db_path) . unwrap ( ) ;
417+ db. init_schema ( ) . unwrap ( ) ;
418+ }
419+ // Second open runs integrity check on existing DB
420+ let result = Database :: open ( & db_path) ;
421+ assert ! ( result. is_ok( ) ) ;
422+ }
423+ }
0 commit comments