##// END OF EJS Templates
Merged r11827 to r11833 from trunk (#14015)....
Jean-Philippe Lang -
r11766:7375dff6d6bc
parent child
Show More
@@ -854,18 +854,99 class Issue < ActiveRecord::Base
854 end
854 end
855
855
856 # Returns all the other issues that depend on the issue
856 # Returns all the other issues that depend on the issue
857 # The algorithm is a modified breadth first search (bfs)
857 def all_dependent_issues(except=[])
858 def all_dependent_issues(except=[])
858 except << self
859 # The found dependencies
859 dependencies = []
860 dependencies = []
860 dependencies += relations_from.map(&:issue_to)
861
861 dependencies += children unless leaf?
862 # The visited flag for every node (issue) used by the breadth first search
862 dependencies.compact!
863 eNOT_DISCOVERED = 0 # The issue is "new" to the algorithm, it has not seen it before.
864
865 ePROCESS_ALL = 1 # The issue is added to the queue. Process both children and relations of
866 # the issue when it is processed.
867
868 ePROCESS_RELATIONS_ONLY = 2 # The issue was added to the queue and will be output as dependent issue,
869 # but its children will not be added to the queue when it is processed.
870
871 eRELATIONS_PROCESSED = 3 # The related issues, the parent issue and the issue itself have been added to
872 # the queue, but its children have not been added.
873
874 ePROCESS_CHILDREN_ONLY = 4 # The relations and the parent of the issue have been added to the queue, but
875 # the children still need to be processed.
876
877 eALL_PROCESSED = 5 # The issue and all its children, its parent and its related issues have been
878 # added as dependent issues. It needs no further processing.
879
880 issue_status = Hash.new(eNOT_DISCOVERED)
881
882 # The queue
883 queue = []
884
885 # Initialize the bfs, add start node (self) to the queue
886 queue << self
887 issue_status[self] = ePROCESS_ALL
888
889 while (!queue.empty?) do
890 current_issue = queue.shift
891 current_issue_status = issue_status[current_issue]
892 dependencies << current_issue
893
894 # Add parent to queue, if not already in it.
895 parent = current_issue.parent
896 parent_status = issue_status[parent]
897
898 if parent && (parent_status == eNOT_DISCOVERED) && !except.include?(parent)
899 queue << parent
900 issue_status[parent] = ePROCESS_RELATIONS_ONLY
901 end
902
903 # Add children to queue, but only if they are not already in it and
904 # the children of the current node need to be processed.
905 if (current_issue_status == ePROCESS_CHILDREN_ONLY || current_issue_status == ePROCESS_ALL)
906 current_issue.children.each do |child|
907 next if except.include?(child)
908
909 if (issue_status[child] == eNOT_DISCOVERED)
910 queue << child
911 issue_status[child] = ePROCESS_ALL
912 elsif (issue_status[child] == eRELATIONS_PROCESSED)
913 queue << child
914 issue_status[child] = ePROCESS_CHILDREN_ONLY
915 elsif (issue_status[child] == ePROCESS_RELATIONS_ONLY)
916 queue << child
917 issue_status[child] = ePROCESS_ALL
918 end
919 end
920 end
921
922 # Add related issues to the queue, if they are not already in it.
923 current_issue.relations_from.map(&:issue_to).each do |related_issue|
924 next if except.include?(related_issue)
925
926 if (issue_status[related_issue] == eNOT_DISCOVERED)
927 queue << related_issue
928 issue_status[related_issue] = ePROCESS_ALL
929 elsif (issue_status[related_issue] == eRELATIONS_PROCESSED)
930 queue << related_issue
931 issue_status[related_issue] = ePROCESS_CHILDREN_ONLY
932 elsif (issue_status[related_issue] == ePROCESS_RELATIONS_ONLY)
933 queue << related_issue
934 issue_status[related_issue] = ePROCESS_ALL
935 end
936 end
937
938 # Set new status for current issue
939 if (current_issue_status == ePROCESS_ALL) || (current_issue_status == ePROCESS_CHILDREN_ONLY)
940 issue_status[current_issue] = eALL_PROCESSED
941 elsif (current_issue_status == ePROCESS_RELATIONS_ONLY)
942 issue_status[current_issue] = eRELATIONS_PROCESSED
943 end
944 end # while
945
946 # Remove the issues from the "except" parameter from the result array
863 dependencies -= except
947 dependencies -= except
864 dependencies += dependencies.map {|issue| issue.all_dependent_issues(except)}.flatten
948 dependencies.delete(self)
865 if parent
949
866 dependencies << parent
867 dependencies += parent.all_dependent_issues(except + parent.descendants)
868 end
869 dependencies
950 dependencies
870 end
951 end
871
952
@@ -1792,6 +1792,136 class IssueTest < ActiveSupport::TestCase
1792 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
1792 assert_equal [2, 3, 8], Issue.find(1).all_dependent_issues.collect(&:id).sort
1793 end
1793 end
1794
1794
1795 def test_all_dependent_issues_with_subtask
1796 IssueRelation.delete_all
1797
1798 project = Project.generate!(:name => "testproject")
1799
1800 parentIssue = Issue.generate!(:project => project)
1801 childIssue1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1802 childIssue2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1803
1804 assert_equal [childIssue1.id, childIssue2.id].sort, parentIssue.all_dependent_issues.collect(&:id).uniq.sort
1805 end
1806
1807 def test_all_dependent_issues_does_not_include_self
1808 IssueRelation.delete_all
1809
1810 project = Project.generate!(:name => "testproject")
1811
1812 parentIssue = Issue.generate!(:project => project)
1813 childIssue = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1814
1815 assert_equal [childIssue.id], parentIssue.all_dependent_issues.collect(&:id)
1816 end
1817
1818 def test_all_dependent_issues_with_parenttask_and_sibling
1819 IssueRelation.delete_all
1820
1821 project = Project.generate!(:name => "testproject")
1822
1823 parentIssue = Issue.generate!(:project => project)
1824 childIssue1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1825 childIssue2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue.id)
1826
1827 assert_equal [parentIssue.id].sort, childIssue1.all_dependent_issues.collect(&:id)
1828 end
1829
1830 def test_all_dependent_issues_with_relation_to_leaf_in_other_tree
1831 IssueRelation.delete_all
1832
1833 project = Project.generate!(:name => "testproject")
1834
1835 parentIssue1 = Issue.generate!(:project => project)
1836 childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1837 childIssue1_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1838
1839 parentIssue2 = Issue.generate!(:project => project)
1840 childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1841 childIssue2_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1842
1843
1844 assert IssueRelation.create(:issue_from => parentIssue1,
1845 :issue_to => childIssue2_2,
1846 :relation_type => IssueRelation::TYPE_BLOCKS)
1847
1848 assert_equal [childIssue1_1.id, childIssue1_2.id, parentIssue2.id, childIssue2_2.id].sort,
1849 parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
1850 end
1851
1852 def test_all_dependent_issues_with_relation_to_parent_in_other_tree
1853 IssueRelation.delete_all
1854
1855 project = Project.generate!(:name => "testproject")
1856
1857 parentIssue1 = Issue.generate!(:project => project)
1858 childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1859 childIssue1_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1860
1861 parentIssue2 = Issue.generate!(:project => project)
1862 childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1863 childIssue2_2 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1864
1865
1866 assert IssueRelation.create(:issue_from => parentIssue1,
1867 :issue_to => parentIssue2,
1868 :relation_type => IssueRelation::TYPE_BLOCKS)
1869
1870 assert_equal [childIssue1_1.id, childIssue1_2.id, parentIssue2.id, childIssue2_1.id, childIssue2_2.id].sort,
1871 parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
1872 end
1873
1874 def test_all_dependent_issues_with_transitive_relation
1875 IssueRelation.delete_all
1876
1877 project = Project.generate!(:name => "testproject")
1878
1879 parentIssue1 = Issue.generate!(:project => project)
1880 childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1881
1882 parentIssue2 = Issue.generate!(:project => project)
1883 childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1884
1885 independentIssue = Issue.generate!(:project => project)
1886
1887 assert IssueRelation.create(:issue_from => parentIssue1,
1888 :issue_to => childIssue2_1,
1889 :relation_type => IssueRelation::TYPE_RELATES)
1890
1891 assert IssueRelation.create(:issue_from => childIssue2_1,
1892 :issue_to => independentIssue,
1893 :relation_type => IssueRelation::TYPE_RELATES)
1894
1895 assert_equal [childIssue1_1.id, parentIssue2.id, childIssue2_1.id, independentIssue.id].sort,
1896 parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
1897 end
1898
1899 def test_all_dependent_issues_with_transitive_relation2
1900 IssueRelation.delete_all
1901
1902 project = Project.generate!(:name => "testproject")
1903
1904 parentIssue1 = Issue.generate!(:project => project)
1905 childIssue1_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue1.id)
1906
1907 parentIssue2 = Issue.generate!(:project => project)
1908 childIssue2_1 = Issue.generate!(:project => project, :parent_issue_id => parentIssue2.id)
1909
1910 independentIssue = Issue.generate!(:project => project)
1911
1912 assert IssueRelation.create(:issue_from => parentIssue1,
1913 :issue_to => independentIssue,
1914 :relation_type => IssueRelation::TYPE_RELATES)
1915
1916 assert IssueRelation.create(:issue_from => independentIssue,
1917 :issue_to => childIssue2_1,
1918 :relation_type => IssueRelation::TYPE_RELATES)
1919
1920 assert_equal [childIssue1_1.id, parentIssue2.id, childIssue2_1.id, independentIssue.id].sort,
1921 parentIssue1.all_dependent_issues.collect(&:id).uniq.sort
1922
1923 end
1924
1795 def test_all_dependent_issues_with_persistent_circular_dependency
1925 def test_all_dependent_issues_with_persistent_circular_dependency
1796 IssueRelation.delete_all
1926 IssueRelation.delete_all
1797 assert IssueRelation.create!(:issue_from => Issue.find(1),
1927 assert IssueRelation.create!(:issue_from => Issue.find(1),
General Comments 0
You need to be logged in to leave comments. Login now