blob: 08ac64adb818e2c9955c988673d47c9e116e97f4 [file] [log] [blame]
#!/usr/bin/env python3
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS-IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from nose2.tools import params
from fruit_test_common import *
COMMON_DEFINITIONS = '''
#include <fruit/fruit.h>
#include <vector>
#include "test_macros.h"
struct Annotation1 {};
struct Annotation2 {};
'''
@params(
('Scaler',
'ScalerImpl',
'std::function<std::unique_ptr<Scaler>(double)>'),
('fruit::Annotated<Annotation1, Scaler>',
'fruit::Annotated<Annotation2, ScalerImpl>',
'fruit::Annotated<Annotation1, std::function<std::unique_ptr<Scaler>(double)>>'))
def test_success(ScalerAnnot, ScalerImplAnnot, ScalerFactoryAnnot):
expect_success(
COMMON_DEFINITIONS + '''
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
ScalerImpl(double factor)
: factor(factor) {
}
double scale(double x) override {
return x * factor;
}
};
using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
fruit::Component<ScalerFactoryAnnot> getScalerComponent() {
return fruit::createComponent()
.bind<ScalerAnnot, ScalerImplAnnot>()
.registerFactory<ScalerImplAnnot(fruit::Assisted<double>)>([](double factor) { return ScalerImpl(factor); });
}
int main() {
fruit::Injector<ScalerFactoryAnnot> injector(getScalerComponent());
ScalerFactory scalerFactory = injector.get<ScalerFactoryAnnot>();
std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
std::cout << scaler->scale(3) << std::endl;
}
''',
locals())
def test_with_annotation_returning_value():
expect_success(
COMMON_DEFINITIONS + '''
struct Scaler {
private:
double factor;
public:
Scaler(double factor)
: factor(factor) {
}
double scale(double x) {
return x * factor;
}
};
using ScalerAnnot1 = fruit::Annotated<Annotation1, Scaler>;
using ScalerFactory = std::function<Scaler(double)>;
using ScalerFactoryAnnot1 = fruit::Annotated<Annotation1, ScalerFactory>;
fruit::Component<ScalerFactoryAnnot1> getScalerComponent() {
return fruit::createComponent()
.registerFactory<ScalerAnnot1(fruit::Assisted<double>)>(
[](double factor) {
return Scaler(factor);
});
}
int main() {
fruit::Injector<ScalerFactoryAnnot1> injector(getScalerComponent());
ScalerFactory scalerFactory = injector.get<ScalerFactoryAnnot1>();
Scaler scaler = scalerFactory(12.1);
std::cout << scaler.scale(3) << std::endl;
}
''')
def test_with_different_annotation():
expect_success(
COMMON_DEFINITIONS + '''
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
ScalerImpl(double factor)
: factor(factor) {
}
double scale(double x) override {
return x * factor;
}
};
using ScalerAnnot1 = fruit::Annotated<Annotation1, Scaler>;
using ScalerImplAnnot2 = fruit::Annotated<Annotation2, ScalerImpl>;
using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
using ScalerFactoryAnnot1 = fruit::Annotated<Annotation1, ScalerFactory>;
fruit::Component<ScalerFactoryAnnot1> getScalerComponent() {
return fruit::createComponent()
.bind<ScalerAnnot1, ScalerImplAnnot2>()
.registerFactory<ScalerImplAnnot2(fruit::Assisted<double>)>(
[](double factor) {
return ScalerImpl(factor);
});
}
int main() {
fruit::Injector<ScalerFactoryAnnot1> injector(getScalerComponent());
ScalerFactory scalerFactory = injector.get<ScalerFactoryAnnot1>();
std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
std::cout << scaler->scale(3) << std::endl;
}
''')
def test_with_different_annotation_error():
expect_compile_error(
'NoBindingFoundError<fruit::Annotated<Annotation1,std::function<std::unique_ptr<ScalerImpl(,std::default_delete<ScalerImpl>)?>\(double\)>>>',
'',
COMMON_DEFINITIONS + '''
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
ScalerImpl(double factor)
: factor(factor) {
}
double scale(double x) override {
return x * factor;
}
};
using ScalerAnnot1 = fruit::Annotated<Annotation1, Scaler>;
using ScalerImplAnnot1 = fruit::Annotated<Annotation1, ScalerImpl>;
using ScalerImplAnnot2 = fruit::Annotated<Annotation2, ScalerImpl>;
using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
using ScalerFactoryAnnot1 = fruit::Annotated<Annotation1, ScalerFactory>;
fruit::Component<ScalerFactoryAnnot1> getScalerComponent() {
return fruit::createComponent()
.bind<ScalerAnnot1, ScalerImplAnnot1>()
.registerFactory<ScalerImplAnnot2(fruit::Assisted<double>)>([](double factor) { return ScalerImpl(factor); });
}
int main() {
fruit::Injector<ScalerFactoryAnnot1> injector(getScalerComponent());
ScalerFactory scalerFactory = injector.get<ScalerFactoryAnnot1>();
std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
std::cout << scaler->scale(3) << std::endl;
}
''')
def test_autoinject_success():
expect_success(
COMMON_DEFINITIONS + '''
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
INJECT(ScalerImpl(ASSISTED(double) factor))
: factor(factor) {
}
double scale(double x) override {
return x * factor;
}
};
using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
fruit::Component<ScalerFactory> getScalerComponent() {
return fruit::createComponent()
.bind<Scaler, ScalerImpl>();
}
int main() {
fruit::Injector<ScalerFactory> injector(getScalerComponent());
ScalerFactory scalerFactory(injector);
std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
std::cout << scaler->scale(3) << std::endl;
}
''')
@params(
('Scaler',
'std::function<std::unique_ptr<Scaler>(double)>'),
('fruit::Annotated<Annotation1, Scaler>',
'fruit::Annotated<Annotation1, std::function<std::unique_ptr<Scaler>(double)>>'))
def test_autoinject(ScalerAnnot, ScalerFactoryAnnot):
expect_success(
COMMON_DEFINITIONS + '''
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
INJECT(ScalerImpl(ASSISTED(double) factor))
: factor(factor) {
}
double scale(double x) override {
return x * factor;
}
};
using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
fruit::Component<ScalerFactoryAnnot> getScalerComponent() {
return fruit::createComponent()
.bind<ScalerAnnot, ScalerImpl>();
}
int main() {
fruit::Injector<ScalerFactoryAnnot> injector(getScalerComponent());
ScalerFactory scalerFactory = injector.get<ScalerFactoryAnnot>();
std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
std::cout << scaler->scale(3) << std::endl;
}
''',
locals())
def test_autoinject_returning_value():
expect_success(
COMMON_DEFINITIONS + '''
struct X {
INJECT(X()) = default;
};
struct Scaler {
private:
double factor;
public:
INJECT(Scaler(ASSISTED(double) factor, X))
: factor(factor) {
}
double scale(double x) {
return x * factor;
}
};
using ScalerFactory = std::function<Scaler(double)>;
fruit::Component<ScalerFactory> getScalerComponent() {
return fruit::createComponent();
}
int main() {
fruit::Injector<ScalerFactory> injector(getScalerComponent());
ScalerFactory scalerFactory(injector);
Scaler scaler = scalerFactory(12.1);
std::cout << scaler.scale(3) << std::endl;
}
''')
@params(
('Scaler', 'ScalerImpl', 'std::function<std::unique_ptr<Scaler>(double)>'),
('fruit::Annotated<Annotation1, Scaler>', 'fruit::Annotated<Annotation2, ScalerImpl>', 'fruit::Annotated<Annotation1, std::function<std::unique_ptr<Scaler>(double)>>'))
def test_autoinject_error_abstract_class(ScalerAnnot, ScalerImplAnnot, ScalerFactoryAnnot):
expect_compile_error(
'NoBindingFoundForAbstractClassError<ScalerImpl>',
'No explicit binding was found for C, and C is an abstract class',
COMMON_DEFINITIONS + '''
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
ScalerImpl(double factor)
: factor(factor) {
}
// Note: here we "forgot" to implement scale() (on purpose, for this test) so ScalerImpl is an abstract class.
};
fruit::Component<ScalerFactoryAnnot> getScalerComponent() {
return fruit::createComponent()
.bind<ScalerAnnot, ScalerImplAnnot>();
}
''',
locals())
def test_autoinject_nonmovable_ok():
expect_success(
COMMON_DEFINITIONS + '''
struct I {};
struct C : public I {
INJECT(C()) = default;
C(const C&) = delete;
C(C&&) = delete;
C& operator=(const C&) = delete;
C& operator=(C&&) = delete;
};
using IFactory = std::function<std::unique_ptr<I>()>;
fruit::Component<IFactory> getIFactory() {
return fruit::createComponent()
.bind<I, C>();
}
int main() {
fruit::Injector<IFactory> injector(getIFactory());
IFactory iFactory(injector);
std::unique_ptr<I> i = iFactory();
(void)i;
}
''')
def test_autoinject_2_assisted_params():
expect_success(
COMMON_DEFINITIONS + '''
struct Foo {
Foo(int x, float y) {
(void)x;
(void)y;
}
};
using FooFactory = std::function<Foo(int, float)>;
fruit::Component<FooFactory> getComponent() {
return fruit::createComponent()
.registerFactory<Foo(fruit::Assisted<int>, fruit::Assisted<float>)>(
[](int x, float y) {
return Foo(x, y);
});
}
int main() {
fruit::Injector<FooFactory> injector(getComponent());
FooFactory fooFactory(injector);
Foo foo = fooFactory(1, 2.3);
(void)foo;
}
''')
def test_autoinject_2_assisted_params_returning_value():
expect_success(
COMMON_DEFINITIONS + '''
struct Foo {
Foo(int x, float y) {
(void)x;
(void)y;
}
};
using FooFactory = std::function<Foo(int, float)>;
fruit::Component<FooFactory> getComponent() {
return fruit::createComponent()
.registerFactory<Foo(fruit::Assisted<int>, fruit::Assisted<float>)>(
[](int x, float y) {
return Foo(x, y);
});
}
int main() {
fruit::Injector<FooFactory> injector(getComponent());
FooFactory fooFactory(injector);
Foo foo = fooFactory(1, 2.3);
(void)foo;
}
''')
def test_autoinject_instances_bound_to_assisted_params():
expect_success(
COMMON_DEFINITIONS + '''
struct X {};
struct Y {};
struct Foo {
Foo(X x, Y y) {
(void)x;
(void)y;
}
};
using FooFactory = std::function<Foo()>;
fruit::Component<FooFactory> getComponent() {
static X x = X();
static Y y = Y();
return fruit::createComponent()
.bindInstance(x)
.bindInstance(y)
.registerFactory<Foo(X, Y)>(
[](X x, Y y) {
return Foo(x, y);
});
}
int main() {
fruit::Injector<FooFactory> injector(getComponent());
FooFactory fooFactory(injector);
Foo foo = fooFactory();
(void)foo;
}
''')
def test_autoinject_2_assisted_params_plus_nonassisted_params():
expect_success(
COMMON_DEFINITIONS + '''
struct X {};
struct Y {};
struct Z {};
struct Foo {
Foo(X, Y, int, float, Z) {
}
};
using FooPtrFactory = std::function<std::unique_ptr<Foo>(int, float)>;
fruit::Component<FooPtrFactory> getComponent() {
static X x = X();
static Y y = Y();
static Z z = Z();
return fruit::createComponent()
.bindInstance(x)
.bindInstance(y)
.bindInstance(z)
.registerFactory<std::unique_ptr<Foo>(X, Y, fruit::Assisted<int>, fruit::Assisted<float>, Z)>(
[](X x, Y y, int n, float a, Z z) {
return std::unique_ptr<Foo>(new Foo(x, y, n, a, z));
});
}
int main() {
fruit::Injector<FooPtrFactory> injector(getComponent());
FooPtrFactory fooPtrFactory(injector);
std::unique_ptr<Foo> foo = fooPtrFactory(1, 3.4);
(void)foo;
}
''')
def test_autoinject_2_assisted_params_plus_nonassisted_params_returning_value():
expect_success(
COMMON_DEFINITIONS + '''
struct X {};
struct Y {};
struct Z {};
struct Foo {
Foo(X, Y, int, float, Z) {
}
};
using FooFactory = std::function<Foo(int, float)>;
fruit::Component<FooFactory> getComponent() {
static X x = X();
static Y y = Y();
static Z z = Z();
return fruit::createComponent()
.bindInstance(x)
.bindInstance(y)
.bindInstance(z)
.registerFactory<Foo(X, Y, fruit::Assisted<int>, fruit::Assisted<float>, Z)>(
[](X x, Y y, int n, float a, Z z) {
return Foo(x, y, n, a, z);
});
}
int main() {
fruit::Injector<FooFactory> injector(getComponent());
FooFactory fooFactory(injector);
Foo foo = fooFactory(1, 3.4);
(void)foo;
}
''')
def test_autoinject_mixed_assisted_and_injected_params():
expect_success(
COMMON_DEFINITIONS + '''
struct X {};
struct Y {};
struct Foo {
Foo(int, float, X, Y, double) {
}
};
using FooFactory = std::function<Foo(int, float, double)>;
fruit::Component<FooFactory> getComponent() {
static X x = X();
static Y y = Y();
return fruit::createComponent()
.bindInstance(x)
.bindInstance(y)
.registerFactory<Foo(fruit::Assisted<int>, fruit::Assisted<float>, X, Y, fruit::Assisted<double>)>(
[](int n, float a, X x, Y y, double d) {
return Foo(n, a, x, y, d);
});
}
int main() {
fruit::Injector<FooFactory> injector(getComponent());
FooFactory fooFactory(injector);
Foo foo = fooFactory(1, 3.4, 3.456);
(void)foo;
}
''')
def test_autoinject_annotation_in_signature_return_type():
expect_compile_error(
'InjectTypedefWithAnnotationError<X>',
'C::Inject is a signature that returns an annotated type',
COMMON_DEFINITIONS + '''
struct X {
using Inject = fruit::Annotated<Annotation1, X>();
};
fruit::Component<fruit::Annotated<Annotation1, std::function<std::unique_ptr<X>()>>> getComponent() {
return fruit::createComponent();
}
''')
def test_autoinject_annotation_in_signature_return_type_returning_value():
expect_compile_error(
'InjectTypedefWithAnnotationError<X>',
'C::Inject is a signature that returns an annotated type',
COMMON_DEFINITIONS + '''
struct X {
using Inject = fruit::Annotated<Annotation1, X>();
};
fruit::Component<fruit::Annotated<Annotation1, std::function<X()>>> getComponent() {
return fruit::createComponent();
}
''')
def test_autoinject_from_provider():
expect_success(
COMMON_DEFINITIONS + '''
struct X {
INJECT(X()) = default;
};
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
ScalerImpl(double factor, X)
: factor(factor) {
}
double scale(double x) override {
return x * factor;
}
};
using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
fruit::Component<ScalerFactory> getScalerComponent() {
return fruit::createComponent()
.registerProvider([](X x) {
return std::function<std::unique_ptr<ScalerImpl>(double)>([x](double n){
return std::unique_ptr<ScalerImpl>(new ScalerImpl(n, x));
});
})
.bind<Scaler, ScalerImpl>();
}
int main() {
fruit::Injector<ScalerFactory> injector(getScalerComponent());
ScalerFactory scalerFactory(injector);
std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
std::cout << scaler->scale(3) << std::endl;
}
''')
@params(
('Scaler',
'std::function<std::unique_ptr<Scaler>(double)>',
'ScalerImpl',
'std::function<std::unique_ptr<ScalerImpl>(double)>'),
('fruit::Annotated<Annotation1, Scaler>',
'fruit::Annotated<Annotation1, std::function<std::unique_ptr<Scaler>(double)>>',
'fruit::Annotated<Annotation2, ScalerImpl>',
'fruit::Annotated<Annotation2, std::function<std::unique_ptr<ScalerImpl>(double)>>'))
def test_autoinject_from_provider(ScalerAnnot, ScalerFactoryAnnot, ScalerImplAnnot, ScalerImplFactoryAnnot):
expect_success(
COMMON_DEFINITIONS + '''
struct X {
INJECT(X()) = default;
};
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
ScalerImpl(double factor, X)
: factor(factor) {
}
double scale(double x) override {
return x * factor;
}
};
using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
using ScalerImplFactory = std::function<std::unique_ptr<ScalerImpl>(double)>;
fruit::Component<ScalerFactoryAnnot> getScalerComponent() {
return fruit::createComponent()
.registerProvider<ScalerImplFactoryAnnot(X)>([](X x) {
return std::function<std::unique_ptr<ScalerImpl>(double)>([x](double n){
return std::unique_ptr<ScalerImpl>(new ScalerImpl(n, x));
});
})
.bind<ScalerAnnot, ScalerImplAnnot>();
}
int main() {
fruit::Injector<ScalerFactoryAnnot> injector(getScalerComponent());
ScalerFactory scalerFactory = injector.get<ScalerFactoryAnnot>();
std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
std::cout << scaler->scale(3) << std::endl;
}
''',
locals())
@params('ScalerFactory', 'fruit::Annotated<Annotation1, ScalerFactory>')
def test_autoinject_from_provider_returning_value(ScalerFactoryAnnot):
expect_success(
COMMON_DEFINITIONS + '''
struct X {
INJECT(X()) = default;
};
struct Scaler {
private:
double factor;
public:
Scaler(double factor, X)
: factor(factor) {
}
double scale(double x) {
return x * factor;
}
};
using ScalerFactory = std::function<Scaler(double)>;
fruit::Component<ScalerFactoryAnnot> getScalerComponent() {
return fruit::createComponent()
.registerProvider<ScalerFactoryAnnot(X)>([](X x) {
return std::function<Scaler(double)>([x](double n){
return Scaler(n, x);
});
});
}
int main() {
fruit::Injector<ScalerFactoryAnnot> injector(getScalerComponent());
ScalerFactory scalerFactory = injector.get<ScalerFactoryAnnot>();
Scaler scaler = scalerFactory(12.1);
std::cout << scaler.scale(3) << std::endl;
}
''',
locals())
@params('X', 'ANNOTATED(Annotation1, X)')
def test_autoinject_with_binding(X_ANNOT):
expect_success(
COMMON_DEFINITIONS + '''
struct X {
using Inject = X();
};
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
INJECT(ScalerImpl(ASSISTED(double) factor, X_ANNOT x))
: factor(factor) {
(void)x;
}
double scale(double x) override {
return x * factor;
}
};
using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
fruit::Component<ScalerFactory> getScalerComponent() {
return fruit::createComponent()
.bind<Scaler, ScalerImpl>();
}
int main() {
fruit::Injector<ScalerFactory> injector(getScalerComponent());
ScalerFactory scalerFactory(injector);
std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
std::cout << scaler->scale(3) << std::endl;
}
''',
locals())
@params('X', 'ANNOTATED(Annotation1, X)')
def test_autoinject_with_binding_returning_value(X_ANNOT):
expect_success(
COMMON_DEFINITIONS + '''
struct X {
using Inject = X();
};
struct Scaler {
private:
double factor;
public:
INJECT(Scaler(ASSISTED(double) factor, X_ANNOT x))
: factor(factor) {
(void)x;
}
double scale(double x) {
return x * factor;
}
};
using ScalerFactory = std::function<Scaler(double)>;
fruit::Component<ScalerFactory> getScalerComponent() {
return fruit::createComponent();
}
int main() {
fruit::Injector<ScalerFactory> injector(getScalerComponent());
ScalerFactory scalerFactory(injector);
Scaler scaler = scalerFactory(12.1);
std::cout << scaler.scale(3) << std::endl;
}
''',
locals())
def test_autoinject_with_binding2():
expect_success(
COMMON_DEFINITIONS + '''
struct X {
INJECT(X()) = default;
};
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
INJECT(ScalerImpl(X, ASSISTED(double) factor))
: factor(factor) {
}
double scale(double x) override {
return x * factor;
}
};
using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
fruit::Component<ScalerFactory> getScalerComponent() {
return fruit::createComponent()
.bind<Scaler, ScalerImpl>();
}
int main() {
fruit::Injector<ScalerFactory> injector(getScalerComponent());
ScalerFactory scalerFactory(injector);
std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
std::cout << scaler->scale(3) << std::endl;
}
''')
def test_autoinject_with_binding2_returning_value():
expect_success(
COMMON_DEFINITIONS + '''
struct X {
INJECT(X()) = default;
};
struct Scaler {
private:
double factor;
public:
INJECT(Scaler(X, ASSISTED(double) factor))
: factor(factor) {
}
double scale(double x) {
return x * factor;
}
};
using ScalerFactory = std::function<Scaler(double)>;
fruit::Component<ScalerFactory> getScalerComponent() {
return fruit::createComponent();
}
int main() {
fruit::Injector<ScalerFactory> injector(getScalerComponent());
ScalerFactory scalerFactory(injector);
Scaler scaler = scalerFactory(12.1);
std::cout << scaler.scale(3) << std::endl;
}
''')
def test_dep_on_provider():
expect_success(
COMMON_DEFINITIONS + '''
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
ScalerImpl(double factor)
: factor(factor) {
}
double scale(double x) override {
return x * factor;
}
};
using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
fruit::Component<ScalerFactory> getScalerComponent() {
return fruit::createComponent()
.bind<Scaler, ScalerImpl>()
.registerProvider([](){return 23;})
.registerFactory<ScalerImpl(fruit::Assisted<double>, fruit::Provider<int>)>(
[](double factor, fruit::Provider<int> provider) {
return ScalerImpl(factor * provider.get<int>());
});
}
int main() {
fruit::Injector<ScalerFactory> injector(getScalerComponent());
ScalerFactory scalerFactory(injector);
std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
std::cout << scaler->scale(3) << std::endl;
}
''')
def test_dep_on_provider_returning_value():
expect_success(
COMMON_DEFINITIONS + '''
struct Scaler {
private:
double factor;
public:
Scaler(double factor)
: factor(factor) {
}
double scale(double x) {
return x * factor;
}
};
using ScalerFactory = std::function<Scaler(double)>;
fruit::Component<ScalerFactory> getScalerComponent() {
return fruit::createComponent()
.registerProvider([](){return 23;})
.registerFactory<Scaler(fruit::Assisted<double>, fruit::Provider<int>)>(
[](double factor, fruit::Provider<int> provider) {
return Scaler(factor * provider.get<int>());
});
}
int main() {
fruit::Injector<ScalerFactory> injector(getScalerComponent());
ScalerFactory scalerFactory(injector);
Scaler scaler = scalerFactory(12.1);
std::cout << scaler.scale(3) << std::endl;
}
''')
def test_error_abstract_class():
expect_compile_error(
'CannotConstructAbstractClassError<ScalerImpl>',
'The specified class can.t be constructed because it.s an abstract class.',
COMMON_DEFINITIONS + '''
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
ScalerImpl(double factor)
: factor(factor) {
}
// Note: here we "forgot" to implement scale() (on purpose, for this test) so ScalerImpl is an abstract class.
};
using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
fruit::Component<ScalerFactory> getScalerComponent() {
return fruit::createComponent()
.bind<Scaler, ScalerImpl>()
.registerFactory<fruit::Annotated<Annotation1, ScalerImpl>(fruit::Assisted<double>)>([](double) { return (ScalerImpl*)nullptr; });
}
''')
def test_error_not_function():
expect_compile_error(
'LambdaWithCapturesError<.*>',
'Only lambdas with no captures are supported',
COMMON_DEFINITIONS + '''
struct X {
X(int) {}
};
fruit::Component<std::function<X()>> getComponent() {
int n = 3;
return fruit::createComponent()
.registerFactory<X()>([=]{return X(n);});
}
''')
@params(
('Scaler',
'ScalerImpl',
'ScalerImpl*',
'std::function<std::unique_ptr<Scaler>(double)>',
'ScalerImpl\*\(fruit::Assisted<double>\)'),
('fruit::Annotated<Annotation1, Scaler>',
'fruit::Annotated<Annotation2, ScalerImpl>',
'fruit::Annotated<Annotation2, ScalerImpl*>',
'fruit::Annotated<Annotation2, std::function<std::unique_ptr<Scaler>(double)>>',
'fruit::Annotated<Annotation2,ScalerImpl\*>\(fruit::Assisted<double>\)'))
def test_for_pointer(ScalerAnnot, ScalerImplAnnot, ScalerImplPtrAnnot, ScalerFactoryAnnot, ScalerImplFactorySignatureAnnotRegex):
expect_compile_error(
'FactoryReturningPointerError<ScalerImplFactorySignatureAnnotRegex>',
'The specified factory returns a pointer. This is not supported',
COMMON_DEFINITIONS + '''
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
ScalerImpl(double factor)
: factor(factor) {
}
double scale(double x) override {
return x * factor;
}
};
using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
fruit::Component<ScalerFactoryAnnot> getScalerComponent() {
return fruit::createComponent()
.bind<ScalerAnnot, ScalerImplAnnot>()
.registerFactory<ScalerImplPtrAnnot(fruit::Assisted<double>)>([](double factor) { return new ScalerImpl(factor); });
}
int main() {
fruit::Injector<ScalerFactoryAnnot> injector(getScalerComponent());
ScalerFactory scalerFactory = injector.get<ScalerFactoryAnnot>();
std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
std::cout << scaler->scale(3) << std::endl;
}
''',
locals())
@params(
('Scaler*',
'std::function<Scaler(double)>',
'Scaler\*\(fruit::Assisted<double>\)'),
('fruit::Annotated<Annotation1, Scaler*>',
'fruit::Annotated<Annotation1, std::function<Scaler(double)>>',
'fruit::Annotated<Annotation1,Scaler\*>\(fruit::Assisted<double>\)'),
)
def test_for_pointer_returning_value(ScalerPtrAnnot, ScalerFactoryAnnot, ScalerFactorySignatureAnnotRegex):
expect_compile_error(
'FactoryReturningPointerError<ScalerFactorySignatureAnnotRegex>',
'The specified factory returns a pointer. This is not supported',
COMMON_DEFINITIONS + '''
struct Scaler {
private:
double factor;
public:
Scaler(double factor)
: factor(factor) {
}
double scale(double x) {
return x * factor;
}
};
using ScalerFactory = std::function<Scaler(double)>;
fruit::Component<ScalerFactoryAnnot> getScalerComponent() {
return fruit::createComponent()
.registerFactory<ScalerPtrAnnot(fruit::Assisted<double>)>([](double factor) { return new Scaler(factor); });
}
int main() {
fruit::Injector<ScalerFactoryAnnot> injector(getScalerComponent());
ScalerFactory scalerFactory = injector.get<ScalerFactoryAnnot>();
Scaler scaler = scalerFactory(12.1);
std::cout << scaler.scale(3) << std::endl;
}
''',
locals())
@params(
('Scaler',
'ScalerImpl',
'std::unique_ptr<ScalerImpl>',
'std::function<std::unique_ptr<Scaler>(double)>'),
('fruit::Annotated<Annotation1, Scaler>',
'fruit::Annotated<Annotation2, ScalerImpl>',
'fruit::Annotated<Annotation2, std::unique_ptr<ScalerImpl>>',
'fruit::Annotated<Annotation1, std::function<std::unique_ptr<Scaler>(double)>>'))
def test_for_unique_pointer(ScalerAnnot, ScalerImplAnnot, ScalerImplPtrAnnot, ScalerFactoryAnnot):
expect_success(
COMMON_DEFINITIONS + '''
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
ScalerImpl(double factor)
: factor(factor) {
}
double scale(double x) override {
return x * factor;
}
};
using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
fruit::Component<ScalerFactoryAnnot> getScalerComponent() {
return fruit::createComponent()
.bind<ScalerAnnot, ScalerImplAnnot>()
.registerFactory<ScalerImplPtrAnnot(fruit::Assisted<double>)>(
[](double factor) {
return std::unique_ptr<ScalerImpl>(new ScalerImpl(factor));
});
}
int main() {
fruit::Injector<ScalerFactoryAnnot> injector(getScalerComponent());
ScalerFactory scalerFactory = injector.get<ScalerFactoryAnnot>();
std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
std::cout << scaler->scale(3) << std::endl;
}
''',
locals())
@params(
('Scaler',
'std::function<Scaler(double)>'),
('fruit::Annotated<Annotation1, Scaler>',
'fruit::Annotated<Annotation1, std::function<Scaler(double)>>'))
def test_for_unique_pointer_returning_value(ScalerAnnot, ScalerFactoryAnnot):
expect_success(
COMMON_DEFINITIONS + '''
struct Scaler {
private:
double factor;
public:
Scaler(double factor)
: factor(factor) {
}
double scale(double x) {
return x * factor;
}
};
using ScalerFactory = std::function<Scaler(double)>;
fruit::Component<ScalerFactoryAnnot> getScalerComponent() {
return fruit::createComponent()
.registerFactory<ScalerAnnot(fruit::Assisted<double>)>(
[](double factor) {
return Scaler(factor);
});
}
int main() {
fruit::Injector<ScalerFactoryAnnot> injector(getScalerComponent());
ScalerFactory scalerFactory = injector.get<ScalerFactoryAnnot>();
Scaler scaler = scalerFactory(12.1);
std::cout << scaler.scale(3) << std::endl;
}
''',
locals())
@params('ScalerImpl', 'fruit::Annotated<Annotation1, ScalerImpl>')
def test_inconsistent_signature(ScalerImplAnnot):
expect_compile_error(
'FunctorSignatureDoesNotMatchError<ScalerImpl\(double\),ScalerImpl\(float\)>',
'Unexpected functor signature',
COMMON_DEFINITIONS + '''
struct Scaler {
virtual double scale(double x) = 0;
};
struct ScalerImpl : public Scaler {
private:
double factor;
public:
ScalerImpl(double factor)
: factor(factor) {
}
double scale(double x) override {
return x * factor;
}
};
using ScalerFactory = std::function<std::unique_ptr<Scaler>(double)>;
fruit::Component<ScalerFactory> getScalerComponent() {
return fruit::createComponent()
.bind<Scaler, ScalerImplAnnot>()
.registerFactory<ScalerImplAnnot(fruit::Assisted<double>)>([](float factor) { return ScalerImpl(factor); });
}
int main() {
fruit::Injector<ScalerFactory> injector(getScalerComponent());
ScalerFactory scalerFactory(injector);
std::unique_ptr<Scaler> scaler = scalerFactory(12.1);
std::cout << scaler->scale(3) << std::endl;
}
''',
locals())
def test_inconsistent_signature_returning_value():
expect_compile_error(
'FunctorSignatureDoesNotMatchError<Scaler\(double\),Scaler\(float\)>',
'Unexpected functor signature',
COMMON_DEFINITIONS + '''
struct Scaler {
private:
double factor;
public:
Scaler(double factor)
: factor(factor) {
}
double scale(double x) {
return x * factor;
}
};
using ScalerFactory = std::function<Scaler(double)>;
fruit::Component<ScalerFactory> getScalerComponent() {
return fruit::createComponent()
.registerFactory<Scaler(fruit::Assisted<double>)>([](float factor) { return Scaler(factor); });
}
int main() {
fruit::Injector<ScalerFactory> injector(getScalerComponent());
ScalerFactory scalerFactory(injector);
Scaler scaler = scalerFactory(12.1);
std::cout << scaler.scale(3) << std::endl;
}
''')
def test_nonmovable_ok():
expect_success(
COMMON_DEFINITIONS + '''
struct C {
INJECT(C()) = default;
C(const C&) = delete;
C(C&&) = delete;
C& operator=(const C&) = delete;
C& operator=(C&&) = delete;
};
using CFactory = std::function<std::unique_ptr<C>()>;
fruit::Component<CFactory> getCFactory() {
return fruit::createComponent();
}
int main() {
fruit::Injector<CFactory> injector(getCFactory());
CFactory cFactory(injector);
std::unique_ptr<C> c = cFactory();
(void)c;
}
''')
# TODO: this might not be the best error message, maybe we should ignore the constructor entirely in the message,
# or mention that there are other ways to satisfy that dependency.
@params(
('X',
'std::function<X(int)>'),
('fruit::Annotated<Annotation1, X>',
'fruit::Annotated<Annotation1, std::function<X(int)>>'))
def test_not_existing_constructor1(XAnnot, XFactoryAnnot):
expect_compile_error(
'FunctorSignatureDoesNotMatchError<XAnnot\(int\),XAnnot\(\)>',
'Unexpected functor signature',
COMMON_DEFINITIONS + '''
struct X {
INJECT(X()) = default;
};
fruit::Component<XFactoryAnnot> getComponent() {
return fruit::createComponent();
}
''',
locals())
# TODO: this might not be the best error message, maybe we should ignore the constructor entirely in the message,
# or mention that there are other ways to satisfy that dependency.
@params(
('std::function<std::unique_ptr<X>(int)>',
'std::unique_ptr<X(,std::default_delete<X>)?>\(int\)',
'std::unique_ptr<X(,std::default_delete<X>)?>\(\)'),
('fruit::Annotated<Annotation1, std::function<std::unique_ptr<X>(int)>>',
'fruit::Annotated<Annotation1,std::unique_ptr<X(,std::default_delete<X>)?>>\(int\)',
'fruit::Annotated<Annotation1,std::unique_ptr<X(,std::default_delete<X>)?>>\(\)'))
def test_not_existing_constructor2(XIntFactoryAnnot, XIntFactoryAnnotRegex, XVoidFactoryAnnotRegex):
expect_compile_error(
'FunctorSignatureDoesNotMatchError<XIntFactoryAnnotRegex,XVoidFactoryAnnotRegex>',
'Unexpected functor signature',
COMMON_DEFINITIONS + '''
struct X {
using Inject = X();
};
fruit::Component<XIntFactoryAnnot> getComponent() {
return fruit::createComponent();
}
''',
locals())
# TODO: this might not be the best error message, maybe we should ignore the constructor entirely in the message,
# or mention that there are other ways to satisfy that dependency.
@params(
('X',
'std::function<X(int)>'),
('fruit::Annotated<Annotation1, X>',
'fruit::Annotated<Annotation1, std::function<X(int)>>'))
def test_not_existing_constructor2_returning_value(XAnnot, XFactoryAnnot):
expect_compile_error(
'FunctorSignatureDoesNotMatchError<XAnnot\(int\), XAnnot\(\)>',
'Unexpected functor signature',
COMMON_DEFINITIONS + '''
struct X {
using Inject = X();
};
fruit::Component<XFactoryAnnot> getComponent() {
return fruit::createComponent();
}
''',
locals())
if __name__ == '__main__':
import nose2
nose2.main()