mirror of
https://github.com/dlang/dmd.git
synced 2025-04-26 13:10:12 +03:00
231 lines
5.5 KiB
D
231 lines
5.5 KiB
D
// See ../../../README.md for information about DMD unit tests.
|
|
|
|
/// Test cases for diagnostic messages on Objective-C protocols
|
|
module objc.protocols.optional_methods;
|
|
|
|
version (D_ObjectiveC):
|
|
|
|
import dmd.location;
|
|
|
|
import support : afterEach, beforeEach, compiles, stripDelimited, Diagnostic;
|
|
|
|
@beforeEach initializeFrontend()
|
|
{
|
|
import dmd.frontend : initDMD;
|
|
initDMD();
|
|
}
|
|
|
|
@afterEach deinitializeFrontend()
|
|
{
|
|
import dmd.frontend : deinitializeDMD;
|
|
deinitializeDMD();
|
|
}
|
|
|
|
@("when an optional method is not implemented")
|
|
{
|
|
@("when the method is an instance method")
|
|
@("it should successfully compile")
|
|
unittest
|
|
{
|
|
enum code = q{
|
|
import core.attribute : optional;
|
|
|
|
extern (Objective-C)
|
|
interface Foo
|
|
{
|
|
@optional void foo();
|
|
}
|
|
|
|
extern (Objective-C)
|
|
class Bar : Foo { }
|
|
}.stripDelimited;
|
|
|
|
const result = compiles(code);
|
|
assert(result, '\n' ~ result.toString);
|
|
}
|
|
|
|
@("when the method is a static method")
|
|
@("it should successfully compile")
|
|
unittest
|
|
{
|
|
enum filename = "test.d";
|
|
|
|
enum code = q{
|
|
import core.attribute : optional;
|
|
|
|
extern (Objective-C)
|
|
interface Foo
|
|
{
|
|
@optional static void foo();
|
|
}
|
|
|
|
extern (Objective-C)
|
|
class Bar : Foo { }
|
|
}.stripDelimited;
|
|
|
|
const result = compiles(code);
|
|
assert(result, '\n' ~ result.toString);
|
|
}
|
|
|
|
@("when the `@optional:` syntax is used")
|
|
@("it should successfully compile")
|
|
unittest
|
|
{
|
|
enum code = q{
|
|
import core.attribute : optional;
|
|
|
|
extern (Objective-C)
|
|
interface Foo
|
|
{
|
|
@optional:
|
|
void foo();
|
|
}
|
|
|
|
extern (Objective-C)
|
|
class Bar : Foo { }
|
|
}.stripDelimited;
|
|
|
|
const result = compiles(code);
|
|
assert(result, '\n' ~ result.toString);
|
|
}
|
|
|
|
@("when the `@optional {}` syntax is used")
|
|
@("it should successfully compile")
|
|
unittest
|
|
{
|
|
enum code = q{
|
|
import core.attribute : optional;
|
|
|
|
extern (Objective-C)
|
|
interface Foo
|
|
{
|
|
@optional
|
|
{
|
|
void foo();
|
|
}
|
|
}
|
|
|
|
extern (Objective-C)
|
|
class Bar : Foo { }
|
|
}.stripDelimited;
|
|
|
|
const result = compiles(code);
|
|
assert(result, '\n' ~ result.toString);
|
|
}
|
|
}
|
|
|
|
@("when attaching `@optional` to method that doesn't have Objective-C linkage")
|
|
@("it should report an error")
|
|
unittest
|
|
{
|
|
enum filename = "test.d";
|
|
|
|
enum code = q{
|
|
import core.attribute : optional;
|
|
|
|
interface Foo
|
|
{
|
|
@optional void foo();
|
|
}
|
|
}.stripDelimited;
|
|
|
|
SourceLoc loc = SourceLoc(filename, 5, 20);
|
|
enum message = "Error: function test.Foo.foo only functions with Objective-C linkage can be declared as optional";
|
|
enum supplemental = "function is declared with D linkage";
|
|
auto expected = [Diagnostic(loc, message), Diagnostic(loc, supplemental)];
|
|
|
|
const diagnostics = compiles(code, filename);
|
|
assert(diagnostics == expected, "\n" ~ diagnostics.toString);
|
|
}
|
|
|
|
@("when attaching `@optional` more than once to the same method")
|
|
@("it should report an error")
|
|
unittest
|
|
{
|
|
enum filename = "test.d";
|
|
|
|
enum code = q{
|
|
import core.attribute : optional;
|
|
|
|
extern (Objective-C)
|
|
interface Foo
|
|
{
|
|
@optional @optional void foo();
|
|
}
|
|
}.stripDelimited;
|
|
|
|
SourceLoc loc = SourceLoc(filename, 6, 30);
|
|
enum message = "Error: function test.Foo.foo can only declare a function as optional once";
|
|
auto expected = Diagnostic(loc, message);
|
|
|
|
const diagnostics = compiles(code, filename);
|
|
assert(diagnostics == [expected], "\n" ~ diagnostics.toString);
|
|
}
|
|
|
|
@("when attaching `@optional` to a template method")
|
|
@("it should report an error")
|
|
unittest
|
|
{
|
|
enum filename = "test.d";
|
|
|
|
enum code = q{
|
|
import core.attribute : optional;
|
|
|
|
extern (Objective-C)
|
|
interface Foo
|
|
{
|
|
@optional void foo()();
|
|
}
|
|
|
|
void main()
|
|
{
|
|
Foo f;
|
|
f.foo();
|
|
}
|
|
}.stripDelimited;
|
|
|
|
auto expected = [
|
|
Diagnostic(
|
|
SourceLoc(filename, 6, 20),
|
|
"Error: function test.Foo.foo!().foo template cannot be optional"
|
|
),
|
|
Diagnostic(
|
|
SourceLoc(filename, 12, 10),
|
|
"Error: template instance test.Foo.foo!() error instantiating"
|
|
)
|
|
];
|
|
|
|
const diagnostics = compiles(code, filename);
|
|
assert(diagnostics == expected, "\n" ~ diagnostics.toString);
|
|
}
|
|
|
|
@("when attaching `@optional` to a method _not_ declared in an interface")
|
|
@("it should report an error")
|
|
unittest
|
|
{
|
|
enum filename = "test.d";
|
|
|
|
enum code = q{
|
|
import core.attribute : optional;
|
|
|
|
extern (Objective-C)
|
|
class Foo
|
|
{
|
|
@optional void foo() {};
|
|
}
|
|
|
|
void main()
|
|
{
|
|
Foo f;
|
|
f.foo();
|
|
}
|
|
}.stripDelimited;
|
|
|
|
SourceLoc loc = SourceLoc(filename, 6, 20);
|
|
enum message = "Error: function test.Foo.foo only functions declared inside interfaces can be optional";
|
|
enum supplemental = "function is declared inside class";
|
|
auto expected = [Diagnostic(loc, message), Diagnostic(loc, supplemental)];
|
|
|
|
const diagnostics = compiles(code, filename);
|
|
assert(diagnostics == expected, "\n" ~ diagnostics.toString);
|
|
}
|