1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3 4# 5# Copyright 2017, Data61 6# Commonwealth Scientific and Industrial Research Organisation (CSIRO) 7# ABN 41 687 119 230. 8# 9# This software may be distributed and modified according to the terms of 10# the BSD 2-Clause license. Note that NO WARRANTY is provided. 11# See "LICENSE_BSD2.txt" for details. 12# 13# @TAG(DATA61_BSD) 14# 15 16from __future__ import absolute_import, division, print_function, \ 17 unicode_literals 18 19import os, sys, unittest 20 21ME = os.path.abspath(__file__) 22 23# Make CAmkES importable 24sys.path.append(os.path.join(os.path.dirname(ME), '../../..')) 25 26from camkes.ast import Component, Composition, Connection, ConnectionEnd, \ 27 Export, Instance, Provides, Uses 28from camkes.internal.tests.utils import CAmkESTest 29from camkes.parser.exception import ParseError 30from camkes.parser.stage0 import CPP, Reader 31from camkes.parser.stage1 import Parse1 32from camkes.parser.stage2 import Parse2 33from camkes.parser.stage3 import Parse3 34from camkes.parser.stage4 import Parse4 35from camkes.parser.stage5 import Parse5 36 37class TestStage5(CAmkESTest): 38 def setUp(self): 39 super(TestStage5, self).setUp() 40 r = Reader() 41 s1 = Parse1(r) 42 s2 = Parse2(s1) 43 s3 = Parse3(s2, debug=True) 44 s4 = Parse4(s3) 45 self.parser = Parse5(s4) 46 47 def test_group_basic(self): 48 ast, _ = self.parser.parse_string(''' 49 component A {} 50 component B {} 51 composition { 52 group foo { 53 component A a; 54 component B b; 55 } 56 } 57 ''') 58 59 self.assertLen(ast.items, 3) 60 comp = ast.items[2] 61 62 self.assertIsInstance(comp, Composition) 63 self.assertLen(comp.instances, 2) 64 self.assertLen(comp.groups, 0) 65 a, b = comp.instances 66 67 self.assertIsInstance(a, Instance) 68 self.assertEqual(a.address_space, 'foo') 69 70 self.assertIsInstance(b, Instance) 71 self.assertEqual(b.address_space, 'foo') 72 73 def test_group_mixed(self): 74 ast, _ = self.parser.parse_string(''' 75 component A {} 76 composition { 77 component A a1; 78 group b { 79 component A a2; 80 } 81 component A a3; 82 group c { 83 component A a4; 84 } 85 } 86 ''') 87 88 self.assertLen(ast.items, 2) 89 comp = ast.items[1] 90 91 self.assertIsInstance(comp, Composition) 92 self.assertLen(comp.instances, 4) 93 94 seen = set() 95 for a in comp.instances: 96 if a.name == 'a1': 97 self.assertEqual(a.address_space, 'a1') 98 elif a.name == 'a2': 99 self.assertEqual(a.address_space, 'b') 100 elif a.name == 'a3': 101 self.assertEqual(a.address_space, 'a3') 102 elif a.name == 'a4': 103 self.assertEqual(a.address_space, 'c') 104 else: 105 self.fail('unexpected instance %s found' % a.name) 106 seen.add(a.name) 107 108 self.assertLen(seen, 4, 'some expected instances not found') 109 110 def test_group_with_connection(self): 111 ast, _ = self.parser.parse_string(''' 112 connector Conn { 113 from Procedure; 114 to Procedure; 115 } 116 procedure P {} 117 component A { 118 provides P a; 119 uses P b; 120 } 121 composition { 122 component A a1; 123 group g { 124 component A a2; 125 } 126 connection Conn c(from a1.b, to g.a2.a); 127 connection Conn c2(from g.a2.b, to a1.a); 128 } 129 ''') 130 131 self.assertLen(ast.items, 4) 132 _, _, A, comp = ast.items 133 134 self.assertIsInstance(A, Component) 135 self.assertLen(A.provides, 1) 136 a = A.provides[0] 137 self.assertIsInstance(a, Provides) 138 self.assertLen(A.uses, 1) 139 b = A.uses[0] 140 self.assertIsInstance(b, Uses) 141 142 self.assertIsInstance(comp, Composition) 143 144 # The group will have been collapsed, so we'll now have two instances. 145 146 self.assertLen(comp.instances, 2) 147 a1, a2 = comp.instances 148 self.assertIsInstance(a1, Instance) 149 self.assertIsInstance(a2, Instance) 150 151 self.assertLen(comp.connections, 2) 152 c, c2 = comp.connections 153 self.assertIsInstance(c, Connection) 154 self.assertIsInstance(c2, Connection) 155 156 self.assertLen(c.from_ends, 1) 157 a1_b = c.from_ends[0] 158 self.assertIsInstance(a1_b, ConnectionEnd) 159 160 self.assertIs(a1_b.instance, a1) 161 self.assertIs(a1_b.interface, b) 162 163 self.assertLen(c.to_ends, 1) 164 g_a2_a = c.to_ends[0] 165 self.assertIsInstance(g_a2_a, ConnectionEnd) 166 167 self.assertIs(g_a2_a.instance, a2) 168 self.assertIs(g_a2_a.interface, a) 169 170 def test_group_with_connection2(self): 171 ''' 172 For the purpose of this, see the identically named test case in the 173 stage 4 tests. 174 ''' 175 ast, _ = self.parser.parse_string(''' 176 connector Conn { 177 from Procedure; 178 to Procedure; 179 } 180 procedure P {} 181 component A { 182 provides P a; 183 uses P b; 184 } 185 composition { 186 group g { 187 component A a2; 188 } 189 component A a1; 190 connection Conn c(from a1.b, to g.a2.a); 191 connection Conn c2(from g.a2.b, to a1.a); 192 } 193 ''') 194 195 self.assertLen(ast.items, 4) 196 _, _, A, comp = ast.items 197 198 self.assertIsInstance(A, Component) 199 self.assertLen(A.provides, 1) 200 a = A.provides[0] 201 self.assertIsInstance(a, Provides) 202 self.assertLen(A.uses, 1) 203 b = A.uses[0] 204 self.assertIsInstance(b, Uses) 205 206 self.assertIsInstance(comp, Composition) 207 208 # The group will have been collapsed, so we'll now have two instances. 209 210 self.assertLen(comp.instances, 2) 211 a1, a2 = comp.instances 212 self.assertIsInstance(a1, Instance) 213 self.assertIsInstance(a2, Instance) 214 215 self.assertLen(comp.connections, 2) 216 c, c2 = comp.connections 217 self.assertIsInstance(c, Connection) 218 self.assertIsInstance(c2, Connection) 219 220 self.assertLen(c.from_ends, 1) 221 a1_b = c.from_ends[0] 222 self.assertIsInstance(a1_b, ConnectionEnd) 223 224 self.assertIs(a1_b.instance, a1) 225 self.assertIs(a1_b.interface, b) 226 227 self.assertLen(c.to_ends, 1) 228 g_a2_a = c.to_ends[0] 229 self.assertIsInstance(g_a2_a, ConnectionEnd) 230 231 self.assertIs(g_a2_a.instance, a2) 232 self.assertIs(g_a2_a.interface, a) 233 234 def test_export_reference(self): 235 ast, _ = self.parser.parse_string(''' 236 procedure P {} 237 component Foo { 238 provides P a; 239 } 240 component Bar { 241 provides P b; 242 composition { 243 component Foo c; 244 export c.a -> b; 245 } 246 } 247 ''') 248 249 self.assertLen(ast.items, 3) 250 P, Foo, Bar = ast.items 251 252 self.assertIsInstance(Bar, Component) 253 comp = Bar.composition 254 255 self.assertIsInstance(comp, Composition) 256 self.assertLen(comp.instances, 1) 257 c = comp.instances[0] 258 259 self.assertLen(comp.exports, 1) 260 e = comp.exports[0] 261 262 self.assertIsInstance(e.source_instance, Instance) 263 self.assertIs(e.source_instance, c) 264 self.assertIsInstance(e.source_interface, Provides) 265 self.assertIs(e.source_interface, Foo.provides[0]) 266 self.assertIsInstance(e.destination, Provides) 267 self.assertIs(e.destination, Bar.provides[0]) 268 269 def test_invalid_export(self): 270 with self.assertRaises(ParseError): 271 self.parser.parse_string(''' 272 procedure P {} 273 component Foo { 274 provides P a; 275 } 276 composition { 277 component Foo b; 278 } 279 component Bar { 280 composition { 281 component Foo c; 282 export c.a -> b; 283 } 284 } 285 ''') 286 287if __name__ == '__main__': 288 unittest.main() 289