public void TestAchievements()
        {
            const string achievementBaseNamespace = "Strokes.BasicAchievements.Test.";
            var achievementService = ObjectFactory.GetInstance<IAchievementService>();
            achievementService.ResetAchievementProgress();

            var achievementTests = GetType().Assembly.GetTypes().Where(a => a.GetCustomAttributes(typeof(ExpectUnlockAttribute), false).Length > 0);
            foreach(var test in achievementTests)
            {
                var testCasePath = test.FullName.Replace(achievementBaseNamespace, "").Replace(".", "/") + ".cs";
                var sourceFile = Path.GetFullPath(testCasePath);
                var staticAnalysisManifest = new StaticAnalysisManifest()
                                           {
                                               ActiveFile = sourceFile,
                                               ActiveProject = null,
                                               ActiveProjectOutputDirectory = Path.GetDirectoryName(sourceFile),
                                               ChangedFiles = new []{sourceFile},
                                               CodeFiles = new[] { sourceFile }
                                           };

                var unlockedAchievementTypes = achievementService.PerformStaticAnalysis(staticAnalysisManifest, false).Select(a => a.AchievementType).ToList();
                var expectedAchievements = test.GetCustomAttributes(typeof(ExpectUnlockAttribute), false).Select(a => ((ExpectUnlockAttribute)a).ExpectedAchievementType).ToList();

                foreach(var expectedAchievement in expectedAchievements)
                {
                    Assert.IsTrue(unlockedAchievementTypes.Contains(expectedAchievement), Path.GetFileName(sourceFile) + " did not unlock expected achievement: " + expectedAchievement.Name);
                }

                //Test that only expected achievements unlocked
                var unexpectedAchievements = unlockedAchievementTypes.Except(expectedAchievements).Except(_globallyIgnoredAchievements).ToList();
                Assert.IsTrue(unexpectedAchievements.Count() == 0, Path.GetFileName(sourceFile) + " unlocks unexpected achievements: " + string.Join(", ", unexpectedAchievements.Select(a => a.Name)));
            }
        }
        public IEnumerable<Achievement> PerformStaticAnalysis(StaticAnalysisManifest staticAnalysisManifest, bool onlyUnlockable)
        {
            IEnumerable<Achievement> unlockedAchievements = Enumerable.Empty<Achievement>();

            using (var statisAnalysisSession = new StatisAnalysisSession(staticAnalysisManifest))
            {
                OnStaticAnalysisStarted(this, new EventArgs());
                var stopwatch = new Stopwatch();
                stopwatch.Start();

                var allAchievements = onlyUnlockable
                                    ? AchievementRepository.GetUnlockableAchievements()
                                    : AchievementRepository.GetAchievements();

                var availableStaticAnalysisAchievements = allAchievements.Where
                (
                    a => typeof(StaticAnalysisAchievementBase).IsAssignableFrom(a.AchievementType)
                ).ToList();

                unlockedAchievements = GetUnlockedAchievements
                (
                    statisAnalysisSession, availableStaticAnalysisAchievements
                ).ToList();

                stopwatch.Stop();
                OnStaticAnalysisCompleted(this, new StaticAnalysisEventArgs
                {
                    AchievementsTested = availableStaticAnalysisAchievements.Count,
                    ElapsedMilliseconds = (int)stopwatch.ElapsedMilliseconds
                });
            }

            if (unlockedAchievements.Any())
            {
                foreach (var completedAchievement in unlockedAchievements)
                {
                    AchievementRepository.MarkAchievementAsCompleted(completedAchievement);
                }

                OnAchievementsUnlocked(this, new AchievementEventArgs
                {
                    UnlockedAchievements = unlockedAchievements
                });
            }

            return unlockedAchievements;
        }
        /// <summary>
        /// Gets all type declarations made in the current codebase that is being compiled. 
        /// This is a tool method to be used in more complex achievements.
        /// This method is caching and can be called without discretion, and is thread safe.
        /// </summary>
        /// <param name="staticAnalysisManifest">StaticAnalysisManifest object used to locate the codebase</param>
        /// <returns>Cached collection of DeclarationInfo</returns>
        public IEnumerable<DeclarationInfo> GetCodebaseDeclarations(StaticAnalysisManifest staticAnalysisManifest)
        {
            lock (codebaseTypeDefinitionPadLock)
            {
                if (codebaseDeclarations == null)
                {
                    codebaseDeclarations = new List<DeclarationInfo>();

                    foreach (var filename in staticAnalysisManifest.CodeFiles)
                    {
                        var compilationUnit = GetCompilationUnit(filename);
                        var typeDeclarationInfoVisitor = new CodebaseAnalysisVisitor();
                        compilationUnit.AcceptVisitor(typeDeclarationInfoVisitor, null);

                        codebaseDeclarations.AddRange(typeDeclarationInfoVisitor.TypeDeclarations);
                    }
                }

                return codebaseDeclarations;
            }
        }
Example #4
0
        /// <summary>
        /// Called when a build is completed.
        /// </summary>
        /// <param name="fSucceeded"><c>true</c> if no update actions failed.</param>
        /// <param name="fModified"><c>true</c> if any update action succeeded.</param>
        /// <param name="fCancelCommand"><c>true</c> if update actions were canceled.</param>
        /// <returns>
        /// If the method succeeds, it returns <c>S_OK</c>. If it fails, it returns an error code.
        /// </returns>
        int IVsUpdateSolutionEvents.UpdateSolution_Done(int fSucceeded, int fModified, int fCancelCommand)
        {
            if (fSucceeded != 0)
            {
                try
                {
                    ProjectTypeDef projectTypeDef = null;

                    if (dte.ActiveDocument != null && dte.ActiveDocument.ProjectItem != null && dte.ActiveDocument.ProjectItem.ContainingProject != null)
                    {
                        var containingProject = dte.ActiveDocument.ProjectItem.ContainingProject;

                        var projectFile = containingProject.FileName;
                        if (!string.IsNullOrEmpty(projectFile) && !projectTypeDefCache.TryGetValue(projectFile, out projectTypeDef))
                        {
                            XNamespace ns = "http://schemas.microsoft.com/developer/msbuild/2003";
                            var csProj = XDocument.Load(containingProject.FileName);
                            var strokesAchievementTypeNodes = csProj.Descendants(ns + "StrokesProjectType");
                            var strokesAchievementTypeNode = strokesAchievementTypeNodes.FirstOrDefault();
                            if (strokesAchievementTypeNode != null && strokesAchievementTypeNode.HasElements)
                            {
                                projectTypeDef = new ProjectTypeDef()
                                {
                                    IsAchievementProject = strokesAchievementTypeNode.Elements().Any(a => a.Name == ns + "Achievements" && a.Value == "true"),
                                    IsChallengeProject = strokesAchievementTypeNode.Elements().Any(a => a.Name == ns + "Challenges" && a.Value == "true")
                                };

                                projectTypeDefCache.Add(projectFile, projectTypeDef);
                            }
                        }
                    }

                    if (projectTypeDef == null)
                    {
                        projectTypeDef = new ProjectTypeDef(); // Assume default values (false, false);
                    }

                    // Return out if we're not compiling an achievement project.
                    if (!projectTypeDef.IsAchievementProject && !projectTypeDef.IsChallengeProject)
                    {
                        return VSConstants.S_OK;
                    }

                    // Get all .cs files in solution projects, that has changed since lastAchievementCheck
                    var changedFiles = FileTracker.GetFiles(dte.Solution);

                    // Update lastAchievementCheck
                    lastAchievementCheck = DateTime.Now;

                    // Construct build information
                    var buildInformation = new StaticAnalysisManifest();
                    buildInformation.CodeFiles = FileTracker.GetFiles(dte.Solution).ToArray();

                    var activeDocument = dte.ActiveDocument;
                    if (activeDocument != null)
                    {
                        var documentFile = activeDocument.FullName;

                        if (documentFile.EndsWith(".cs"))
                        {
                            buildInformation.ActiveFile = documentFile;

                            if (!changedFiles.Contains(documentFile))
                            {
                                // Always check active document.
                                changedFiles.Add(documentFile);
                            }

                            // Fill relevant values on StaticAnalysisManifest
                            var projectItem = activeDocument.ProjectItem.ContainingProject;
                            buildInformation.ActiveProject = projectItem.FileName;
                            buildInformation.ActiveProjectOutputDirectory = FileTracker.GetProjectOutputDirectory(projectItem);
                        }
                    }

                    buildInformation.ChangedFiles = changedFiles.ToArray();

                    // Validate build information
                    if (buildInformation.ActiveProject == null && buildInformation.ChangedFiles.Length == 0)
                    {
                        // Build information contains nothing - so we won't detect achievements
                        return VSConstants.S_OK;
                    }

                    // Lock builds while detection is occuring - this prevents parallel detection
                    isAchievementDetectionRunning = true;
                    _achievementService.PerformStaticAnalysis(buildInformation, true);
                }
                finally
                {
                    // Unlock builds
                    isAchievementDetectionRunning = false;
                }
            }

            return VSConstants.S_OK;
        }
        public List<SystemTypeInvocaton> GetSystemInvocations(StaticAnalysisManifest staticAnalysisManifest)
        {
            lock (systemInvocationsTypeDefinitionPadLock)
            {
                if (systemTypeInvocations == null)
                {
                    systemTypeInvocations = new List<SystemTypeInvocaton>();

                    foreach (var filename in staticAnalysisManifest.CodeFiles)
                    {
                        var compilationUnit = GetCompilationUnit(filename);
                        var systemTypesInvocationVisitor = new SystemTypeInvocationVisitor();
                        compilationUnit.AcceptVisitor(systemTypesInvocationVisitor, null);

                        systemTypeInvocations.AddRange(systemTypesInvocationVisitor.InvokedSystemTypes);
                    }
                }

                return systemTypeInvocations;
            }
        }