借助网络配置,控制Modbus工具的日志显示,避免卡死界面
智能大石头 authored at 2021-12-11 22:09:19
9.17 KiB
XCoder
using System.Security.Cryptography;
using System.Text;
using Xunit.Abstractions;

namespace CrazyCoder.E2E;

/// <summary>纯本地工具功能断言:驱动真实 UI 操作并校验结果</summary>
[Collection("CrazyCoder")]
public class LocalToolTests
{
    readonly CrazyCoderSession _s;
    readonly ITestOutputHelper _log;

    public LocalToolTests(CrazyCoderSession session, ITestOutputHelper log)
    {
        _s = session;
        _log = log;
    }

    /// <summary>打开工具并返回子窗体</summary>
    FlaUI.Core.AutomationElements.AutomationElement Open(String category, String name)
    {
        _s.Start();
        var child = _s.OpenTool(new ToolDef(category, name));
        Assert.NotNull(child);
        Thread.Sleep(800);
        return child!;
    }

    /// <summary>取首行(RichTextBox 换行可能是 \r 或 \n)</summary>
    static String? FirstLine(String? text)
    {
        if (text == null) return null;
        return text.Split(['\r', '\n']).FirstOrDefault(x => !String.IsNullOrWhiteSpace(x))?.Trim();
    }

    void Shot(FlaUI.Core.AutomationElements.AutomationElement? child, String name)
    {
        if (child == null) return;
        try { _s.Capture(child, name); } catch { }
    }

    [Fact]
    public void 加密解密工具_MD5计算正确()
    {
        var child = Open("安全工具", "加密解密");
        var ops = new UiOps(_s);
        try
        {
            ops.SelectRadio(child, "rbString");          // 原文=字符串
            ops.SetCheck(child, "cbString", false);      // 结果只要 HEX
            ops.SetCheck(child, "cbBase64", false);
            ops.SetCheck(child, "cbHex", true);
            ops.SetText(child, "rtSource", "123456");
            Thread.Sleep(200);
            ops.Click(child, "btnMD5");                  // MD5_32
            Thread.Sleep(600);

            var result = ops.Read(child, "rtResult");
            var first = FirstLine(result);
            var expected = Convert.ToHexString(MD5.HashData(Encoding.UTF8.GetBytes("123456")));
            Assert.Equal(expected, first);
            _log.WriteLine($"MD5(123456)={first}");
        }
        catch
        {
            Shot(child, "失败-加密解密-MD5");
            throw;
        }
        finally { _s.CloseAllChildren(); }
    }

    [Fact]
    public void 对称加密_AES加解密往返一致()
    {
        var child = Open("安全工具", "对称加密");
        var ops = new UiOps(_s);
        try
        {
            const String plain = "Hello XCoder 2026!";
            const String pass = "NewLife@2026";

            // 输入=字符串、密码=字符串,结果=Base64
            ops.SelectRadio(child, "rbString");
            ops.SelectRadio(child, "rbString2");
            ops.SetCheck(child, "cbString", false);
            ops.SetCheck(child, "cbHex", false);
            ops.SetCheck(child, "cbBase64", true);
            ops.SetText(child, "rtSource", plain);
            ops.SetText(child, "rtPass", pass);
            Thread.Sleep(200);

            // AES 加密
            ops.Click(child, "btnAES");
            Thread.Sleep(600);
            var encB64 = FirstLine(ops.Read(child, "rtResult"));
            Assert.False(String.IsNullOrEmpty(encB64), "AES 加密结果为空");
            _log.WriteLine($"AES 加密密文(Base64)={encB64}");

            // 回填密文并以 Base64 解析原文格式,再解密
            ops.SetText(child, "rtSource", encB64!);
            Thread.Sleep(200);
            ops.SelectRadio(child, "rbBase64");
            Thread.Sleep(200);
            ops.Click(child, "btnAES2");                 // AES 解密
            Thread.Sleep(600);
            var decB64 = FirstLine(ops.Read(child, "rtResult"));
            var expected = Convert.ToBase64String(Encoding.UTF8.GetBytes(plain));
            Assert.Equal(expected, decB64);
            _log.WriteLine($"AES 解密明文(Base64)={decB64}");
        }
        catch
        {
            Shot(child, "失败-对称加密-AES");
            throw;
        }
        finally { _s.CloseAllChildren(); }
    }

    [Fact]
    public void 正则表达式工具_匹配计数正确()
    {
        var child = Open("工具(T)", "正则表达式工具");
        var ops = new UiOps(_s);
        try
        {
            ops.SelectRadio(child, "radioButton1");      // 切到「匹配」模式
            ops.SetText(child, "txtPattern", @"\d+");
            ops.SetText(child, "txtContent", "ab12cd345ef678");
            Thread.Sleep(300);
            ops.Click(child, "button2");                 // 正则匹配
            Thread.Sleep(1200);

            var content = _s.GetTexts(child);
            _log.WriteLine("匹配后状态/内容片段: " + content[..Math.Min(200, content.Length)]);
            Assert.Contains("成功匹配 3 项", content);
        }
        catch
        {
            Shot(child, "失败-正则表达式-匹配");
            throw;
        }
        finally { _s.CloseAllChildren(); }
    }

    [Fact]
    public void GPS辅助_HEX坐标转浮点()
    {
        var child = Open("地理信息", "GPS辅助");
        var ops = new UiOps(_s);
        try
        {
            var lat = 39.9042f;
            var lng = 116.4074f;
            var latHex = Convert.ToHexString(BitConverter.GetBytes(lat));
            var lngHex = Convert.ToHexString(BitConverter.GetBytes(lng));

            ops.SetText(child, "txt_16_lat", latHex);
            ops.SetText(child, "txt_16_long", lngHex);
            Thread.Sleep(200);
            ops.Click(child, "btn_latlong");
            Thread.Sleep(500);

            var actual = ops.Read(child, "txt_latlong");
            var expected = $"{lat},{lng}";
            Assert.Equal(expected, actual);
            _log.WriteLine($"GPS 转换: {actual}");
        }
        catch
        {
            Shot(child, "失败-GPS-Hex转换");
            throw;
        }
        finally { _s.CloseAllChildren(); }
    }

    [Fact]
    public void 加密解密工具_Base64编解码往返一致()
    {
        var child = Open("安全工具", "加密解密");
        var ops = new UiOps(_s);
        try
        {
            const String plain = "Hello XCoder 2026!";
            var expectedB64 = Convert.ToBase64String(Encoding.UTF8.GetBytes(plain));

            // 编码:原文=字符串 → Base64编码
            ops.SelectRadio(child, "rbString");
            ops.SetText(child, "rtSource", plain);
            Thread.Sleep(200);
            ops.Click(child, "btnB64");
            Thread.Sleep(400);
            var encB64 = FirstLine(ops.Read(child, "rtResult"));
            Assert.Equal(expectedB64, encB64);
            _log.WriteLine($"Base64 编码: {encB64}");

            // 解码:结果只要字符串
            ops.SetText(child, "rtSource", expectedB64);
            ops.SetCheck(child, "cbString", true);
            ops.SetCheck(child, "cbHex", false);
            ops.SetCheck(child, "cbBase64", false);
            Thread.Sleep(200);
            ops.Click(child, "btnB642");
            Thread.Sleep(400);
            var dec = FirstLine(ops.Read(child, "rtResult"));
            Assert.Equal(plain, dec);
            _log.WriteLine($"Base64 解码: {dec}");
        }
        catch
        {
            Shot(child, "失败-加密解密-Base64");
            throw;
        }
        finally { _s.CloseAllChildren(); }
    }

    [Fact]
    public void 加密解密工具_MD5_16计算正确()
    {
        var child = Open("安全工具", "加密解密");
        var ops = new UiOps(_s);
        try
        {
            ops.SelectRadio(child, "rbString");
            ops.SetCheck(child, "cbString", false);
            ops.SetCheck(child, "cbBase64", false);
            ops.SetCheck(child, "cbHex", true);
            ops.SetText(child, "rtSource", "123456");
            Thread.Sleep(200);
            ops.Click(child, "btnMD52");                 // MD5_16
            Thread.Sleep(400);

            var result = ops.Read(child, "rtResult");
            var first = FirstLine(result);
            var full = Convert.ToHexString(MD5.HashData(Encoding.UTF8.GetBytes("123456")));
            Assert.Equal(full[..16], first);
            _log.WriteLine($"MD5_16(123456)={first}");
        }
        catch
        {
            Shot(child, "失败-加密解密-MD5_16");
            throw;
        }
        finally { _s.CloseAllChildren(); }
    }

    [Fact]
    public void 正则表达式工具_替换功能正确()
    {
        var child = Open("工具(T)", "正则表达式工具");
        var ops = new UiOps(_s);
        try
        {
            ops.SelectRadio(child, "radioButton2");      // 切到「替换」模式
            ops.SetText(child, "txtPattern", @"\d+");
            ops.SetText(child, "txtContent", "a1b22c333");
            ops.SetText(child, "rtReplace", "X");
            Thread.Sleep(300);
            ops.Click(child, "button2");                 // 正则替换
            Thread.Sleep(1200);

            var content = ops.Read(child, "txtContent");
            _log.WriteLine($"替换结果: {content}");
            Assert.Equal("aXbXcX", content?.Trim());
        }
        catch
        {
            Shot(child, "失败-正则表达式-替换");
            throw;
        }
        finally { _s.CloseAllChildren(); }
    }
}