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; } }
/// <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; } }