< Summary

Class:Willykc.Templ.Editor.Scaffold.TemplScaffoldFacade
Assembly:Willykc.Templ.Editor
File(s):/github/workspace/Packages/package.to.test/Editor/Scaffold/TemplScaffoldFacade.cs
Covered lines:108
Uncovered lines:0
Coverable lines:108
Total lines:289
Line coverage:100% (108 of 108)
Covered branches:0
Total branches:0
Covered methods:8
Total methods:8
Method coverage:100% (8 of 8)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
TemplScaffoldFacade(...)0%110100%
get_IsGenerating()0%110100%
Willykc-Templ-Editor-Scaffold-ITemplScaffoldFacade-GenerateScaffoldAsync()0%17.0617094.12%
EnableScaffoldForSelection(...)0%660100%
DisableScaffoldForSelection(...)0%550100%
ShowScaffoldInputFormAsync()0%10100100%
TryGenerateScaffoldAsync()0%11110100%
GetSkipPaths()0%440100%

File(s)

/github/workspace/Packages/package.to.test/Editor/Scaffold/TemplScaffoldFacade.cs

#LineLine coverage
 1/*
 2 * Copyright (c) 2024 Willy Alberto Kuster
 3 *
 4 * Permission is hereby granted, free of charge, to any person obtaining a copy
 5 * of this software and associated documentation files (the "Software"), to deal
 6 * in the Software without restriction, including without limitation the rights
 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 8 * copies of the Software, and to permit persons to whom the Software is
 9 * furnished to do so, subject to the following conditions:
 10 *
 11 * The above copyright notice and this permission notice shall be included in
 12 * all copies or substantial portions of the Software.
 13 *
 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 20 * THE SOFTWARE.
 21 */
 22using JetBrains.Annotations;
 23using System;
 24using System.IO;
 25using System.Linq;
 26using System.Threading;
 27using System.Threading.Tasks;
 28using UnityEngine;
 29using UnityObject = UnityEngine.Object;
 30
 31namespace Willykc.Templ.Editor.Scaffold
 32{
 33    using Abstraction;
 34    using static TemplSettings;
 35
 36    internal sealed class TemplScaffoldFacade : ITemplScaffoldFacade
 37    {
 38        private const int MaxOverwriteTries = 20;
 39
 40        private readonly ILogger log;
 41        private readonly ISettingsProvider settingsProvider;
 42        private readonly IAssetDatabase assetDatabase;
 43        private readonly IEditorUtility editorUtility;
 44        private readonly ITemplScaffoldWindowManager windowManager;
 45        private readonly ITemplScaffoldCore scaffoldCore;
 4246        private readonly object lockHandle = new object();
 47
 48        private bool isGenerating;
 49
 250        bool ITemplScaffoldFacade.IsGenerating => isGenerating;
 51
 4252        internal TemplScaffoldFacade(
 53            ILogger log,
 54            ISettingsProvider settingsProvider,
 55            IAssetDatabase assetDatabase,
 56            IEditorUtility editorUtility,
 57            ITemplScaffoldWindowManager windowManager,
 58            ITemplScaffoldCore scaffoldCore)
 4259        {
 4260            this.log = log;
 4261            this.settingsProvider = settingsProvider;
 4262            this.assetDatabase = assetDatabase;
 4263            this.editorUtility = editorUtility;
 4264            this.windowManager = windowManager;
 4265            this.scaffoldCore = scaffoldCore;
 4266        }
 67
 68        [ItemCanBeNull]
 69        async Task<string[]> ITemplScaffoldFacade.GenerateScaffoldAsync(
 70            TemplScaffold scaffold,
 71            string targetPath,
 72            object input,
 73            UnityObject selection,
 74            OverwriteOptions overwriteOption,
 75            CancellationToken cancellationToken)
 2976        {
 2977            if (cancellationToken.IsCancellationRequested)
 178            {
 179                return null;
 80            }
 81
 2882            scaffold = scaffold ? scaffold : throw new ArgumentNullException(nameof(scaffold));
 2783            targetPath = !string.IsNullOrWhiteSpace(targetPath)
 84                ? targetPath
 85                : throw new ArgumentException($"{nameof(targetPath)} must not be null or empty",
 86                nameof(targetPath));
 87
 2588            if (!scaffold.IsValid)
 189            {
 190                throw new ArgumentException($"{nameof(scaffold)} must be valid",
 91                    nameof(scaffold));
 92            }
 93
 2494            targetPath = targetPath.SanitizePath();
 95
 2496            if (!assetDatabase.IsValidFolder(targetPath))
 197            {
 198                throw new DirectoryNotFoundException($"Directory does not exist in the asset database: '{targetPath}'");
 99            }
 100
 23101            lock (lockHandle)
 23102            {
 23103                if (isGenerating)
 1104                {
 1105                    log.Error("Only one scaffold can be generated at a time");
 1106                    return null;
 107                }
 108
 22109                isGenerating = true;
 22110            }
 111
 22112            string[] generatedPaths = null;
 113
 114            try
 22115            {
 34116                generatedPaths = scaffold.DefaultInput && input == null
 117                    ? await ShowScaffoldInputFormAsync(
 118                        scaffold,
 119                        targetPath,
 120                        selection,
 121                        overwriteOption,
 122                        cancellationToken)
 123                    : await TryGenerateScaffoldAsync(
 124                        scaffold,
 125                        targetPath,
 126                        input,
 127                        selection,
 128                        overwriteOption,
 129                        cancellationToken);
 22130            }
 131            finally
 22132            {
 22133                isGenerating = false;
 22134            }
 135
 22136            return generatedPaths;
 24137        }
 138
 139        void ITemplScaffoldFacade.EnableScaffoldForSelection(TemplScaffold scaffold)
 7140        {
 7141            if (!settingsProvider.SettingsExist())
 1142            {
 1143                throw new InvalidOperationException($"{nameof(TemplSettings)} not found");
 144            }
 145
 6146            scaffold = scaffold ? scaffold : throw new ArgumentNullException(nameof(scaffold));
 147
 5148            if (!scaffold.IsValid)
 1149            {
 1150                throw new ArgumentException("Can not enable for selection an invalid scaffold",
 151                    nameof(scaffold));
 152            }
 153
 4154            var settings = settingsProvider.GetSettings();
 155
 4156            lock (lockHandle)
 4157            {
 4158                if (settings.Scaffolds.Contains(scaffold))
 1159                {
 1160                    return;
 161                }
 162
 3163                settings.Scaffolds.Add(scaffold);
 164
 3165                editorUtility.SetDirty(settings);
 3166                assetDatabase.SaveAssets();
 3167            }
 4168        }
 169
 170        void ITemplScaffoldFacade.DisableScaffoldForSelection(TemplScaffold scaffold)
 7171        {
 7172            if (!settingsProvider.SettingsExist())
 1173            {
 1174                throw new InvalidOperationException($"{nameof(TemplSettings)} not found");
 175            }
 176
 6177            scaffold = scaffold ? scaffold : throw new ArgumentNullException(nameof(scaffold));
 178
 5179            var settings = settingsProvider.GetSettings();
 180
 5181            lock (lockHandle)
 5182            {
 5183                if (!settings.Scaffolds.Contains(scaffold))
 1184                {
 1185                    return;
 186                }
 187
 4188                settings.Scaffolds.Remove(scaffold);
 189
 4190                editorUtility.SetDirty(settings);
 4191                assetDatabase.SaveAssets();
 4192            }
 5193        }
 194
 195        private async Task<string[]> ShowScaffoldInputFormAsync(
 196            TemplScaffold scaffold,
 197            string targetPath,
 198            UnityObject selection,
 199            OverwriteOptions overwriteOption,
 200            CancellationToken cancellationToken)
 13201        {
 13202            var completionSource = new TaskCompletionSource<string[]>();
 13203            var tokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
 204
 5205            void OnInputFormClosed() => tokenSource.Cancel();
 206
 13207            var tries = 0;
 208
 40209            while (!tokenSource.IsCancellationRequested &&
 210                tries++ < MaxOverwriteTries &&
 211                await windowManager.ShowInputFormAsync(
 212                scaffold,
 213                targetPath,
 214                selection,
 215                OnInputFormClosed,
 216                cancellationToken) is { } input)
 27217            {
 35218                string[] generatedPaths = await TryGenerateScaffoldAsync(
 219                    scaffold,
 220                    targetPath,
 221                    input,
 222                    selection,
 223                    overwriteOption,
 224                    tokenSource.Token);
 225
 27226                if (generatedPaths == null && !tokenSource.IsCancellationRequested)
 21227                {
 21228                    continue;
 229                }
 230
 6231                windowManager.CloseInputForm();
 6232                return generatedPaths;
 233            }
 234
 7235            windowManager.CloseInputForm();
 7236            return null;
 13237        }
 238
 239        private async Task<string[]> TryGenerateScaffoldAsync(
 240            TemplScaffold scaffold,
 241            string targetPath,
 242            object input,
 243            UnityObject selection,
 244            OverwriteOptions overwriteOption,
 245            CancellationToken cancellationToken)
 36246        {
 36247            var errors =
 248                scaffoldCore.ValidateScaffoldGeneration(scaffold, targetPath, input, selection);
 249
 36250            var existingFilePaths = errors
 32251                .Where(e => e.Type == TemplScaffoldErrorType.Overwrite)
 31252                .Select(e => e.Message)
 253                .ToArray();
 254
 68255            if (errors.Any(e => e.Type != TemplScaffoldErrorType.Overwrite))
 1256            {
 1257                log.Error($"Aborted generation of {scaffold.name} scaffold due to errors");
 1258                return null;
 259            }
 260
 43261            var skipPaths = overwriteOption switch
 262            {
 263                OverwriteOptions.OverwriteAll => EmptyStringArray,
 264                OverwriteOptions.SkipAll => existingFilePaths,
 265                _ => await GetSkipPaths(scaffold, targetPath, existingFilePaths, cancellationToken)
 266            };
 267
 35268            if (existingFilePaths.Length > 0 && skipPaths == null)
 23269            {
 23270                return null;
 271            }
 272
 12273            return scaffoldCore
 274                .GenerateScaffold(scaffold, targetPath, input, selection, skipPaths);
 36275        }
 276
 277        private async Task<string[]> GetSkipPaths(
 278            TemplScaffold scaffold,
 279            string targetPath,
 280            string[] existingFilePaths,
 39281            CancellationToken cancellationToken) => existingFilePaths.Length > 0
 282            ? await windowManager.ShowOverwriteDialogAsync(
 283                scaffold,
 284                targetPath,
 285                existingFilePaths,
 286                cancellationToken)
 287            : null;
 288    }
 289}
hild(newScript); })(); /* ]]> */