Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Test Generation) Fix #3726 bug leading to stack overflow during test generation #3727

Merged
merged 10 commits into from
May 25, 2023
Next Next commit
Fix self-referencing issue
  • Loading branch information
Dargones committed Mar 10, 2023
commit b15343cbb4521a5a47e909b8f47410cf95856538
79 changes: 79 additions & 0 deletions Source/DafnyTestGeneration.Test/Various.cs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,85 @@ class List {
m.ValueCreation.Count == 2)));
}

/// <summary>
/// This test addresses the situation in which there is a class-type object
/// that does not matter for the construction of a counterexample.
/// Furthermore, this class-type object is self-referential,
/// with a field of the same type. Test generation must not enter infinite
/// loop and must figure out that it needs to set the field of the object
/// to itself.
/// </summary>
[TestMethod]
public async Task TestByDefaultConstructionOfSelfReferentialValue() {
var source = @"
module M {

class LoopingList {

var next:LoopingList;
var value:int;

constructor() {
value := 0;
next := this;
}

method getValue() returns (value:int) {
return this.value;
}
}
}
".TrimStart();
var options = Setup.GetDafnyOptions();
var program = Utils.Parse(options, source);
options.TestGenOptions.TargetMethod =
"M.LoopingList.getValue";
var methods = await Main.GetTestMethodsForProgram(program).ToListAsync();
Assert.IsTrue(methods.Count == 1);
}

/// <summary>
/// This test models the situation in which there is a class-type object
/// that does not matter for the construction of a counterexample.
/// Furthermore, this class-type object is potentially self-referential,
/// with a field of the same (nullable) type.
/// Test generation must not enter infinite loop and must figure out
/// that it needs to set the field to null (with self-referencing being
/// prohibited by a precondition).
/// </summary>
[TestMethod]
public async Task TestByDefaultConstructionOfPotentiallySelfReferentialValue() {
var source = @"
module M {

class List {

var next:List?;
var value:int;

predicate isEndOfList() reads this {
next == null
}

method getValue()
returns (value:int)
requires isEndOfList()
{
return this.value;
}
}
}
".TrimStart();
var options = Setup.GetDafnyOptions();
var program = Utils.Parse(options, source);
options.TestGenOptions.TargetMethod =
"M.List.getValue";
var methods = await Main.GetTestMethodsForProgram(program).ToListAsync();
Assert.IsTrue(methods.Count == 1);
Assert.IsTrue(methods[0].ValueCreation.Count == 1);
Assert.IsTrue(methods[0].Assignments.Exists(assignment => assignment.fieldName == "next" && assignment.childId == "null"));
}

[TestMethod]
public async Task RecursivelyExtractDatatypeFields() {
var source = @"
Expand Down
4 changes: 2 additions & 2 deletions Source/DafnyTestGeneration/TestMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -499,8 +499,8 @@ public class TestMethod {
variable.Children[field.name].Count == 1) {
return ExtractVariable(variable.Children[field.name].First(), null);
}
if (ValueCreation.Any(obj => obj.type == field.type)) {
return ValueCreation.First(obj => obj.type == field.type).id;
if (ValueCreation.Any(obj => obj.type.ToString() == field.type.ToString())) {
return ValueCreation.First(obj => obj.type.ToString() == field.type.ToString()).id;
}
return GetDefaultValue(field.type, field.type);
}
Expand Down
4 changes: 3 additions & 1 deletion Source/DafnyTestGeneration/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@ public static class Utils {
return DafnyModelTypeUtils
.ReplaceType(type, _ => true, typ => new UserDefinedType(
new Token(),
typ?.ResolvedClass?.FullName ?? typ.Name,
typ?.ResolvedClass?.FullName == null ?
typ.Name :
typ.ResolvedClass.FullName + (typ.Name.Last() == '?' ? "?" : ""),
typ.TypeArgs));
}

Expand Down