#!/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. import pytest from fruit_test_common import * COMMON_DEFINITIONS = ''' #include "test_common.h" struct Annotation1 {}; struct Annotation2 {}; template using WithNoAnnot = T; template using WithAnnot1 = fruit::Annotated; template using WithAnnot2 = fruit::Annotated; ''' @pytest.mark.parametrize('IAnnot,XAnnot,WithAnnot', [ ('I', 'X', 'WithNoAnnot'), ('fruit::Annotated', 'fruit::Annotated', 'WithAnnot1'), ]) def test_provider_returning_value_success_with_annotation(IAnnot, XAnnot, WithAnnot): source = ''' struct I { int value = 5; }; struct X : public I, ConstructionTracker { }; fruit::Component getComponent() { return fruit::createComponent() .registerProvider([](){return X();}) .bind(); } int main() { fruit::Injector injector(getComponent); Assert((injector.get>() .value == 5)); Assert((injector.get>()->value == 5)); Assert((injector.get>() .value == 5)); Assert((injector.get>() .value == 5)); Assert((injector.get>()->value == 5)); Assert((injector.get>() .value == 5)); Assert((injector.get>>()->value == 5)); Assert(fruit::impl::InjectorAccessorForTests::unsafeGet>(injector) == nullptr); Assert(X::num_objects_constructed == 1); } ''' expect_success( COMMON_DEFINITIONS, source, locals()) @pytest.mark.parametrize('IAnnot,XAnnot,XPtrAnnot,WithAnnot', [ ('I', 'X', 'X*', 'WithNoAnnot'), ('fruit::Annotated', 'fruit::Annotated', 'fruit::Annotated', 'WithAnnot1'), ]) def test_provider_returning_pointer_success_with_annotation(IAnnot, XAnnot, XPtrAnnot, WithAnnot): source = ''' struct I { int value = 5; }; struct X : public I, ConstructionTracker { }; fruit::Component getComponent() { return fruit::createComponent() .registerProvider([](){return new X();}) .bind(); } int main() { fruit::Injector injector(getComponent); Assert((injector.get>() .value == 5)); Assert((injector.get>()->value == 5)); Assert((injector.get>() .value == 5)); Assert((injector.get>() .value == 5)); Assert((injector.get>()->value == 5)); Assert((injector.get>() .value == 5)); Assert((injector.get>>()->value == 5)); Assert(fruit::impl::InjectorAccessorForTests::unsafeGet>(injector) == nullptr); Assert(X::num_objects_constructed == 1); } ''' expect_success( COMMON_DEFINITIONS, source, locals()) def test_compression_undone(): source = ''' struct I1 {}; struct C1 : public I1, ConstructionTracker { INJECT(C1()) = default; }; struct I2 {}; struct C2 : public I2 { INJECT(C2(I1*)) {} }; fruit::Component getI1Component() { return fruit::createComponent() .bind(); } fruit::Component getI2Component() { return fruit::createComponent() .install(getI1Component) .bind(); } struct X { // Intentionally C1 and not I1. This prevents binding compression for the I1->C1 edge. INJECT(X(C1*)) {} }; fruit::Component getXComponent() { return fruit::createComponent(); } int main() { // Here the binding C2->I1->C1 is compressed into C2->C1. fruit::NormalizedComponent normalizedComponent(getI2Component); // However the binding X->C1 prevents binding compression on I1->C1, the binding compression must be undone. fruit::Injector injector(normalizedComponent, getXComponent); Assert(C1::num_objects_constructed == 0); injector.get(); injector.get(); Assert(fruit::impl::InjectorAccessorForTests::unsafeGet(injector) != nullptr); Assert(C1::num_objects_constructed == 1); } ''' expect_success( COMMON_DEFINITIONS, source) if __name__== '__main__': main(__file__)