/** * Copyright 2014-2017 Linagora, Université Joseph Fourier, Floralis * * The present code is developed in the scope of the joint LINAGORA - * Université Joseph Fourier - Floralis research program and is designated * as a "Result" pursuant to the terms and conditions of the LINAGORA * - Université Joseph Fourier - Floralis research program. Each copyright * holder of Results enumerated here above fully & independently holds complete * ownership of the complete Intellectual Property rights applicable to the whole * of said Results, and may freely exploit it in any manner which does not infringe * the moral rights of the other copyright holders. * * 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. */ package net.roboconf.core.internal.dsl.parsing; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStreamReader; import java.io.StringReader; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import org.junit.Assert; import org.junit.Test; import net.roboconf.core.ErrorCode; import net.roboconf.core.ErrorCode.ErrorCategory; import net.roboconf.core.dsl.ParsingModelIo; import net.roboconf.core.dsl.converters.FromGraphDefinition; import net.roboconf.core.dsl.parsing.AbstractBlock; import net.roboconf.core.dsl.parsing.BlockBlank; import net.roboconf.core.dsl.parsing.BlockComment; import net.roboconf.core.dsl.parsing.BlockComponent; import net.roboconf.core.dsl.parsing.BlockImport; import net.roboconf.core.dsl.parsing.BlockInstanceOf; import net.roboconf.core.dsl.parsing.BlockProperty; import net.roboconf.core.dsl.parsing.FileDefinition; import net.roboconf.core.internal.tests.TestUtils; import net.roboconf.core.model.ParsingError; import net.roboconf.core.model.beans.Component; import net.roboconf.core.model.beans.Graphs; import net.roboconf.core.model.beans.ImportedVariable; import net.roboconf.core.model.helpers.ComponentHelpers; import net.roboconf.core.utils.Utils; /** * @author Vincent Zurczak - Linagora */ public class FileDefinitionParserTest { @Test public void testRecognizeComment() { Collection<AbstractBlock> blocks = new ArrayList<> (); String[] validLines = { "# ok", "#", " # woo ", " ###############" }; // Without ignoring comments for( String line : validLines ) { blocks.clear(); FileDefinitionParser parser = new FileDefinitionParser( null, false ); int code = parser.recognizeComment( line, blocks ); Assert.assertEquals( "Expected a YES code for '" + line + "'", FileDefinitionParser.P_CODE_YES, code ); Assert.assertEquals( "No parsing error was expected for '" + line + "'", 0, parser.getFileRelations().getParsingErrors().size()); Assert.assertEquals( "Expected ONE block to be registered for '" + line + "'", 1, blocks.size()); Assert.assertEquals( "Expected ONE comment block for '" + line + "'", AbstractBlock.COMMENT, blocks.iterator().next().getInstructionType()); } // Ignoring comments for( String line : validLines ) { blocks.clear(); FileDefinitionParser parser = new FileDefinitionParser( null, true ); int code = parser.recognizeComment( line, blocks ); Assert.assertEquals( "Expected a YES code for '" + line + "'", FileDefinitionParser.P_CODE_YES, code ); Assert.assertEquals( "No parsing error was expected for '" + line + "'", 0, parser.getFileRelations().getParsingErrors().size()); Assert.assertEquals( "Expected ZERO block to be registered for '" + line + "'", 0, blocks.size()); } // Testing invalid comments String[] invalidLines = { "", " ", "something", "something # with a comment after" }; for( String line : invalidLines ) { blocks.clear(); FileDefinitionParser parser = new FileDefinitionParser( null, true ); int code = parser.recognizeComment( line, blocks ); Assert.assertEquals( "Expected a NO code for '" + line + "'", FileDefinitionParser.P_CODE_NO, code ); Assert.assertEquals( "No parsing error was expected for '" + line + "'", 0, parser.getFileRelations().getParsingErrors().size()); Assert.assertEquals( "Expected ZERO block to be registered for '" + line + "'", 0, blocks.size()); } } @Test public void testRecognizeBlank() { Collection<AbstractBlock> blocks = new ArrayList<> (); String[] validLines = { " ", "" }; for( String line : validLines ) { blocks.clear(); FileDefinitionParser parser = new FileDefinitionParser( null, false ); int code = parser.recognizeBlankLine( line, blocks ); Assert.assertEquals( "Expected a YES code for '" + line + "'", FileDefinitionParser.P_CODE_YES, code ); Assert.assertEquals( "No parsing error was expected for '" + line + "'", 0, parser.getFileRelations().getParsingErrors().size()); Assert.assertEquals( "Expected ONE block to be registered for '" + line + "'", 1, blocks.size()); Assert.assertEquals( "Expected ONE blank block for '" + line + "'", AbstractBlock.BLANK, blocks.iterator().next().getInstructionType()); } String[] invalidLines = { "#", "something", " something with spaces before an after " }; for( String line : invalidLines ) { blocks.clear(); FileDefinitionParser parser = new FileDefinitionParser( null, false ); int code = parser.recognizeBlankLine( line, blocks ); Assert.assertEquals( "Expected a NO code for '" + line + "'", FileDefinitionParser.P_CODE_NO, code ); Assert.assertEquals( "No parsing error was expected for '" + line + "'", 0, parser.getFileRelations().getParsingErrors().size()); Assert.assertEquals( "Expected ZERO block to be registered for '" + line + "'", 0, blocks.size()); } } @Test public void testSplitFromInlineComment() { String[][] beforeToAfter = { { "import facets.rcf;", "# import the facets" }, { "import facets.rcf;", "\t# import the facets" }, { "import facets.rcf;", "#" }, { "import facets.rcf;", "" }, { "import facets.rcf; ", "" }, { "import facets.rcf;", " #### import the facets" }, { "", " #### import the facets" }, { "", " # " }, { "", "#" } }; // Parsing comments for( String[] line : beforeToAfter ) { FileDefinitionParser parser = new FileDefinitionParser( null, false ); String theLine = line[ 0 ] + line[ 1 ]; String[] parts = parser.splitFromInlineComment( theLine ); Assert.assertEquals( "Test failed for '" + theLine + "'", line[ 0 ], parts[ 0 ]); Assert.assertEquals( "Test failed for '" + theLine + "'", line[ 1 ], parts[ 1 ]); } // Ignoring comments for( String[] line : beforeToAfter ) { FileDefinitionParser parser = new FileDefinitionParser( null, true ); String theLine = line[ 0 ] + line[ 1 ]; String[] parts = parser.splitFromInlineComment( theLine ); Assert.assertEquals( "Test failed for '" + theLine + "'", line[ 0 ], parts[ 0 ]); Assert.assertEquals( "Comment should be empty for '" + theLine + "'", "", parts[ 1 ]); } } @Test public void testRecognizeImport() { String[] validLines = { "import facets.rcf;", "IMPORT facets.rcf;", "import http://some-host.com/some/path/facets.rcf;", "import http://some-host.com/some/path/?file=facets.rcf;", " import facets.rcf ; ", "import facets.rcf; # with an inline comment" }; // Comments do not matter here for( String line : validLines ) { FileDefinitionParser parser = new FileDefinitionParser( null, false ); int code = parser.recognizeImport( line ); FileDefinition def = parser.getFileRelations(); Assert.assertEquals( "Expected a YES code for '" + line + "'", FileDefinitionParser.P_CODE_YES, code ); Assert.assertEquals( "No parsing error was expected for '" + line + "'", 0, def.getParsingErrors().size()); Assert.assertEquals( "Expected ONE block to be registered for '" + line + "'", 1, def.getBlocks().size()); BlockImport imp = (BlockImport) def.getBlocks().iterator().next(); Assert.assertEquals( "Expected ONE import block for '" + line + "'", AbstractBlock.IMPORT, imp.getInstructionType()); Assert.assertFalse( "URI cannot be empty for '" + line + "'", Utils.isEmptyOrWhitespaces( imp.getUri())); Assert.assertEquals( "URI cannot have surrounding spaces '" + line + "'", imp.getUri(), imp.getUri().trim()); Assert.assertNotSame( "URI cannot be the entire line for '" + line + "'", imp.getUri(), line ); Assert.assertTrue( "The URI was not found in '" + line + "'", line.contains( imp.getUri())); } // In-line comments String[][] commentedLines = { { "import facets.rcf;", "" }, { "import facets.rcf;", "# stuck comment" }, { "import facets.rcf;", "#" }, { "import facets.rcf;", "\t# some in-line comment " } }; for( String[] line : commentedLines ) { FileDefinitionParser parser = new FileDefinitionParser( null, false ); String theLine = line[ 0 ] + line[ 1 ]; int code = parser.recognizeImport( theLine ); FileDefinition def = parser.getFileRelations(); Assert.assertEquals( "Expected a YES code for '" + theLine + "'", FileDefinitionParser.P_CODE_YES, code ); Assert.assertEquals( "No parsing error was expected for '" + theLine + "'", 0, def.getParsingErrors().size()); Assert.assertEquals( "Expected ONE block to be registered for '" + theLine + "'", 1, def.getBlocks().size()); BlockImport imp = (BlockImport) def.getBlocks().iterator().next(); Assert.assertEquals( "Expected ONE import block for '" + theLine + "'", AbstractBlock.IMPORT, imp.getInstructionType()); String expected = Utils.isEmptyOrWhitespaces( line[ 1 ]) ? null : line[ 1 ]; Assert.assertEquals( "Invalid in-line comment for '" + theLine + "'", expected, imp.getInlineComment()); } // Invalid lines String[] invalidLines = { "imports facets.rcf;", "IPORT facets.rcf;", "facet", "", " #" }; for( String line : invalidLines ) { FileDefinitionParser parser = new FileDefinitionParser( null, false ); int code = parser.recognizeImport( line ); Assert.assertEquals( "Expected a NO code for '" + line + "'", FileDefinitionParser.P_CODE_NO, code ); } // Test error codes Map<String,ErrorCode> invalidLineToErrorCode = new LinkedHashMap<> (); invalidLineToErrorCode.put( "import facets.rcf", ErrorCode.P_IMPORT_ENDS_WITH_SEMI_COLON ); invalidLineToErrorCode.put( "import facets.rcf ; facet toto {", ErrorCode.P_ONE_BLOCK_PER_LINE ); invalidLineToErrorCode.put( "import facets.rcf ; invalid comment", ErrorCode.P_ONE_BLOCK_PER_LINE ); invalidLineToErrorCode.put( "import facets.rcf ;;", ErrorCode.P_ONE_BLOCK_PER_LINE ); for( Map.Entry<String,ErrorCode> entry : invalidLineToErrorCode.entrySet()) { String line = entry.getKey(); FileDefinitionParser parser = new FileDefinitionParser( null, false ); int code = parser.recognizeImport( entry.getKey()); FileDefinition def = parser.getFileRelations(); Assert.assertEquals( "Expected a YES code for '" + line + "'", FileDefinitionParser.P_CODE_YES, code ); Assert.assertEquals( "A parsing error was expected for '" + line + "'", 1, def.getParsingErrors().size()); Assert.assertEquals( "Expected ONE block to be registered for '" + line + "'", 1, def.getBlocks().size()); Assert.assertEquals( "Expected ONE import block for '" + line + "'", AbstractBlock.IMPORT, def.getBlocks().iterator().next().getInstructionType()); ParsingError error = def.getParsingErrors().iterator().next(); Assert.assertEquals( "Expecting parsing error for '" + line + "'", entry.getValue().getCategory(), ErrorCategory.PARSING ); Assert.assertEquals( "Invalid error code for '" + line + "'", entry.getValue(), error.getErrorCode()); } } @Test public void testRecognizeProperty() { FileDefinition file = new FileDefinition( new File( "some-file" )); String[] validLines = { "property: value;", " property : value ;", "PROPERTY: value; # with an inline comment", "property: value1, value2 , value3;", "property:;", "property : key6 = \" key; 6 \";" }; // Comments do not matter here for( String line : validLines ) { FileDefinitionParser parser = new FileDefinitionParser( null, false ); BlockComponent holder = new BlockComponent( file ); int code = parser.recognizeProperty( line, holder ); Assert.assertEquals( "Expected a YES code for '" + line + "'", FileDefinitionParser.P_CODE_YES, code ); Assert.assertEquals( "No parsing error was expected for '" + line + "'", 0, parser.getFileRelations().getParsingErrors().size()); Assert.assertEquals( "Expected ONE block to be registered for '" + line + "'", 1, holder.getInnerBlocks().size()); BlockProperty prop = (BlockProperty) holder.getInnerBlocks().iterator().next(); Assert.assertEquals( "Expected ONE property for '" + line + "'", AbstractBlock.PROPERTY, prop.getInstructionType()); Assert.assertEquals( "Invalid property name for '" + line + "'", "property", prop.getName().toLowerCase()); } // Exports with quotes and semicolons in values validLines = new String[] { "exports : random[port] key6 = \" key; 6 \";", "exports : random[port] key6 = \" key; 6 \", key7=\"value7\";" }; // Comments do not matter here for( String line : validLines ) { FileDefinitionParser parser = new FileDefinitionParser( null, false ); BlockComponent holder = new BlockComponent( file ); int code = parser.recognizeProperty( line, holder ); Assert.assertEquals( "Expected a YES code for '" + line + "'", FileDefinitionParser.P_CODE_YES, code ); Assert.assertEquals( "No parsing error was expected for '" + line + "'", 0, parser.getFileRelations().getParsingErrors().size()); Assert.assertEquals( "Expected ONE block to be registered for '" + line + "'", 1, holder.getInnerBlocks().size()); BlockProperty prop = (BlockProperty) holder.getInnerBlocks().iterator().next(); Assert.assertEquals( "Expected ONE property for '" + line + "'", AbstractBlock.PROPERTY, prop.getInstructionType()); Assert.assertEquals( "Invalid property name for '" + line + "'", "exports", prop.getName().toLowerCase()); } // In-line comments String[][] commentedLines = { { "property: value;", "" }, { "property: value;", "# stuck comment" }, { "property: value;", "#" }, { "property: value1, value2;", "\t# some in-line comment " } }; for( String[] line : commentedLines ) { FileDefinitionParser parser = new FileDefinitionParser( null, false ); String theLine = line[ 0 ] + line[ 1 ]; BlockComponent holder = new BlockComponent( file ); int code = parser.recognizeProperty( theLine, holder ); Assert.assertEquals( "Expected a YES code for '" + theLine + "'", FileDefinitionParser.P_CODE_YES, code ); Assert.assertEquals( "No parsing error was expected for '" + theLine + "'", 0, parser.getFileRelations().getParsingErrors().size()); Assert.assertEquals( "Expected ONE block to be registered for '" + theLine + "'", 1, holder.getInnerBlocks().size()); BlockProperty prop = (BlockProperty) holder.getInnerBlocks().iterator().next(); Assert.assertEquals( "Expected ONE property for '" + theLine + "'", AbstractBlock.PROPERTY, prop.getInstructionType()); String expected = Utils.isEmptyOrWhitespaces( line[ 1 ]) ? null : line[ 1 ]; Assert.assertEquals( "Invalid in-line comment for '" + theLine + "'", expected, prop.getInlineComment()); } // Invalid lines String[] invalidLines = { "property = value;", "property", "facet", "", " #" }; for( String line : invalidLines ) { FileDefinitionParser parser = new FileDefinitionParser( null, false ); BlockComponent holder = new BlockComponent( file ); int code = parser.recognizeProperty( line, holder ); Assert.assertEquals( "Expected a NO code for '" + line + "'", FileDefinitionParser.P_CODE_NO, code ); } // Test error codes Map<String,ErrorCode> invalidLineToErrorCode = new LinkedHashMap<> (); invalidLineToErrorCode.put( "property: value", ErrorCode.P_PROPERTY_ENDS_WITH_SEMI_COLON ); invalidLineToErrorCode.put( "property:", ErrorCode.P_PROPERTY_ENDS_WITH_SEMI_COLON ); invalidLineToErrorCode.put( "property: value;;", ErrorCode.P_ONE_BLOCK_PER_LINE ); invalidLineToErrorCode.put( "exports : key6 = key; 6 \";", ErrorCode.P_ONE_BLOCK_PER_LINE ); for( Map.Entry<String,ErrorCode> entry : invalidLineToErrorCode.entrySet()) { String line = entry.getKey(); FileDefinitionParser parser = new FileDefinitionParser( null, false ); BlockComponent holder = new BlockComponent( file ); FileDefinition def = parser.getFileRelations(); int code = parser.recognizeProperty( line, holder ); Assert.assertEquals( "Expected a YES code for '" + line + "'", FileDefinitionParser.P_CODE_YES, code ); Assert.assertEquals( "A parsing error was expected for '" + line + "'", 1, def.getParsingErrors().size()); Assert.assertEquals( "Expected ONE block to be registered for '" + line + "'", 1, holder.getInnerBlocks().size()); Assert.assertEquals( "Expected ONE property for '" + line + "'", AbstractBlock.PROPERTY, holder.getInnerBlocks().iterator().next().getInstructionType()); ParsingError error = def.getParsingErrors().iterator().next(); Assert.assertEquals( "Expecting parsing error for '" + line + "'", entry.getValue().getCategory(), ErrorCategory.PARSING ); Assert.assertEquals( "Invalid error code for '" + line + "'", entry.getValue(), error.getErrorCode()); } // Complex errors invalidLines = new String[] { "property: value ; facet toto {", "property: value ; invalid comment" }; for( String line : invalidLines ) { FileDefinitionParser parser = new FileDefinitionParser( null, false ); BlockComponent holder = new BlockComponent( file ); FileDefinition def = parser.getFileRelations(); int code = parser.recognizeProperty( line, holder ); Assert.assertEquals( "Expected a YES code for '" + line + "'", FileDefinitionParser.P_CODE_YES, code ); Assert.assertEquals( "Two parsing errors were expected for '" + line + "'", 2, def.getParsingErrors().size()); Assert.assertEquals( "Expected ONE block to be registered for '" + line + "'", 1, holder.getInnerBlocks().size()); Assert.assertEquals( "Expected ONE property for '" + line + "'", AbstractBlock.PROPERTY, holder.getInnerBlocks().iterator().next().getInstructionType()); Iterator<ParsingError> iterator = def.getParsingErrors().iterator(); ParsingError error = iterator.next(); Assert.assertEquals( "Expecting parsing error for '" + line + "'", error.getErrorCode().getCategory(), ErrorCategory.PARSING ); Assert.assertEquals( "Invalid error code for '" + line + "'", ErrorCode.P_PROPERTY_ENDS_WITH_SEMI_COLON, error.getErrorCode()); error = iterator.next(); Assert.assertEquals( "Expecting parsing error for '" + line + "'", error.getErrorCode().getCategory(), ErrorCategory.PARSING ); Assert.assertEquals( "Invalid error code for '" + line + "'", ErrorCode.P_ONE_BLOCK_PER_LINE, error.getErrorCode()); } } @Test public void testMergeContiguousRegions() { FileDefinition file = new FileDefinition( new File( "some-file" )); FileDefinitionParser parser = new FileDefinitionParser( null, false ); List<AbstractBlock> blocks = new ArrayList<> (); blocks.add( new BlockImport( file )); blocks.add( new BlockImport( file )); parser.mergeContiguousRegions( blocks ); Assert.assertEquals( 2, blocks.size()); blocks.clear(); blocks.add( new BlockProperty( file )); blocks.add( new BlockProperty( file )); parser.mergeContiguousRegions( blocks ); Assert.assertEquals( 2, blocks.size()); blocks.clear(); blocks.add( new BlockComment( file, "# comment 1" )); blocks.add( new BlockComment( file, "# comment 2" )); parser.mergeContiguousRegions( blocks ); Assert.assertEquals( 1, blocks.size()); Assert.assertEquals( AbstractBlock.COMMENT, blocks.get( 0 ).getInstructionType()); blocks.clear(); blocks.add( new BlockComment( file, "# comment 1" )); blocks.add( new BlockBlank( file, "" )); blocks.add( new BlockComment( file, "# comment 2" )); parser.mergeContiguousRegions( blocks ); Assert.assertEquals( 3, blocks.size()); blocks.clear(); blocks.add( new BlockComment( file, "# comment 1" )); blocks.add( new BlockBlank( file, "" )); blocks.add( new BlockComment( file, "# comment 2" )); blocks.add( new BlockComment( file, "# comment 3" )); parser.mergeContiguousRegions( blocks ); Assert.assertEquals( 3, blocks.size()); Assert.assertEquals( AbstractBlock.COMMENT, blocks.get( 0 ).getInstructionType()); Assert.assertEquals( AbstractBlock.BLANK, blocks.get( 1 ).getInstructionType()); Assert.assertEquals( AbstractBlock.COMMENT, blocks.get( 0 ).getInstructionType()); blocks.clear(); blocks.add( new BlockBlank( file, "" )); blocks.add( new BlockBlank( file, "" )); parser.mergeContiguousRegions( blocks ); Assert.assertEquals( 1, blocks.size()); Assert.assertEquals( AbstractBlock.BLANK, blocks.get( 0 ).getInstructionType()); blocks.clear(); blocks.add( new BlockBlank( file, "" )); blocks.add( new BlockComment( file, "# comment 1" )); blocks.add( new BlockBlank( file, "" )); parser.mergeContiguousRegions( blocks ); Assert.assertEquals( 3, blocks.size()); blocks.clear(); blocks.add( new BlockBlank( file, "" )); blocks.add( new BlockBlank( file, "" )); blocks.add( new BlockComment( file, "# comment 1" )); blocks.add( new BlockBlank( file, "" )); parser.mergeContiguousRegions( blocks ); Assert.assertEquals( 3, blocks.size()); Assert.assertEquals( AbstractBlock.BLANK, blocks.get( 0 ).getInstructionType()); Assert.assertEquals( AbstractBlock.COMMENT, blocks.get( 1 ).getInstructionType()); Assert.assertEquals( AbstractBlock.BLANK, blocks.get( 0 ).getInstructionType()); } @Test public void testRecognizeFacet() throws Exception { Map<String,ParsingError> resourceNameToErrorCode = new LinkedHashMap<> (); resourceNameToErrorCode.put( "facet-invalid-property.graph", new ParsingError( ErrorCode.P_INVALID_PROPERTY, null, 2 )); resourceNameToErrorCode.put( "facet-invalid-end.graph", new ParsingError( ErrorCode.P_C_C_BRACKET_EXTRA_CHARACTERS, null, 3 )); resourceNameToErrorCode.put( "facet-missing-closing-cb.graph", new ParsingError( ErrorCode.P_C_C_BRACKET_MISSING, null, 3 )); resourceNameToErrorCode.put( "facet-missing-opening-cb.graph", new ParsingError( ErrorCode.P_O_C_BRACKET_MISSING, null, 1 )); resourceNameToErrorCode.put( "facet-extra-char.graph", new ParsingError( ErrorCode.P_O_C_BRACKET_EXTRA_CHARACTERS, null, 1 )); resourceNameToErrorCode.put( "facet-line-number.graph", new ParsingError( ErrorCode.P_C_C_BRACKET_MISSING, null, 6 )); testRecognizePropertiesHolder( resourceNameToErrorCode, AbstractBlock.FACET ); } @Test public void testRecognizeComponent() throws Exception { Map<String,ParsingError> resourceNameToErrorCode = new LinkedHashMap<> (); resourceNameToErrorCode.put( "component-invalid-property.graph", new ParsingError( ErrorCode.P_INVALID_PROPERTY, null, 2 )); resourceNameToErrorCode.put( "component-invalid-end.graph", new ParsingError( ErrorCode.P_C_C_BRACKET_EXTRA_CHARACTERS, null, 3 )); resourceNameToErrorCode.put( "component-missing-closing-cb.graph", new ParsingError( ErrorCode.P_C_C_BRACKET_MISSING, null, 3 )); resourceNameToErrorCode.put( "component-missing-opening-cb.graph", new ParsingError( ErrorCode.P_O_C_BRACKET_MISSING, null, 1 )); resourceNameToErrorCode.put( "component-extra-char.graph", new ParsingError( ErrorCode.P_O_C_BRACKET_EXTRA_CHARACTERS, null, 1 )); resourceNameToErrorCode.put( "component-line-number.graph", new ParsingError( ErrorCode.P_C_C_BRACKET_MISSING, null, 6 )); testRecognizePropertiesHolder( resourceNameToErrorCode, AbstractBlock.COMPONENT ); } @Test public void testRecognizeInstanceOf() throws Exception { Map<String,ParsingError> resourceNameToErrorCode = new LinkedHashMap<> (); resourceNameToErrorCode.put( "instanceof-invalid-property.instances", new ParsingError( ErrorCode.P_INVALID_PROPERTY_OR_INSTANCE, null, 2 )); resourceNameToErrorCode.put( "instanceof-invalid-property-2.instances", new ParsingError( ErrorCode.P_INVALID_PROPERTY_OR_INSTANCE, null, 3 )); resourceNameToErrorCode.put( "instanceof-invalid-end.instances", new ParsingError( ErrorCode.P_C_C_BRACKET_EXTRA_CHARACTERS, null, 3 )); resourceNameToErrorCode.put( "instanceof-missing-closing-cb.instances", new ParsingError( ErrorCode.P_C_C_BRACKET_MISSING, null, 3 )); resourceNameToErrorCode.put( "instanceof-missing-opening-cb.instances", new ParsingError( ErrorCode.P_O_C_BRACKET_MISSING, null, 1 )); resourceNameToErrorCode.put( "instanceof-extra-char.instances", new ParsingError( ErrorCode.P_O_C_BRACKET_EXTRA_CHARACTERS, null, 1 )); resourceNameToErrorCode.put( "instanceof-line-number.instances", new ParsingError( ErrorCode.P_C_C_BRACKET_MISSING, null, 6 )); resourceNameToErrorCode.put( "instanceof-imbricated-invalid-property.instances", new ParsingError( ErrorCode.P_INVALID_PROPERTY_OR_INSTANCE, null, 4 )); resourceNameToErrorCode.put( "instanceof-imbricated-invalid-end.instances", new ParsingError( ErrorCode.P_C_C_BRACKET_EXTRA_CHARACTERS, null, 5 )); resourceNameToErrorCode.put( "instanceof-imbricated-missing-closing-cb.instances", new ParsingError( ErrorCode.P_C_C_BRACKET_MISSING, null, 7 )); resourceNameToErrorCode.put( "instanceof-imbricated-missing-opening-cb.instances", new ParsingError( ErrorCode.P_O_C_BRACKET_MISSING, null, 3 )); resourceNameToErrorCode.put( "instanceof-imbricated-extra-char.instances", new ParsingError( ErrorCode.P_O_C_BRACKET_EXTRA_CHARACTERS, null, 3 )); resourceNameToErrorCode.put( "instanceof-very-imbricated-invalid-property.instances", new ParsingError( ErrorCode.P_INVALID_PROPERTY_OR_INSTANCE, null, 5 )); resourceNameToErrorCode.put( "instanceof-very-imbricated-invalid-end.instances", new ParsingError( ErrorCode.P_C_C_BRACKET_EXTRA_CHARACTERS, null, 6 )); resourceNameToErrorCode.put( "instanceof-very-imbricated-missing-closing-cb.instances", new ParsingError( ErrorCode.P_C_C_BRACKET_MISSING, null, 8 )); resourceNameToErrorCode.put( "instanceof-very-imbricated-missing-opening-cb.instances", new ParsingError( ErrorCode.P_O_C_BRACKET_MISSING, null, 5 )); resourceNameToErrorCode.put( "instanceof-very-imbricated-extra-char.instances", new ParsingError( ErrorCode.P_O_C_BRACKET_EXTRA_CHARACTERS, null, 4 )); testRecognizePropertiesHolder( resourceNameToErrorCode, AbstractBlock.INSTANCEOF ); } private void testRecognizePropertiesHolder( Map<String,ParsingError> resourceNameToErrorCode, int blockType ) throws Exception { final String root = "/configurations/invalid/"; for( Map.Entry<String,ParsingError> entry : resourceNameToErrorCode.entrySet()) { BufferedReader br = null; try { File f = TestUtils.findTestFile( root + entry.getKey()); Assert.assertNotNull( f ); Assert.assertTrue( f.getName(), f.exists()); br = new BufferedReader( new InputStreamReader( new FileInputStream( f ), "UTF-8" )); String line = br.readLine(); Assert.assertNotNull( line ); // This test skips the #read() method. // Therefore, the first line is considered as not being read. // We have to counter-balance this by updating the current line number. FileDefinitionParser parser = new FileDefinitionParser( f, false ); parser.currentLineNumber = 1; if( blockType == AbstractBlock.FACET ) parser.recognizeFacet( line, br ); else if( blockType == AbstractBlock.COMPONENT ) parser.recognizeComponent( line, br ); else if( blockType == AbstractBlock.INSTANCEOF ) parser.recognizeInstanceOf( line, br, null ); else Assert.fail( "Invalid block type." ); Assert.assertEquals( "ONE parsing error was expected for '" + entry.getKey() + "'", 1, parser.getFileRelations().getParsingErrors().size()); ParsingError error = parser.getFileRelations().getParsingErrors().iterator().next(); Assert.assertEquals( "Expected error code " + entry.getValue().getErrorCode() + " for '" + entry.getKey() + "'", entry.getValue().getErrorCode(), error.getErrorCode()); Assert.assertEquals( "Expected error line to be " + entry.getValue().getLine() + " for '" + entry.getKey() + "'", entry.getValue().getLine(), error.getLine()); Assert.assertEquals( "Expected a parsing error for '" + entry.getKey() + "'", ErrorCategory.PARSING, error.getErrorCode().getCategory()); Assert.assertEquals( f, error.getFile()); } finally { Utils.closeQuietly( br ); } } } @Test public void testComplexInstancesParsing() { // Parse the file FileDefinition def; File f; try { f = TestUtils.findTestFile( "/configurations/valid/instance-imbricated-3.instances" ); def = ParsingModelIo.readConfigurationFile( f, false ); } catch( Exception e ) { Assert.fail( "Failed to find the file." ); return; } // Make some checks to be sure it is parsed correctly Assert.assertEquals( FileDefinition.INSTANCE, def.getFileType()); Assert.assertEquals( f, def.getEditedFile()); Assert.assertEquals( 0, def.getParsingErrors().size()); // Check blocks Assert.assertEquals( AbstractBlock.COMMENT, def.getBlocks().get( 0 ).getInstructionType()); Assert.assertEquals( AbstractBlock.BLANK, def.getBlocks().get( 1 ).getInstructionType()); Assert.assertEquals( AbstractBlock.INSTANCEOF, def.getBlocks().get( 2 ).getInstructionType()); Assert.assertEquals( AbstractBlock.BLANK, def.getBlocks().get( 3 ).getInstructionType()); Assert.assertEquals( AbstractBlock.INSTANCEOF, def.getBlocks().get( 4 ).getInstructionType()); Assert.assertEquals( AbstractBlock.BLANK, def.getBlocks().get( 5 ).getInstructionType()); Assert.assertEquals( 6, def.getBlocks().size()); // Check instance 1 BlockInstanceOf block = (BlockInstanceOf) def.getBlocks().get( 2 ); Assert.assertEquals( "vm", block.getName()); Assert.assertEquals( AbstractBlock.PROPERTY, block.getInnerBlocks().get( 0 ).getInstructionType()); Assert.assertEquals( AbstractBlock.BLANK, block.getInnerBlocks().get( 1 ).getInstructionType()); Assert.assertEquals( AbstractBlock.INSTANCEOF, block.getInnerBlocks().get( 2 ).getInstructionType()); Assert.assertEquals( 3, block.getInnerBlocks().size()); Assert.assertEquals( "name", ((BlockProperty) block.getInnerBlocks().get( 0 )).getName()); Assert.assertEquals( "vm1", ((BlockProperty) block.getInnerBlocks().get( 0 )).getValue()); Assert.assertFalse( Utils.isEmptyOrWhitespaces(((BlockProperty) block.getInnerBlocks().get( 0 )).getInlineComment())); block = (BlockInstanceOf) block.getInnerBlocks().get( 2 ); Assert.assertEquals( "server", block.getName()); Assert.assertEquals( AbstractBlock.PROPERTY, block.getInnerBlocks().get( 0 ).getInstructionType()); Assert.assertEquals( AbstractBlock.PROPERTY, block.getInnerBlocks().get( 1 ).getInstructionType()); Assert.assertEquals( AbstractBlock.BLANK, block.getInnerBlocks().get( 2 ).getInstructionType()); Assert.assertEquals( AbstractBlock.INSTANCEOF, block.getInnerBlocks().get( 3 ).getInstructionType()); Assert.assertEquals( 4, block.getInnerBlocks().size()); Assert.assertEquals( "name", ((BlockProperty) block.getInnerBlocks().get( 0 )).getName()); Assert.assertEquals( "server", ((BlockProperty) block.getInnerBlocks().get( 0 )).getValue()); Assert.assertTrue( Utils.isEmptyOrWhitespaces(((BlockProperty) block.getInnerBlocks().get( 0 )).getInlineComment())); Assert.assertEquals( "port", ((BlockProperty) block.getInnerBlocks().get( 1 )).getName()); Assert.assertEquals( "9878", ((BlockProperty) block.getInnerBlocks().get( 1 )).getValue()); block = (BlockInstanceOf) block.getInnerBlocks().get( 3 ); Assert.assertEquals( "web-app1", block.getName()); Assert.assertEquals( AbstractBlock.PROPERTY, block.getInnerBlocks().get( 0 ).getInstructionType()); Assert.assertEquals( 1, block.getInnerBlocks().size()); Assert.assertEquals( "name", ((BlockProperty) block.getInnerBlocks().get( 0 )).getName()); Assert.assertEquals( "web-app1-1", ((BlockProperty) block.getInnerBlocks().get( 0 )).getValue()); Assert.assertTrue( Utils.isEmptyOrWhitespaces(((BlockProperty) block.getInnerBlocks().get( 0 )).getInlineComment())); // Check instance 2 block = (BlockInstanceOf) def.getBlocks().get( 4 ); Assert.assertEquals( "vm", block.getName()); Assert.assertEquals( AbstractBlock.BLANK, block.getInnerBlocks().get( 0 ).getInstructionType()); Assert.assertEquals( AbstractBlock.PROPERTY, block.getInnerBlocks().get( 1 ).getInstructionType()); Assert.assertEquals( AbstractBlock.PROPERTY, block.getInnerBlocks().get( 2 ).getInstructionType()); Assert.assertEquals( AbstractBlock.BLANK, block.getInnerBlocks().get( 3 ).getInstructionType()); Assert.assertEquals( AbstractBlock.INSTANCEOF, block.getInnerBlocks().get( 4 ).getInstructionType()); Assert.assertEquals( 5, block.getInnerBlocks().size()); Assert.assertEquals( "name", ((BlockProperty) block.getInnerBlocks().get( 1 )).getName()); Assert.assertEquals( "vm-", ((BlockProperty) block.getInnerBlocks().get( 1 )).getValue()); Assert.assertFalse( Utils.isEmptyOrWhitespaces(((BlockProperty) block.getInnerBlocks().get( 1 )).getInlineComment())); Assert.assertEquals( "count", ((BlockProperty) block.getInnerBlocks().get( 2 )).getName()); Assert.assertEquals( "7", ((BlockProperty) block.getInnerBlocks().get( 2 )).getValue()); Assert.assertTrue( Utils.isEmptyOrWhitespaces(((BlockProperty) block.getInnerBlocks().get( 2 )).getInlineComment())); block = (BlockInstanceOf) block.getInnerBlocks().get( 4 ); Assert.assertEquals( "server", block.getName()); Assert.assertEquals( AbstractBlock.PROPERTY, block.getInnerBlocks().get( 0 ).getInstructionType()); Assert.assertEquals( AbstractBlock.PROPERTY, block.getInnerBlocks().get( 1 ).getInstructionType()); Assert.assertEquals( AbstractBlock.BLANK, block.getInnerBlocks().get( 2 ).getInstructionType()); Assert.assertEquals( AbstractBlock.INSTANCEOF, block.getInnerBlocks().get( 3 ).getInstructionType()); Assert.assertEquals( 4, block.getInnerBlocks().size()); Assert.assertEquals( "name", ((BlockProperty) block.getInnerBlocks().get( 0 )).getName()); Assert.assertEquals( "server4osgi", ((BlockProperty) block.getInnerBlocks().get( 0 )).getValue()); Assert.assertTrue( Utils.isEmptyOrWhitespaces(((BlockProperty) block.getInnerBlocks().get( 0 )).getInlineComment())); Assert.assertEquals( "port", ((BlockProperty) block.getInnerBlocks().get( 1 )).getName()); Assert.assertEquals( "9878", ((BlockProperty) block.getInnerBlocks().get( 1 )).getValue()); block = (BlockInstanceOf) block.getInnerBlocks().get( 3 ); Assert.assertEquals( "osgi-container", block.getName()); Assert.assertEquals( AbstractBlock.PROPERTY, block.getInnerBlocks().get( 0 ).getInstructionType()); Assert.assertEquals( AbstractBlock.BLANK, block.getInnerBlocks().get( 1 ).getInstructionType()); Assert.assertEquals( AbstractBlock.INSTANCEOF, block.getInnerBlocks().get( 2 ).getInstructionType()); Assert.assertEquals( 3, block.getInnerBlocks().size()); Assert.assertEquals( "name", ((BlockProperty) block.getInnerBlocks().get( 0 )).getName()); Assert.assertEquals( "osgi-container-app", ((BlockProperty) block.getInnerBlocks().get( 0 )).getValue()); Assert.assertTrue( Utils.isEmptyOrWhitespaces(((BlockProperty) block.getInnerBlocks().get( 0 )).getInlineComment())); block = (BlockInstanceOf) block.getInnerBlocks().get( 2 ); Assert.assertEquals( "bundle", block.getName()); Assert.assertEquals( AbstractBlock.COMMENT, block.getInnerBlocks().get( 0 ).getInstructionType()); Assert.assertEquals( AbstractBlock.PROPERTY, block.getInnerBlocks().get( 1 ).getInstructionType()); Assert.assertEquals( 2, block.getInnerBlocks().size()); Assert.assertEquals( "name", ((BlockProperty) block.getInnerBlocks().get( 1 )).getName()); Assert.assertEquals( "my-bundle", ((BlockProperty) block.getInnerBlocks().get( 1 )).getValue()); Assert.assertTrue( Utils.isEmptyOrWhitespaces(((BlockProperty) block.getInnerBlocks().get( 1 )).getInlineComment())); } @Test public void testParsingWithRuntimeInformation() { // Parse the file FileDefinition def; File f; try { f = TestUtils.findTestFile( "/configurations/valid/single-runtime-instance.instances" ); def = ParsingModelIo.readConfigurationFile( f, false ); } catch( Exception e ) { Assert.fail( "Failed to find the file." ); return; } // Make some checks to be sure it is parsed correctly Assert.assertEquals( FileDefinition.INSTANCE, def.getFileType()); Assert.assertEquals( f, def.getEditedFile()); Assert.assertEquals( 0, def.getParsingErrors().size()); } @Test public void testLoadGraph_withImportedVariables_andInheritance() throws Exception { File file = TestUtils.findTestFile( "/configurations/valid/extending-component-with-imported-variables.graph" ); FromGraphDefinition fromDef = new FromGraphDefinition( file.getParentFile()); Graphs graph = fromDef.buildGraphs( file ); Assert.assertEquals( 0, fromDef.getErrors().size()); Assert.assertEquals( 4, ComponentHelpers.findAllComponents( graph ).size()); Component vmComponent = ComponentHelpers.findComponent( graph, "VM" ); Component dbComponent = ComponentHelpers.findComponent( graph, "db" ); Component serverComponent = ComponentHelpers.findComponent( graph, "server" ); Component myServerComponent = ComponentHelpers.findComponent( graph, "my-server" ); Collection<Component> children = ComponentHelpers.findAllChildren( vmComponent ); Assert.assertEquals( 3, children.size()); Assert.assertTrue( children.contains( dbComponent )); Assert.assertTrue( children.contains( serverComponent )); Assert.assertTrue( children.contains( myServerComponent )); Assert.assertNotNull( serverComponent.importedVariables.get( "db.ip" )); Assert.assertTrue( serverComponent.importedVariables.get( "db.ip" ).isOptional()); Assert.assertNotNull( serverComponent.importedVariables.get( "db.port" )); Assert.assertTrue( serverComponent.importedVariables.get( "db.port" ).isOptional()); Map<String,ImportedVariable> imports = ComponentHelpers.findAllImportedVariables( serverComponent ); Assert.assertEquals( 2, imports.size()); Assert.assertNotNull( imports.get( "db.ip" )); Assert.assertTrue( imports.get( "db.ip" ).isOptional()); Assert.assertNotNull( imports.get( "db.port" )); Assert.assertTrue( imports.get( "db.port" ).isOptional()); Assert.assertNotNull( myServerComponent.importedVariables.get( "db.ip" )); Assert.assertFalse( myServerComponent.importedVariables.get( "db.ip" ).isOptional()); Assert.assertNull( myServerComponent.importedVariables.get( "db.port" )); imports = ComponentHelpers.findAllImportedVariables( myServerComponent ); Assert.assertEquals( 2, imports.size()); Assert.assertNotNull( imports.get( "db.ip" )); Assert.assertFalse( imports.get( "db.ip" ).isOptional()); Assert.assertNotNull( imports.get( "db.port" )); Assert.assertTrue( imports.get( "db.port" ).isOptional()); } @Test public void testNextLine() throws Exception { FileDefinitionParser parser = new FileDefinitionParser( new File( "whatever" ), true ); Assert.assertEquals( 0, parser.currentLineNumber ); StringBuilder sb = new StringBuilder(); sb.append( "# this is a comment\n" ); sb.append( "\n" ); sb.append( "VM {\n" ); sb.append( "\tinstaller: target; # !!!\n" ); sb.append( "\n" ); sb.append( "}\n" ); sb.append( "\r\n" ); sb.append( "\n" ); BufferedReader br = new BufferedReader( new StringReader( sb.toString())); Assert.assertEquals( "# this is a comment", parser.nextLine( br )); Assert.assertEquals( 1, parser.currentLineNumber ); Assert.assertEquals( "", parser.nextLine( br )); Assert.assertEquals( 2, parser.currentLineNumber ); Assert.assertEquals( "VM {", parser.nextLine( br )); Assert.assertEquals( 3, parser.currentLineNumber ); Assert.assertEquals( "\tinstaller: target; # !!!", parser.nextLine( br )); Assert.assertEquals( 4, parser.currentLineNumber ); Assert.assertEquals( "", parser.nextLine( br )); Assert.assertEquals( 5, parser.currentLineNumber ); Assert.assertEquals( "}", parser.nextLine( br )); Assert.assertEquals( 6, parser.currentLineNumber ); Assert.assertEquals( "", parser.nextLine( br )); Assert.assertEquals( 7, parser.currentLineNumber ); Assert.assertEquals( "", parser.nextLine( br )); Assert.assertEquals( 8, parser.currentLineNumber ); } }