diff --git a/src/DynamoCore/Utilities/LuceneSearchUtility.cs b/src/DynamoCore/Utilities/LuceneSearchUtility.cs index 579fac5fb12..29d1e65f8ce 100644 --- a/src/DynamoCore/Utilities/LuceneSearchUtility.cs +++ b/src/DynamoCore/Utilities/LuceneSearchUtility.cs @@ -264,6 +264,18 @@ internal void SetDocumentFieldValue(Document doc, string field, string value, bo } } + /// + /// Check if the term passed as parameter is found inside the FullCategoryName + /// + /// Splitted search term e.g. if the search term is "set parameter" the parameter will be "set" or "parameter" + /// The complete category used for a specific node, like Core.File.FileSystem + /// + private bool IsMatchingCategory(string term, string FullCategoryName) + { + var categoryTerms = FullCategoryName.Split(".").Select(x => x.ToLower()); + return categoryTerms.Contains(term); + } + /// /// Creates a search query with adjusted priority, fuzzy logic and wildcards. /// Complete Search term appearing in Name of the package will be given highest priority. @@ -306,6 +318,8 @@ internal string CreateSearchQuery(string[] fields, string SearchTerm) foreach (string f in fields) { + Occur occurQuery = Occur.SHOULD; + //Needs to be again due that now a query can contain different values per field (e.g. CategorySplitted:list, Name:tr) searchTerm = QueryParser.Escape(SearchTerm); if (searchType == SearchType.ByCategory) @@ -335,6 +349,36 @@ internal string CreateSearchQuery(string[] fields, string SearchTerm) if (string.IsNullOrEmpty(searchTerm)) continue; + bool firstTermIsCategory = false; + + //This will only valid when the search term has empty spaces + if (hasEmptySpaces) + { + //Check if the first term of the search criteria match any category + var possibleCategory = searchTerm.Split(' ')[0]; + if (string.IsNullOrEmpty(possibleCategory)) continue; + + var specificCategoryEntries = dynamoModel.SearchModel.Entries.Where(entry => IsMatchingCategory(possibleCategory, entry.FullCategoryName) == true); + firstTermIsCategory = specificCategoryEntries.Any(); + + //Get the node matching the Category provided in the search term + var matchingCategory = specificCategoryEntries.FirstOrDefault(); + if (matchingCategory == null && firstTermIsCategory == true) continue; + + if (f == nameof(LuceneConfig.NodeFieldsEnum.FullCategoryName) && firstTermIsCategory == true) + { + //Means that the first term is a category when we will be using the FullCategoryName for making a specific search based in the category + trimmedSearchTerm = matchingCategory?.FullCategoryName; + occurQuery = Occur.MUST; + } + else if (f == nameof(LuceneConfig.NodeFieldsEnum.Name) && firstTermIsCategory == true) + { + //If the field being iterated is Name and we are sure that the first term is a Category when we remove the term from the string so we can search for the specific node Name + trimmedSearchTerm = trimmedSearchTerm?.Replace(possibleCategory, string.Empty); + if (string.IsNullOrEmpty(trimmedSearchTerm)) continue; + } + } + FuzzyQuery fuzzyQuery; if (searchTerm.Length > LuceneConfig.FuzzySearchMinimalTermLength) { @@ -347,14 +391,11 @@ internal string CreateSearchQuery(string[] fields, string SearchTerm) if (searchType == SearchType.ByCategory && f == nameof(LuceneConfig.NodeFieldsEnum.CategorySplitted)) { - booleanQuery.Add(fieldQuery, Occur.MUST); - booleanQuery.Add(wildcardQuery, Occur.MUST); - } - else - { - booleanQuery.Add(fieldQuery, Occur.SHOULD); - booleanQuery.Add(wildcardQuery, Occur.SHOULD); + occurQuery = Occur.MUST; } + + booleanQuery.Add(fieldQuery, occurQuery); + booleanQuery.Add(wildcardQuery, occurQuery); if (searchTerm.Contains(' ')) { diff --git a/src/DynamoCoreWpf/ViewModels/PackageManager/PackageItemRootViewModel.cs b/src/DynamoCoreWpf/ViewModels/PackageManager/PackageItemRootViewModel.cs index ab254bf1a2c..b439581fd99 100644 --- a/src/DynamoCoreWpf/ViewModels/PackageManager/PackageItemRootViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/PackageManager/PackageItemRootViewModel.cs @@ -131,8 +131,14 @@ internal void AddChildren(PackageItemRootViewModel item) if (this.ChildItems.Contains(item)) return; this.ChildItems.Add(item); } - - internal void AddChild(PackageItemRootViewModel elem) + /// + /// The methods is used for adding a child item to all the encountered parent folders in a nested path + /// and make sure all the intermediate file paths are created as separate PackageItemRootViewModel. + /// For example if we have a path like "\dir1\dir2\dir3" and we want to add a child item to "dir1", the method will + /// add "dir 3" to "dir2" and then "dir2" to "dir1". + /// + /// Child item to be added. + internal void AddChildRecursively(PackageItemRootViewModel elem) { if (elem.DependencyType.Equals(DependencyType.CustomNode)) return; @@ -149,7 +155,7 @@ internal void AddChild(PackageItemRootViewModel elem) while (di.Parent != null) { - // if we already have a subfodler item with that name, + // if we already have a subfolder item with that name, // add this element's children to its children instead of creating a new subfolder branch if(existingSubFolders.Keys.Contains(elem.DirectoryName)) { diff --git a/src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs b/src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs index 267d663be9e..869aced73fe 100644 --- a/src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/PackageManager/PublishPackageViewModel.cs @@ -893,6 +893,10 @@ public bool RetainFolderStructureOverride } } } + /// + /// The root directory of the package + /// + private string CurrentPackageDirectory { get; set; } private static MetadataLoadContext sharedMetaDataLoadContext = null; /// /// A shared MetaDataLoadContext that is used for assembly inspection during package publishing. @@ -996,7 +1000,7 @@ private void RefreshPackageContents() var items = new Dictionary(); - if(!String.IsNullOrEmpty(RootFolder)) + if (!String.IsNullOrEmpty(RootFolder)) { var root = new PackageItemRootViewModel(RootFolder); items[RootFolder] = root; @@ -1022,7 +1026,7 @@ private void RefreshPackageContents() } } - var updatedItems = BindParentToChild(items); + var updatedItems = BindParentToChild(items); updatedItems.AddRange(itemsToAdd.Where(pa => pa.DependencyType.Equals(DependencyType.CustomNode))); @@ -1050,8 +1054,6 @@ private bool IsDuplicateFile(PackageItemRootViewModel item1, PackageItemRootView private List BindParentToChild(Dictionary items) { - var updatedItems = new List(); - foreach (var parent in items) { foreach(var child in items) @@ -1060,25 +1062,53 @@ private List BindParentToChild(Dictionary !x.isChild).ToList(); + var updatedItems = GetRootItems(items); return updatedItems; } + /// + /// Gets the list PackageItemRootViewModel items which will be at the root directory of the package with all the child items. + /// + /// + /// + private List GetRootItems(Dictionary items) + { + var rootItems = items.Values.Where(x => !x.isChild).ToList(); + if (!rootItems.Any()) return rootItems; + var packageSourceDir = CurrentPackageDirectory ??= GetLongestCommonPrefix(items.Keys.ToArray()); + + var root = new PackageItemRootViewModel(packageSourceDir); + var updatedItems = new List(); + //check each root item and create any missing connections + foreach (var item in rootItems) + { + var itemDir = new DirectoryInfo(item.DirectoryName); + if (!itemDir.Parent.FullName.Equals(packageSourceDir)) + { + root.AddChildRecursively(item); + } + else + { + root.ChildItems.Add(item); + } + } + return root.ChildItems.ToList(); + } + /// /// Test if path2 is subpath of path1 - /// If it is, make sure all the intermediate file paths are created as separte PackageItemRootViewModel /// /// /// /// - private bool IsSubPathOfDeep(PackageItemRootViewModel path1, PackageItemRootViewModel path2) + internal bool IsSubPathOfDeep(PackageItemRootViewModel path1, PackageItemRootViewModel path2) { var di1 = new DirectoryInfo(path1.DirectoryName); var di2 = new DirectoryInfo(path2.DirectoryName); @@ -1089,12 +1119,37 @@ private bool IsSubPathOfDeep(PackageItemRootViewModel path1, PackageItemRootView { return true; } - else di2 = di2.Parent; + else + { + if (di2.Parent.FullName.Length < di1.FullName.Length) return false; + di2 = di2.Parent; + } } return false; } + /// + /// Utility method to get the common file path, this may fail for files with the same partial name. + /// + /// A collection of filepaths + /// + internal string GetLongestCommonPrefix(string[] s) + { + int k = s[0].Length; + for (int i = 1; i < s.Length; i++) + { + k = Math.Min(k, s[i].Length); + for (int j = 0; j < k; j++) + if (s[i][j] != s[0][j]) + { + k = j; + break; + } + } + return Path.GetDirectoryName(s[0].Substring(0, k)); + } + /// /// Return a list of HostComboboxEntry describing known hosts from PM. /// Return an empty list if PM is down. @@ -1403,6 +1458,7 @@ internal static PublishPackageViewModel FromLocalPackage(DynamoViewModel dynamoV CopyrightHolder = pkg.CopyrightHolder, CopyrightYear = pkg.CopyrightYear, IsPublishFromLocalPackage = true, + CurrentPackageDirectory = pkg.RootDirectory, //default retain folder structure to true when publishing a new version from local. RetainFolderStructureOverride = retainFolderStructure }; @@ -1636,7 +1692,7 @@ internal IEnumerable GetAllFiles() // union with additional files files = files.Union(AdditionalFiles); // if we retain the folder structure, we don't want to lose assemblies in sub-folders - // othrewise we need to delete duplicate assemblies which will end up in the same `dll` folder + // otherwise we need to delete duplicate assemblies which will end up in the same `dll` folder files = RetainFolderStructureOverride && !IsPublishFromLocalPackage ? files.Union(Assemblies.Select(x => x.LocalFilePath)) : files.Union(Assemblies.Select(x => x.Assembly.Location)); @@ -2232,6 +2288,10 @@ private void PublishLocally() var remapper = new CustomNodePathRemapper(DynamoViewModel.Model.CustomNodeManager, DynamoModel.IsTestMode); var builder = new PackageDirectoryBuilder(new MutatingFileSystem(), remapper); + if (string.IsNullOrEmpty(Package.RootDirectory)) + { + Package.RootDirectory = CurrentPackageDirectory; + } builder.BuildRetainDirectory(Package, publishPath, updatedFiles, MarkdownFiles); UploadState = PackageUploadHandle.State.Uploaded; } @@ -2647,7 +2707,7 @@ internal PackageItemRootViewModel GetPreBuildRootItemViewModel(string publishPat var docItemPreview = new PackageItemRootViewModel(docDir) { isChild = true }; var pkg = new PackageItemRootViewModel(new FileInfo(Path.Combine(rootDir, "pkg.json"))); - rootItemPreview.AddChild(pkg); + rootItemPreview.AddChildRecursively(pkg); foreach (var file in files) { @@ -2657,12 +2717,12 @@ internal PackageItemRootViewModel GetPreBuildRootItemViewModel(string publishPat if (Path.GetDirectoryName(file).EndsWith(PackageDirectoryBuilder.DocumentationDirectoryName)) { var doc = new PackageItemRootViewModel(new FileInfo(Path.Combine(docDir, fileName))); - docItemPreview.AddChild(doc); + docItemPreview.AddChildRecursively(doc); } else if (file.EndsWith(".dyf")) { var dyfPreview = new PackageItemRootViewModel(fileName, Path.Combine(dyfDir, fileName)); - dyfItemPreview.AddChild(dyfPreview); + dyfItemPreview.AddChildRecursively(dyfPreview); } else if (file.EndsWith(".dll") || PackageDirectoryBuilder.IsXmlDocFile(file, files) || PackageDirectoryBuilder.IsDynamoCustomizationFile(file, files)) { @@ -2677,13 +2737,13 @@ internal PackageItemRootViewModel GetPreBuildRootItemViewModel(string publishPat else { var dll = new PackageItemRootViewModel(new FileInfo(Path.Combine(binDir, fileName))); - binItemPreview.AddChild(dll); + binItemPreview.AddChildRecursively(dll); } } else { var extra = new PackageItemRootViewModel(new FileInfo(Path.Combine(extraDir, fileName))); - extraItemPreview.AddChild(extra); + extraItemPreview.AddChildRecursively(extra); } } @@ -2691,13 +2751,13 @@ internal PackageItemRootViewModel GetPreBuildRootItemViewModel(string publishPat { var fileName = Path.GetFileName(docFile); var doc = new PackageItemRootViewModel(new FileInfo(Path.Combine(docDir, fileName))); - docItemPreview.AddChild(doc); + docItemPreview.AddChildRecursively(doc); } - rootItemPreview.AddChild(dyfItemPreview); - rootItemPreview.AddChild(binItemPreview); - rootItemPreview.AddChild(extraItemPreview); - rootItemPreview.AddChild(docItemPreview); + rootItemPreview.AddChildRecursively(dyfItemPreview); + rootItemPreview.AddChildRecursively(binItemPreview); + rootItemPreview.AddChildRecursively(extraItemPreview); + rootItemPreview.AddChildRecursively(docItemPreview); return rootItemPreview; } diff --git a/src/DynamoPackages/PackageDirectoryBuilder.cs b/src/DynamoPackages/PackageDirectoryBuilder.cs index c64f1d0c1ff..844249560ac 100644 --- a/src/DynamoPackages/PackageDirectoryBuilder.cs +++ b/src/DynamoPackages/PackageDirectoryBuilder.cs @@ -69,12 +69,13 @@ public IDirectoryInfo BuildRetainDirectory(Package package, string packagesDirec var rootPath = Path.Combine(packagesDirectory, package.Name); var rootDir = fileSystem.TryCreateDirectory(rootPath); + var sourcePackageDir = package.RootDirectory; package.RootDirectory = rootDir.FullName; var dyfFiles = new List(); RemoveUnselectedFiles(contentFiles.SelectMany(files => files).ToList(), rootDir); - CopyFilesIntoRetainedPackageDirectory(contentFiles, markdownFiles, rootDir, out dyfFiles); + CopyFilesIntoRetainedPackageDirectory(contentFiles, markdownFiles, sourcePackageDir, rootDir, out dyfFiles); RemoveRetainDyfFiles(contentFiles.SelectMany(files => files).ToList(), dyfFiles); RemapRetainCustomNodeFilePaths(contentFiles.SelectMany(files => files).ToList(), dyfFiles); @@ -212,19 +213,12 @@ private void WritePackageHeader(Package package, IDirectoryInfo rootDir) fileSystem.WriteAllText(headerPath, pkgHeaderStr); } - internal void CopyFilesIntoRetainedPackageDirectory(IEnumerable> contentFiles, IEnumerable markdownFiles, IDirectoryInfo rootDir, out List dyfFiles) + internal void CopyFilesIntoRetainedPackageDirectory(IEnumerable> contentFiles, IEnumerable markdownFiles, string sourcePackageDir, IDirectoryInfo rootDir, out List dyfFiles) { dyfFiles = new List(); foreach (var files in contentFiles) { - // We expect that files are bundled in root folders - // For single files, just get its folder - var commonPath = files.Count() > 1 ? GetLongestCommonPrefix(files.ToArray()) : Path.GetDirectoryName(files.FirstOrDefault()); - commonPath = commonPath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); - var commonRootPath = Path.GetDirectoryName(commonPath); - if (commonRootPath == null) commonRootPath = commonPath; // already at the root - foreach (var file in files.Where(x => x != null)) { // If the file doesn't actually exist, don't copy it @@ -233,11 +227,12 @@ internal void CopyFilesIntoRetainedPackageDirectory(IEnumerable - /// Utility method to get the common file path, this may fail for files with the same partial name. - /// - /// A collection of filepaths - /// - public static string GetLongestCommonPrefix(string[] s) - { - int k = s[0].Length; - for (int i = 1; i < s.Length; i++) - { - k = Math.Min(k, s[i].Length); - for (int j = 0; j < k; j++) - if (s[i][j] != s[0][j]) - { - k = j; - break; - } - } - return Path.GetDirectoryName(s[0].Substring(0, k)); - } - #endregion } diff --git a/test/DynamoCoreWpfTests/PackageManager/PackageManagerUITests.cs b/test/DynamoCoreWpfTests/PackageManager/PackageManagerUITests.cs index 54c67870f0b..5635f2ed3cc 100644 --- a/test/DynamoCoreWpfTests/PackageManager/PackageManagerUITests.cs +++ b/test/DynamoCoreWpfTests/PackageManager/PackageManagerUITests.cs @@ -1829,7 +1829,7 @@ public void AddsFilesAndFoldersFromFilePathsCorrectly() Assert.AreEqual(additionalFiles.Count, allFiles.Count(f => !f.EndsWith(".dll"))); var packageContents = vm.PackageContents; - Assert.AreEqual(packageContents.Count, 1); // We expect only 1 root item here + Assert.AreEqual(1, packageContents.Count); // We expect only 1 root item here // Assert that the PackageContents contains the correct number of items var allFilesAndFoldres = PackageItemRootViewModel.GetFiles(packageContents.First()); @@ -2162,7 +2162,7 @@ public void CanRemoveAllDependencyTypes() // This makes sense as we don't want to try to establish 'common parent' for folders that maybe too far apart in a tree structure rootFolder = vm.PackageContents.Where(x => x.DependencyType.Equals(DependencyType.Folder)); Assert.AreEqual(1, rootFolder.Count()); - Assert.AreEqual(3, PackageItemRootViewModel.GetFiles(rootFolder.First()).Count()); + Assert.AreEqual(4, PackageItemRootViewModel.GetFiles(rootFolder.First()).Count()); Assert.DoesNotThrow(() => vm.RemoveItemCommand.Execute(rootFolder.First())); Assert.IsFalse(vm.PackageContents.Any()); @@ -2272,6 +2272,46 @@ public void AssertPreviewPackageRetainFolderStructureEqualsPublishLocalPackageRe Directory.Delete(publishPath, true); } + [Test] + public void AssertPreviewPackageRetainFolderStructureEqualsPublishLocalPackageResultsForNestedFolders() + { + var packageName = "NestedPackage"; + var pathManager = this.ViewModel.Model.PathManager as PathManager; + var publishPath = Path.Combine(pathManager.DefaultPackagesDirectory, packageName); + + string nodePath = Path.Combine(TestDirectory, "pkgs", packageName); + var allFiles = Directory.GetFiles(nodePath, "*", SearchOption.AllDirectories).ToList(); + var allFolders = Directory.GetDirectories(nodePath, "*", SearchOption.AllDirectories).ToList(); + + //now lets publish this package. + var newPkgVm = new PublishPackageViewModel(this.ViewModel); + newPkgVm.RetainFolderStructureOverride = true; + newPkgVm.AddAllFilesAfterSelection(allFiles); + + var previewFilesAndFolders = PackageItemRootViewModel.GetFiles(newPkgVm.PreviewPackageContents.ToList()); + var previewFiles = previewFilesAndFolders.Where(x => !x.DependencyType.Equals(DependencyType.Folder)); + var previewFolders = previewFilesAndFolders.Where(x => x.DependencyType.Equals(DependencyType.Folder)); + + newPkgVm.Name = packageName; + newPkgVm.MajorVersion = "0"; + newPkgVm.MinorVersion = "0"; + newPkgVm.BuildVersion = "1"; + newPkgVm.PublishLocallyCommand.Execute(); + + Assert.IsTrue(Directory.Exists(publishPath)); + + // Arrange + var createdFiles = Directory.GetFiles(publishPath, "*", SearchOption.AllDirectories).ToList(); + var createdFolders = Directory.GetDirectories(publishPath, "*", SearchOption.AllDirectories).ToList(); + + // Assert + Assert.AreEqual(createdFiles.Count(), previewFiles.Count() + 1); + Assert.AreEqual(1, createdFolders.Count(), previewFolders.Count()); // One subfolder was created + + // Clean up + Directory.Delete(publishPath, true); + } + [Test] public void AssertPublishLocalHandleType() { diff --git a/test/DynamoCoreWpfTests/PackagePathTests.cs b/test/DynamoCoreWpfTests/PackagePathTests.cs index 3c2f4fcb444..59e6e30ddc2 100644 --- a/test/DynamoCoreWpfTests/PackagePathTests.cs +++ b/test/DynamoCoreWpfTests/PackagePathTests.cs @@ -233,17 +233,17 @@ public void InstalledPackagesContainsCorrectNumberOfPackages() vm.packageLoader.PackagesLoaded += pkgsLoadedDelegate; vm.packageLoader.LoadAll(vm.loadPackageParams); - Assert.AreEqual(20, vm.packageLoader.LocalPackages.Count()); + Assert.AreEqual(21, vm.packageLoader.LocalPackages.Count()); Assert.AreEqual(true, packagesLoaded); var installedPackagesViewModel = new InstalledPackagesViewModel(ViewModel, vm.packageLoader); - Assert.AreEqual(20, installedPackagesViewModel.LocalPackages.Count); + Assert.AreEqual(21, installedPackagesViewModel.LocalPackages.Count); var installedPackagesView = new Dynamo.Wpf.Controls.InstalledPackagesControl(); installedPackagesView.DataContext = installedPackagesViewModel; DispatcherUtil.DoEvents(); - Assert.AreEqual(20, installedPackagesView.SearchResultsListBox.Items.Count); + Assert.AreEqual(21, installedPackagesView.SearchResultsListBox.Items.Count); Assert.AreEqual(2, installedPackagesView.Filters.Items.Count); vm.packageLoader.PackagesLoaded -= libraryLoader.LoadPackages; @@ -267,7 +267,7 @@ public void RemoveAddPackagePathChangesInstalledPackageState() // Load packages in package path. vm.packageLoader.LoadAll(vm.loadPackageParams); - Assert.AreEqual(20, vm.packageLoader.LocalPackages.Count()); + Assert.AreEqual(21, vm.packageLoader.LocalPackages.Count()); // Remove package path. vm.DeletePathCommand.Execute(0); @@ -323,7 +323,7 @@ public void EnableCustomPackagePathsLoadsPackagesOnClosingPreferences() vm.SaveSettingCommand.Execute(null); // packages are expected to load from 'PackagesDirectory' above when toggle is turned off - Assert.AreEqual(20, vm.packageLoader.LocalPackages.Count()); + Assert.AreEqual(21, vm.packageLoader.LocalPackages.Count()); vm.packageLoader.PackagesLoaded -= libraryLoader.LoadPackages; vm.packageLoader.RequestLoadNodeLibrary -= libraryLoader.LoadLibraryAndSuppressZTSearchImport; diff --git a/test/DynamoCoreWpfTests/PublishPackageViewModelTests.cs b/test/DynamoCoreWpfTests/PublishPackageViewModelTests.cs index ec0f7f9cbac..2f039048924 100644 --- a/test/DynamoCoreWpfTests/PublishPackageViewModelTests.cs +++ b/test/DynamoCoreWpfTests/PublishPackageViewModelTests.cs @@ -236,5 +236,69 @@ public void PublishingCustomNodeAsNewVersionWorks_SetsPackageInfoCorrectly() { throw new NotImplementedException(); } + + [Test] + public void AssertIsSubPathOfDeep_IsSuccessful() + { + var newPkgVm = new PublishPackageViewModel(this.ViewModel); + + //arrange + Dictionary testDirs = new Dictionary { + { @"C:\Package\bin\Dir1|C:\Package\bin\Dir1\Dir2", true }, + { @"C:\Package\bin\Dir1|C:\Package\bin\Dir1", false }, + { @"C:\Package\bin\Dir1\Dir2\Dir3\Dir4\Dir5\Dir6\Dir7\Dir8\Dir8\Dir9\Dir10|C:\Package\bin\Dir1", false }, + { @"C:\Package\bin\Dir1|C:\Package\bin\Dir1\Dir2\Dir3\Dir4\Dir5\Dir6\Dir7\Dir8\Dir8\Dir9\Dir10", true }, + { @"bin\Dir1|bin\Dir1\Dir2", true }, + }; + + //assert + foreach (var testDir in testDirs) + { + var paths = testDir.Key.Split('|'); + Assert.AreEqual(testDir.Value, newPkgVm.IsSubPathOfDeep(new PackageItemRootViewModel(paths[0]), new PackageItemRootViewModel(paths[1]))); + } + } + [Test] + public void AssertAddChildRecursively_IsSuccessful() + { + //arrange + List testDirs = new List { + { @"C:\Package\bin\Dir1\Dir3" }, + { @"C:\Package\bin\Dir2\Dir3" }, + { @"C:\Package\bin\Dir3\Dir4" }, + }; + var root = new PackageItemRootViewModel(@"C:\Package"); + + //assert + foreach (var testDir in testDirs) + { + root.AddChildRecursively(new PackageItemRootViewModel(testDir)); + } + + var bin = root.ChildItems.First(); + var d1 = bin.ChildItems.ElementAt(0); + var d2 = bin.ChildItems.ElementAt(1); + var d3 = bin.ChildItems.ElementAt(2); + + + Assert.IsTrue(root.ChildItems.Count == 1); + Assert.IsTrue(root.ChildItems.Select(x => x.DirectoryName.EndsWith("bin")).Any()); + + Assert.IsTrue(bin.ChildItems.Count == 3); + Assert.IsTrue(bin.ChildItems.Select(x => x.DirectoryName.EndsWith("Dir1")).Any()); + Assert.IsTrue(bin.ChildItems.Select(x => x.DirectoryName.EndsWith("Dir2")).Any()); + Assert.IsTrue(bin.ChildItems.Select(x => x.DirectoryName.EndsWith("Dir3")).Any()); + + Assert.IsTrue(d1.ChildItems.Count == 1); + Assert.IsTrue(d2.ChildItems.Count == 1); + Assert.IsTrue(d3.ChildItems.Count == 1); + Assert.IsTrue(d1.ChildItems.Select(x => x.DirectoryName.EndsWith("Dir3")).Any()); + Assert.IsTrue(d2.ChildItems.Select(x => x.DirectoryName.EndsWith("Dir3")).Any()); + Assert.IsTrue(d3.ChildItems.Select(x => x.DirectoryName.EndsWith("Dir4")).Any()); + + Assert.IsTrue(d1.ChildItems.First().ChildItems.Count == 0); + Assert.IsTrue(d2.ChildItems.First().ChildItems.Count == 0); + Assert.IsTrue(d3.ChildItems.First().ChildItems.Count == 0); + } } } diff --git a/test/Libraries/PackageManagerTests/PackageDirectoryBuilderTests.cs b/test/Libraries/PackageManagerTests/PackageDirectoryBuilderTests.cs index 71b230337f8..56d6170aa5d 100644 --- a/test/Libraries/PackageManagerTests/PackageDirectoryBuilderTests.cs +++ b/test/Libraries/PackageManagerTests/PackageDirectoryBuilderTests.cs @@ -41,7 +41,7 @@ public void BuildPackageDirectory_DoesExpectedNumberOfOperations() [Test] public void BuildRetainPackageDirectory_DoesExpectedNumberOfOperations() { - var files = new List>() { new[] { @"C:\folder1\file1.dyf" }, new[] { @"C:\folder2\file2.dyf" } }; + var files = new List>() { new[] { @"C:\pkg\folder1\file1.dyf" }, new[] { @"C:\pkg\folder2\file2.dyf" } }; var pkg = new Package(@"C:\pkg", "Foo", "0.1.0", "MIT"); var fs = new RecordedFileSystem((fn) => files.SelectMany(files => files).ToList().Any((x) => ComparePaths(x, fn))); var db = new PackageDirectoryBuilder(fs, MockMaker.Empty()); @@ -86,7 +86,7 @@ public void BuildPackageDirectory_BuildsExpectedDirectories() [Test] public void BuildRetainPackageDirectory_BuildsExpectedDirectories() { - var files = new List>() { new[] { @"C:\folder1\file1.dyf" }, new[] { @"C:\folder2\file2.dyf" } }; + var files = new List>() { new[] { @"C:\pkg\folder1\file1.dyf" }, new[] { @"C:\pkg\folder2\file2.dyf" } }; var pkg = new Package(@"C:\pkg", "Foo", "0.1.0", "MIT"); var fs = new RecordedFileSystem((fn) => files.SelectMany(files => files).ToList().Any((x) => ComparePaths(x, fn))); var db = new PackageDirectoryBuilder(fs, MockMaker.Empty()); @@ -103,7 +103,7 @@ public void BuildRetainPackageDirectory_BuildsExpectedDirectories() [Test] public void BuildPackageDirectory_FormsPackageHeader() { - var files = new[] { @"C:\file1.dyf", @"C:\file2.dyf" }; + var files = new[] { @"C:\pkg\file1.dyf", @"C:\pkg\file2.dyf" }; var pkg = new Package(@"C:\pkg", "Foo", "0.1.0", "MIT"); var fs = new RecordedFileSystem((fn) => files.Contains(fn)); @@ -125,7 +125,7 @@ public void BuildPackageDirectory_FormsPackageHeader() [Test] public void BuildRetainPackageDirectory_FormsPackageHeader() { - var files = new List>() { new[] { @"C:\folder1\file1.dyf" }, new[] { @"C:\folder2\file2.dyf" } }; + var files = new List>() { new[] { @"C:\pkg\folder1\file1.dyf" }, new[] { @"C:\pkg\folder2\file2.dyf" } }; var pkg = new Package(@"C:\pkg", "Foo", "0.1.0", "MIT"); var fs = new RecordedFileSystem((fn) => files.SelectMany(files => files).ToList().Any((x) => ComparePaths(x, fn))); @@ -176,7 +176,7 @@ public void BuildPackageDirectory_RemapsCustomNodePaths() [Test] public void BuildRetainPackageDirectory_RemapsCustomNodePaths() { - var files = new List>() { new[] { @"C:\folder1\file1.dyf" }, new[] { @"C:\folder2\file2.dyf" } }; + var files = new List>() { new[] { @"C:\pkg\folder1\file1.dyf" }, new[] { @"C:\pkg\folder2\file2.dyf" } }; var pkg = new Package(@"C:\pkg", "Foo", "0.1.0", "MIT"); var fs = new RecordedFileSystem((fn) => files.SelectMany(files => files).ToList().Any((x) => ComparePaths(x, fn))); @@ -235,7 +235,7 @@ public void BuildPackageDirectory_UpdatesTheArgumentPackageWithNewDirectories() [Test] public void BuildRetainPackageDirectory_UpdatesTheArgumentPackageWithNewDirectories() { - var files = new List>() { new[] { @"C:\folder1\file1.dyf" }, new[] { @"C:\folder2\file2.dyf" } }; + var files = new List>() { new[] { @"C:\pkg\folder1\file1.dyf" }, new[] { @"C:\pkg\folder2\file2.dyf" } }; var pkg = new Package(@"C:\pkg", "Foo", "0.1.0", "MIT"); var fs = new RecordedFileSystem((fn) => files.SelectMany(files => files).ToList().Any((x) => ComparePaths(x, fn))); @@ -257,7 +257,7 @@ public void BuildRetainPackageDirectory_UpdatesTheArgumentPackageWithNewDirector [Test] public void BuildPackageDirectory_CopiesTheOriginalFiles() { - var files = new[] { @"C:\file1.dyf", @"C:\file2.dyf" }; + var files = new[] { @"C:\pkg\file1.dyf", @"C:\pkg\file2.dyf" }; var pkg = new Package(@"C:\pkg", "Foo", "0.1.0", "MIT"); var fs = new RecordedFileSystem((fn) => files.Contains(fn)); @@ -282,7 +282,7 @@ public void BuildPackageDirectory_CopiesTheOriginalFiles() [Test] public void BuildPackageRetainDirectory_CopiesTheOriginalFiles() { - var files = new List>() { new[] { @"C:\folder1\file1.dyf" }, new[] { @"C:\folder2\file2.dyf" } }; + var files = new List>() { new[] { @"C:\pkg\folder1\file1.dyf" }, new[] { @"C:\pkg\folder2\file2.dyf" } }; var pkg = new Package(@"C:\pkg", "Foo", "0.1.0", "MIT"); var fs = new RecordedFileSystem((fn) => files.SelectMany(files => files).ToList().Any((x) => ComparePaths(x, fn))); @@ -307,7 +307,7 @@ public void BuildPackageRetainDirectory_CopiesTheOriginalFiles() [Test] public void BuildPackageDirectory_CopiesMarkDownFiles() { - var files = new[] { @"C:\file1.dyn", @"C:\file2.dyn" }; + var files = new[] { @"C:\pkg\file1.dyn", @"C:\pkg\file2.dyn" }; var markdownFiles = new[] { @"C:\file1.md", @"C:\file2.md", @"C:\image\file3.jpg" }; var pkg = new Package(@"C:\pkg", "Foo", "0.1.0", "MIT"); @@ -360,7 +360,7 @@ public void BuildRetainPackageDirectory_CopiesMarkDownFiles() [Test] public void BuildPackageDirectory_DeletesTheOriginalFiles() { - var files = new[] { @"C:\file1.dyf", @"C:\file2.dyf" }; + var files = new[] { @"C:\pkg\file1.dyf", @"C:\pkg\file2.dyf" }; var pkg = new Package(@"C:\pkg", "Foo", "0.1.0", "MIT"); var fs = new RecordedFileSystem((fn) => files.Contains(fn)); @@ -385,7 +385,7 @@ public void BuildPackageDirectory_DeletesTheOriginalFiles() [Test] public void BuildRetainPackageDirectory_DeletesTheOriginalFiles() { - var files = new List>() { new[] { @"C:\folder1\file1.dyf" }, new[] { @"C:\folder2\file2.dyf" } }; + var files = new List>() { new[] { @"C:\pkg\folder1\file1.dyf" }, new[] { @"C:\pkg\folder2\file2.dyf" } }; var pkg = new Package(@"C:\pkg", "Foo", "0.1.0", "MIT"); var fs = new RecordedFileSystem((fn) => files.SelectMany(files => files).ToList().Any((x) => ComparePaths(x, fn))); diff --git a/test/Libraries/PackageManagerTests/PackageLoaderTests.cs b/test/Libraries/PackageManagerTests/PackageLoaderTests.cs index 153497466f1..427453a62d0 100644 --- a/test/Libraries/PackageManagerTests/PackageLoaderTests.cs +++ b/test/Libraries/PackageManagerTests/PackageLoaderTests.cs @@ -141,7 +141,7 @@ public void PackageDoesNotReloadOnAbsenceOfNewPackagePath() }; loader.LoadAll(loadPackageParams); - Assert.AreEqual(20, loader.LocalPackages.Count()); + Assert.AreEqual(21, loader.LocalPackages.Count()); Assert.AreEqual(true, packagesLoaded); var entries = CurrentDynamoModel.SearchModel.Entries.ToList(); @@ -150,7 +150,7 @@ public void PackageDoesNotReloadOnAbsenceOfNewPackagePath() packagesLoaded = false; // This function is called upon addition of new package paths in the UI. loader.LoadNewCustomNodesAndPackages(new List(), CurrentDynamoModel.CustomNodeManager); - Assert.AreEqual(20, loader.LocalPackages.Count()); + Assert.AreEqual(21, loader.LocalPackages.Count()); // Assert packages are not reloaded if there are no new package paths. Assert.False(packagesLoaded); @@ -187,7 +187,7 @@ public void NoPackageNodeDuplicatesOnAddingNewPackagePath() Preferences =settings, }; loader.LoadAll(loadPackageParams); - Assert.AreEqual(20, loader.LocalPackages.Count()); + Assert.AreEqual(21, loader.LocalPackages.Count()); Assert.AreEqual(true, packagesLoaded); var entries = CurrentDynamoModel.SearchModel.Entries.ToList(); @@ -198,7 +198,7 @@ public void NoPackageNodeDuplicatesOnAddingNewPackagePath() var newPaths = new List { Path.Combine(TestDirectory, "builtinpackages testdir") }; // This function is called upon addition of new package paths in the UI. loader.LoadNewCustomNodesAndPackages(newPaths, CurrentDynamoModel.CustomNodeManager); - Assert.AreEqual(21, loader.LocalPackages.Count()); + Assert.AreEqual(22, loader.LocalPackages.Count()); // Assert packages are reloaded if there are new package paths. Assert.True(packagesLoaded); @@ -503,8 +503,8 @@ public void LoadPackagesReturnsAllValidPackagesInValidDirectory() Preferences = CurrentDynamoModel.PreferenceSettings, }); - // There are 20 packages in "Dynamo\test\pkgs" - Assert.AreEqual(20, loader.LocalPackages.Count()); + // There are 21 packages in "Dynamo\test\pkgs" + Assert.AreEqual(21, loader.LocalPackages.Count()); // Verify that interdependent packages are resolved successfully // TODO: Review these assertions. Lambdas are not using x, so they are basically just checking that test files exist. @@ -541,8 +541,8 @@ public void LoadingPackageDoesNotAffectLoadedSearchEntries() Preferences = CurrentDynamoModel.PreferenceSettings, }); - // There are 20 packages in "Dynamo\test\pkgs" - Assert.AreEqual(20, loader.LocalPackages.Count()); + // There are 21 packages in "Dynamo\test\pkgs" + Assert.AreEqual(21, loader.LocalPackages.Count()); // Simulate loading new package from PM string packageDirectory = Path.Combine(TestDirectory, @"core\packageDependencyTests\ZTTestPackage"); @@ -555,7 +555,7 @@ public void LoadingPackageDoesNotAffectLoadedSearchEntries() // Check that node belonging to one of the preloaded packages exists and is unique var entries = CurrentDynamoModel.SearchModel.Entries.ToList(); - Assert.IsTrue(entries.Count(x => x.FullName == "AnotherPackage.AnotherPackage.AnotherPackage.HelloAnotherWorld") == 1); + Assert.IsTrue(entries.Count(x => x.FullName == "Package.Package.Package.Package") == 1); loader.PackagesLoaded -= libraryLoader.LoadPackages; loader.RequestLoadNodeLibrary -= libraryLoader.LoadLibraryAndSuppressZTSearchImport; @@ -669,8 +669,8 @@ public void LoadingConflictingCustomNodePackageDoesNotGetLoaded() Preferences = CurrentDynamoModel.PreferenceSettings, }); - // There are 20 packages in "Dynamo\test\pkgs" - Assert.AreEqual(20, loader.LocalPackages.Count()); + // There are 21 packages in "Dynamo\test\pkgs" + Assert.AreEqual(21, loader.LocalPackages.Count()); var entries = CurrentDynamoModel.SearchModel.Entries.OfType(); diff --git a/test/pkgs/NestedPackage/extra/lib/static/test.xml b/test/pkgs/NestedPackage/extra/lib/static/test.xml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/pkgs/NestedPackage/extra/lib/test4.xml b/test/pkgs/NestedPackage/extra/lib/test4.xml new file mode 100644 index 00000000000..e69de29bb2d diff --git a/test/pkgs/NestedPackage/pkg.json b/test/pkgs/NestedPackage/pkg.json new file mode 100644 index 00000000000..468595e5429 --- /dev/null +++ b/test/pkgs/NestedPackage/pkg.json @@ -0,0 +1,18 @@ +{ + "license": "", + "file_hash": null, + "name": "NestedPackage", + "version": "1.0.0", + "description": "original package", + "group": "", + "keywords": null, + "dependencies": [], + "contents": "", + "engine_version": "2.1.0.7840", + "engine": "dynamo", + "engine_metadata": "", + "site_url": "", + "repository_url": "", + "contains_binaries": true, + "node_libraries": [] +} \ No newline at end of file