using Xunit; using Moq; using FluentAssertions; using Microsoft.Extensions.Logging; using Haoliang.Core.Services; using Haoliang.Models.DataCollection; namespace Haoliang.Tests; public class DataParserServiceTests { private readonly DataParserService _parserService; private readonly Mock> _loggerMock; public DataParserServiceTests() { _loggerMock = new Mock>(); _parserService = new DataParserService(_loggerMock.Object); } [Fact] public async Task ParseRawDataAsync_ValidJson_ReturnsDeviceData() { var json = @"{ ""device"": ""CNC001"", ""desc"": ""加工中心1"", ""tags"": [ {""id"": ""Tag5"", ""desc"": ""程序名"", ""quality"": ""good"", ""value"": ""PROGRAM001"", ""time"": ""2024-01-01T10:00:00""}, {""id"": ""Tag8"", ""desc"": ""加工数量"", ""quality"": ""good"", ""value"": ""100"", ""time"": ""2024-01-01T10:00:00""} ] }"; var result = await _parserService.ParseRawDataAsync(json, 1); result.Should().NotBeNull(); result.DeviceName.Should().Be("CNC001"); result.Tags.Should().NotBeNull(); result.Tags.Should().ContainKey("Tag5"); } [Fact] public async Task ParseRawDataAsync_InvalidJson_ThrowsException() { var json = "invalid json"; var action = async () => await _parserService.ParseRawDataAsync(json, 1); await action.Should().ThrowAsync(); } [Fact] public async Task ParseRawDataAsync_ValidJson_ContainsTags() { var json = @"{ ""device"": ""CNC001"", ""desc"": ""加工中心1"", ""tags"": [ {""id"": ""Tag5"", ""desc"": ""程序名"", ""quality"": ""good"", ""value"": ""TEST_PROGRAM"", ""time"": ""2024-01-01T10:00:00""} ] }"; var result = await _parserService.ParseRawDataAsync(json, 1); result.Should().NotBeNull(); result.Tags.Should().ContainKey("Tag5"); result.Tags!["Tag5"].Value.Should().Be("TEST_PROGRAM"); } [Fact] public async Task ParseRawDataAsync_ExtractsTag8Value() { var json = @"{ ""device"": ""CNC001"", ""desc"": ""加工中心1"", ""tags"": [ {""id"": ""Tag8"", ""desc"": ""加工数量"", ""quality"": ""good"", ""value"": ""150"", ""time"": ""2024-01-01T10:00:00""} ] }"; var result = await _parserService.ParseRawDataAsync(json, 1); result.Should().NotBeNull(); result.Tags.Should().ContainKey("Tag8"); } [Fact] public async Task ParseRawDataAsync_RemovesDecimalSuffix() { var json = @"{ ""device"": ""CNC001"", ""desc"": ""加工中心1"", ""tags"": [ {""id"": ""Tag8"", ""desc"": ""加工数量"", ""quality"": ""good"", ""value"": ""150.00000"", ""time"": ""2024-01-01T10:00:00""} ] }"; var result = await _parserService.ParseRawDataAsync(json, 1); result.Should().NotBeNull(); result.Tags.Should().ContainKey("Tag8"); } [Fact] public async Task ParseRawDataAsync_ExtractsIoStatus() { var json = @"{ ""device"": ""CNC001"", ""desc"": ""加工中心1"", ""tags"": [ {""id"": ""_io_status"", ""desc"": ""运行状态"", ""quality"": ""good"", ""value"": ""RUN"", ""time"": ""2024-01-01T10:00:00""} ] }"; var result = await _parserService.ParseRawDataAsync(json, 1); result.Should().NotBeNull(); result.Tags.Should().ContainKey("_io_status"); result.Tags!["_io_status"].Value.Should().Be("RUN"); } [Fact] public void ValidateDataFormat_ValidJson_ReturnsTrue() { var json = @"{""device"": ""CNC001"", ""tags"": []}"; var result = _parserService.ValidateDataFormat(json); result.Should().BeTrue(); } [Fact] public void ValidateDataFormat_InvalidJson_ReturnsFalse() { var json = "not valid json"; var result = _parserService.ValidateDataFormat(json); result.Should().BeFalse(); } [Fact] public async Task ParseMultiDeviceDataAsync_MultipleDevices_ReturnsAll() { var json = @"[ { ""device"": ""CNC001"", ""desc"": ""加工中心1"", ""tags"": [] }, { ""device"": ""CNC002"", ""desc"": ""加工中心2"", ""tags"": [] } ]"; var result = await _parserService.ParseMultiDeviceDataAsync(json, 1); result.Should().HaveCount(2); } }