• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

KSP-CKAN / CKAN / 15432034930

04 Jun 2025 02:19AM UTC coverage: 30.322% (+0.04%) from 30.28%
15432034930

Pull #4386

github

web-flow
Merge f8b59bcd0 into 4cf303cc8
Pull Request #4386: Mod list multi-select

4063 of 14340 branches covered (28.33%)

Branch coverage included in aggregate %.

55 of 170 new or added lines in 12 files covered. (32.35%)

59 existing lines in 5 files now uncovered.

13712 of 44281 relevant lines covered (30.97%)

0.63 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

26.74
/GUI/Model/ModChange.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.ComponentModel.DataAnnotations;
5

6
#if NET5_0_OR_GREATER
7
using System.Runtime.Versioning;
8
#endif
9

10
using CKAN.Configuration;
11
using CKAN.Extensions;
12

13
namespace CKAN.GUI
14
{
15
    public enum GUIModChangeType
16
    {
17
        [Display(Description  = "ChangeTypeNone",
18
                 ResourceType = typeof(Properties.Resources))]
19
        None    = 0,
20

21
        [Display(Description  = "ChangeTypeInstall",
22
                 ResourceType = typeof(Properties.Resources))]
23
        Install = 1,
24

25
        [Display(Description  = "ChangeTypeRemove",
26
                 ResourceType = typeof(Properties.Resources))]
27
        Remove  = 2,
28

29
        [Display(Description  = "ChangeTypeUpdate",
30
                 ResourceType = typeof(Properties.Resources))]
31
        Update  = 3,
32

33
        [Display(Description  = "ChangeTypeReplace",
34
                 ResourceType = typeof(Properties.Resources))]
35
        Replace = 4,
36
    }
37

38
    /// <summary>
39
    /// Everything the GUI needs to know about a change, including
40
    /// the mod itself, the change we're making, and the reason why.
41
    /// </summary>
42
    #if NET5_0_OR_GREATER
43
    [SupportedOSPlatform("windows")]
44
    #endif
45
    public class ModChange
46
    {
47
        public CkanModule        Mod        { get; private set; }
48
        public GUIModChangeType  ChangeType { get; private set; }
49
        public SelectionReason[] Reasons    { get; private set; }
50

51
        /// <summary>
52
        /// true if the reason for this change is that an installed dependency is no longer needed,
53
        /// false otherwise
54
        /// </summary>
55
        public readonly bool IsAutoRemoval;
56

57
        /// <summary>
58
        /// true if this change is user requested and no other changes depend on it, false otherwise.
59
        /// </summary>
60
        public readonly bool IsUserRequested;
61

62
        /// <summary>
63
        /// true if this change can be removed from a changeset, false otherwise
64
        /// </summary>
65
        public bool IsRemovable => IsAutoRemoval || IsUserRequested;
×
66

67
        // If we don't have a Reason, the user probably wanted to install it
68
        public ModChange(CkanModule       mod,
69
                         GUIModChangeType changeType,
70
                         IConfiguration   config)
71
            : this(mod, changeType, new SelectionReason.UserRequested(), config)
2✔
72
        {
2✔
73
        }
2✔
74

75
        public ModChange(CkanModule       mod,
76
                         GUIModChangeType changeType,
77
                         SelectionReason  reason,
78
                         IConfiguration   config)
79
            : this(mod, changeType, Enumerable.Repeat(reason, 1), config)
2✔
80
        {
2✔
81
        }
2✔
82

83
        public ModChange(CkanModule                   mod,
2✔
84
                         GUIModChangeType             changeType,
85
                         IEnumerable<SelectionReason> reasons,
86
                         IConfiguration               config)
87
        {
2✔
88
            Mod        = mod;
2✔
89
            ChangeType = changeType;
2✔
90
            Reasons    = reasons.ToArray();
2✔
91
            this.config = config;
2✔
92
            IsAutoRemoval   = Reasons.All(r => r is SelectionReason.NoLongerUsed);
2✔
93
            IsUserRequested = Reasons.All(r => r is SelectionReason.UserRequested);
2✔
94
        }
2✔
95

96
        public override bool Equals(object? obj)
97
        {
×
98
            if (obj is null)
×
99
            {
×
100
                return false;
×
101
            }
102

103
            if (ReferenceEquals(this, obj))
×
104
            {
×
105
                return true;
×
106
            }
107

108
            if (obj.GetType() != GetType())
×
109
            {
×
110
                return false;
×
111
            }
112

113
            return (obj as ModChange)?.Mod.Equals(Mod) ?? false;
×
114
        }
×
115

116
        private static readonly int maxEnumVal = Enum.GetValues(typeof(GUIModChangeType)).Cast<int>().Max();
2✔
117

118
        public override int GetHashCode()
119
            // Distinguish between installing and removing
120
            => Mod == null
2!
121
                ? 0
122
                : (((maxEnumVal + 1) * Mod.GetHashCode()) + (int)ChangeType);
123

124
        public override string ToString()
125
            => $"{ChangeType.LocalizeDescription()} {Mod} ({Description})";
×
126

127
        public virtual string? NameAndStatus
128
            => Main.Instance?.Manager?.Cache?.DescribeAvailability(config, Mod);
×
129

130
        private static string DescribeGroup(IEnumerable<SelectionReason> reasons)
131
            => reasons.First().DescribeWith(reasons.Skip(1));
×
132

133
        public virtual string Description
134
            => string.Join("; ",
×
135
                Reasons.GroupBy(r => r.GetType(), (t, reasons) =>
×
136
                    DescribeGroup(
×
137
                        t.IsSubclassOf(typeof(SelectionReason.RelationshipReason))
138
                            ? reasons.OfType<SelectionReason.RelationshipReason>()
139
                                     .OrderBy(r => r.Parent.name)
×
140
                            : reasons)));
141

142
        protected IConfiguration config;
143
    }
144

145
    #if NET5_0_OR_GREATER
146
    [SupportedOSPlatform("windows")]
147
    #endif
148
    public class ModUpgrade : ModChange
149
    {
150
        public ModUpgrade(CkanModule       mod,
151
                          CkanModule       targetMod,
152
                          bool             userReinstall,
153
                          bool             metadataChanged,
154
                          IConfiguration   config)
NEW
155
            : base(mod, GUIModChangeType.Update, config)
×
156
        {
×
157
            this.targetMod       = targetMod;
×
158
            this.userReinstall   = userReinstall;
×
159
            this.metadataChanged = metadataChanged;
×
160
        }
×
161

162
        public override string? NameAndStatus
163
            => Main.Instance?.Manager?.Cache?.DescribeAvailability(config, targetMod);
×
164

165
        public override string Description
166
            => IsReinstall
×
167
                ? userReinstall ? Properties.Resources.MainChangesetReinstallUser
168
                                : metadataChanged ? Properties.Resources.MainChangesetReinstallMetadataChanged
169
                                                  : Properties.Resources.MainChangesetReinstallMissing
170
                : string.Format(Properties.Resources.MainChangesetUpdateSelected,
171
                                targetMod.version);
172

173
        /// <summary>
174
        /// The target version for upgrading
175
        /// </summary>
176
        public CkanModule targetMod;
177

178
        private bool IsReinstall
179
            => targetMod.identifier == Mod.identifier
×
180
                && targetMod.version == Mod.version;
181

182
        private readonly bool userReinstall;
183
        private readonly bool metadataChanged;
184
    }
185
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc