Tôi đã hiểu. Và vâng, đó là một lỗi.
Vấn đề là có hai cấp độ string.Format
đang diễn ra ở đây.
Các đầu tiên mức độ định dạng là một cái gì đó như:
string template = string.Format("Expected: {0}; Actual: {1}; Message: {2}",
expected, actual, message);
Sau đó, chúng tôi sử dụng string.Format
với các thông số bạn đã cung cấp:
string finalMessage = string.Format(template, parameters);
(Rõ ràng là có các nền văn hóa đang được cung cấp, và một số loại vệ sinh ... nhưng không đủ.)
Điều đó có vẻ ổn - trừ khi bản thân các giá trị kỳ vọng và thực tế kết thúc bằng dấu ngoặc nhọn, sau khi được chuyển đổi thành một chuỗi - mà chúng thực hiện Size
. Ví dụ: kích thước đầu tiên của bạn sẽ được chuyển đổi thành:
{Width=0, Height=0}
Vì vậy, mức định dạng thứ hai là như sau:
string.Format("Expected: {Width=0, Height=0}; Actual: {Width=1, Height=1 }; " +
"Message = Failed expected {0} actually is {1}", struct1, struct2);
... và đó là những gì đang thất bại. Ôi chao.
Thật vậy, chúng tôi có thể chứng minh điều này thực sự dễ dàng bằng cách đánh lừa định dạng để sử dụng các tham số của chúng tôi cho các phần mong đợi và thực tế:
var x = "{0}";
var y = "{1}";
Assert.AreEqual<object>(x, y, "What a surprise!", "foo", "bar");
Kết quả là:
Assert.AreEqual failed. Expected:<foo>. Actual:<bar>. What a surprise!
Rõ ràng là bị hỏng, như chúng tôi không mong đợi foo
cũng như giá trị thực tế bar
!
Về cơ bản, điều này giống như một cuộc tấn công SQL injection, nhưng trong bối cảnh ít đáng sợ hơn string.Format
.
Để giải quyết vấn đề, bạn có thể sử dụng string.Format
như StriplingWarrior đề xuất. Điều đó tránh được mức định dạng thứ hai được thực hiện dựa trên kết quả của việc định dạng với các giá trị thực tế / mong đợi.
Assert.AreEqual(struct1, struct2, string.Format("Failed expected {0} actually is {1}
, struct1.ToString (), struct2.ToString ()))) chưa?