Пример #1
0
        public void MatchTeamByRegex_InvalidRegex()
        {
            UnitTestDatabase   database   = new UnitTestDatabase();
            SplatTagController controller = new SplatTagController(database);

            controller.Initialise();

            Team t1 = CreateTeam("Inkology");

            t1.AddClanTag("¡g", Builtins.ManualSource, TagOption.Front);

            Team t2 = CreateTeam("Inkfected");

            t2.AddClanTag("τイ", Builtins.ManualSource, TagOption.Front);

            database.expectedTeams = new List <Team> {
                t1, t2
            };

            controller.LoadDatabase();
            Team[] matched = controller.MatchTeam("[", new MatchOptions {
                IgnoreCase = true, QueryIsRegex = true
            });
            Assert.IsNotNull(matched);
            Assert.AreEqual(0, matched.Length);
        }
Пример #2
0
        public void MatchTeamAmbiguous()
        {
            UnitTestDatabase   database   = new UnitTestDatabase();
            SplatTagController controller = new SplatTagController(database);

            Team t1 = CreateTeam("Team 17");

            t1.AddClanTag("x", Builtins.ManualSource, TagOption.Front);

            Team t2 = CreateTeam("Example 18");

            t2.AddClanTag("e", Builtins.ManualSource, TagOption.Front);

            database.expectedTeams = new List <Team> {
                t1, t2
            };
            controller.Initialise();

            // Match 'e' which will match the  'e' for a tag and 'e' in team
            Team[] matched = controller.MatchTeam("e");
            Assert.IsNotNull(matched);
            Assert.IsTrue(matched.Length == 2);

            // Assert that the returned order is t2 then t1.
            Assert.IsTrue(matched[0] == t2);
            Assert.IsTrue(matched[1] == t1);
        }
Пример #3
0
        public void LoadDatabaseTest()
        {
            UnitTestDatabase   database   = new UnitTestDatabase();
            SplatTagController controller = new SplatTagController(database);

            controller.Initialise();
            Assert.IsTrue(database.loadCalled);

            database.loadCalled = false;
            Team exampleTeam = new Team("Example Team", Builtins.ManualSource);

            exampleTeam.AddClanTag("e.g", Builtins.ManualSource, TagOption.Front);
            exampleTeam.AddDivision(new Division(1, DivType.DSB), Builtins.ManualSource);
            var TEAM_ID = exampleTeam.Id;

            database.expectedTeams = new List <Team> {
                exampleTeam
            };
            var PLAYER_NAME = "Example Name";

            database.expectedPlayers = new List <Player>
            {
                new Player(PLAYER_NAME, new Guid[] { TEAM_ID }, Builtins.ManualSource)
            };
            var PLAYER_ID = database.expectedPlayers[0].Id;

            controller.LoadDatabase();
            Assert.IsTrue(database.loadCalled);

            // Also check the player and team is now in the controller
            var players = controller.MatchPlayer(PLAYER_ID.ToString(), new MatchOptions {
                FilterOptions = FilterOptions.SlappId
            });

            Assert.IsNotNull(players.FirstOrDefault());
            var player = players[0];

            Assert.IsTrue(player.Name.Value == PLAYER_NAME);

            var teams = controller.MatchTeam(TEAM_ID.ToString(), new MatchOptions {
                FilterOptions = FilterOptions.SlappId
            });

            Assert.IsNotNull(teams.FirstOrDefault());
            var team = teams[0];

            Assert.IsTrue(team.CurrentDiv.Value == 1);
            Assert.IsTrue(team.CurrentDiv.DivType == DivType.DSB);

            // Verify getting the players for that team returns our player
            var playersForExampleTeam = controller.GetPlayersForTeam(exampleTeam);

            Assert.IsNotNull(playersForExampleTeam);
            Assert.IsTrue(playersForExampleTeam.Count == 1);
            Assert.IsTrue(playersForExampleTeam[0].player.Equals(player));
        }
Пример #4
0
        public void MatchTeamByNameTest()
        {
            UnitTestDatabase   database   = new UnitTestDatabase();
            SplatTagController controller = new SplatTagController(database);

            controller.Initialise();

            Team t = CreateTeam("Team 17");                             // Purposefully mixed case

            t.AddClanTag("WO", Builtins.ManualSource, TagOption.Front); // Purposefully upper-case
            database.expectedTeams = new List <Team> {
                t
            };

            controller.LoadDatabase();
            Team[] matched = controller.MatchTeam("team"); // Purposefully mixed case
            Assert.IsNotNull(matched);
            Assert.IsTrue(matched.Length == 1);
        }
Пример #5
0
        public void MatchTeamByTagTest_NearMatched()
        {
            UnitTestDatabase   database   = new UnitTestDatabase();
            SplatTagController controller = new SplatTagController(database);

            controller.Initialise();

            Team t = CreateTeam("Inkology");

            t.AddClanTag("¡g", Builtins.ManualSource, TagOption.Front);
            database.expectedTeams = new List <Team> {
                t
            };

            controller.LoadDatabase();
            Team[] matched = controller.MatchTeam("ig"); // Note i != ¡
            Assert.IsNotNull(matched);
            Assert.IsTrue(matched.Length == 1);
        }
Пример #6
0
        public Source Load()
        {
            Debug.WriteLine("Loading " + tsvFile);
            string[] text = File.ReadAllLines(tsvFile);
            if (text.Length < 1)
            {
                throw new ArgumentException("TSV does not have any data. Check format of spreadsheet.");
            }

            // Build a map of the incoming data
            string headerRow = text[0];

            string[] columns         = headerRow.Split('\t').Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();
            int      numberOfHeaders = columns.Length;

            PropertyEnum[] resolved = new PropertyEnum[numberOfHeaders];
            for (int i = 0; i < numberOfHeaders; ++i)
            {
                string header = columns[i].ToLowerInvariant()
                                .Replace("your ", "")
                                .Replace(" ", "")
                                .Replace("_", "")
                                .Replace(":", "")
                                .Replace("-", "")
                                .Replace("'s", "")
                                .Replace("teamcaptain", "captain")
                                .Replace("teammember", "player")
                ;
                if (string.IsNullOrWhiteSpace(header))
                {
                    Console.WriteLine($"Warning: Unable to resolve header, it is blank after processing: \"{header}\", (was \"{columns[i]}\")");
                    resolved[i] = PropertyEnum.UNKNOWN;
                }
                // Quick case
                else if (propertyValueStringMap.ContainsKey(header))
                {
                    resolved[i] = propertyValueStringMap[header];
                }
                else
                {
                    // Need to do some searching
                    int playerNum = 0;
                    if (header.Contains("captain"))
                    {
                        playerNum = 1;
                        header    = header.Replace("captain", "");
                    }
                    else
                    {
                        for (playerNum = 10; playerNum > 0; --playerNum)
                        {
                            if (header.Contains(playerNum.ToString()))
                            {
                                header = header.Replace(playerNum.ToString(), "");
                                break;
                            }
                        }
                    }

                    var matchedKey = propertyValueStringMap.Keys.FirstOrDefault(key => header.StartsWith(key));
                    if (matchedKey != null)
                    {
                        // For player num = 0 (not found), this will just return the appropriate header.
                        resolved[i] = (playerNum * (int)PropertyEnum.PlayerN_Offset) + propertyValueStringMap[matchedKey];
                    }
                    else if (playerNum == 0)
                    {
                        resolved[i] = PropertyEnum.UNKNOWN;
                        Console.WriteLine("Warning: Unable to resolve header: " + header);
                    }
                    else
                    {
                        resolved[i] = PropertyEnum.UNKNOWN;
                        Console.WriteLine("Warning: Unable to resolve header for player " + playerNum + ": " + header);
                    }
                }
            }

            // Now read the data...
            // Most tsv files will be team sheets, but for draft cups and verif they could be player records instead.
            // Each row therefore might be a single team with players, or a single player entry.
            List <Team>   teams   = new List <Team>();
            List <Player> players = new List <Player>();

            // From 1 as [0] is header row
            for (int lineIndex = 1; lineIndex < text.Length; ++lineIndex)
            {
                string line = text[lineIndex];
                if (!line.Contains('\t'))
                {
                    continue;
                }

                string[] cells = line.Split('\t').ToArray();

                // Warn if the values exceeds the number of defined headers (but don't bother if we're only one over and it's empty -- trailing tab)
                if (numberOfHeaders < cells.Length && (numberOfHeaders != cells.Length - 1 || !string.IsNullOrWhiteSpace(cells[cells.Length - 1])))
                {
                    Console.WriteLine($"Warning: Line {lineIndex} contains more cells in this row {cells.Length} than headers {numberOfHeaders}.");
                    Debug.WriteLine(line);
                }

                SortedDictionary <int, Player> rowPlayers = new SortedDictionary <int, Player>();
                Team t = new Team();

                for (int i = 0; i < cells.Length && i < numberOfHeaders; ++i)
                {
                    int          playerNum        = 0;
                    PropertyEnum resolvedProperty = resolved[i];
                    if (resolvedProperty > PropertyEnum.PlayerN_Offset)
                    {
                        playerNum        = (int)resolved[i] / (int)PropertyEnum.PlayerN_Offset;
                        resolvedProperty = (PropertyEnum)((int)resolved[i] % (int)PropertyEnum.PlayerN_Offset);
                    }

                    string value = cells[i];
                    if (string.IsNullOrWhiteSpace(value))
                    {
                        continue;
                    }

                    switch (resolvedProperty)
                    {
                    case PropertyEnum.UNKNOWN:
                    {
                        continue;
                    }

                    case PropertyEnum.Country:
                    {
                        var p = GetCurrentPlayer(ref rowPlayers, playerNum, tsvFile);
                        p.Country = value;
                        break;
                    }

                    case PropertyEnum.DiscordId:
                    {
                        var p = GetCurrentPlayer(ref rowPlayers, playerNum, tsvFile);
                        if (value.Length >= 14 && value.Length < 21)
                        {
                            // First, test is decimal (of length 17+)
                            bool isDecimal = value.Length >= 17 && value.All("0123456789".Contains);
                            if (isDecimal)
                            {
                                p.AddDiscordId(value, source);
                            }
                            // Otherwise test if we can get from a hex string (of length 14+ to give the correct 17 digit decimal)
                            else if (ulong.TryParse(value, NumberStyles.HexNumber, CultureInfo.CurrentCulture, out ulong parsedId))
                            {
                                p.AddDiscordId(value, source);
                            }
                            else
                            {
                                Console.WriteLine($"Warning: DiscordId was specified ({lineIndex},{i}), but the value could not be parsed from a decimal or hex string. {value}.");
                                Debug.WriteLine(line);
                            }
                        }
                        else
                        {
                            Console.WriteLine($"Warning: DiscordId was specified ({lineIndex},{i}), but the value length does not fit into a discord id. {value}.");
                            Debug.WriteLine(line);
                        }
                        break;
                    }

                    case PropertyEnum.DiscordName:
                    {
                        var p = GetCurrentPlayer(ref rowPlayers, playerNum, tsvFile);
                        if (Discord.DISCORD_NAME_REGEX.IsMatch(value))
                        {
                            p.AddDiscordUsername(value, source);
                        }
                        else if (FriendCode.TryParse(value, out FriendCode friendCode))
                        {
                            p.AddFCs(friendCode, source);
                            Console.WriteLine($"Warning: This value was declared as a Discord name but looks like a friend code. Bad data formatting? {value} on ({lineIndex},{i}).");
                        }
                        else
                        {
                            Console.WriteLine($"Warning: DiscordName was specified ({lineIndex},{i}), but the value was not in a Discord format of name#0000. {value}.");
                            Debug.WriteLine(line);
                        }
                        break;
                    }

                    case PropertyEnum.FC:
                    {
                        var p = GetCurrentPlayer(ref rowPlayers, playerNum, tsvFile);
                        if (FriendCode.TryParse(value, out FriendCode friendCode))
                        {
                            p.AddFCs(friendCode, source);
                        }
                        else
                        {
                            Console.WriteLine($"Warning: FC was specified ({lineIndex},{i}), but the value was not in an FC format of 0000-0000-0000 or 0000 0000 0000. {value}.");
                            Debug.WriteLine(line);
                        }
                        break;
                    }

                    case PropertyEnum.Div:
                    {
                        t.AddDivision(new Division(value, divType, season), source);

                        if (divType == DivType.Unknown)
                        {
                            Console.WriteLine($"Warning: Div was specified ({lineIndex},{i}), but I don't know what type of division this file represents.");
                        }
                        break;
                    }

                    case PropertyEnum.LUTIDiv:
                    {
                        t.AddDivision(new Division(value, DivType.LUTI, season), source);
                        break;
                    }

                    case PropertyEnum.EBTVDiv:
                    {
                        t.AddDivision(new Division(value, DivType.EBTV, season), source);
                        break;
                    }

                    case PropertyEnum.DSBDiv:
                    {
                        t.AddDivision(new Division(value, DivType.DSB, season), source);
                        break;
                    }

                    case PropertyEnum.Timestamp:
                    {
                        // TODO - not supported right now. In future we could customise the source timestamp for this entry.
                        break;
                    }

                    case PropertyEnum.Name:
                    {
                        var p = GetCurrentPlayer(ref rowPlayers, playerNum, tsvFile);

                        var playerName = value.Trim();
                        playerName = t.Tag?.StripFromPlayer(playerName) ?? playerName;
                        p.AddName(playerName, source);

                        if (FriendCode.TryParse(value, out FriendCode friendCode))
                        {
                            p.AddFCs(friendCode, source);
                            Console.WriteLine($"Warning: This value was declared as a name but looks like a friend code. Bad data formatting? {value} on ({lineIndex},{i}).");
                            Debug.WriteLine(line);
                        }
                        break;
                    }

                    case PropertyEnum.Role:
                    {
                        var p = GetCurrentPlayer(ref rowPlayers, playerNum, tsvFile);
                        p.AddWeapons(value.Split(',').Select(s => s.Trim()).Where(s => !string.IsNullOrWhiteSpace(s)));
                        break;
                    }

                    case PropertyEnum.Pronouns:
                    {
                        var p = GetCurrentPlayer(ref rowPlayers, playerNum, tsvFile);
                        p.PronounInformation.SetPronoun(value, source);
                        break;
                    }

                    case PropertyEnum.Tag:
                    {
                        t.AddClanTag(value, source);
                        break;
                    }

                    case PropertyEnum.TeamName:
                    {
                        t.AddName(value, source);
                        break;
                    }

                    case PropertyEnum.Twitter:
                    {
                        var p = GetCurrentPlayer(ref rowPlayers, playerNum, tsvFile);
                        p.AddTwitter(value, source);
                        break;
                    }

                    case PropertyEnum.Twitch:
                    {
                        var p = GetCurrentPlayer(ref rowPlayers, playerNum, tsvFile);
                        p.AddTwitch(value, source);
                        break;
                    }

                    case PropertyEnum.Team_Offset:
                    case PropertyEnum.UnspecifiedPlayer_Offset:
                    case PropertyEnum.PlayerN_Offset:
                    default:
                    {
                        Console.WriteLine($"Warning: Unhandled header {resolvedProperty}. {value}. Line {lineIndex}:");
                        Debug.WriteLine(line);
                        break;
                    }
                    }
                }

                // End of the row, add the data.
                foreach (var pair in rowPlayers)
                {
                    // Don't add empty players
                    Player p = pair.Value;
                    if (p.Name.Equals(Builtins.UnknownPlayerName))
                    {
                        continue;
                    }
                    // Don't add the team to the player if it's not complete (e.g. single player record)
                    if (!t.Name.Equals(Builtins.UnknownTeamName))
                    {
                        p.TeamInformation.Add(t.Id, source);
                    }
                    players.Add(p);
                }

                // Don't bother adding the team if it has no players
                if (players.Count > 0)
                {
                    // Don't register a team if that information doesn't exist.
                    if (!t.Name.Equals(Builtins.UnknownTeamName))
                    {
                        // Recalculate the ClanTag layout
                        if (t.Tag != null)
                        {
                            t.Tag.CalculateTagOption(players[0].Name.Value);
                        }
                        else
                        {
                            ClanTag?newTag = ClanTag.CalculateTagFromNames(players.Select(p => p.Name.Value).ToArray(), source);

                            if (newTag != null)
                            {
                                t.AddClanTag(newTag);
                            }
                        }
                        teams.Add(t);
                    }
                }
            }

            source.Players = players.ToArray();
            source.Teams   = teams.ToArray();
            return(source);
        }
Пример #7
0
        public void SerializeTeam()
        {
            var sources      = new Dictionary <string, Source>();
            var oldestSource = new Source("old_source", DateTime.Now.AddDays(-6));
            var newestSource = new Source("new_source", DateTime.Now);

            sources.Add(newestSource.Id, newestSource);
            sources.Add(oldestSource.Id, oldestSource);

            Team team = new Team();

            team.AddBattlefyId("2teamid2", oldestSource);
            team.AddBattlefyId("1teamid1", newestSource);

            team.AddClanTag("old", oldestSource);
            team.AddClanTag("new", newestSource);

            team.AddDivision(new Division(10, DivType.DSB, "S9"), oldestSource);
            team.AddDivision(new Division(8, DivType.LUTI, "SX"), newestSource);

            team.AddName("team2", oldestSource);
            team.AddName("team1", newestSource);

            string json = Serialize(team);

            Console.WriteLine(nameof(SerializeTeam) + ": ");
            Console.WriteLine(json);
            Team deserialized = Deserialize <Team>(json, sources);

            var battlefy = deserialized.BattlefyPersistentTeamIdInformation.GetItemsOrdered();

            Assert.AreEqual(2, battlefy.Count, "Unexpected number of team battlefy slugs");
            Assert.AreEqual("1teamid1", battlefy[0].Value, "Slug [0] unexpected handle");
            Assert.AreEqual("2teamid2", battlefy[1].Value, "Slug [1] unexpected handle");
            Assert.AreEqual("new_source", battlefy[0].Sources[0].Name, "Slug [0] unexpected source");
            Assert.AreEqual("old_source", battlefy[1].Sources[0].Name, "Slug [1] unexpected source");

            var clanTags = deserialized.ClanTagInformation.GetItemsOrdered();

            Assert.AreEqual(2, clanTags.Count, "Unexpected number of clanTags");
            Assert.AreEqual("new", clanTags[0].Value, "clanTags[0] Unexpected Value");
            Assert.AreEqual("old", clanTags[1].Value, "clanTags[1] Unexpected Value");
            Assert.AreEqual("new_source", clanTags[0].Sources[0].Name, "clanTags[0] unexpected source");
            Assert.AreEqual("old_source", clanTags[1].Sources[0].Name, "clanTags[1] unexpected source");

            var divisions = deserialized.DivisionInformation.GetDivisionsOrdered();

            Assert.AreEqual(2, divisions.Count, "Unexpected number of divisions");
            // First - most recent
            Assert.AreEqual(8, divisions[0].Value, "Unexpected Value");
            Assert.AreEqual(DivType.LUTI, divisions[0].DivType, "Unexpected DivType");
            Assert.AreEqual("SX", divisions[0].Season, "Unexpected Season");
            // Next
            Assert.AreEqual(10, divisions[1].Value, "Unexpected Value");
            Assert.AreEqual(DivType.DSB, divisions[1].DivType, "Unexpected DivType");
            Assert.AreEqual("S9", divisions[1].Season, "Unexpected Season");

            var names = deserialized.NamesInformation.GetItemsOrdered();

            Assert.AreEqual(2, names.Count, "Unexpected number of team names");
            Assert.AreEqual("team1", names[0].Value, "Names [0] unexpected handle");
            Assert.AreEqual("team2", names[1].Value, "Names [1] unexpected handle");
            Assert.AreEqual("new_source", names[0].Sources[0].Name, "Names [0] unexpected source");
            Assert.AreEqual("old_source", names[1].Sources[0].Name, "Names [1] unexpected source");
        }