Skip to content

Commit 1a16892

Browse files
Fix AdvOcr error handling
1 parent faa311d commit 1a16892

File tree

3 files changed

+157
-2
lines changed

3 files changed

+157
-2
lines changed

CloudinaryDotNet.Tests/AdminApi/GetResourceTest.cs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,42 @@ public class GetResourceTest
6666
}
6767
";
6868

69+
// OCR response with successful data array
70+
private const string SuccessfulOcrResponse = @"
71+
{
72+
""asset_id"": ""8abd06560fc75b3bbe80299b988035b0"",
73+
""public_id"": ""ocr_test_id"",
74+
""format"": ""jpg"",
75+
""info"": {
76+
""ocr"": {
77+
""adv_ocr"": {
78+
""status"": ""complete"",
79+
""data"": [
80+
{}
81+
]
82+
}
83+
}
84+
}
85+
}
86+
";
87+
88+
// OCR response with failed string error
89+
private const string FailedOcrResponse = @"
90+
{
91+
""asset_id"": ""8abd06560fc75b3bbe80299b988035b0"",
92+
""public_id"": ""ocr_failed_test_id"",
93+
""format"": ""jpg"",
94+
""info"": {
95+
""ocr"": {
96+
""adv_ocr"": {
97+
""status"": ""failed"",
98+
""data"": ""Failed to process request""
99+
}
100+
}
101+
}
102+
}
103+
";
104+
69105
[Test]
70106
public void TestGetResourceModerationResponse_WithLabels()
71107
{
@@ -115,5 +151,38 @@ public void TestGetResourceModerationResponse_WithDuplicates()
115151
Assert.AreEqual("duplicate_id", firstModeration.Response.ModerationLabels[0].PublicId);
116152
Assert.AreEqual(1.0f, firstModeration.Response.ModerationLabels[0].Confidence);
117153
}
154+
155+
[Test]
156+
public void TestGetResourceAdvOcr_WithSuccessfulData()
157+
{
158+
var localCloudinaryMock = new MockedCloudinary(SuccessfulOcrResponse);
159+
var result = localCloudinaryMock.GetResource("ocr_test_id");
160+
161+
Assert.NotNull(result);
162+
Assert.AreEqual("ocr_test_id", result.PublicId);
163+
Assert.NotNull(result.Info);
164+
Assert.NotNull(result.Info.Ocr);
165+
Assert.NotNull(result.Info.Ocr.AdvOcr);
166+
Assert.AreEqual("complete", result.Info.Ocr.AdvOcr.Status);
167+
Assert.NotNull(result.Info.Ocr.AdvOcr.Data);
168+
Assert.AreEqual(1, result.Info.Ocr.AdvOcr.Data.Count);
169+
Assert.IsNull(result.Info.Ocr.AdvOcr.ErrorMessage);
170+
}
171+
172+
[Test]
173+
public void TestGetResourceAdvOcr_WithFailedString()
174+
{
175+
var localCloudinaryMock = new MockedCloudinary(FailedOcrResponse);
176+
var result = localCloudinaryMock.GetResource("ocr_failed_test_id");
177+
178+
Assert.NotNull(result);
179+
Assert.AreEqual("ocr_failed_test_id", result.PublicId);
180+
Assert.NotNull(result.Info);
181+
Assert.NotNull(result.Info.Ocr);
182+
Assert.NotNull(result.Info.Ocr.AdvOcr);
183+
Assert.AreEqual("failed", result.Info.Ocr.AdvOcr.Status);
184+
Assert.IsNull(result.Info.Ocr.AdvOcr.Data);
185+
Assert.AreEqual("Failed to process request", result.Info.Ocr.AdvOcr.ErrorMessage);
186+
}
118187
}
119188
}

CloudinaryDotNet/Actions/AssetsManagement/NestedTypes/AdvOcr.cs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22
{
33
using System.Collections.Generic;
44
using System.Runtime.Serialization;
5+
using Newtonsoft.Json;
56

67
/// <summary>
78
/// Details of executing an ADV_OCR engine.
89
/// </summary>
910
[DataContract]
11+
[JsonConverter(typeof(AdvOcrDataConverter))]
1012
public class AdvOcr
1113
{
1214
/// <summary>
@@ -16,9 +18,16 @@ public class AdvOcr
1618
public string Status { get; set; }
1719

1820
/// <summary>
19-
/// Gets or sets data returned by OCR plugin.
21+
/// Gets or sets data returned by OCR plugin when successful.
22+
/// This will be null if the operation failed and ErrorMessage contains the error.
2023
/// </summary>
2124
[DataMember(Name = "data")]
2225
public List<AdvOcrData> Data { get; set; }
26+
27+
/// <summary>
28+
/// Gets or sets the error message when the OCR operation fails.
29+
/// This property captures the string value of 'data' field when status is "failed".
30+
/// </summary>
31+
public string ErrorMessage { get; set; }
2332
}
24-
}
33+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
namespace CloudinaryDotNet.Actions
2+
{
3+
using System;
4+
using System.Collections.Generic;
5+
using Newtonsoft.Json;
6+
using Newtonsoft.Json.Linq;
7+
8+
/// <summary>
9+
/// Custom JSON converter to handle ADV_OCR data that can be either an array of objects or an error string.
10+
/// </summary>
11+
public class AdvOcrDataConverter : JsonConverter
12+
{
13+
/// <summary>
14+
/// Gets a value indicating whether this <see cref="AdvOcrDataConverter"/> can write JSON.
15+
/// </summary>
16+
public override bool CanWrite => false;
17+
18+
/// <summary>
19+
/// Reads the JSON representation of the object.
20+
/// </summary>
21+
/// <param name="reader">The <see cref="JsonReader"/> to read from.</param>
22+
/// <param name="objectType">Type of the object.</param>
23+
/// <param name="existingValue">The existing value of object being read.</param>
24+
/// <param name="serializer">The calling serializer.</param>
25+
/// <returns>The object value.</returns>
26+
public override object ReadJson(
27+
JsonReader reader,
28+
Type objectType,
29+
object existingValue,
30+
JsonSerializer serializer)
31+
{
32+
var jObject = JObject.Load(reader);
33+
var advOcr = new AdvOcr();
34+
35+
// Handle status field
36+
if (jObject["status"] != null)
37+
{
38+
advOcr.Status = jObject["status"].Value<string>();
39+
}
40+
41+
// Handle data field - can be array or string
42+
if (jObject["data"] != null)
43+
{
44+
var dataToken = jObject["data"];
45+
46+
if (dataToken.Type == JTokenType.Array)
47+
{
48+
advOcr.Data = dataToken.ToObject<List<AdvOcrData>>(serializer);
49+
}
50+
else if (dataToken.Type == JTokenType.String)
51+
{
52+
advOcr.ErrorMessage = dataToken.Value<string>();
53+
}
54+
}
55+
56+
return advOcr;
57+
}
58+
59+
/// <summary>
60+
/// Determines whether this instance can convert the specified object type.
61+
/// </summary>
62+
/// <param name="objectType">Type of the object.</param>
63+
/// <returns>True if this instance can convert the specified object type; otherwise, false.</returns>
64+
public override bool CanConvert(Type objectType) => objectType == typeof(AdvOcr);
65+
66+
/// <summary>
67+
/// Writes the JSON representation of the object.
68+
/// </summary>
69+
/// <param name="writer">The <see cref="JsonWriter"/> to write to.</param>
70+
/// <param name="existingValue">The value.</param>
71+
/// <param name="serializer">The calling serializer.</param>
72+
public override void WriteJson(JsonWriter writer, object existingValue, JsonSerializer serializer)
73+
{
74+
throw new NotImplementedException("Unnecessary because of using just for Deserialization");
75+
}
76+
}
77+
}

0 commit comments

Comments
 (0)