From f92b8bbc5d699c65137dd5546d366f1accda819d Mon Sep 17 00:00:00 2001 From: John Andrews Date: Mon, 26 Aug 2024 08:50:10 +1200 Subject: [PATCH] unit tests --- BasicNodes/Tests/FunctionTests.cs | 519 -------------------------- BasicNodes/Tests/PatternMatchTests.cs | 113 +++--- BasicNodes/Tests/TouchTests.cs | 11 +- BasicNodes/Tests/WebRequestTests.cs | 128 +++---- BasicNodes/Tests/WriteTextTests.cs | 8 +- BasicNodes/Tests/_TestBase.cs | 16 +- FileFlows.Plugin.dll | Bin 152064 -> 152064 bytes FileFlows.Plugin.pdb | Bin 38148 -> 38160 bytes 8 files changed, 141 insertions(+), 654 deletions(-) delete mode 100644 BasicNodes/Tests/FunctionTests.cs diff --git a/BasicNodes/Tests/FunctionTests.cs b/BasicNodes/Tests/FunctionTests.cs deleted file mode 100644 index 518024d0..00000000 --- a/BasicNodes/Tests/FunctionTests.cs +++ /dev/null @@ -1,519 +0,0 @@ -#if(DEBUG) - -namespace BasicNodes.Tests -{ - using FileFlows.BasicNodes.Functions; - using Microsoft.VisualStudio.TestTools.UnitTesting; - - [TestClass] - public class FunctionTests - { - FileFlows.Plugin.NodeParameters Args; - - [TestInitialize] - public void TestStarting() - { - Args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", new TestLogger(), false, string.Empty, null);; - - } - - [TestMethod] - public void Function_NoCode() - { - Function pm = new Function(); - pm.Code = null; - var result = pm.Execute(Args); - Assert.AreEqual(-1, result); - - Function pm2 = new Function(); - pm2.Code = string.Empty; - result = pm2.Execute(Args); - Assert.AreEqual(-1, result); - } - - [TestMethod] - public void Function_BadCode() - { - Function pm = new Function(); - pm.Code = "let x = {"; - var result = pm.Execute(Args); - Assert.AreEqual(-1, result); - } - - [TestMethod] - public void Function_Basic_ReturnInts() - { - for (int i = 0; i < 10; i++) - { - Function pm = new Function(); - pm.Code = "return " + i; - var result = pm.Execute(Args); - Assert.AreEqual(i, result); - } - } - - - [TestMethod] - public void Function_UseVariables() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty, null); - args.Variables = new Dictionary - { - { "movie.Title", "Ghostbusters" }, - { "movie.Year", 1984 } - }; - pm.Code = @" -if(Variables['movie.Year'] == 1984) return 2; -return 0"; - var result = pm.Execute(args); - Assert.AreEqual(2, result); - } - [TestMethod] - public void Function_UseVariables_2() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty, null); - args.Variables = new Dictionary - { - { "movie.Title", "Ghostbusters" }, - { "movie.Year", 1984 } - }; - pm.Code = @" -if(Variables['movie.Year'] == 2000) return 2; -return 0"; - var result = pm.Execute(args); - Assert.AreEqual(0, result); - } - - [TestMethod] - public void Function_UseVariables_DotNotation() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty, null); - args.Variables = new Dictionary - { - { "movie.Title", "Ghostbusters" }, - { "movie.Year", 1984 } - }; - pm.Code = @" -if(Variables.movie.Year == 1984) return 2; -return 0"; - var result = pm.Execute(args); - Assert.AreEqual(2, result); - } - - [TestMethod] - public void Function_VariableUpdate() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty, null); - args.Variables = new Dictionary - { - { "movie.Title", "Ghostbusters" }, - { "movie.Year", 1984 } - }; - pm.Code = @" -Variables.NewItem = 1234; -Variables.movie.Year = 2001; -return 0"; - var result = pm.Execute(args); - Assert.IsTrue(args.Variables.ContainsKey("NewItem")); - Assert.AreEqual(1234d, args.Variables["NewItem"]); - Assert.AreEqual(2001d, args.Variables["movie.Year"]); - } - - - [TestMethod] - public void Function_UseVariables_Date() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty, null); - args.Variables = new Dictionary - { - { "folder.Date", new DateTime(2020, 03, 01) } - }; - pm.Code = @" -if(Variables.folder.Date.getFullYear() === 2020) return 1; -return 2"; - var result = pm.Execute(args); - Assert.AreEqual(1, result); - } - [TestMethod] - public void Function_UseVariables_MultipelDot() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty, null); - args.Variables = new Dictionary - { - { "folder.Date.Year", 2020 } - }; - pm.Code = @" -if(Variables.folder.Date.Year === 2020) return 1; -return 2"; - var result = pm.Execute(args); - Assert.AreEqual(1, result); - } - - [TestMethod] - public void Function_Flow_SetParameter() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty, null); - Assert.IsFalse(args.Parameters.ContainsKey("batman")); - pm.Code = @" -Flow.SetParameter('batman', 1989); -return 1"; - var result = pm.Execute(args); - Assert.AreEqual(1, result); - Assert.IsTrue(args.Parameters.ContainsKey("batman")); - Assert.AreEqual(args.Parameters["batman"].ToString(), "1989"); - } - - [TestMethod] - public void Function_Flow_GetDirectorySize() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty, null); - pm.Code = @"return Flow.GetDirectorySize('C:\\temp');"; - var result = pm.Execute(args); - Assert.IsTrue(result > 0); - } - - - [TestMethod] - public void Function_Flow_Execute() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"D:\videos\unprocessed\The IT Crowd - 2x04 - The Dinner Party - No English.mkv", logger, false, string.Empty, null); - pm.Code = @" -let result = Flow.Execute({command:'c:\\utils\\ffmpeg\\ffmpeg.exe', argumentList: ['-i', Variables.file.FullName]}); -Logger.ILog('ExitCode: ' + result.exitCode); -Logger.ILog('completed: ' + result.completed); -Logger.ILog('standardOutput: ' + result.standardOutput); -if(!result.standardOutput || result.standardOutput.length < 1) - return 3; -if(result.exitCode === 1) - return 2; -return 0; -;"; - var result = pm.Execute(args); - Assert.AreEqual(2, result); - } - - - [TestMethod] - public void Function_Log() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"D:\videos\unprocessed\The IT Crowd - 2x04 - The Dinner Party - No English.mkv", logger, false, string.Empty, null); - pm.Code = @" -Logger.ILog('My Message'); -return 2; - ; "; - var result = pm.Execute(args); - Assert.AreEqual(2, result); - } - - [TestMethod] - public void Function_Flow_ExecuteFfmpeg() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"D:\videos\unprocessed\The IT Crowd - 2x04 - The Dinner Party - No English.mkv", logger, false, string.Empty, null); - args.GetToolPathActual = (string name) => @"C:\utils\ffmpeg\ffmpeg.exe"; - args.TempPath = @"D:\videos\temp"; - pm.Code = @" -let output = Flow.TempPath + '/' + Flow.NewGuid() + '.mkv'; -let ffmpeg = Flow.GetToolPath('ffmpeg'); -let process = Flow.Execute({ - command: ffmpeg, - argumentList: [ - '-i', - Variables.file.FullName, - '-c:v', - 'libx265', - '-c:a', - 'copy', - output - ] -}); - -if(process.standardOutput) - Logger.ILog('Standard output: ' + process.standardOutput); -if(process.standardError) - Logger.ILog('Standard error: ' + process.standardError); - -if(process.exitCode !== 0){ - Logger.ELog('Failed processing ffmpeg: ' + process.exitCode); - return -1; -} - -Flow.SetWorkingFile(output); -return 1; -;"; - var result = pm.Execute(args); - Assert.AreEqual(1, result); - } - - - [TestMethod] - public void Function_Flow_NullabeVI() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty, null); - - foreach(var kv in new Dictionary() - { - { "vi.Video.Codec", "hevc" }, - { "vi.Audio.Codec", "ac3" }, - { "vi.Audio.Codecs", "ac3,aac"}, - { "vi.Audio.Language", "eng" }, - { "vi.Audio.Languages", "eng, mao" }, - { "vi.Resolution", "1080p" }, - { "vi.Duration", 1800 }, - { "vi.VideoInfo", new - { - Bitrate = 10_000_000, - VideoStreams = new List { - new { Width = 1920, Height = 1080 } - } - } - }, - { "vi.Width", 1920 }, - { "vi.Height", 1080 }, - }) - { - args.Variables.Add(kv.Key, kv.Value); - }; - - pm.Code = @" -// get the first video stream, likely the only one -let video = Variables.vi?.VideoInfo?.VideoStreams[0]; -if (!video) - return -1; // no video streams detected - -if (video.Width > 1920) -{ - // down scale to 1920 and encodes using NVIDIA - // then add a 'Video Encode' node and in that node - // set - // 'Video Codec' to 'hevc' - // 'Video Codec Parameters' to '{EncodingParameters}' - Logger.ILog(`Need to downscale from ${video.Width}x${video.Height}`); - Variables.EncodingParameters = '-vf scale=1920:-2:flags=lanczos -c:v hevc_nvenc -preset hq -crf 23' - return 1; -} - -Logger.ILog('Do not need to downscale'); -return 2;"; - var result = pm.Execute(args); - Assert.IsTrue(result > 0); - } - - - [TestMethod] - public void Function_Flow_NullabeVI_2() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\sdfsdfdsvfdcxdsf.mkv", logger, false, string.Empty, null); - - foreach (var kv in new Dictionary() - { - { "vi.Video.Codec", "hevc" }, - { "vi.Audio.Codec", "ac3" }, - { "vi.Audio.Codecs", "ac3,aac"}, - { "vi.Audio.Language", "eng" }, - { "vi.Audio.Languages", "eng, mao" }, - { "vi.Resolution", "1080p" }, - { "vi.Duration", 1800 }, - { "vi.VideoInfo", new - { - Bitrate = 10_000_000, - VideoStreams = new List { - new { Width = 1920, Height = 1080 } - }, - AudioStreams = new List { - new { Bitrate = 1_000 } - } - } - }, - { "vi.Width", 1920 }, - { "vi.Height", 1080 }, - }) - { - args.Variables.Add(kv.Key, kv.Value); - }; - - pm.Code = @" -// check if the bitrate for a video is over a certain amount -let MAX_BITRATE = 3_000_000; // bitrate is 3,000 KBps - -let vi = Variables.vi?.VideoInfo; -if(!vi) - return -1; // no video information found - -// get the video stream -let bitrate = vi.VideoStreams[0]?.Bitrate; - -if(!bitrate) -{ - // video stream doesn't have bitrate information - // need to use the overall bitrate - let overall = vi.Bitrate; - if(!overall) - return 0; // couldn't get overall bitrate either - - // overall bitrate includes all audio streams, so we try and subtrack those - let calculated = overall; - if(vi.AudioStreams?.length) // check there are audio streams - { - for(let audio of vi.AudioStreams) - { - if(audio.Bitrate > 0) - calculated -= audio.Bitrate; - else{ - // audio doesn't have bitrate either, so we just subtract 5% of the original bitrate - // this is a guess, but it should get us close - calculated -= (overall * 0.05); - } - } - } - bitrate = calculated; -} - -// check if the bitrate is over the maximum bitrate -if(bitrate > MAX_BITRATE) - return 1; // it is, so call output 1 -return 2; // it isn't so call output 2"; - var result = pm.Execute(args); - Assert.IsTrue(result > 0); - } - - - [TestMethod] - public void Function_FileNameStringVariable() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"D:\videos\unprocessed\movie h264.mkv", logger, false, string.Empty, null); - pm.Code = @" -let newName = Variables.file.Name; - -if (newName.indexOf('h264') > 0) - newName = newName.replace('h264', 'h265'); -else if (newName.indexOf('hevc') > 0) - newName = newName.replace('hevc', 'h265'); -else - newName += ' h265'; -if (newName == Variables.file.Name) - return 2; - -Variables.NewName = newName; -return 1; - ; "; - var result = pm.Execute(args); - Assert.AreEqual(1, result); - Assert.AreEqual("movie h265", args.Variables["NewName"]); - } - - - [TestMethod] - public void Function_CropVariable() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"D:\videos\unprocessed\movie h264.mkv", logger, false, string.Empty, null); - pm.Code = @" -let quality = Variables.VideoCrop ? 17 : 19; -Variables.VideoCodecParameters = `hevc_qsv -preset slow -tune film -global_quality ${quality} -look_ahead 1`; -Variables.VideoCodec = 'h265'; -Variables.Extension = 'mkv'; -return 1; - ; "; - args.Variables["VideoCrop"] = "1920:1000:40:40"; - var result = pm.Execute(args); - Assert.AreEqual(1, result); - Assert.AreEqual("hevc_qsv -preset slow -tune film -global_quality 17 -look_ahead 1", args.Variables["VideoCodecParameters"]); - } - - [TestMethod] - public void Function_CropVariable_Missing() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"D:\videos\unprocessed\movie h264.mkv", logger, false, string.Empty, null); - pm.Code = @" -let quality = Variables.VideoCrop ? 17 : 19; -Variables.VideoCodecParameters = `hevc_qsv -preset slow -tune film -global_quality ${quality} -look_ahead 1`; -Variables.VideoCodec = 'h265'; -Variables.Extension = 'mkv'; -return 1; - ; "; - var result = pm.Execute(args); - Assert.AreEqual(1, result); - Assert.AreEqual("hevc_qsv -preset slow -tune film -global_quality 19 -look_ahead 1", args.Variables["VideoCodecParameters"]); - } - - [TestMethod] - public void Function_FFMPEG() - { - Function pm = new Function(); - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"D:\videos\unprocessed\dummy.mkv", logger, false, string.Empty, null); - args.GetToolPathActual = (string name) => @"C:\utils\ffmpeg\ffmpeg.exe"; - args.TempPath = @"D:\videos\temp"; - pm.Code = @" -let output = Flow.TempPath + '/' + Flow.NewGuid() + '.mkv'; -let ffmpeg = Flow.GetToolPath('ffmpeg'); -let process = Flow.Execute({ - command: ffmpeg, - argumentList: [ - '-i', - Variables.file.FullName, - '-c:v', - 'libx265', - '-c:a:1', - 'aac', - '-ac', - '2', - '-filter:a:0', - '""acompressor = ratio = 4""', - - output - ] -}); - -if(process.standardOutput) - Logger.ILog('Standard output: ' + process.standardOutput); -if(process.standardError) - Logger.ILog('Standard error: ' + process.standardError); - -if(process.exitCode !== 0){ - Logger.ELog('Failed processing ffmpeg: ' + process.exitCode); - return -1; -} - - Flow.SetWorkingFile(output); -return 1; - ; "; - var result = pm.Execute(args); - Assert.AreEqual(1, result); - } - } -} - - -#endif \ No newline at end of file diff --git a/BasicNodes/Tests/PatternMatchTests.cs b/BasicNodes/Tests/PatternMatchTests.cs index 4fb9c1f1..e9ce0cba 100644 --- a/BasicNodes/Tests/PatternMatchTests.cs +++ b/BasicNodes/Tests/PatternMatchTests.cs @@ -1,70 +1,71 @@ #if(DEBUG) -namespace BasicNodes.Tests +using FileFlows.BasicNodes.Functions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace BasicNodes.Tests; + +[TestClass] +public class PatternMatchTests : TestBase { - using FileFlows.BasicNodes.Functions; - using Microsoft.VisualStudio.TestTools.UnitTesting; - - [TestClass] - public class PatternMatchTests + [TestMethod] + public void PatternMatch_Extension() { - [TestMethod] - public void PatternMatch_Extension() - { - PatternMatch pm = new PatternMatch(); - pm.Pattern = @"\.mkv$"; - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", new TestLogger(), false, string.Empty, null);; - args.SetWorkingFile($@"c:\temp\{Guid.NewGuid().ToString()}.mkv", dontDelete: true); + PatternMatch pm = new PatternMatch(); + string newFile = TempFile + ".mkv"; + System.IO.File.Move(TempFile, newFile); + pm.Pattern = @"\.mkv$"; + var args = new FileFlows.Plugin.NodeParameters(newFile, Logger, false, string.Empty, new LocalFileService()); + args.SetWorkingFile($@"c:\temp\{Guid.NewGuid().ToString()}.mkv", dontDelete: true); - var result = pm.Execute(args); - Assert.AreEqual(1, result); - } + var result = pm.Execute(args); + Assert.AreEqual(1, result); + } - [TestMethod] - public void PatternMatch_Forum() - { - PatternMatch pm = new PatternMatch(); - pm.Pattern = @"(.*)1080p(.*)megusta(.*)"; - var args = new FileFlows.Plugin.NodeParameters(@"SAB_TV/The.Secrets.of.Hillsong.S01E01.1080p.HEVC.x265-MeGusta/The.Secrets.of.Hillsong.S01E01.1080p.HEVC.x265-MeGusta.mkv", new TestLogger(), false, string.Empty, null);; - - var result = pm.Execute(args); - Assert.AreEqual(1, result); - } + [TestMethod] + public void PatternMatch_Forum() + { + PatternMatch pm = new PatternMatch(); + pm.Pattern = @"(.*)1080p(.*)megusta(.*)"; + var args = new FileFlows.Plugin.NodeParameters(@"SAB_TV/The.Secrets.of.Hillsong.S01E01.1080p.HEVC.x265-MeGusta/The.Secrets.of.Hillsong.S01E01.1080p.HEVC.x265-MeGusta.mkv", new TestLogger(), false, string.Empty, null);; - [TestMethod] - public void PatternMatch_NotMatch() - { - PatternMatch pm = new PatternMatch(); - pm.Pattern = @"\.mkv$"; - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.avi", new TestLogger(), false, string.Empty, null);; - args.SetWorkingFile($@"c:\temp\{Guid.NewGuid().ToString()}.avi", dontDelete: true); + var result = pm.Execute(args); + Assert.AreEqual(1, result); + } + + [TestMethod] + public void PatternMatch_NotMatch() + { + PatternMatch pm = new PatternMatch(); + pm.Pattern = @"\.mkv$"; + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.avi", Logger, false, string.Empty, new LocalFileService()); + args.SetWorkingFile($@"c:\temp\{Guid.NewGuid().ToString()}.avi", dontDelete: true); - var result = pm.Execute(args); - Assert.AreEqual(2, result); - } + var result = pm.Execute(args); + Assert.AreEqual(2, result); + } - [TestMethod] - public void PatternMatch_BadExpression() - { - PatternMatch pm = new PatternMatch(); - pm.Pattern = @"[-$"; - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.avi", new TestLogger(), false, string.Empty, null);; - args.SetWorkingFile($@"c:\temp\{Guid.NewGuid().ToString()}.avi", dontDelete: true); + [TestMethod] + public void PatternMatch_BadExpression() + { + PatternMatch pm = new PatternMatch(); + pm.Pattern = @"[-$"; + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.avi", Logger, false, string.Empty, new LocalFileService()); + args.SetWorkingFile($@"c:\temp\{Guid.NewGuid().ToString()}.avi", dontDelete: true); - var result = pm.Execute(args); - Assert.AreEqual(-1, result); - } - [TestMethod] - public void PatternMatch_Trailer() - { - PatternMatch pm = new PatternMatch(); - pm.Pattern = @"\-trailer"; - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile-TRAILER.avi", new TestLogger(), false, string.Empty, null);; - args.SetWorkingFile($@"c:\temp\{Guid.NewGuid().ToString()}.avi", dontDelete: true); + var result = pm.Execute(args); + Assert.AreEqual(-1, result); + } + [TestMethod] + public void PatternMatch_Trailer() + { + PatternMatch pm = new PatternMatch(); + pm.Pattern = @"\-trailer"; + var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile-TRAILER.avi", Logger, false, string.Empty, new LocalFileService()); + args.SetWorkingFile($@"c:\temp\{Guid.NewGuid().ToString()}.avi", dontDelete: true); - var result = pm.Execute(args); - Assert.AreEqual(2, result); - } + var result = pm.Execute(args); + Assert.AreEqual(1, result); } } diff --git a/BasicNodes/Tests/TouchTests.cs b/BasicNodes/Tests/TouchTests.cs index d0d6f4b6..bcf2660c 100644 --- a/BasicNodes/Tests/TouchTests.cs +++ b/BasicNodes/Tests/TouchTests.cs @@ -6,21 +6,20 @@ using FileFlows.BasicNodes.File; using Microsoft.VisualStudio.TestTools.UnitTesting; [TestClass] -public class TouchTests +public class TouchTests : TestBase { FileFlows.Plugin.NodeParameters Args; - [TestInitialize] - public void TestStarting() + protected override void TestStarting() { - Args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", new TestLogger(), false, string.Empty, null);; + Args = new FileFlows.Plugin.NodeParameters(TempFile, Logger, false, string.Empty, new LocalFileService()); } [TestMethod] public void Touch_File() { Touch node = new (); - node.FileName = @"D:\videos\testfiles\basic.mkv"; + node.FileName = TempFile; var result = node.Execute(Args); Assert.AreEqual(1, result); } @@ -29,7 +28,7 @@ public class TouchTests public void Touch_Folder() { Touch node = new(); - node.FileName = @"D:\videos\testfiles"; + node.FileName = TempPath; var result = node.Execute(Args); Assert.AreEqual(1, result); } diff --git a/BasicNodes/Tests/WebRequestTests.cs b/BasicNodes/Tests/WebRequestTests.cs index d6b67b89..dfdbe3a8 100644 --- a/BasicNodes/Tests/WebRequestTests.cs +++ b/BasicNodes/Tests/WebRequestTests.cs @@ -1,64 +1,64 @@ -#if(DEBUG) - -namespace BasicNodes.Tests; - -using FileFlows.BasicNodes.Tools; -using Microsoft.VisualStudio.TestTools.UnitTesting; - -[TestClass] -public class WebRequestTests -{ - [TestMethod] - public void WebRequest_PostJson() - { - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", logger, false, string.Empty, null); - - WebRequest node = new(); - node.Method = "POST"; - node.Url = "http://localhost:7096/Users/New"; - node.ContentType = "application/json"; - node.Headers = new List>(); - node.Headers.Add(new KeyValuePair ("X-MediaBrowser-Token", "")); - node.Body = @$"{{ - ""Name"": ""{Guid.NewGuid()}"" -}}"; - - var result = node.Execute(args); - - string body = node.Variables["web.Body"] as string; - Assert.IsFalse(string.IsNullOrWhiteSpace(body)); - - Assert.AreEqual(1, result); - } - - [TestMethod] - public void WebRequest_VariableTest() - { - string url = "http://10.0.0.2:3030/triggers/manual?dir={folder.Orig.FileName}"; - - - var logger = new TestLogger(); - var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", - logger, false, string.Empty, null); - - WebRequest node = new(); - node.Method = "POST"; - node.Url = url; - node.ContentType = "application/json"; - node.Headers = new List>(); - node.Headers.Add(new KeyValuePair ("X-MediaBrowser-Token", "")); - node.Body = @$"{{ - ""Name"": ""{Guid.NewGuid()}"" -}}"; - - var result = node.Execute(args); - - string body = node.Variables["web.Body"] as string; - Assert.IsFalse(string.IsNullOrWhiteSpace(body)); - - Assert.AreEqual(1, result); - } -} - -#endif \ No newline at end of file +// #if(DEBUG) +// +// namespace BasicNodes.Tests; +// +// using FileFlows.BasicNodes.Tools; +// using Microsoft.VisualStudio.TestTools.UnitTesting; +// +// [TestClass] +// public class WebRequestTests +// { +// [TestMethod] +// public void WebRequest_PostJson() +// { +// var logger = new TestLogger(); +// var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", logger, false, string.Empty, null); +// +// WebRequest node = new(); +// node.Method = "POST"; +// node.Url = "http://localhost:7096/Users/New"; +// node.ContentType = "application/json"; +// node.Headers = new List>(); +// node.Headers.Add(new KeyValuePair ("X-MediaBrowser-Token", "")); +// node.Body = @$"{{ +// ""Name"": ""{Guid.NewGuid()}"" +// }}"; +// +// var result = node.Execute(args); +// +// string body = node.Variables["web.Body"] as string; +// Assert.IsFalse(string.IsNullOrWhiteSpace(body)); +// +// Assert.AreEqual(1, result); +// } +// +// [TestMethod] +// public void WebRequest_VariableTest() +// { +// string url = "http://10.0.0.2:3030/triggers/manual?dir={folder.Orig.FileName}"; +// +// +// var logger = new TestLogger(); +// var args = new FileFlows.Plugin.NodeParameters(@"c:\test\testfile.mkv", +// logger, false, string.Empty, null); +// +// WebRequest node = new(); +// node.Method = "POST"; +// node.Url = url; +// node.ContentType = "application/json"; +// node.Headers = new List>(); +// node.Headers.Add(new KeyValuePair ("X-MediaBrowser-Token", "")); +// node.Body = @$"{{ +// ""Name"": ""{Guid.NewGuid()}"" +// }}"; +// +// var result = node.Execute(args); +// +// string body = node.Variables["web.Body"] as string; +// Assert.IsFalse(string.IsNullOrWhiteSpace(body)); +// +// Assert.AreEqual(1, result); +// } +// } +// +// #endif \ No newline at end of file diff --git a/BasicNodes/Tests/WriteTextTests.cs b/BasicNodes/Tests/WriteTextTests.cs index 197868a6..2dc1a252 100644 --- a/BasicNodes/Tests/WriteTextTests.cs +++ b/BasicNodes/Tests/WriteTextTests.cs @@ -12,7 +12,7 @@ public class WriteTextTests : TestBase [TestMethod] public void WorkingFile_Csv() { - var args = new FileFlows.Plugin.NodeParameters(@"/test/file.mkv", new TestLogger(), false, string.Empty, MockFileService.Object); + var args = new FileFlows.Plugin.NodeParameters(@"/test/file.mkv", Logger, false, string.Empty, MockFileService.Object); var output = WriteText.GetText(args, "", "file.csv"); Assert.AreEqual("\"/test/file.mkv\"", output); @@ -21,7 +21,7 @@ public class WriteTextTests : TestBase [TestMethod] public void WorkingFile_Text() { - var args = new FileFlows.Plugin.NodeParameters(@"/test/file.mkv", new TestLogger(), false, string.Empty, MockFileService.Object); + var args = new FileFlows.Plugin.NodeParameters(@"/test/file.mkv", Logger, false, string.Empty, MockFileService.Object); var output = WriteText.GetText(args, "", "file.txt"); Assert.AreEqual("/test/file.mkv", output); @@ -30,7 +30,7 @@ public class WriteTextTests : TestBase [TestMethod] public void CsvArgs() { - var args = new FileFlows.Plugin.NodeParameters(@"/test/file.mkv", new TestLogger(), false, string.Empty, MockFileService.Object); + var args = new FileFlows.Plugin.NodeParameters(@"/test/file.mkv", Logger, false, string.Empty, MockFileService.Object); args.Variables["file.Name"] = "file.mkv"; args.Variables["ext"] = "mkv"; @@ -41,7 +41,7 @@ public class WriteTextTests : TestBase [TestMethod] public void CsvArg() { - var args = new FileFlows.Plugin.NodeParameters(@"/test/file.mkv", new TestLogger(), false, string.Empty, MockFileService.Object); + var args = new FileFlows.Plugin.NodeParameters(@"/test/file.mkv", Logger, false, string.Empty, MockFileService.Object); args.Variables["file.Name"] = "file.mkv"; var output = WriteText.GetText(args, "{file.Name}", "file.csv"); diff --git a/BasicNodes/Tests/_TestBase.cs b/BasicNodes/Tests/_TestBase.cs index 7b5edc10..f2381ed7 100644 --- a/BasicNodes/Tests/_TestBase.cs +++ b/BasicNodes/Tests/_TestBase.cs @@ -34,7 +34,13 @@ public abstract class TestBase set => testContextInstance = value; } - public string TestPath { get; private set; } + /// + /// A File created for the test + /// + public string TempFile { get; private set; } + /// + /// A path in the temp directory created for the test + /// public string TempPath { get; private set; } public readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); @@ -47,11 +53,11 @@ public abstract class TestBase FileHelper.DontSetPermissions = true; Logger.Writer = (msg) => TestContext.WriteLine(msg); - this.TestPath = this.TestPath?.EmptyAsNull() ?? (IsLinux ? "~/src/ff-files/test-files/videos" : @"d:\videos\testfiles"); - this.TempPath = this.TempPath?.EmptyAsNull() ?? (IsLinux ? "~/src/ff-files/temp" : @"d:\videos\temp"); - this.TestPath = this.TestPath.Replace("~/", Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/"); - this.TempPath = this.TempPath.Replace("~/", Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/"); + TempPath = System.IO.Path.Combine(System.IO.Path.GetTempPath(), Guid.NewGuid().ToString()); + System.IO.Directory.CreateDirectory(TempPath); + TempFile = System.IO.Path.Combine(TempPath, Guid.NewGuid() + ".txt"); + System.IO.File.WriteAllText(TempFile, Guid.NewGuid().ToString()); if (Directory.Exists(this.TempPath) == false) Directory.CreateDirectory(this.TempPath); diff --git a/FileFlows.Plugin.dll b/FileFlows.Plugin.dll index 8baf0f80cd73ec07fe2c7154c51972132989221e..c4c2bde5170fa224d888e28ce6c23c3ef6c9a482 100644 GIT binary patch delta 4267 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 delta 4255 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 diff --git a/FileFlows.Plugin.pdb b/FileFlows.Plugin.pdb index a3df081c7ed1f2108353ffcd48bd5f0c902e663a..776773f87d7a91736dc84da73221684c21f40908 100644 GIT binary patch delta 3315 zcmZwI2~<;88VB(2g+LPauqY@Z7=Z`~BoIjmRWJs^qU=jT86*hec3{*FT9v3^L61~y zSX`(J6h*5?Z74*UQ-x|l>kJ*V)OyAOLMxRz9kDuNE$#f1nR?Eg!-L;yve?UkuFm>%f~>F!Ilr&#kmrJi&J1Ts(Z z2N9&mFoQg4J@PFwy@=zY3#Lk0F#QF7fR|tu5lqezrhy?;9T7qYpaI@D*TU$7h%ovP z`k)^M;Q@@n1Wdw9AbA*Zz#d#71j0cjHyv9-NpcBg>JV~a6|94euoZSf6}$`euq0AK zF|ZucAqTXu1$6KZ)Ic2^g=RPd7oihAfg5le?!bK*0o^#lkMIJffc=JqY`_WJ!3%^C z0#b+q6(mD8tb}4Hg)OiXs-YGR!3k)Ci(rIn&<9_@y*DH}8b&e>|Ac=7EtU`$9Kj8| zKnNiqg(y%#GGxO_D27s~f&p{McK?L`ARxHp4d94SS*1JVQ*4Dlr{{RyYR+xB}hK2mLSz4`2)?U=m&e#fgan_Hm{w zGHs#c8W&0)pc5eYg9xOs1Y%%0q(cs9VGWc*8I+q3B&0oYLfQ{{I06Qh5Emt+lgQiP z0!#rrUPv}@5^55Jv@uagIyjmr^rKEBqwpKVEf-P>l)<~;u|h~ykdTCDm8|n8ZIVB& zg^lnw?1p{t9vp#YI13-al_b-x`cn_`TQC6k;UPSRN%$F9$^K*wPB1IkG$(-OB?nL* zybZgc8V=|X^eKTfk{U=8@H}-PHKds)%%vM?b7|C^dr@J!7i~y4)xD`P-J6b?^Lf;o zK96pha{>LDE+CH#0SPip;{J{SjX7K?mN;By#-SJ_a4SWz`i>1q!>X09WW;mm^qh7Vnp6;j}Xh`iy6EF!cfi#X-k{pSH z)?ULWe~l9@(m2ynjSKG51$XH}D>SZ@2c=M^nL*{6nY0fM!Xb?tK2SG0i}sSnoq9C0 z=%!{ieW~%J5sm3d2UA#1FhxcqEQ3Tyhc{srtcT689V%gej%ku<3#Pi)IhKzcyu}_K zQX0;Y(l|VSz0))}lJ4i4mUs@{uw1M$2DvTc@J11f=mj~EFMjX&7!}6+x9^932>QbR z^#jmvLf(j)X?!61t%j|$!)K%@ljO8F1$C58N^v~0Fz0NUC0Z+U-Y(;!<(c!3@M{p+ zn)8{F_Gle|M`KD`a#JxhqG!a;y69v#RNY|~Sc4s{$z+?`UFumZ4u!M6rKPN3mLFNt zcYHsbsmRHXICQ~9L2Mf17noy(IkuSNr{*YN*z^rwVUDAS_xK7Hn+Ev>hoZl~kb ziju?5zie?oB6X=28v|Md1yy`wj+I1V5GdVPx{ltC#SI;&-WpW;uP`pOoV)LF+Raqs zv-q1Uo?eVszhHJ{JjUZcuV22dC(7}iA78pwoNmx+6Eidk-PR4B*3AQ+@eYQY^VRo$ zXqajn8!9Wva9MNHTYh@S>KBI{idx!+zUMV_J-<+Y8LWCQCgJOX7RlFB+RusNYsU29uD-zYy8H*DKzd2U_7nIp#@^tgW8)7f3$WYx`?rEqnA zKGiC3da`3v#*UNcRu8WIYg6lo-}LksdEXtZOc=2a+NS&J_=Xhmqdm`dYxQa|!3gjrW5-yF8MaJoAKZ_1A$jBx{FEN6`M`lgcQ9@FmXW{g9OaZ+ztS~u<7%k}yTrQ^=i z%r%_-V=Ch_%?{>rJ=4|1bhR^GcbKj*rfbUJy{V07hoLwXuC5*zWf-L`%O$qqUMM=7zVSK9`ZMLRocg)=be;1J|0?fc+^0Jy&UU%pFt9V$ zYW8%yuTgTKX+T)j`z(fM7}#54!NxeLL0RKs!82vdHBy%vw6&>hW`X|Wx+I4F1L9I` A!vFvP delta 3299 zcmZwI3s6&68VB(21`v4@35cM)-){neB!KeRKtPbUkRUR=YYPR%(TYk6S^<@cge656 zUnnA5>}a|If={|_MOQ`ziWC%dMV9W`+N!9n>;9A7IZ2{o_}nxF-a!=K?S^uT5K25!PIjKf2a%_2O7m+%%Agz(4!IA95O;09a}LO8@g z5=bEj-iHlP4pp!l8sGpNgAOq4_tw3a0~9j6#Qekj7J(Pc%%m=U7+3Ym}(K4CnHg0=7nm~gBK+0X-DgINTRtl%@~hhZ7QKj9gK{sC77dGH+G zfR-qL41fccUzNXy^#`6LqYDHf7J3fb@;l)xs~4m&YkM#QH*=rlkx z9D$Q?8vX)(&<_J}3r61^hzURb%)R70D+VbVUm22Hb%$n2Hpv zq!}dt2CXOo>4OPafGq@rI4YP@fGt)n7DT?{AmT$}P!O$9*Mt-)7E+uT-*dH$d?`ij zOBs*@>!1`iLj`=Ip24NPVlK(y033yO_yW$s1^5cC!)>?=lkgaxz;pNwG@?~!q}u#Q zH`1}E?Ye+Ytbh=v46gSC(kMNp<*$c4(IU8oXjU>~%LU2sw^)P%eRj>FIJ z3MdA3s9Nblg|RNQ5$a=Ioau8Uqwoxt$GK1>6u}N)uX3Sn5E_qrl^}DYw0JklfP z%^-tn*ar$Y3@71>c-5u4Q5W({@C^*YcW@sb!;dfrZ$Uf3jf@ghbKGfhf;*)^32cJx zuv3OmljuPsNggx_vq_$`Cs{SYn$9O%)2KSPA!&*Y<)oQ(Is_m zPrszt6Fb$O%u`k4?5Qr*fg0hUy6;HGQXT0OOsM;+G3s~UiQc3-QSfS2m!YK9EXs!> zD1&mSgc{ffP0#`tU;^I2vNRTjq-jtl6{UE)dfC=A4~ zTd0R$mLA1R^r;Hkg!=e(=~FH8dQiY2i2?OVWQO#u#E6C@#xx0!;R!s4tRQ3h4XuWh zP1e#ygu0{_bWv(a z15zs*k*e;rH@RkblW!P;090)>B!UF8VI8c8El`=EnxxvisrFsYqrYX~End2mPs15} znt<7NJ5_^&X)sgui`T{*mdT?DWsp8&6oN-aFK7`t;dwh?lmqkMzBBqh=$rqq?~eXn zmIho(jPWFTf}M9y$cWC020s4f8u&;{my7Mw2Gl5$gC5af}_o(xg##F5(EgUmbUNX=u_A zyHy<@BHm-$YiiOsdk5m**{z5V*bmiFLkqe53YTYMkue#mLv@*xk-F5D87kHx6Qzz{ zmZ6QqiNZivw!Y~3iIPhFisIpjrzu(q+0x0l!qrFb9ZL`^Yr?i_*w{XqTOT`R_&Q>h z)T7z9)aBc#>K{DYALutlS`_!6E*MeTi_BTFZF6bI+qaDSo{@cLo0~u5b;NxQyYDfp zSJYu~WgX+pRHn`1_IJwTR`!P)@A~nTX+->P|5L?vb*4wn+^lxqHVdh#j^-ZpDB6_2 z!sFH4haH}tqHDIwliLelG#eGPw%>h#!5-}tA6i}?Nd%nxJf9c|8CrJ~rE0o@IEY(9$0ZI2Oc-~7a| z@Y2Pej^&9Xejo7STTbk`cXhD9c4%bh$|+s1tulpmabm;MtFJCzDA!!G-^PFFz#Yy{ zF=Ky9I^7>uCQUx%n0$V0xaxt?xT)o*4SD{nBD*%q4VRp~X0u1R{>Im?E1fux*I#W2 z{_BWDA${bf%-mbn-+9C<^zF^FlChHy2k#WkU4MOR{r>)g(@oPA!;3BU>^}ZU?908` z#@jR)A;XuS6X&`VaQy@VKYxK=U_LL0TaaDA_sI>&^$#fU&nXb_^8@k%1O?NP`(OJ_{x znX7DHpTs!MvxDhTFujME-g8XvFw;BD^uASEm$mB{U?>iSvs2)tltbIH7^X|^U%{1^ zRq*sz*ccF*sJ`lDV)>U9QQ8V?e5@v!N|x*@vt+)bVErD2a^mBt1(x&ezDx