Skip to content

Commit ea3ff65

Browse files
Improve error reporting from serialized-file command
Use detection helpers to print more informative messages when command is run against the wrong file type.
1 parent 84c3d2a commit ea3ff65

2 files changed

Lines changed: 119 additions & 18 deletions

File tree

UnityDataTool.Tests/SerializedFileCommandTests.cs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,73 @@ public async Task ErrorHandling_NonExistentFile_ReturnsError()
495495
Assert.AreNotEqual(0, result, "Should return error code for non-existent file");
496496
}
497497

498+
[Test]
499+
public async Task ErrorHandling_ArchiveFile_ReturnsHelpfulError()
500+
{
501+
// Use an AssetBundle from test data
502+
var assetBundlesDir = Path.Combine(TestContext.CurrentContext.TestDirectory, "Data", "AssetBundles", "2022.1.20f1");
503+
504+
// Skip if the test data doesn't exist (CI environments might not have all test data)
505+
if (!Directory.Exists(assetBundlesDir))
506+
{
507+
Assert.Ignore("AssetBundle test data not found");
508+
return;
509+
}
510+
511+
var archiveFiles = Directory.GetFiles(assetBundlesDir, "*", SearchOption.TopDirectoryOnly);
512+
if (archiveFiles.Length == 0)
513+
{
514+
Assert.Ignore("No AssetBundle test files found");
515+
return;
516+
}
517+
518+
var archivePath = archiveFiles[0]; // Use first archive file found
519+
520+
using var sw = new StringWriter();
521+
var currentErr = Console.Error;
522+
try
523+
{
524+
Console.SetError(sw);
525+
526+
var result = await Program.Main(new string[] { "serialized-file", "objectlist", archivePath });
527+
528+
Assert.AreNotEqual(0, result, "Should return error code for archive file");
529+
530+
var errorOutput = sw.ToString();
531+
StringAssert.Contains("Unity Archive", errorOutput, "Error message should mention Unity Archive");
532+
StringAssert.Contains("archive extract", errorOutput, "Error message should suggest using archive extract command");
533+
}
534+
finally
535+
{
536+
Console.SetError(currentErr);
537+
}
538+
}
539+
540+
[Test]
541+
public async Task ErrorHandling_InvalidFile_ShowsHelpfulMessage()
542+
{
543+
var path = Path.Combine(m_TestDataFolder, "README.md");
544+
545+
using var sw = new StringWriter();
546+
var currentErr = Console.Error;
547+
try
548+
{
549+
Console.SetError(sw);
550+
551+
var result = await Program.Main(new string[] { "serialized-file", "objectlist", path });
552+
553+
Assert.AreNotEqual(0, result, "Should return error code for invalid file");
554+
555+
var errorOutput = sw.ToString();
556+
StringAssert.Contains("not appear to be a valid Unity SerializedFile", errorOutput,
557+
"Error message should explain that the file is not a valid SerializedFile");
558+
}
559+
finally
560+
{
561+
Console.SetError(currentErr);
562+
}
563+
}
564+
498565
#endregion
499566
}
500567

UnityDataTool/SerializedFileCommands.cs

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.IO;
33
using System.Text.Json;
4+
using UnityDataTools.Analyzer.Util;
45
using UnityDataTools.FileSystem;
56

67
namespace UnityDataTools.UnityDataTool;
@@ -9,44 +10,77 @@ public static class SerializedFileCommands
910
{
1011
public static int HandleExternalRefs(FileInfo filename, OutputFormat format)
1112
{
12-
try
13+
return OpenSerializedFileAndProcess(filename, sf =>
1314
{
14-
using var sf = UnityFileSystem.OpenSerializedFile(filename.FullName);
15-
1615
if (format == OutputFormat.Json)
1716
OutputExternalRefsJson(sf);
1817
else
1918
OutputExternalRefsText(sf);
20-
}
21-
catch (Exception err) when (err is NotSupportedException || err is FileFormatException)
22-
{
23-
Console.Error.WriteLine($"Error opening serialized file: {filename.FullName}");
24-
Console.Error.WriteLine(err.Message);
25-
return 1;
26-
}
27-
28-
return 0;
19+
});
2920
}
3021

3122
public static int HandleObjectList(FileInfo filename, OutputFormat format)
3223
{
33-
try
24+
return OpenSerializedFileAndProcess(filename, sf =>
3425
{
35-
using var sf = UnityFileSystem.OpenSerializedFile(filename.FullName);
36-
3726
if (format == OutputFormat.Json)
3827
OutputObjectListJson(sf);
3928
else
4029
OutputObjectListText(sf);
30+
});
31+
}
32+
33+
/// <summary>
34+
/// Opens a SerializedFile and processes it with the given action.
35+
/// Provides helpful error messages if the file is not a valid SerializedFile.
36+
/// </summary>
37+
private static int OpenSerializedFileAndProcess(FileInfo filename, Action<SerializedFile> processAction)
38+
{
39+
string filePath = filename.FullName;
40+
41+
// Check if file exists (should already be validated by System.CommandLine, but be defensive)
42+
if (!File.Exists(filePath))
43+
{
44+
Console.Error.WriteLine($"Error: File not found: {filePath}");
45+
return 1;
46+
}
47+
48+
// Common misuse would be to try to use the command with an AssetBundle
49+
// so give an instructive error message for that case.
50+
if (ArchiveDetector.IsUnityArchive(filePath))
51+
{
52+
Console.Error.WriteLine($"Error: The file is an AssetBundle or other Unity Archive, not a SerializedFile.");
53+
Console.Error.WriteLine($"File: {filePath}");
54+
Console.Error.WriteLine();
55+
Console.Error.WriteLine("Unity Archives can contain SerializedFiles inside them.");
56+
Console.Error.WriteLine("To access the SerializedFiles, first extract the archive using:");
57+
Console.Error.WriteLine($" UnityDataTool archive extract \"{filePath}\" -o <output-directory>");
58+
Console.Error.WriteLine();
59+
Console.Error.WriteLine("Then you can run serialized-file commands on the extracted files.");
60+
return 1;
61+
}
62+
63+
bool isSerializedFile = SerializedFileDetector.TryDetectSerializedFile(filePath, out var _);
64+
if (!isSerializedFile)
65+
{
66+
Console.Error.WriteLine($"Error: The file does not appear to be a valid Unity SerializedFile.");
67+
Console.Error.WriteLine($"File: {filePath}");
68+
return 1;
69+
}
70+
71+
// Try to open and process the SerializedFile
72+
try
73+
{
74+
using var sf = UnityFileSystem.OpenSerializedFile(filePath);
75+
processAction(sf);
76+
return 0;
4177
}
4278
catch (Exception err) when (err is NotSupportedException || err is FileFormatException)
4379
{
44-
Console.Error.WriteLine($"Error opening serialized file: {filename.FullName}");
80+
Console.Error.WriteLine($"Error opening SerializedFile: {filePath}");
4581
Console.Error.WriteLine(err.Message);
4682
return 1;
4783
}
48-
49-
return 0;
5084
}
5185

5286
private static void OutputExternalRefsText(SerializedFile sf)

0 commit comments

Comments
 (0)