| 
					
				 | 
			
			
				@@ -1,12 +1,79 @@ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 package main 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 import ( 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"fmt" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"os" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	"testing" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	"time" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 ) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 const DEBUG_DB bool = false 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func TestLock(t *testing.T) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const testdb = ".space-settings.db" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	db := DBData{} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// Start with empty database 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	os.Remove(testdb) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	db.Open(testdb) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	defer db.Close() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if !DEBUG_DB { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		defer os.Remove(testdb) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	db.User = LOCK_USERNAME 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	when := time.Now().Add(-time.Hour).Unix() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	var oldLock string = fmt.Sprintf("%d,%d", os.Getpid(), when) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	db.SetSetting(LOCK_SETTING, oldLock) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	b := db.Lock(1) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if !b { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		t.Error("Failed to get lock (time on lock expired).") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+func TestSettings(t *testing.T) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	const testdb = ".space-settings.db" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	db := DBData{} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// Start with empty database 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	os.Remove(testdb) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	db.Open(testdb) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	defer db.Close() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	if !DEBUG_DB { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		defer os.Remove(testdb) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	users := []string{"test", "bob", "fish"} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	settings := map[string]string{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		"LastPlayed": "20200101", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		"Deck":       "green", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		"Rabbit":     "carrot", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	for _, user := range users { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		db.User = user 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		for key, value := range settings { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			db.SetSetting(key, value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	for _, user := range users { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		db.User = user 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		for key, value := range settings { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			found := db.GetSetting(key, "?") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			if found != value { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				t.Errorf("Settings %s/%s: got %s, expected %s\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+					user, key, found, value) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		found := db.GetSetting("missing", "ok") 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if found != "ok" { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			t.Errorf("Default %s: expected ok, got %s\n", user, found) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 // Test the db.ExpireScores 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 func TestExpireScores(t *testing.T) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	const testdb = ".space-test.db" 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -21,6 +88,8 @@ func TestExpireScores(t *testing.T) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		defer os.Remove(testdb) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	db.Unlock() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	db.User = "Testing" 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	// stuff score data into database 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -34,10 +103,18 @@ func TestExpireScores(t *testing.T) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		score int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	type TScore struct { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Score int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Run   int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		Won   int 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	var scoredata map[YMD]TScore = make(map[YMD]TScore) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	var data []TData = []TData{ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		{20230101, 20230101, 1, 0, 8, 750}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		{20230101, 20230101, 2, 0, 8, 780}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-		{20230101, 20230101, 3, 1, 5, 980}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		// {20230101, 20230101, 3, 1, 5, 980}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		{20230101, 20230102, 1, 1, 9, 945}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		{20230101, 20230102, 2, 1, 6, 985}, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		{20230101, 20230102, 3, 0, 10, 700}, 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -57,6 +134,54 @@ func TestExpireScores(t *testing.T) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 			best = data[idx].run 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		won += data[idx].won 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		w := data[idx].date 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		_, has := scoredata[w] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if !has { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			scoredata[w] = TScore{} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		sd, has := scoredata[w] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		sd.Score += data[idx].score 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		sd.Won += data[idx].won 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if sd.Run < data[idx].run { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			sd.Run = data[idx].run 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		scoredata[w] = sd 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	played := db.WhenPlayed() 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	playdata := map[YMD]int{20230101: 2, 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		20230102: 3, 20230115: 3} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	for k, v := range played { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if v != playdata[k] { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			t.Errorf("WhenPlayed %d: expected %d, got %d\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				k, playdata[k], v) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	scores := db.GetScores(5) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// Verify this has the expected scores (pre-expire) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// t.Errorf("ScoreData: %#v\n", scoredata) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	// t.Errorf("GetScores: %#v\n", scores) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+ 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	for _, s := range scores { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		sd, _ := scoredata[s.Date] 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if sd.Score != s.Score { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			t.Errorf("GetScores %d: Got score %d, expected %d\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				s.Date, s.Score, sd.Score) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if sd.Won != s.Won { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			t.Errorf("GetScores %d: Got Won %d, expected %d\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				s.Date, s.Won, sd.Won) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		if sd.Run != s.Run { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+			t.Errorf("GetScores %d: Got Run %d, expected %d\n", 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+				s.Date, s.Run, sd.Run) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+		} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	} 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	// Data loaded .. call Expire! 
			 | 
		
	
	
		
			
				| 
					
				 | 
			
			
				@@ -65,7 +190,7 @@ func TestExpireScores(t *testing.T) { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	db.ExpireScores(next_month) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	// 1. Verify the scores table is empty. 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				-	scores := db.GetScores(5) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				+	scores = db.GetScores(5) 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				  
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 	if len(scores) != 0 { 
			 | 
		
	
		
			
				 | 
				 | 
			
			
				 		t.Errorf("Scores not empty after ExpireScores got %d expected 0.\n", len(scores)) 
			 |